summaryrefslogtreecommitdiffstats
path: root/servers
diff options
context:
space:
mode:
Diffstat (limited to 'servers')
-rw-r--r--servers/audio/audio_driver_dummy.h2
-rw-r--r--servers/audio/audio_stream.cpp49
-rw-r--r--servers/audio/audio_stream.h6
-rw-r--r--servers/audio_server.cpp84
-rw-r--r--servers/audio_server.h12
-rw-r--r--servers/camera/camera_feed.cpp20
-rw-r--r--servers/camera/camera_feed.h5
-rw-r--r--servers/camera_server.cpp26
-rw-r--r--servers/camera_server.h2
-rw-r--r--servers/display_server.cpp9
-rw-r--r--servers/display_server.h4
-rw-r--r--servers/display_server_headless.h4
-rw-r--r--servers/navigation_server_2d_dummy.h4
-rw-r--r--servers/rendering/dummy/rasterizer_dummy.h16
-rw-r--r--servers/rendering/dummy/storage/light_storage.h2
-rw-r--r--servers/rendering/dummy/storage/material_storage.h2
-rw-r--r--servers/rendering/dummy/storage/mesh_storage.h2
-rw-r--r--servers/rendering/dummy/storage/texture_storage.h26
-rw-r--r--servers/rendering/dummy/storage/utilities.h2
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp3
-rw-r--r--servers/rendering/renderer_compositor.h2
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.cpp18
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.h1
-rw-r--r--servers/rendering/renderer_rd/environment/fog.cpp84
-rw-r--r--servers/rendering/renderer_rd/environment/fog.h4
-rw-r--r--servers/rendering/renderer_rd/environment/gi.cpp2
-rw-r--r--servers/rendering/renderer_rd/environment/gi.h6
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp4
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp12
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp8
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h20
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp41
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp12
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h39
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp422
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h82
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp14
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.h6
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp1
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h2
-rw-r--r--servers/rendering/renderer_rd/shaders/blit.glsl18
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl5
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl44
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl37
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl328
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl75
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.cpp19
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.h13
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.h6
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.h8
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.cpp35
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.h8
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h1
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp4
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.h19
-rw-r--r--servers/rendering/renderer_rd/storage_rd/utilities.h4
-rw-r--r--servers/rendering/renderer_scene_cull.cpp25
-rw-r--r--servers/rendering/renderer_scene_cull.h2
-rw-r--r--servers/rendering/renderer_scene_occlusion_cull.h10
-rw-r--r--servers/rendering/renderer_scene_render.cpp14
-rw-r--r--servers/rendering/renderer_scene_render.h9
-rw-r--r--servers/rendering/rendering_device.cpp140
-rw-r--r--servers/rendering/rendering_device.h6
-rw-r--r--servers/rendering/rendering_device_binds.cpp5
-rw-r--r--servers/rendering/rendering_device_driver.cpp2
-rw-r--r--servers/rendering/rendering_device_driver.h18
-rw-r--r--servers/rendering/rendering_device_graph.cpp91
-rw-r--r--servers/rendering/rendering_device_graph.h26
-rw-r--r--servers/rendering/rendering_method.h1
-rw-r--r--servers/rendering/rendering_server_default.cpp2
-rw-r--r--servers/rendering/rendering_server_default.h5
-rw-r--r--servers/rendering/shader_compiler.cpp10
-rw-r--r--servers/rendering/shader_language.cpp129
-rw-r--r--servers/rendering/shader_language.h6
-rw-r--r--servers/rendering/shader_preprocessor.cpp34
-rw-r--r--servers/rendering/shader_preprocessor.h1
-rw-r--r--servers/rendering/shader_types.cpp11
-rw-r--r--servers/rendering/storage/camera_attributes_storage.h4
-rw-r--r--servers/rendering/storage/environment_storage.cpp12
-rw-r--r--servers/rendering/storage/environment_storage.h5
-rw-r--r--servers/rendering/storage/light_storage.h2
-rw-r--r--servers/rendering/storage/render_scene_buffers.cpp2
-rw-r--r--servers/rendering_server.cpp18
-rw-r--r--servers/rendering_server.h5
-rw-r--r--servers/text/text_server_dummy.h2
-rw-r--r--servers/text_server.h4
-rw-r--r--servers/xr/xr_interface.cpp4
-rw-r--r--servers/xr/xr_interface.h2
-rw-r--r--servers/xr/xr_positional_tracker.cpp6
-rw-r--r--servers/xr/xr_tracker.cpp10
92 files changed, 1565 insertions, 758 deletions
diff --git a/servers/audio/audio_driver_dummy.h b/servers/audio/audio_driver_dummy.h
index 823bad1d2e..96f8182732 100644
--- a/servers/audio/audio_driver_dummy.h
+++ b/servers/audio/audio_driver_dummy.h
@@ -61,7 +61,7 @@ class AudioDriverDummy : public AudioDriver {
public:
virtual const char *get_name() const override {
return "Dummy";
- };
+ }
virtual Error init() override;
virtual void start() override;
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp
index 1886ebe1ac..d5c37c2acc 100644
--- a/servers/audio/audio_stream.cpp
+++ b/servers/audio/audio_stream.cpp
@@ -76,6 +76,42 @@ int AudioStreamPlayback::mix(AudioFrame *p_buffer, float p_rate_scale, int p_fra
return ret;
}
+PackedVector2Array AudioStreamPlayback::_mix_audio_bind(float p_rate_scale, int p_frames) {
+ Vector<AudioFrame> frames = mix_audio(p_rate_scale, p_frames);
+
+ PackedVector2Array res;
+ res.resize(frames.size());
+
+ Vector2 *res_ptrw = res.ptrw();
+ for (int i = 0; i < frames.size(); i++) {
+ res_ptrw[i] = Vector2(frames[i].left, frames[i].right);
+ }
+
+ return res;
+}
+
+Vector<AudioFrame> AudioStreamPlayback::mix_audio(float p_rate_scale, int p_frames) {
+ Vector<AudioFrame> res;
+ res.resize(p_frames);
+
+ int frames = mix(res.ptrw(), p_rate_scale, p_frames);
+ res.resize(frames);
+
+ return res;
+}
+
+void AudioStreamPlayback::start_playback(double p_from_pos) {
+ start(p_from_pos);
+}
+
+void AudioStreamPlayback::stop_playback() {
+ stop();
+}
+
+void AudioStreamPlayback::seek_playback(double p_time) {
+ seek(p_time);
+}
+
void AudioStreamPlayback::tag_used_streams() {
GDVIRTUAL_CALL(_tag_used_streams);
}
@@ -108,6 +144,13 @@ void AudioStreamPlayback::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sample_playback", "playback_sample"), &AudioStreamPlayback::set_sample_playback);
ClassDB::bind_method(D_METHOD("get_sample_playback"), &AudioStreamPlayback::get_sample_playback);
+ ClassDB::bind_method(D_METHOD("mix_audio", "rate_scale", "frames"), &AudioStreamPlayback::_mix_audio_bind);
+ ClassDB::bind_method(D_METHOD("start", "from_pos"), &AudioStreamPlayback::start_playback, DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("seek", "time"), &AudioStreamPlayback::seek_playback, DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayback::stop_playback);
+ ClassDB::bind_method(D_METHOD("get_loop_count"), &AudioStreamPlayback::get_loop_count);
+ ClassDB::bind_method(D_METHOD("get_playback_position"), &AudioStreamPlayback::get_playback_position);
+ ClassDB::bind_method(D_METHOD("is_playing"), &AudioStreamPlayback::is_playing);
}
AudioStreamPlayback::AudioStreamPlayback() {}
@@ -238,7 +281,7 @@ double AudioStream::get_bpm() const {
}
bool AudioStream::has_loop() const {
- bool ret = 0;
+ bool ret = false;
GDVIRTUAL_CALL(_has_loop, ret);
return ret;
}
@@ -347,7 +390,7 @@ int AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fra
Vector<int32_t> buf = AudioDriver::get_singleton()->get_input_buffer();
unsigned int input_size = AudioDriver::get_singleton()->get_input_size();
- int mix_rate = AudioDriver::get_singleton()->get_mix_rate();
+ int mix_rate = AudioDriver::get_singleton()->get_input_mix_rate();
unsigned int playback_delay = MIN(((50 * mix_rate) / 1000) * 2, buf.size() >> 1);
#ifdef DEBUG_ENABLED
unsigned int input_position = AudioDriver::get_singleton()->get_input_position();
@@ -398,7 +441,7 @@ int AudioStreamPlaybackMicrophone::mix(AudioFrame *p_buffer, float p_rate_scale,
}
float AudioStreamPlaybackMicrophone::get_stream_sampling_rate() {
- return AudioDriver::get_singleton()->get_mix_rate();
+ return AudioDriver::get_singleton()->get_input_mix_rate();
}
void AudioStreamPlaybackMicrophone::start(double p_from_pos) {
diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h
index 3feaa53630..65efccdc28 100644
--- a/servers/audio/audio_stream.h
+++ b/servers/audio/audio_stream.h
@@ -83,6 +83,7 @@ class AudioStreamPlayback : public RefCounted {
protected:
static void _bind_methods();
+ PackedVector2Array _mix_audio_bind(float p_rate_scale, int p_frames);
GDVIRTUAL1(_start, double)
GDVIRTUAL0(_stop)
GDVIRTUAL0RC(bool, _is_playing)
@@ -118,6 +119,11 @@ public:
AudioStreamPlayback();
~AudioStreamPlayback();
+
+ Vector<AudioFrame> mix_audio(float p_rate_scale, int p_frames);
+ void start_playback(double p_from_pos = 0.0);
+ void stop_playback();
+ void seek_playback(double p_time);
};
class AudioStreamPlaybackResampled : public AudioStreamPlayback {
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 70ef88e36d..63b2f28e74 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -371,10 +371,14 @@ void AudioServer::_mix_step() {
bus->soloed = false;
}
}
+ // This is legacy code from 3.x that allows video players and other audio sources that do not implement AudioStreamPlayback to output audio.
for (CallbackItem *ci : mix_callback_list) {
ci->callback(ci->userdata);
}
+ // Main mixing loop for audio streams.
+ // The basic idea here is to copy the samples returned by the AudioStreamPlayback's mix function into the audio buffers,
+ // while always maintaining a lookahead buffer of size LOOKAHEAD_BUFFER_SIZE to allow fade-outs for sudden stoppages.
for (AudioStreamPlaybackListNode *playback : playback_list) {
// Paused streams are no-ops. Don't even mix audio from the stream playback.
if (playback->state.load() == AudioStreamPlaybackListNode::PAUSED) {
@@ -385,22 +389,26 @@ void AudioServer::_mix_step() {
continue;
}
+ // If `fading_out` is true, we're in the process of fading out the stream playback.
+ // TODO: Currently this sets the volume of the stream to 0 which creates a linear interpolation between its previous volume and silence.
+ // A more punchy option for fading out could be to just use the lookahead buffer.
bool fading_out = playback->state.load() == AudioStreamPlaybackListNode::FADE_OUT_TO_DELETION || playback->state.load() == AudioStreamPlaybackListNode::FADE_OUT_TO_PAUSE;
AudioFrame *buf = mix_buffer.ptrw();
- // Copy the lookeahead buffer into the mix buffer.
+ // Copy the old contents of the lookahead buffer into the beginning of the mix buffer.
for (int i = 0; i < LOOKAHEAD_BUFFER_SIZE; i++) {
buf[i] = playback->lookahead[i];
}
- // Mix the audio stream
+ // Mix the audio stream.
unsigned int mixed_frames = playback->stream_playback->mix(&buf[LOOKAHEAD_BUFFER_SIZE], playback->pitch_scale.get(), buffer_size);
if (tag_used_audio_streams && playback->stream_playback->is_playing()) {
playback->stream_playback->tag_used_streams();
}
+ // Check to see if the stream has run out of samples.
if (mixed_frames != buffer_size) {
// We know we have at least the size of our lookahead buffer for fade-out purposes.
@@ -416,42 +424,52 @@ void AudioServer::_mix_step() {
new_state = AudioStreamPlaybackListNode::AWAITING_DELETION;
playback->state.store(new_state);
} else {
- // Move the last little bit of what we just mixed into our lookahead buffer.
+ // Move the last little bit of what we just mixed into our lookahead buffer for the next call to _mix_step.
for (int i = 0; i < LOOKAHEAD_BUFFER_SIZE; i++) {
playback->lookahead[i] = buf[buffer_size + i];
}
}
- AudioStreamPlaybackBusDetails *ptr = playback->bus_details.load();
- ERR_FAIL_NULL(ptr);
- // By putting null into the bus details pointers, we're taking ownership of their memory for the duration of this mix.
- AudioStreamPlaybackBusDetails bus_details = *ptr;
+ // Get the bus details for this playback. This contains information about which buses the playback is assigned to and the volume of the playback on each bus.
+ AudioStreamPlaybackBusDetails *bus_details_ptr = playback->bus_details.load();
+ ERR_FAIL_NULL(bus_details_ptr);
+ // Make a copy of the bus details so we can modify it without worrying about other threads.
+ AudioStreamPlaybackBusDetails bus_details = *bus_details_ptr;
// Mix to any active buses.
for (int idx = 0; idx < MAX_BUSES_PER_PLAYBACK; idx++) {
if (!bus_details.bus_active[idx]) {
continue;
}
+ // This is the AudioServer-internal index of the bus we're mixing to in this step of the loop. Not to be confused with `idx` which is an index into `AudioStreamPlaybackBusDetails` member var arrays.
int bus_idx = thread_find_bus_index(bus_details.bus[idx]);
+ // It's important to know whether or not this bus was active in the previous mix step of this stream. If it was, we need to perform volume interpolation to avoid pops.
int prev_bus_idx = -1;
for (int search_idx = 0; search_idx < MAX_BUSES_PER_PLAYBACK; search_idx++) {
if (!playback->prev_bus_details->bus_active[search_idx]) {
continue;
}
+ // If the StringNames of the buses match, we've found the previous bus index. This indicates that this playback mixed to `prev_bus_details->bus[prev_bus_index]` in the previous mix step, which gives us a way to look up the playback's previous volume.
if (playback->prev_bus_details->bus[search_idx].hash() == bus_details.bus[idx].hash()) {
prev_bus_idx = search_idx;
+ break;
}
}
+ // It's now time to mix to the bus. We do this by going through each channel of the bus and mixing to it.
+ // The channels correspond to output channels of the audio device, e.g. stereo or 5.1. To reduce needless nesting, this is done with a helper method named `_mix_step_for_channel`.
for (int channel_idx = 0; channel_idx < channel_count; channel_idx++) {
AudioFrame *channel_buf = thread_get_channel_mix_buffer(bus_idx, channel_idx);
+ // TODO: This `fading_out` check could be replaced with with an exponential fadeout of the samples from the lookahead buffer for more punchy results.
if (fading_out) {
bus_details.volume[idx][channel_idx] = AudioFrame(0, 0);
}
AudioFrame channel_vol = bus_details.volume[idx][channel_idx];
- AudioFrame prev_channel_vol = AudioFrame(0, 0);
+ // If this bus was not active in the previous mix step, we want to start playback at the full volume to avoid crushing transients.
+ AudioFrame prev_channel_vol = channel_vol;
+ // If this bus was active in the previous mix step, we need to interpolate between the previous volume and the current volume to avoid pops. Set `prev_channel_volume` accordingly.
if (prev_bus_idx != -1) {
prev_channel_vol = playback->prev_bus_details->volume[prev_bus_idx][channel_idx];
}
@@ -480,7 +498,7 @@ void AudioServer::_mix_step() {
for (int channel_idx = 0; channel_idx < channel_count; channel_idx++) {
AudioFrame *channel_buf = thread_get_channel_mix_buffer(bus_idx, channel_idx);
AudioFrame prev_channel_vol = playback->prev_bus_details->volume[idx][channel_idx];
- // Fade out to silence
+ // Fade out to silence. This could be replaced with an exponential fadeout of the samples from the lookahead buffer for more punchy results.
_mix_step_for_channel(channel_buf, buf, prev_channel_vol, AudioFrame(0, 0), playback->attenuation_filter_cutoff_hz.get(), playback->highshelf_gain.get(), &playback->filter_process[channel_idx * 2], &playback->filter_process[channel_idx * 2 + 1]);
}
}
@@ -501,15 +519,12 @@ void AudioServer::_mix_step() {
switch (playback->state.load()) {
case AudioStreamPlaybackListNode::AWAITING_DELETION:
case AudioStreamPlaybackListNode::FADE_OUT_TO_DELETION:
+ // Remove the playback from the list.
_delete_stream_playback_list_node(playback);
break;
case AudioStreamPlaybackListNode::FADE_OUT_TO_PAUSE: {
// Pause the stream.
- AudioStreamPlaybackListNode::PlaybackState old_state, new_state;
- do {
- old_state = playback->state.load();
- new_state = AudioStreamPlaybackListNode::PAUSED;
- } while (!playback->state.compare_exchange_strong(/* expected= */ old_state, new_state));
+ playback->state.store(AudioStreamPlaybackListNode::PAUSED);
} break;
case AudioStreamPlaybackListNode::PLAYING:
case AudioStreamPlaybackListNode::PAUSED:
@@ -518,13 +533,13 @@ void AudioServer::_mix_step() {
}
}
+ // Now that all of the buses have their audio sources mixed into them, we can process the effects and bus sends.
for (int i = buses.size() - 1; i >= 0; i--) {
- //go bus by bus
Bus *bus = buses[i];
for (int k = 0; k < bus->channels.size(); k++) {
if (bus->channels[k].active && !bus->channels[k].used) {
- //buffer was not used, but it's still active, so it must be cleaned
+ // Buffer was not used, but it's still active, so it must be cleaned.
AudioFrame *buf = bus->channels.write[k].buffer.ptrw();
for (uint32_t j = 0; j < buffer_size; j++) {
@@ -533,7 +548,7 @@ void AudioServer::_mix_step() {
}
}
- //process effects
+ // Process effects.
if (!bus->bypass) {
for (int j = 0; j < bus->effects.size(); j++) {
if (!bus->effects[j].enabled) {
@@ -551,7 +566,7 @@ void AudioServer::_mix_step() {
bus->channels.write[k].effect_instances.write[j]->process(bus->channels[k].buffer.ptr(), temp_buffer.write[k].ptrw(), buffer_size);
}
- //swap buffers, so internal buffer always has the right data
+ // Swap buffers, so internal buffer always has the right data.
for (int k = 0; k < bus->channels.size(); k++) {
if (!(buses[i]->channels[k].active || bus->channels[k].effect_instances[j]->process_silence())) {
continue;
@@ -565,17 +580,17 @@ void AudioServer::_mix_step() {
}
}
- //process send
+ // Process send.
Bus *send = nullptr;
if (i > 0) {
- //everything has a send save for master bus
+ // Everything has a send except for the master bus.
if (!bus_map.has(bus->send)) {
send = buses[0];
} else {
send = bus_map[bus->send];
- if (send->index_cache >= bus->index_cache) { //invalid, send to master
+ if (send->index_cache >= bus->index_cache) { // Invalid, send to master.
send = buses[0];
}
}
@@ -603,7 +618,7 @@ void AudioServer::_mix_step() {
}
}
- //apply volume and compute peak
+ // Apply volume and compute peak.
for (uint32_t j = 0; j < buffer_size; j++) {
buf[j] *= volume;
@@ -620,7 +635,7 @@ void AudioServer::_mix_step() {
bus->channels.write[k].peak_volume = AudioFrame(Math::linear_to_db(peak.left + AUDIO_PEAK_OFFSET), Math::linear_to_db(peak.right + AUDIO_PEAK_OFFSET));
if (!bus->channels[k].used) {
- //see if any audio is contained, because channel was not used
+ // See if any audio is contained, because channel was not used.
if (MAX(peak.right, peak.left) > Math::db_to_linear(channel_disable_threshold_db)) {
bus->channels.write[k].last_mix_with_audio = mix_frames;
@@ -631,7 +646,7 @@ void AudioServer::_mix_step() {
}
if (send) {
- //if not master bus, send
+ // If not master bus, send.
AudioFrame *target_buf = thread_get_channel_mix_buffer(send->index_cache, k);
for (uint32_t j = 0; j < buffer_size; j++) {
@@ -646,6 +661,7 @@ void AudioServer::_mix_step() {
}
void AudioServer::_mix_step_for_channel(AudioFrame *p_out_buf, AudioFrame *p_source_buf, AudioFrame p_vol_start, AudioFrame p_vol_final, float p_attenuation_filter_cutoff_hz, float p_highshelf_gain, AudioFilterSW::Processor *p_processor_l, AudioFilterSW::Processor *p_processor_r) {
+ // TODO: In the future it could be nice to replace all of these hardcoded effects with something a bit cleaner and more flexible, but for now this is what we do to support 3D audio players.
if (p_highshelf_gain != 0) {
AudioFilterSW filter;
filter.set_mode(AudioFilterSW::HIGHSHELF);
@@ -665,7 +681,7 @@ void AudioServer::_mix_step_for_channel(AudioFrame *p_out_buf, AudioFrame *p_sou
p_processor_r->update_coeffs(buffer_size);
for (unsigned int frame_idx = 0; frame_idx < buffer_size; frame_idx++) {
- // Make this buffer size invariant if buffer_size ever becomes a project setting.
+ // TODO: Make lerp speed buffer-size-invariant if buffer_size ever becomes a project setting to avoid very small buffer sizes causing pops due to too-fast lerps.
float lerp_param = (float)frame_idx / buffer_size;
AudioFrame vol = p_vol_final * lerp_param + (1 - lerp_param) * p_vol_start;
AudioFrame mixed = vol * p_source_buf[frame_idx];
@@ -676,7 +692,7 @@ void AudioServer::_mix_step_for_channel(AudioFrame *p_out_buf, AudioFrame *p_sou
} else {
for (unsigned int frame_idx = 0; frame_idx < buffer_size; frame_idx++) {
- // Make this buffer size invariant if buffer_size ever becomes a project setting.
+ // TODO: Make lerp speed buffer-size-invariant if buffer_size ever becomes a project setting to avoid very small buffer sizes causing pops due to too-fast lerps.
float lerp_param = (float)frame_idx / buffer_size;
p_out_buf[frame_idx] += (p_vol_final * lerp_param + (1 - lerp_param) * p_vol_start) * p_source_buf[frame_idx];
}
@@ -701,6 +717,7 @@ void AudioServer::_delete_stream_playback(Ref<AudioStreamPlayback> p_playback) {
}
void AudioServer::_delete_stream_playback_list_node(AudioStreamPlaybackListNode *p_playback_node) {
+ // Remove the playback from the list, registering a destructor to be run on the main thread.
playback_list.erase(p_playback_node, [](AudioStreamPlaybackListNode *p) {
delete p->prev_bus_details;
delete p->bus_details.load();
@@ -1440,6 +1457,10 @@ uint64_t AudioServer::get_mixed_frames() const {
return mix_frames;
}
+String AudioServer::get_driver_name() const {
+ return AudioDriver::get_singleton()->get_name();
+}
+
void AudioServer::notify_listener_changed() {
for (CallbackItem *ci : listener_changed_callback_list) {
ci->callback(ci->userdata);
@@ -1467,7 +1488,9 @@ void AudioServer::init_channels_and_buffers() {
void AudioServer::init() {
channel_disable_threshold_db = GLOBAL_DEF_RST("audio/buses/channel_disable_threshold_db", -60.0);
channel_disable_frames = float(GLOBAL_DEF_RST(PropertyInfo(Variant::FLOAT, "audio/buses/channel_disable_time", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"), 2.0)) * get_mix_rate();
- buffer_size = 512; //hardcoded for now
+ // TODO: Buffer size is hardcoded for now. This would be really nice to have as a project setting because currently it limits audio latency to an absolute minimum of 11ms with default mix rate, but there's some additional work required to make that happen. See TODOs in `_mix_step_for_channel`.
+ // When this becomes a project setting, it should be specified in milliseconds rather than raw sample count, because 512 samples at 192khz is shorter than it is at 48khz, for example.
+ buffer_size = 512;
init_channels_and_buffers();
@@ -1614,6 +1637,10 @@ float AudioServer::get_mix_rate() const {
return AudioDriver::get_singleton()->get_mix_rate();
}
+float AudioServer::get_input_mix_rate() const {
+ return AudioDriver::get_singleton()->get_input_mix_rate();
+}
+
float AudioServer::read_output_peak_db() const {
return 0;
}
@@ -1946,6 +1973,9 @@ void AudioServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_speaker_mode"), &AudioServer::get_speaker_mode);
ClassDB::bind_method(D_METHOD("get_mix_rate"), &AudioServer::get_mix_rate);
+ ClassDB::bind_method(D_METHOD("get_input_mix_rate"), &AudioServer::get_input_mix_rate);
+
+ ClassDB::bind_method(D_METHOD("get_driver_name"), &AudioServer::get_driver_name);
ClassDB::bind_method(D_METHOD("get_output_device_list"), &AudioServer::get_output_device_list);
ClassDB::bind_method(D_METHOD("get_output_device"), &AudioServer::get_output_device);
diff --git a/servers/audio_server.h b/servers/audio_server.h
index 16fcc029b3..9a80882dd7 100644
--- a/servers/audio_server.h
+++ b/servers/audio_server.h
@@ -99,6 +99,7 @@ public:
virtual Error init() = 0;
virtual void start() = 0;
virtual int get_mix_rate() const = 0;
+ virtual int get_input_mix_rate() const { return get_mix_rate(); }
virtual SpeakerMode get_speaker_mode() const = 0;
virtual float get_latency() { return 0; }
@@ -270,6 +271,14 @@ private:
};
struct AudioStreamPlaybackListNode {
+ // The state machine for audio stream playbacks is as follows:
+ // 1. The playback is created and added to the playback list in the playing state.
+ // 2. The playback is (maybe) paused, and the state is set to FADE_OUT_TO_PAUSE.
+ // 2.1. The playback is mixed after being paused, and the audio server thread atomically sets the state to PAUSED after performing a brief fade-out.
+ // 3. The playback is (maybe) deleted, and the state is set to FADE_OUT_TO_DELETION.
+ // 3.1. The playback is mixed after being deleted, and the audio server thread atomically sets the state to AWAITING_DELETION after performing a brief fade-out.
+ // NOTE: The playback is not deallocated at this time because allocation and deallocation are not realtime-safe.
+ // 4. The playback is removed and deallocated on the main thread using the SafeList maybe_cleanup method.
enum PlaybackState {
PAUSED = 0, // Paused. Keep this stream playback around though so it can be restarted.
PLAYING = 1, // Playing. Fading may still be necessary if volume changes!
@@ -427,6 +436,8 @@ public:
uint64_t get_mix_count() const;
uint64_t get_mixed_frames() const;
+ String get_driver_name() const;
+
void notify_listener_changed();
virtual void init();
@@ -441,6 +452,7 @@ public:
virtual SpeakerMode get_speaker_mode() const;
virtual float get_mix_rate() const;
+ virtual float get_input_mix_rate() const;
virtual float read_output_peak_db() const;
diff --git a/servers/camera/camera_feed.cpp b/servers/camera/camera_feed.cpp
index 4021d9564b..e93ab3a544 100644
--- a/servers/camera/camera_feed.cpp
+++ b/servers/camera/camera_feed.cpp
@@ -50,6 +50,8 @@ void CameraFeed::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_rgb_image", "rgb_image"), &CameraFeed::set_rgb_image);
ClassDB::bind_method(D_METHOD("set_ycbcr_image", "ycbcr_image"), &CameraFeed::set_ycbcr_image);
+ ClassDB::bind_method(D_METHOD("set_external", "width", "height"), &CameraFeed::set_external);
+ ClassDB::bind_method(D_METHOD("get_texture_tex_id", "feed_image_type"), &CameraFeed::get_texture_tex_id);
ClassDB::bind_method(D_METHOD("get_datatype"), &CameraFeed::get_datatype);
@@ -68,6 +70,7 @@ void CameraFeed::_bind_methods() {
BIND_ENUM_CONSTANT(FEED_RGB);
BIND_ENUM_CONSTANT(FEED_YCBCR);
BIND_ENUM_CONSTANT(FEED_YCBCR_SEP);
+ BIND_ENUM_CONSTANT(FEED_EXTERNAL);
BIND_ENUM_CONSTANT(FEED_UNSPECIFIED);
BIND_ENUM_CONSTANT(FEED_FRONT);
@@ -137,6 +140,10 @@ RID CameraFeed::get_texture(CameraServer::FeedImage p_which) {
return texture[p_which];
}
+uint64_t CameraFeed::get_texture_tex_id(CameraServer::FeedImage p_which) {
+ return RenderingServer::get_singleton()->texture_get_native_handle(texture[p_which]);
+}
+
CameraFeed::CameraFeed() {
// initialize our feed
id = CameraServer::get_singleton()->get_free_id();
@@ -252,6 +259,19 @@ void CameraFeed::set_ycbcr_images(const Ref<Image> &p_y_img, const Ref<Image> &p
}
}
+void CameraFeed::set_external(int p_width, int p_height) {
+ if ((base_width != p_width) || (base_height != p_height)) {
+ // We're assuming here that our camera image doesn't change around formats etc, allocate the whole lot...
+ base_width = p_width;
+ base_height = p_height;
+
+ auto new_texture = RenderingServer::get_singleton()->texture_external_create(p_width, p_height, 0);
+ RenderingServer::get_singleton()->texture_replace(texture[CameraServer::FEED_YCBCR_IMAGE], new_texture);
+ }
+
+ datatype = CameraFeed::FEED_EXTERNAL;
+}
+
bool CameraFeed::activate_feed() {
// nothing to do here
return true;
diff --git a/servers/camera/camera_feed.h b/servers/camera/camera_feed.h
index 492a909239..365ed7c635 100644
--- a/servers/camera/camera_feed.h
+++ b/servers/camera/camera_feed.h
@@ -49,7 +49,8 @@ public:
FEED_NOIMAGE, // we don't have an image yet
FEED_RGB, // our texture will contain a normal RGB texture that can be used directly
FEED_YCBCR, // our texture will contain a YCbCr texture that needs to be converted to RGB before output
- FEED_YCBCR_SEP // our camera is split into two textures, first plane contains Y data, second plane contains CbCr data
+ FEED_YCBCR_SEP, // our camera is split into two textures, first plane contains Y data, second plane contains CbCr data
+ FEED_EXTERNAL, // specific for android atm, camera feed is managed externally, assumed RGB for now
};
enum FeedPosition {
@@ -104,6 +105,7 @@ public:
void set_transform(const Transform2D &p_transform);
RID get_texture(CameraServer::FeedImage p_which);
+ uint64_t get_texture_tex_id(CameraServer::FeedImage p_which);
CameraFeed();
CameraFeed(String p_name, FeedPosition p_position = CameraFeed::FEED_UNSPECIFIED);
@@ -113,6 +115,7 @@ public:
void set_rgb_image(const Ref<Image> &p_rgb_img);
void set_ycbcr_image(const Ref<Image> &p_ycbcr_img);
void set_ycbcr_images(const Ref<Image> &p_y_img, const Ref<Image> &p_cbcr_img);
+ void set_external(int p_width, int p_height);
virtual bool set_format(int p_index, const Dictionary &p_parameters);
virtual Array get_formats() const;
diff --git a/servers/camera_server.cpp b/servers/camera_server.cpp
index bf698e3945..b78a0c44e7 100644
--- a/servers/camera_server.cpp
+++ b/servers/camera_server.cpp
@@ -53,13 +53,13 @@ void CameraServer::_bind_methods() {
BIND_ENUM_CONSTANT(FEED_YCBCR_IMAGE);
BIND_ENUM_CONSTANT(FEED_Y_IMAGE);
BIND_ENUM_CONSTANT(FEED_CBCR_IMAGE);
-};
+}
CameraServer *CameraServer::singleton = nullptr;
CameraServer *CameraServer::get_singleton() {
return singleton;
-};
+}
int CameraServer::get_free_id() {
bool id_exists = true;
@@ -77,7 +77,7 @@ int CameraServer::get_free_id() {
};
return newid;
-};
+}
int CameraServer::get_feed_index(int p_id) {
for (int i = 0; i < feeds.size(); i++) {
@@ -87,7 +87,7 @@ int CameraServer::get_feed_index(int p_id) {
};
return -1;
-};
+}
Ref<CameraFeed> CameraServer::get_feed_by_id(int p_id) {
int index = get_feed_index(p_id);
@@ -97,7 +97,7 @@ Ref<CameraFeed> CameraServer::get_feed_by_id(int p_id) {
} else {
return feeds[index];
}
-};
+}
void CameraServer::add_feed(const Ref<CameraFeed> &p_feed) {
ERR_FAIL_COND(p_feed.is_null());
@@ -109,7 +109,7 @@ void CameraServer::add_feed(const Ref<CameraFeed> &p_feed) {
// let whomever is interested know
emit_signal(SNAME("camera_feed_added"), p_feed->get_id());
-};
+}
void CameraServer::remove_feed(const Ref<CameraFeed> &p_feed) {
for (int i = 0; i < feeds.size(); i++) {
@@ -126,17 +126,17 @@ void CameraServer::remove_feed(const Ref<CameraFeed> &p_feed) {
return;
};
};
-};
+}
Ref<CameraFeed> CameraServer::get_feed(int p_index) {
ERR_FAIL_INDEX_V(p_index, feeds.size(), nullptr);
return feeds[p_index];
-};
+}
int CameraServer::get_feed_count() {
return feeds.size();
-};
+}
TypedArray<CameraFeed> CameraServer::get_feeds() {
TypedArray<CameraFeed> return_feeds;
@@ -148,7 +148,7 @@ TypedArray<CameraFeed> CameraServer::get_feeds() {
};
return return_feeds;
-};
+}
RID CameraServer::feed_texture(int p_id, CameraServer::FeedImage p_texture) {
int index = get_feed_index(p_id);
@@ -157,12 +157,12 @@ RID CameraServer::feed_texture(int p_id, CameraServer::FeedImage p_texture) {
Ref<CameraFeed> feed = get_feed(index);
return feed->get_texture(p_texture);
-};
+}
CameraServer::CameraServer() {
singleton = this;
-};
+}
CameraServer::~CameraServer() {
singleton = nullptr;
-};
+}
diff --git a/servers/camera_server.h b/servers/camera_server.h
index e9bcd771d2..6a79b62fbd 100644
--- a/servers/camera_server.h
+++ b/servers/camera_server.h
@@ -87,7 +87,7 @@ public:
static CameraServer *create() {
CameraServer *server = create_func ? create_func() : memnew(CameraServer);
return server;
- };
+ }
// Right now we identify our feed by it's ID when it's used in the background.
// May see if we can change this to purely relying on CameraFeed objects or by name.
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 8bfe95aa76..82ac62bc9f 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -550,7 +550,7 @@ DisplayServer::ScreenOrientation DisplayServer::screen_get_orientation(int p_scr
float DisplayServer::screen_get_scale(int p_screen) const {
return 1.0f;
-};
+}
bool DisplayServer::is_touchscreen_available() const {
return Input::get_singleton() && Input::get_singleton()->is_emulating_touch_from_mouse();
@@ -1056,6 +1056,7 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(FEATURE_NATIVE_HELP);
BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_INPUT);
BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_FILE);
+ BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_FILE_EXTRA);
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
@@ -1149,6 +1150,8 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(WINDOW_HANDLE);
BIND_ENUM_CONSTANT(WINDOW_VIEW);
BIND_ENUM_CONSTANT(OPENGL_CONTEXT);
+ BIND_ENUM_CONSTANT(EGL_DISPLAY);
+ BIND_ENUM_CONSTANT(EGL_CONFIG);
BIND_ENUM_CONSTANT(TTS_UTTERANCE_STARTED);
BIND_ENUM_CONSTANT(TTS_UTTERANCE_ENDED);
@@ -1230,6 +1233,10 @@ void DisplayServer::_input_set_custom_mouse_cursor_func(const Ref<Resource> &p_i
}
bool DisplayServer::can_create_rendering_device() {
+ if (get_singleton()->get_name() == "headless") {
+ return false;
+ }
+
#if defined(RD_ENABLED)
RenderingDevice *device = RenderingDevice::get_singleton();
if (device) {
diff --git a/servers/display_server.h b/servers/display_server.h
index f25bf334a4..916c006f01 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -82,6 +82,8 @@ public:
WINDOW_HANDLE,
WINDOW_VIEW,
OPENGL_CONTEXT,
+ EGL_DISPLAY,
+ EGL_CONFIG,
};
enum Context {
@@ -150,6 +152,7 @@ public:
FEATURE_NATIVE_HELP,
FEATURE_NATIVE_DIALOG_INPUT,
FEATURE_NATIVE_DIALOG_FILE,
+ FEATURE_NATIVE_DIALOG_FILE_EXTRA,
};
virtual bool has_feature(Feature p_feature) const = 0;
@@ -367,6 +370,7 @@ public:
INVALID_INDICATOR_ID = -1
};
+public:
typedef int WindowID;
typedef int IndicatorID;
diff --git a/servers/display_server_headless.h b/servers/display_server_headless.h
index a5277479ca..5f53e76235 100644
--- a/servers/display_server_headless.h
+++ b/servers/display_server_headless.h
@@ -72,7 +72,7 @@ public:
// that don't affect the project's behavior in headless mode.
int get_screen_count() const override { return 0; }
- int get_primary_screen() const override { return 0; };
+ int get_primary_screen() const override { return 0; }
Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return Point2i(); }
Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return Size2i(); }
Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return Rect2i(); }
@@ -141,7 +141,7 @@ public:
void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override {}
void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override {}
- bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override { return true; };
+ bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override { return true; }
bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override { return false; }
diff --git a/servers/navigation_server_2d_dummy.h b/servers/navigation_server_2d_dummy.h
index 0664b37ef0..5bc91830e6 100644
--- a/servers/navigation_server_2d_dummy.h
+++ b/servers/navigation_server_2d_dummy.h
@@ -58,7 +58,7 @@ public:
TypedArray<RID> map_get_agents(RID p_map) const override { return TypedArray<RID>(); }
TypedArray<RID> map_get_obstacles(RID p_map) const override { return TypedArray<RID>(); }
void map_force_update(RID p_map) override {}
- Vector2 map_get_random_point(RID p_map, uint32_t p_naviation_layers, bool p_uniformly) const override { return Vector2(); };
+ Vector2 map_get_random_point(RID p_map, uint32_t p_naviation_layers, bool p_uniformly) const override { return Vector2(); }
uint32_t map_get_iteration_id(RID p_map) const override { return 0; }
RID region_create() override { return RID(); }
@@ -84,7 +84,7 @@ public:
Vector2 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override { return Vector2(); }
Vector2 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override { return Vector2(); }
Vector2 region_get_closest_point(RID p_region, const Vector2 &p_point) const override { return Vector2(); }
- Vector2 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const override { return Vector2(); };
+ Vector2 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const override { return Vector2(); }
RID link_create() override { return RID(); }
void link_set_map(RID p_link, RID p_map) override {}
diff --git a/servers/rendering/dummy/rasterizer_dummy.h b/servers/rendering/dummy/rasterizer_dummy.h
index 7640afc711..6205193d9a 100644
--- a/servers/rendering/dummy/rasterizer_dummy.h
+++ b/servers/rendering/dummy/rasterizer_dummy.h
@@ -66,14 +66,14 @@ protected:
RasterizerSceneDummy scene;
public:
- RendererUtilities *get_utilities() override { return &utilities; };
- RendererLightStorage *get_light_storage() override { return &light_storage; };
- RendererMaterialStorage *get_material_storage() override { return &material_storage; };
- RendererMeshStorage *get_mesh_storage() override { return &mesh_storage; };
- RendererParticlesStorage *get_particles_storage() override { return &particles_storage; };
- RendererTextureStorage *get_texture_storage() override { return &texture_storage; };
- RendererGI *get_gi() override { return &gi; };
- RendererFog *get_fog() override { return &fog; };
+ RendererUtilities *get_utilities() override { return &utilities; }
+ RendererLightStorage *get_light_storage() override { return &light_storage; }
+ RendererMaterialStorage *get_material_storage() override { return &material_storage; }
+ RendererMeshStorage *get_mesh_storage() override { return &mesh_storage; }
+ RendererParticlesStorage *get_particles_storage() override { return &particles_storage; }
+ RendererTextureStorage *get_texture_storage() override { return &texture_storage; }
+ RendererGI *get_gi() override { return &gi; }
+ RendererFog *get_fog() override { return &fog; }
RendererCanvasRender *get_canvas() override { return &canvas; }
RendererSceneRender *get_scene() override { return &scene; }
diff --git a/servers/rendering/dummy/storage/light_storage.h b/servers/rendering/dummy/storage/light_storage.h
index c3b63cdbf6..d25523753c 100644
--- a/servers/rendering/dummy/storage/light_storage.h
+++ b/servers/rendering/dummy/storage/light_storage.h
@@ -78,6 +78,8 @@ public:
virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) override {}
virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) override {}
virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) override {}
+ virtual void light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) override {}
+ virtual uint32_t light_get_shadow_caster_mask(RID p_light) const override { return 0xFFFFFFFF; }
virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) override {}
virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) override {}
diff --git a/servers/rendering/dummy/storage/material_storage.h b/servers/rendering/dummy/storage/material_storage.h
index e4c58474e2..74ae71cba6 100644
--- a/servers/rendering/dummy/storage/material_storage.h
+++ b/servers/rendering/dummy/storage/material_storage.h
@@ -92,7 +92,7 @@ public:
virtual RID shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const override { return RID(); }
virtual Variant shader_get_parameter_default(RID p_material, const StringName &p_param) const override { return Variant(); }
- virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override { return RS::ShaderNativeSourceCode(); };
+ virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override { return RS::ShaderNativeSourceCode(); }
/* MATERIAL API */
virtual RID material_allocate() override { return RID(); }
diff --git a/servers/rendering/dummy/storage/mesh_storage.h b/servers/rendering/dummy/storage/mesh_storage.h
index b0953b5dce..855336c71f 100644
--- a/servers/rendering/dummy/storage/mesh_storage.h
+++ b/servers/rendering/dummy/storage/mesh_storage.h
@@ -64,7 +64,7 @@ public:
/* MESH API */
- bool owns_mesh(RID p_rid) { return mesh_owner.owns(p_rid); };
+ bool owns_mesh(RID p_rid) { return mesh_owner.owns(p_rid); }
virtual RID mesh_allocate() override;
virtual void mesh_initialize(RID p_rid) override;
diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h
index 6735f6bcda..63eb441915 100644
--- a/servers/rendering/dummy/storage/texture_storage.h
+++ b/servers/rendering/dummy/storage/texture_storage.h
@@ -53,7 +53,7 @@ public:
/* Canvas Texture API */
- virtual RID canvas_texture_allocate() override { return RID(); };
+ virtual RID canvas_texture_allocate() override { return RID(); }
virtual void canvas_texture_initialize(RID p_rid) override {}
virtual void canvas_texture_free(RID p_rid) override {}
@@ -65,13 +65,13 @@ public:
/* Texture API */
- bool owns_texture(RID p_rid) { return texture_owner.owns(p_rid); };
+ bool owns_texture(RID p_rid) { return texture_owner.owns(p_rid); }
virtual RID texture_allocate() override {
DummyTexture *texture = memnew(DummyTexture);
ERR_FAIL_NULL_V(texture, RID());
return texture_owner.make_rid(texture);
- };
+ }
virtual void texture_free(RID p_rid) override {
// delete the texture
@@ -79,13 +79,13 @@ public:
ERR_FAIL_NULL(texture);
texture_owner.free(p_rid);
memdelete(texture);
- };
+ }
virtual void texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) override {
DummyTexture *t = texture_owner.get_or_null(p_texture);
ERR_FAIL_NULL(t);
t->image = p_image->duplicate();
- };
+ }
virtual void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) override {}
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) override {}
virtual void texture_external_initialize(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) override {}
@@ -107,15 +107,15 @@ public:
DummyTexture *t = texture_owner.get_or_null(p_texture);
ERR_FAIL_NULL_V(t, Ref<Image>());
return t->image;
- };
- virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const override { return Ref<Image>(); };
- virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const override { return Vector<Ref<Image>>(); };
+ }
+ virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const override { return Ref<Image>(); }
+ virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const override { return Vector<Ref<Image>>(); }
- virtual void texture_replace(RID p_texture, RID p_by_texture) override { texture_free(p_by_texture); };
+ virtual void texture_replace(RID p_texture, RID p_by_texture) override { texture_free(p_by_texture); }
virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) override {}
virtual void texture_set_path(RID p_texture, const String &p_path) override {}
- virtual String texture_get_path(RID p_texture) const override { return String(); };
+ virtual String texture_get_path(RID p_texture) const override { return String(); }
virtual Image::Format texture_get_format(RID p_texture) const override { return Image::FORMAT_MAX; }
@@ -127,11 +127,11 @@ public:
virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) override {}
- virtual Size2 texture_size_with_proxy(RID p_proxy) override { return Size2(); };
+ virtual Size2 texture_size_with_proxy(RID p_proxy) override { return Size2(); }
virtual void texture_rd_initialize(RID p_texture, const RID &p_rd_texture, const RS::TextureLayeredType p_layer_type = RS::TEXTURE_LAYERED_2D_ARRAY) override {}
- virtual RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) const override { return RID(); };
- virtual uint64_t texture_get_native_handle(RID p_texture, bool p_srgb = false) const override { return 0; };
+ virtual RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) const override { return RID(); }
+ virtual uint64_t texture_get_native_handle(RID p_texture, bool p_srgb = false) const override { return 0; }
/* DECAL API */
virtual RID decal_allocate() override { return RID(); }
diff --git a/servers/rendering/dummy/storage/utilities.h b/servers/rendering/dummy/storage/utilities.h
index ae83547afd..4e20dee640 100644
--- a/servers/rendering/dummy/storage/utilities.h
+++ b/servers/rendering/dummy/storage/utilities.h
@@ -124,7 +124,7 @@ public:
virtual RenderingDevice::DeviceType get_video_adapter_type() const override { return RenderingDevice::DeviceType::DEVICE_TYPE_OTHER; }
virtual String get_video_adapter_api_version() const override { return String(); }
- virtual Size2i get_maximum_viewport_size() const override { return Size2i(); };
+ virtual Size2i get_maximum_viewport_size() const override { return Size2i(); }
};
} // namespace RendererDummy
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index 701b4da8f8..d01976acf2 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -612,8 +612,9 @@ void RendererCanvasCull::canvas_item_set_visibility_layer(RID p_item, uint32_t p
uint32_t RendererCanvasCull::canvas_item_get_visibility_layer(RID p_item) {
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
- if (!canvas_item)
+ if (!canvas_item) {
return 0;
+ }
return canvas_item->visibility_layer;
}
diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h
index a585c9430b..dbc8f155bf 100644
--- a/servers/rendering/renderer_compositor.h
+++ b/servers/rendering/renderer_compositor.h
@@ -106,7 +106,7 @@ public:
virtual double get_total_time() const = 0;
virtual bool can_create_resources_async() const = 0;
- static bool is_low_end() { return low_end; };
+ static bool is_low_end() { return low_end; }
virtual bool is_xr_enabled() const;
static RendererCompositor *get_singleton() { return singleton; }
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp
index c7a7532d76..808c82f712 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp
@@ -1002,15 +1002,19 @@ void CopyEffects::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuf
MaterialStorage *material_storage = MaterialStorage::get_singleton();
ERR_FAIL_NULL(material_storage);
+ Rect2i screen_rect;
+ float atlas_width = p_dst_size.width / p_rect.size.width;
+ float atlas_height = p_dst_size.height / p_rect.size.height;
+ screen_rect.position.x = (int32_t)(Math::round(p_rect.position.x * atlas_width));
+ screen_rect.position.y = (int32_t)(Math::round(p_rect.position.y * atlas_height));
+ screen_rect.size.width = (int32_t)(Math::round(p_dst_size.width));
+ screen_rect.size.height = (int32_t)(Math::round(p_dst_size.height));
+
CopyToDPPushConstant push_constant;
- 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.texel_size[0] = 1.0f / p_dst_size.x;
- push_constant.texel_size[1] = 1.0f / p_dst_size.y;
+ push_constant.texel_size[0] = 1.0f / p_dst_size.width;
+ push_constant.texel_size[1] = 1.0f / p_dst_size.height;
push_constant.texel_size[0] *= p_dp_flip ? -1.0f : 1.0f; // Encode dp flip as x size sign
// setup our uniforms
@@ -1021,7 +1025,7 @@ void CopyEffects::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuf
RID shader = cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0);
ERR_FAIL_COND(shader.is_null());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, Vector<Color>(), 1.0f, 0, screen_rect);
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, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array());
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.h b/servers/rendering/renderer_rd/effects/copy_effects.h
index 014f78e2b9..b6fc95d0f1 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.h
+++ b/servers/rendering/renderer_rd/effects/copy_effects.h
@@ -217,7 +217,6 @@ private:
float z_far;
float z_near;
float texel_size[2];
- float screen_rect[4];
};
struct CopyToDP {
diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp
index 2dfcd67411..090eab384f 100644
--- a/servers/rendering/renderer_rd/environment/fog.cpp
+++ b/servers/rendering/renderer_rd/environment/fog.cpp
@@ -157,7 +157,7 @@ RendererRD::MaterialStorage::ShaderData *Fog::_create_fog_shader_func() {
RendererRD::MaterialStorage::ShaderData *Fog::_create_fog_shader_funcs() {
return Fog::get_singleton()->_create_fog_shader_func();
-};
+}
RendererRD::MaterialStorage::MaterialData *Fog::_create_fog_material_func(FogShaderData *p_shader) {
FogMaterialData *material_data = memnew(FogMaterialData);
@@ -168,7 +168,7 @@ RendererRD::MaterialStorage::MaterialData *Fog::_create_fog_material_func(FogSha
RendererRD::MaterialStorage::MaterialData *Fog::_create_fog_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader) {
return Fog::get_singleton()->_create_fog_material_func(static_cast<FogShaderData *>(p_shader));
-};
+}
////////////////////////////////////////////////////////////////////////////////
// FOG VOLUMES INSTANCE
@@ -622,6 +622,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
bool any_uses_time = false;
+ Vector3 cam_position = p_cam_transform.get_origin();
for (int i = 0; i < (int)p_fog_volumes.size(); i++) {
FogVolumeInstance *fog_volume_instance = fog_volume_instance_owner.get_or_null(p_fog_volumes[i]);
@@ -652,41 +653,68 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
any_uses_time |= shader_data->uses_time;
- Vector3i min;
- Vector3i max;
+ Vector3i froxel_min;
+ Vector3i froxel_max;
Vector3i kernel_size;
- Vector3 position = fog_volume_instance->transform.get_origin();
+ Vector3 fog_position = fog_volume_instance->transform.get_origin();
RS::FogVolumeShape volume_type = RendererRD::Fog::get_singleton()->fog_volume_get_shape(fog_volume);
Vector3 extents = RendererRD::Fog::get_singleton()->fog_volume_get_size(fog_volume) / 2;
if (volume_type != RS::FOG_VOLUME_SHAPE_WORLD) {
// Local fog volume.
- Vector3i points[8];
Vector3 fog_size = Vector3(fog->width, fog->height, fog->depth);
float volumetric_fog_detail_spread = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_detail_spread(p_settings.env);
- points[0] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
- points[1] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
- points[2] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
- points[3] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
- points[4] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
- points[5] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
- points[6] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
- points[7] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
-
- min = Vector3i(int32_t(fog->width) - 1, int32_t(fog->height) - 1, int32_t(fog->depth) - 1);
- max = Vector3i(1, 1, 1);
-
+ Vector3 corners[8]{
+ fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, extents.z)),
+ fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, extents.z)),
+ fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, extents.z)),
+ fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, extents.z)),
+ fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, -extents.z)),
+ fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, -extents.z)),
+ fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, -extents.z)),
+ fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, -extents.z))
+ };
+ Vector3i froxels[8];
+ Vector3 corner_min = corners[0];
+ Vector3 corner_max = corners[0];
for (int j = 0; j < 8; j++) {
- min = min.min(points[j]);
- max = max.max(points[j]);
+ froxels[j] = _point_get_position_in_froxel_volume(corners[j], fog_end, fog_near_size, fog_far_size, volumetric_fog_detail_spread, fog_size, p_cam_transform);
+ corner_min = corner_min.min(corners[j]);
+ corner_max = corner_max.max(corners[j]);
+ }
+
+ froxel_min = Vector3i(int32_t(fog->width) - 1, int32_t(fog->height) - 1, int32_t(fog->depth) - 1);
+ froxel_max = Vector3i(1, 1, 1);
+
+ // Tracking just the corners of the fog volume can result in missing some fog:
+ // when the camera's near plane is inside the fog, we must always consider the entire screen
+ Vector3 near_plane_corner(frustum_near_size.x, frustum_near_size.y, z_near);
+ float expand = near_plane_corner.length();
+ if (cam_position.x > (corner_min.x - expand) && cam_position.x < (corner_max.x + expand) &&
+ cam_position.y > (corner_min.y - expand) && cam_position.y < (corner_max.y + expand) &&
+ cam_position.z > (corner_min.z - expand) && cam_position.z < (corner_max.z + expand)) {
+ froxel_min.x = 0;
+ froxel_min.y = 0;
+ froxel_min.z = 0;
+ froxel_max.x = int32_t(fog->width);
+ froxel_max.y = int32_t(fog->height);
+ for (int j = 0; j < 8; j++) {
+ froxel_max.z = MAX(froxel_max.z, froxels[j].z);
+ }
+ } else {
+ // Camera is guaranteed to be outside the fog volume
+ for (int j = 0; j < 8; j++) {
+ froxel_min = froxel_min.min(froxels[j]);
+ froxel_max = froxel_max.max(froxels[j]);
+ }
}
- kernel_size = max - min;
+ kernel_size = froxel_max - froxel_min;
} else {
// Volume type global runs on all cells
extents = Vector3(fog->width, fog->height, fog->depth);
- min = Vector3i(0, 0, 0);
+ froxel_min = Vector3i(0, 0, 0);
kernel_size = Vector3i(int32_t(fog->width), int32_t(fog->height), int32_t(fog->depth));
}
@@ -695,15 +723,15 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
}
VolumetricFogShader::FogPushConstant push_constant;
- push_constant.position[0] = position.x;
- push_constant.position[1] = position.y;
- push_constant.position[2] = position.z;
+ push_constant.position[0] = fog_position.x;
+ push_constant.position[1] = fog_position.y;
+ push_constant.position[2] = fog_position.z;
push_constant.size[0] = extents.x * 2;
push_constant.size[1] = extents.y * 2;
push_constant.size[2] = extents.z * 2;
- push_constant.corner[0] = min.x;
- push_constant.corner[1] = min.y;
- push_constant.corner[2] = min.z;
+ push_constant.corner[0] = froxel_min.x;
+ push_constant.corner[1] = froxel_min.y;
+ push_constant.corner[2] = froxel_min.z;
push_constant.shape = uint32_t(RendererRD::Fog::get_singleton()->fog_volume_get_shape(fog_volume));
RendererRD::MaterialStorage::store_transform(fog_volume_instance->transform.affine_inverse(), push_constant.transform);
diff --git a/servers/rendering/renderer_rd/environment/fog.h b/servers/rendering/renderer_rd/environment/fog.h
index 75b9c563f7..23de97a268 100644
--- a/servers/rendering/renderer_rd/environment/fog.h
+++ b/servers/rendering/renderer_rd/environment/fog.h
@@ -233,7 +233,7 @@ public:
/* FOG VOLUMES */
- bool owns_fog_volume(RID p_rid) { return fog_volume_owner.owns(p_rid); };
+ bool owns_fog_volume(RID p_rid) { return fog_volume_owner.owns(p_rid); }
virtual RID fog_volume_allocate() override;
virtual void fog_volume_initialize(RID p_rid) override;
@@ -250,7 +250,7 @@ public:
/* FOG VOLUMES INSTANCE */
- bool owns_fog_volume_instance(RID p_rid) { return fog_volume_instance_owner.owns(p_rid); };
+ bool owns_fog_volume_instance(RID p_rid) { return fog_volume_instance_owner.owns(p_rid); }
RID fog_volume_instance_create(RID p_fog_volume);
void fog_instance_free(RID p_rid);
diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp
index 12ff28d7b0..235aa9f828 100644
--- a/servers/rendering/renderer_rd/environment/gi.cpp
+++ b/servers/rendering/renderer_rd/environment/gi.cpp
@@ -350,7 +350,7 @@ bool GI::voxel_gi_is_using_two_bounces(RID p_voxel_gi) const {
bool GI::voxel_gi_is_interior(RID p_voxel_gi) const {
VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi);
- ERR_FAIL_NULL_V(voxel_gi, 0);
+ ERR_FAIL_NULL_V(voxel_gi, false);
return voxel_gi->interior;
}
diff --git a/servers/rendering/renderer_rd/environment/gi.h b/servers/rendering/renderer_rd/environment/gi.h
index f6f9ab4f75..f34bbde6f0 100644
--- a/servers/rendering/renderer_rd/environment/gi.h
+++ b/servers/rendering/renderer_rd/environment/gi.h
@@ -467,7 +467,7 @@ public:
/* VOXEL GI API */
- bool owns_voxel_gi(RID p_rid) { return voxel_gi_owner.owns(p_rid); };
+ bool owns_voxel_gi(RID p_rid) { return voxel_gi_owner.owns(p_rid); }
virtual RID voxel_gi_allocate() override;
virtual void voxel_gi_free(RID p_voxel_gi) override;
@@ -524,14 +524,14 @@ public:
VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe);
ERR_FAIL_NULL_V(voxel_gi, RID());
return voxel_gi->texture;
- };
+ }
_FORCE_INLINE_ void voxel_gi_instance_set_render_index(RID p_probe, uint32_t p_index) {
VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe);
ERR_FAIL_NULL(voxel_gi);
voxel_gi->render_index = p_index;
- };
+ }
bool voxel_gi_instance_owns(RID p_rid) const {
return voxel_gi_instance_owner.owns(p_rid);
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index 2087989102..63956a7918 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -701,7 +701,7 @@ RendererRD::MaterialStorage::ShaderData *SkyRD::_create_sky_shader_func() {
RendererRD::MaterialStorage::ShaderData *SkyRD::_create_sky_shader_funcs() {
// !BAS! Why isn't _create_sky_shader_func not just static too?
return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->sky._create_sky_shader_func();
-};
+}
RendererRD::MaterialStorage::MaterialData *SkyRD::_create_sky_material_func(SkyShaderData *p_shader) {
SkyMaterialData *material_data = memnew(SkyMaterialData);
@@ -713,7 +713,7 @@ RendererRD::MaterialStorage::MaterialData *SkyRD::_create_sky_material_func(SkyS
RendererRD::MaterialStorage::MaterialData *SkyRD::_create_sky_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader) {
// !BAS! same here, we could just make _create_sky_material_func static?
return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->sky._create_sky_material_func(static_cast<SkyShaderData *>(p_shader));
-};
+}
SkyRD::SkyRD() {
roughness_layers = GLOBAL_GET("rendering/reflections/sky_reflections/roughness_layers");
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 76d8972ad9..eb73a9d7e6 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -395,6 +395,10 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
RID xforms_uniform_set = surf->owner->transforms_uniform_set;
SceneShaderForwardClustered::ShaderSpecialization pipeline_specialization = p_params->base_specialization;
+ pipeline_specialization.multimesh = bool(surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH);
+ pipeline_specialization.multimesh_format_2d = bool(surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D);
+ pipeline_specialization.multimesh_has_color = bool(surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR);
+ pipeline_specialization.multimesh_has_custom_data = bool(surf->owner->base_flags & INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA);
if constexpr (p_pass_mode == PASS_MODE_COLOR) {
pipeline_specialization.use_light_soft_shadows = element_info.uses_softshadow;
@@ -1961,7 +1965,13 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
sky.setup_sky(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, 1, &projection, &eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, Vector2(0.0f, 0.0f), this);
} else {
- sky.setup_sky(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, screen_size, p_render_data->scene_data->taa_jitter, this);
+ Projection projection = p_render_data->scene_data->cam_projection;
+ if (p_render_data->scene_data->cam_frustum) {
+ // Sky is drawn upside down, the frustum offset doesn't know the image is upside down so needs a flip.
+ projection[2].y = -projection[2].y;
+ }
+
+ sky.setup_sky(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, &projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, p_render_data->scene_data->taa_jitter, this);
}
sky_energy_multiplier *= bg_energy_multiplier;
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index 53982af590..00a70e3690 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -374,6 +374,10 @@ void SceneShaderForwardClustered::ShaderData::_create_pipeline(PipelineKey p_pip
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
specialization_constants.push_back(sc);
+ sc.constant_id = 1;
+ sc.int_value = p_pipeline_key.shader_specialization.packed_1;
+ specialization_constants.push_back(sc);
+
RID shader_rid = get_shader_variant(p_pipeline_key.version, p_pipeline_key.color_pass_flags, p_pipeline_key.ubershader);
ERR_FAIL_COND(shader_rid.is_null());
@@ -610,6 +614,8 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.renames["PI"] = _MKSTR(Math_PI);
actions.renames["TAU"] = _MKSTR(Math_TAU);
actions.renames["E"] = _MKSTR(Math_E);
+ actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+ actions.renames["CLIP_SPACE_FAR"] = "SHADER_SPACE_FAR";
actions.renames["VIEWPORT_SIZE"] = "read_viewport_size";
actions.renames["FRAGCOORD"] = "gl_FragCoord";
@@ -649,8 +655,6 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.renames["CUSTOM1"] = "custom1_attrib";
actions.renames["CUSTOM2"] = "custom2_attrib";
actions.renames["CUSTOM3"] = "custom3_attrib";
- actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
- actions.renames["CLIP_SPACE_FAR"] = "SHADER_SPACE_FAR";
actions.renames["LIGHT_VERTEX"] = "light_vertex";
actions.renames["NODE_POSITION_WORLD"] = "read_model_matrix[3].xyz";
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
index 136514588a..e1ed85779e 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
@@ -108,16 +108,26 @@ public:
uint32_t projector_use_mipmaps : 1;
uint32_t use_depth_fog : 1;
uint32_t use_lightmap_bicubic_filter : 1;
- uint32_t soft_shadow_samples : 4;
- uint32_t penumbra_shadow_samples : 4;
- uint32_t directional_soft_shadow_samples : 4;
- uint32_t directional_penumbra_shadow_samples : 4;
+ uint32_t soft_shadow_samples : 6;
+ uint32_t penumbra_shadow_samples : 6;
+ uint32_t directional_soft_shadow_samples : 6;
+ uint32_t directional_penumbra_shadow_samples : 6;
};
uint32_t packed_0;
};
- uint32_t packed_1;
+ union {
+ struct {
+ uint32_t multimesh : 1;
+ uint32_t multimesh_format_2d : 1;
+ uint32_t multimesh_has_color : 1;
+ uint32_t multimesh_has_custom_data : 1;
+ };
+
+ uint32_t packed_1;
+ };
+
uint32_t packed_2;
};
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 978ce097d3..5ad92bd211 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -911,14 +911,19 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
Color clear_color = p_default_bg_color;
bool load_color = false;
bool copy_canvas = false;
+ bool use_ambient_cubemap = false;
+ bool use_reflection_cubemap = false;
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black
} else if (is_environment(p_render_data->environment)) {
+ RS::EnvironmentAmbientSource ambient_source = environment_get_ambient_source(p_render_data->environment);
RS::EnvironmentBG bg_mode = environment_get_background(p_render_data->environment);
float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment);
bg_energy_multiplier *= environment_get_bg_intensity(p_render_data->environment);
RS::EnvironmentReflectionSource reflection_source = environment_get_reflection_source(p_render_data->environment);
+ use_ambient_cubemap = (ambient_source == RS::ENV_AMBIENT_SOURCE_BG && bg_mode == RS::ENV_BG_SKY) || ambient_source == RS::ENV_AMBIENT_SOURCE_SKY;
+ use_reflection_cubemap = (reflection_source == RS::ENV_REFLECTION_SOURCE_BG && bg_mode == RS::ENV_BG_SKY) || reflection_source == RS::ENV_REFLECTION_SOURCE_SKY;
if (p_render_data->camera_attributes.is_valid()) {
bg_energy_multiplier *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
@@ -963,7 +968,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
}
// setup sky if used for ambient, reflections, or background
- if (draw_sky || draw_sky_fog_only || (reflection_source == RS::ENV_REFLECTION_SOURCE_BG && bg_mode == RS::ENV_BG_SKY) || reflection_source == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
+ if (draw_sky || draw_sky_fog_only || (reflection_source == RS::ENV_REFLECTION_SOURCE_BG && bg_mode == RS::ENV_BG_SKY) || reflection_source == RS::ENV_REFLECTION_SOURCE_SKY || ambient_source == RS::ENV_AMBIENT_SOURCE_SKY) {
RENDER_TIMESTAMP("Setup Sky");
RD::get_singleton()->draw_command_begin_label("Setup Sky");
@@ -976,7 +981,13 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, 1, &projection, &eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, Vector2(0.0f, 0.0f), this);
} else {
- sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, screen_size, p_render_data->scene_data->taa_jitter, this);
+ Projection projection = p_render_data->scene_data->cam_projection;
+ if (p_render_data->scene_data->cam_frustum) {
+ // Sky is drawn upside down, the frustum offset doesn't know the image is upside down so needs a flip.
+ projection[2].y = -projection[2].y;
+ }
+
+ sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, &projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, p_render_data->scene_data->taa_jitter, this);
}
sky_energy_multiplier *= bg_energy_multiplier;
@@ -1008,13 +1019,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
SceneShaderForwardMobile::ShaderSpecialization base_specialization = scene_shader.default_specialization;
{
- //figure out spec constants
-
- if (p_render_data->directional_light_count > 0) {
- base_specialization.use_directional_soft_shadows = p_render_data->directional_light_soft_shadows;
- } else {
- base_specialization.disable_directional_lights = true;
- }
+ base_specialization.use_directional_soft_shadows = p_render_data->directional_light_count > 0 ? p_render_data->directional_light_soft_shadows : false;
+ base_specialization.directional_lights = p_render_data->directional_light_count;
if (!is_environment(p_render_data->environment) || !environment_get_fog_enabled(p_render_data->environment)) {
base_specialization.disable_fog = true;
@@ -1023,6 +1029,10 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (p_render_data->environment.is_valid() && environment_get_fog_mode(p_render_data->environment) == RS::EnvironmentFogMode::ENV_FOG_MODE_DEPTH) {
base_specialization.use_depth_fog = true;
}
+
+ base_specialization.scene_use_ambient_cubemap = use_ambient_cubemap;
+ base_specialization.scene_use_reflection_cubemap = use_reflection_cubemap;
+ base_specialization.scene_roughness_limiter_enabled = p_render_data->render_buffers.is_valid() && screen_space_roughness_limiter_is_active();
}
{
@@ -2144,7 +2154,10 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
}
SceneShaderForwardMobile::ShaderSpecialization pipeline_specialization = p_params->base_specialization;
- pipeline_specialization.is_multimesh = bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH);
+ pipeline_specialization.multimesh = bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH);
+ pipeline_specialization.multimesh_format_2d = bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D);
+ pipeline_specialization.multimesh_has_color = bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR);
+ pipeline_specialization.multimesh_has_custom_data = bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA);
SceneState::PushConstant push_constant;
push_constant.base_index = i + p_params->element_offset;
@@ -2165,10 +2178,10 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
} else {
pipeline_specialization.use_light_projector = inst->use_projector;
pipeline_specialization.use_light_soft_shadows = inst->use_soft_shadow;
- pipeline_specialization.disable_omni_lights = inst->omni_light_count == 0;
- pipeline_specialization.disable_spot_lights = inst->spot_light_count == 0;
- pipeline_specialization.disable_reflection_probes = inst->reflection_probe_count == 0;
- pipeline_specialization.disable_decals = inst->decals_count == 0;
+ pipeline_specialization.omni_lights = inst->omni_light_count;
+ pipeline_specialization.spot_lights = inst->spot_light_count;
+ pipeline_specialization.reflection_probes = inst->reflection_probe_count;
+ pipeline_specialization.decals = inst->decals_count;
#ifdef DEBUG_ENABLED
if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) {
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index 69f084f4c0..4525b50b6e 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -237,6 +237,7 @@ void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeli
"VERSION:", p_pipeline_key.version,
"SPEC PACKED #0:", p_pipeline_key.shader_specialization.packed_0,
"SPEC PACKED #1:", p_pipeline_key.shader_specialization.packed_1,
+ "SPEC PACKED #2:", p_pipeline_key.shader_specialization.packed_2,
"RENDER PASS:", p_pipeline_key.render_pass,
"WIREFRAME:", p_pipeline_key.wireframe);
#endif
@@ -322,7 +323,12 @@ void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeli
specialization_constants.push_back(sc);
sc.constant_id = 1;
- sc.float_value = p_pipeline_key.shader_specialization.packed_1;
+ sc.int_value = p_pipeline_key.shader_specialization.packed_1;
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
+ specialization_constants.push_back(sc);
+
+ sc.constant_id = 2;
+ sc.float_value = p_pipeline_key.shader_specialization.packed_2;
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT;
specialization_constants.push_back(sc);
@@ -521,6 +527,8 @@ void SceneShaderForwardMobile::init(const String p_defines) {
actions.renames["PI"] = _MKSTR(Math_PI);
actions.renames["TAU"] = _MKSTR(Math_TAU);
actions.renames["E"] = _MKSTR(Math_E);
+ actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+ actions.renames["CLIP_SPACE_FAR"] = "SHADER_SPACE_FAR";
actions.renames["VIEWPORT_SIZE"] = "read_viewport_size";
actions.renames["FRAGCOORD"] = "gl_FragCoord";
@@ -560,8 +568,6 @@ void SceneShaderForwardMobile::init(const String p_defines) {
actions.renames["CUSTOM1"] = "custom1_attrib";
actions.renames["CUSTOM2"] = "custom2_attrib";
actions.renames["CUSTOM3"] = "custom3_attrib";
- actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
- actions.renames["CLIP_SPACE_FAR"] = "SHADER_SPACE_FAR";
actions.renames["LIGHT_VERTEX"] = "light_vertex";
actions.renames["NODE_POSITION_WORLD"] = "read_model_matrix[3].xyz";
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
index c1095d29dc..f0afeebe79 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
@@ -65,31 +65,42 @@ public:
uint32_t use_directional_soft_shadows : 1;
uint32_t decal_use_mipmaps : 1;
uint32_t projector_use_mipmaps : 1;
- uint32_t disable_omni_lights : 1;
- uint32_t disable_spot_lights : 1;
- uint32_t disable_reflection_probes : 1;
- uint32_t disable_directional_lights : 1;
- uint32_t disable_decals : 1;
uint32_t disable_fog : 1;
uint32_t use_depth_fog : 1;
- uint32_t is_multimesh : 1;
uint32_t use_lightmap_bicubic_filter : 1;
- uint32_t pad : 2;
- uint32_t soft_shadow_samples : 4;
- uint32_t penumbra_shadow_samples : 4;
- uint32_t directional_soft_shadow_samples : 4;
- uint32_t directional_penumbra_shadow_samples : 4;
+ uint32_t multimesh : 1;
+ uint32_t multimesh_format_2d : 1;
+ uint32_t multimesh_has_color : 1;
+ uint32_t multimesh_has_custom_data : 1;
+ uint32_t scene_use_ambient_cubemap : 1;
+ uint32_t scene_use_reflection_cubemap : 1;
+ uint32_t scene_roughness_limiter_enabled : 1;
+ uint32_t padding : 5;
+ uint32_t soft_shadow_samples : 6;
+ uint32_t penumbra_shadow_samples : 6;
};
uint32_t packed_0;
};
union {
- float luminance_multiplier;
- float packed_1;
+ struct {
+ uint32_t directional_soft_shadow_samples : 6;
+ uint32_t directional_penumbra_shadow_samples : 6;
+ uint32_t omni_lights : 4;
+ uint32_t spot_lights : 4;
+ uint32_t reflection_probes : 4;
+ uint32_t directional_lights : 4;
+ uint32_t decals : 4;
+ };
+
+ uint32_t packed_1;
};
- uint32_t packed_2;
+ union {
+ float luminance_multiplier;
+ float packed_2;
+ };
};
struct UbershaderConstants {
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 979f590c4c..0dcdb90948 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -911,7 +911,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
RenderingServerDefault::redraw_request();
}
- state.current_data_buffer_index = (state.current_data_buffer_index + 1) % state.canvas_instance_data_buffers.size();
+ state.current_data_buffer_index = (state.current_data_buffer_index + 1) % BATCH_DATA_BUFFER_COUNT;
state.current_instance_buffer_index = 0;
}
@@ -993,36 +993,43 @@ void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index,
Vector<Color> cc;
cc.push_back(Color(p_far, p_far, p_far, 1.0));
- for (int i = 0; i < 4; i++) {
- //make sure it remains orthogonal, makes easy to read angle later
+ Projection projection;
+ {
+ real_t fov = 90;
+ real_t nearp = p_near;
+ real_t farp = p_far;
+ real_t aspect = 1.0;
- //light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1));
+ real_t ymax = nearp * Math::tan(Math::deg_to_rad(fov * 0.5));
+ real_t ymin = -ymax;
+ real_t xmin = ymin * aspect;
+ real_t xmax = ymax * aspect;
- Rect2i rect((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2);
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect);
+ projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp);
+ }
- Projection projection;
- {
- real_t fov = 90;
- real_t nearp = p_near;
- real_t farp = p_far;
- real_t aspect = 1.0;
+ // Precomputed:
+ // Vector3 cam_target = Basis::from_euler(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0));
+ // projection = projection * Projection(Transform3D().looking_at(cam_targets[i], Vector3(0, 0, -1)).affine_inverse());
+ const Projection projections[4] = {
+ projection * Projection(Vector4(0, 0, -1, 0), Vector4(1, 0, 0, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)),
- real_t ymax = nearp * Math::tan(Math::deg_to_rad(fov * 0.5));
- real_t ymin = -ymax;
- real_t xmin = ymin * aspect;
- real_t xmax = ymax * aspect;
+ projection * Projection(Vector4(-1, 0, 0, 0), Vector4(0, 0, -1, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)),
- projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp);
- }
+ projection * Projection(Vector4(0, 0, 1, 0), Vector4(-1, 0, 0, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1)),
+
+ projection * Projection(Vector4(1, 0, 0, 0), Vector4(0, 0, 1, 0), Vector4(0, -1, 0, 0), Vector4(0, 0, 0, 1))
+
+ };
- Vector3 cam_target = Basis::from_euler(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0));
- projection = projection * Projection(Transform3D().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse());
+ for (int i = 0; i < 4; i++) {
+ Rect2i rect((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect);
ShadowRenderPushConstant push_constant;
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
- push_constant.projection[y * 4 + x] = projection.columns[y][x];
+ push_constant.projection[y * 4 + x] = projections[i].columns[y][x];
}
}
static const Vector2 directions[4] = { Vector2(1, 0), Vector2(0, 1), Vector2(-1, 0), Vector2(0, -1) };
@@ -1647,6 +1654,9 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
default_samplers.default_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
}
+ // preallocate 5 slots for uniform set 3
+ state.batch_texture_uniforms.resize(5);
+
{ //shader variants
String global_defines;
@@ -1974,15 +1984,18 @@ void fragment() {
}
{
+ uint32_t cache_size = uint32_t(GLOBAL_GET("rendering/2d/batching/uniform_set_cache_size"));
+ rid_set_to_uniform_set.set_capacity(cache_size);
+ }
+
+ {
state.max_instances_per_buffer = uint32_t(GLOBAL_GET("rendering/2d/batching/item_buffer_size"));
state.max_instance_buffer_size = state.max_instances_per_buffer * sizeof(InstanceData);
- state.canvas_instance_data_buffers.resize(3);
state.canvas_instance_batches.reserve(200);
- for (int i = 0; i < 3; i++) {
- DataBuffer db;
+ for (uint32_t i = 0; i < BATCH_DATA_BUFFER_COUNT; i++) {
+ DataBuffer &db = state.canvas_instance_data_buffers[i];
db.instance_buffers.push_back(RD::get_singleton()->storage_buffer_create(state.max_instance_buffer_size));
- state.canvas_instance_data_buffers[i] = db;
}
state.instance_data_array = memnew_arr(InstanceData, state.max_instances_per_buffer);
}
@@ -2159,7 +2172,7 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, clear_colors);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, clear_colors, 1, 0, Rect2(), RDD::BreadcrumbMarker::UI_PASS);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, fb_uniform_set, BASE_UNIFORM_SET);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, state.default_transforms_uniform_set, TRANSFORMS_UNIFORM_SET);
@@ -2203,14 +2216,47 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target
RD::get_singleton()->draw_list_end();
+ texture_info_map.clear();
state.current_batch_index = 0;
state.canvas_instance_batches.clear();
state.last_instance_index += instance_index;
}
+RendererCanvasRenderRD::InstanceData *RendererCanvasRenderRD::new_instance_data(float *p_world, uint32_t *p_lights, uint32_t p_base_flags, uint32_t p_index, TextureInfo *p_info) {
+ InstanceData *instance_data = &state.instance_data_array[p_index];
+ // Zero out most fields.
+ for (int i = 0; i < 4; i++) {
+ instance_data->modulation[i] = 0.0;
+ instance_data->ninepatch_margins[i] = 0.0;
+ instance_data->src_rect[i] = 0.0;
+ instance_data->dst_rect[i] = 0.0;
+ }
+
+ instance_data->pad[0] = 0.0;
+ instance_data->pad[1] = 0.0;
+
+ instance_data->lights[0] = p_lights[0];
+ instance_data->lights[1] = p_lights[1];
+ instance_data->lights[2] = p_lights[2];
+ instance_data->lights[3] = p_lights[3];
+
+ for (int i = 0; i < 6; i++) {
+ instance_data->world[i] = p_world[i];
+ }
+
+ instance_data->flags = p_base_flags | p_info->flags; // Reset on each command for safety, keep canvas texture binding config.
+
+ instance_data->color_texture_pixel_size[0] = p_info->texpixel_size.width;
+ instance_data->color_texture_pixel_size[1] = p_info->texpixel_size.height;
+
+ instance_data->pad1 = 0;
+
+ return instance_data;
+}
+
void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, Batch *&r_current_batch) {
- RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? default_filter : p_item->texture_filter;
- RenderingServer::CanvasItemTextureRepeat texture_repeat = p_item->texture_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? default_repeat : p_item->texture_repeat;
+ const RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? default_filter : p_item->texture_filter;
+ const RenderingServer::CanvasItemTextureRepeat texture_repeat = p_item->texture_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? default_repeat : p_item->texture_repeat;
Transform2D base_transform = p_base_transform;
@@ -2241,7 +2287,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
light_count++;
- if (light_count == state.max_lights_per_item - 1) {
+ if (light_count == MAX_LIGHTS_PER_ITEM - 1) {
break;
}
}
@@ -2258,38 +2304,6 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->use_lighting = use_lighting;
}
- // new_instance_data should be called after the current_batch is set.
- auto new_instance_data = [&]() -> InstanceData * {
- InstanceData *instance_data = &state.instance_data_array[r_index];
- // Zero out most fields.
- for (int i = 0; i < 4; i++) {
- instance_data->modulation[i] = 0.0;
- instance_data->ninepatch_margins[i] = 0.0;
- instance_data->src_rect[i] = 0.0;
- instance_data->dst_rect[i] = 0.0;
- }
-
- instance_data->pad[0] = 0.0;
- instance_data->pad[1] = 0.0;
-
- instance_data->lights[0] = lights[0];
- instance_data->lights[1] = lights[1];
- instance_data->lights[2] = lights[2];
- instance_data->lights[3] = lights[3];
-
- for (int i = 0; i < 6; i++) {
- instance_data->world[i] = world[i];
- }
-
- instance_data->flags = base_flags | r_current_batch->tex_info.flags; // Reset on each command for safety, keep canvas texture binding config.
-
- instance_data->color_texture_pixel_size[0] = r_current_batch->tex_info.texpixel_size.width;
- instance_data->color_texture_pixel_size[1] = r_current_batch->tex_info.texpixel_size.height;
- instance_data->specular_shininess = r_current_batch->tex_info.specular_shininess;
-
- return instance_data;
- };
-
const Item::Command *c = p_item->commands;
while (c) {
if (skipping && c->type != Item::Command::TYPE_ANIMATION_SLICE) {
@@ -2311,17 +2325,9 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES;
}
+ RenderingServer::CanvasItemTextureRepeat rect_repeat = texture_repeat;
if (bool(rect->flags & CANVAS_RECT_TILE)) {
- texture_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED;
- }
-
- bool has_msdf = bool(rect->flags & CANVAS_RECT_MSDF);
- TextureState tex_state(rect->texture, texture_filter, texture_repeat, has_msdf, use_linear_colors);
-
- if (tex_state != r_current_batch->tex_info.state) {
- r_current_batch = _new_batch(r_batch_broken);
- r_current_batch->tex_info.state = tex_state;
- _prepare_batch_texture_info(r_current_batch, rect->texture);
+ rect_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED;
}
Color modulated = rect->modulate * base_color;
@@ -2340,12 +2346,25 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES;
}
- InstanceData *instance_data = new_instance_data();
+ bool has_msdf = bool(rect->flags & CANVAS_RECT_MSDF);
+ TextureState tex_state(rect->texture, texture_filter, rect_repeat, has_msdf, use_linear_colors);
+ TextureInfo *tex_info = texture_info_map.getptr(tex_state);
+ if (!tex_info) {
+ tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value;
+ _prepare_batch_texture_info(rect->texture, tex_state, tex_info);
+ }
+
+ if (r_current_batch->tex_info != tex_info) {
+ r_current_batch = _new_batch(r_batch_broken);
+ r_current_batch->tex_info = tex_info;
+ }
+
+ InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
Rect2 src_rect;
Rect2 dst_rect;
if (rect->texture.is_valid()) {
- src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * r_current_batch->tex_info.texpixel_size, rect->source.size * r_current_batch->tex_info.texpixel_size) : Rect2(0, 0, 1, 1);
+ src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * tex_info->texpixel_size, rect->source.size * tex_info->texpixel_size) : Rect2(0, 0, 1, 1);
dst_rect = Rect2(rect->rect.position, rect->rect.size);
if (dst_rect.size.width < 0) {
@@ -2431,13 +2450,18 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
}
TextureState tex_state(np->texture, texture_filter, texture_repeat, false, use_linear_colors);
- if (tex_state != r_current_batch->tex_info.state) {
+ TextureInfo *tex_info = texture_info_map.getptr(tex_state);
+ if (!tex_info) {
+ tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value;
+ _prepare_batch_texture_info(np->texture, tex_state, tex_info);
+ }
+
+ if (r_current_batch->tex_info != tex_info) {
r_current_batch = _new_batch(r_batch_broken);
- r_current_batch->tex_info.state = tex_state;
- _prepare_batch_texture_info(r_current_batch, np->texture);
+ r_current_batch->tex_info = tex_info;
}
- InstanceData *instance_data = new_instance_data();
+ InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
Rect2 src_rect;
Rect2 dst_rect(np->rect.position.x, np->rect.position.y, np->rect.size.x, np->rect.size.y);
@@ -2446,7 +2470,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
src_rect = Rect2(0, 0, 1, 1);
} else {
if (np->source != Rect2()) {
- src_rect = Rect2(np->source.position.x * r_current_batch->tex_info.texpixel_size.width, np->source.position.y * r_current_batch->tex_info.texpixel_size.height, np->source.size.x * r_current_batch->tex_info.texpixel_size.width, np->source.size.y * r_current_batch->tex_info.texpixel_size.height);
+ src_rect = Rect2(np->source.position.x * tex_info->texpixel_size.width, np->source.position.y * tex_info->texpixel_size.height, np->source.size.x * tex_info->texpixel_size.width, np->source.size.y * tex_info->texpixel_size.height);
instance_data->color_texture_pixel_size[0] = 1.0 / np->source.size.width;
instance_data->color_texture_pixel_size[1] = 1.0 / np->source.size.height;
} else {
@@ -2500,10 +2524,15 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->command = c;
TextureState tex_state(polygon->texture, texture_filter, texture_repeat, false, use_linear_colors);
- if (tex_state != r_current_batch->tex_info.state) {
+ TextureInfo *tex_info = texture_info_map.getptr(tex_state);
+ if (!tex_info) {
+ tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value;
+ _prepare_batch_texture_info(polygon->texture, tex_state, tex_info);
+ }
+
+ if (r_current_batch->tex_info != tex_info) {
r_current_batch = _new_batch(r_batch_broken);
- r_current_batch->tex_info.state = tex_state;
- _prepare_batch_texture_info(r_current_batch, polygon->texture);
+ r_current_batch->tex_info = tex_info;
}
// pipeline variant
@@ -2513,7 +2542,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->render_primitive = _primitive_type_to_render_primitive(polygon->primitive);
}
- InstanceData *instance_data = new_instance_data();
+ InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
Color color = base_color;
if (use_linear_colors) {
@@ -2557,17 +2586,22 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
default:
// Unknown point count.
break;
- };
-
- TextureState tex_state(primitive->texture, texture_filter, texture_repeat, false, use_linear_colors);
- if (tex_state != r_current_batch->tex_info.state) {
- r_current_batch = _new_batch(r_batch_broken);
- r_current_batch->tex_info.state = tex_state;
- _prepare_batch_texture_info(r_current_batch, primitive->texture);
}
}
- InstanceData *instance_data = new_instance_data();
+ TextureState tex_state(primitive->texture, texture_filter, texture_repeat, false, use_linear_colors);
+ TextureInfo *tex_info = texture_info_map.getptr(tex_state);
+ if (!tex_info) {
+ tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value;
+ _prepare_batch_texture_info(primitive->texture, tex_state, tex_info);
+ }
+
+ if (r_current_batch->tex_info != tex_info) {
+ r_current_batch = _new_batch(r_batch_broken);
+ r_current_batch->tex_info = tex_info;
+ }
+
+ InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
for (uint32_t j = 0; j < MIN(3u, primitive->point_count); j++) {
instance_data->points[j * 2 + 0] = primitive->points[j].x;
@@ -2585,7 +2619,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
_add_to_batch(r_index, r_batch_broken, r_current_batch);
if (primitive->point_count == 4) {
- instance_data = new_instance_data();
+ instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
for (uint32_t j = 0; j < 3; j++) {
int offset = j == 0 ? 0 : 1;
@@ -2594,7 +2628,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
instance_data->points[j * 2 + 1] = primitive->points[j + offset].y;
instance_data->uvs[j * 2 + 0] = primitive->uvs[j + offset].x;
instance_data->uvs[j * 2 + 1] = primitive->uvs[j + offset].y;
- Color col = primitive->colors[j] * base_color;
+ Color col = primitive->colors[j + offset] * base_color;
if (use_linear_colors) {
col = col.srgb_to_linear();
}
@@ -2621,9 +2655,13 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
if (c->type == Item::Command::TYPE_MESH) {
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
TextureState tex_state(m->texture, texture_filter, texture_repeat, false, use_linear_colors);
- r_current_batch->tex_info.state = tex_state;
- _prepare_batch_texture_info(r_current_batch, m->texture);
- instance_data = new_instance_data();
+ TextureInfo *tex_info = texture_info_map.getptr(tex_state);
+ if (!tex_info) {
+ tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value;
+ _prepare_batch_texture_info(m->texture, tex_state, tex_info);
+ }
+ r_current_batch->tex_info = tex_info;
+ instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
r_current_batch->mesh_instance_count = 1;
_update_transform_2d_to_mat2x3(base_transform * draw_transform * m->transform, instance_data->world);
@@ -2644,9 +2682,13 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
}
TextureState tex_state(mm->texture, texture_filter, texture_repeat, false, use_linear_colors);
- r_current_batch->tex_info.state = tex_state;
- _prepare_batch_texture_info(r_current_batch, mm->texture);
- instance_data = new_instance_data();
+ TextureInfo *tex_info = texture_info_map.getptr(tex_state);
+ if (!tex_info) {
+ tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value;
+ _prepare_batch_texture_info(mm->texture, tex_state, tex_info);
+ }
+ r_current_batch->tex_info = tex_info;
+ instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
instance_data->flags |= 1; // multimesh, trails disabled
@@ -2662,10 +2704,13 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c);
TextureState tex_state(pt->texture, texture_filter, texture_repeat, false, use_linear_colors);
- r_current_batch->tex_info.state = tex_state;
- _prepare_batch_texture_info(r_current_batch, pt->texture);
-
- instance_data = new_instance_data();
+ TextureInfo *tex_info = texture_info_map.getptr(tex_state);
+ if (!tex_info) {
+ tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value;
+ _prepare_batch_texture_info(pt->texture, tex_state, tex_info);
+ }
+ r_current_batch->tex_info = tex_info;
+ instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
uint32_t divisor = 1;
r_current_batch->mesh_instance_count = particles_storage->particles_get_amount(pt->particles, divisor);
@@ -2747,36 +2792,137 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_batch_broken = false;
}
+#ifdef DEBUG_ENABLED
+ if (debug_redraw && p_item->debug_redraw_time > 0.0) {
+ Color dc = debug_redraw_color;
+ dc.a *= p_item->debug_redraw_time / debug_redraw_time;
+
+ // 1: If commands are different, start a new batch.
+ if (r_current_batch->command_type != Item::Command::TYPE_RECT) {
+ r_current_batch = _new_batch(r_batch_broken);
+ r_current_batch->command_type = Item::Command::TYPE_RECT;
+ // it is ok to be null for a TYPE_RECT
+ r_current_batch->command = nullptr;
+ // default variant
+ r_current_batch->shader_variant = SHADER_VARIANT_QUAD;
+ r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES;
+ }
+
+ // 2: If the current batch has lighting, start a new batch.
+ if (r_current_batch->use_lighting) {
+ r_current_batch = _new_batch(r_batch_broken);
+ r_current_batch->use_lighting = false;
+ }
+
+ // 3: If the current batch has blend, start a new batch.
+ if (r_current_batch->has_blend) {
+ r_current_batch = _new_batch(r_batch_broken);
+ r_current_batch->has_blend = false;
+ }
+
+ TextureState tex_state(default_canvas_texture, texture_filter, texture_repeat, false, use_linear_colors);
+ TextureInfo *tex_info = texture_info_map.getptr(tex_state);
+ if (!tex_info) {
+ tex_info = &texture_info_map.insert(tex_state, TextureInfo())->value;
+ _prepare_batch_texture_info(default_canvas_texture, tex_state, tex_info);
+ }
+
+ if (r_current_batch->tex_info != tex_info) {
+ r_current_batch = _new_batch(r_batch_broken);
+ r_current_batch->tex_info = tex_info;
+ }
+
+ InstanceData *instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
+
+ Rect2 src_rect;
+ Rect2 dst_rect;
+
+ dst_rect = Rect2(Vector2(), p_item->rect.size);
+ if (dst_rect.size.width < 0) {
+ dst_rect.position.x += dst_rect.size.width;
+ dst_rect.size.width *= -1;
+ }
+ if (dst_rect.size.height < 0) {
+ dst_rect.position.y += dst_rect.size.height;
+ dst_rect.size.height *= -1;
+ }
+
+ src_rect = Rect2(0, 0, 1, 1);
+
+ instance_data->modulation[0] = dc.r;
+ instance_data->modulation[1] = dc.g;
+ instance_data->modulation[2] = dc.b;
+ instance_data->modulation[3] = dc.a;
+
+ instance_data->src_rect[0] = src_rect.position.x;
+ instance_data->src_rect[1] = src_rect.position.y;
+ instance_data->src_rect[2] = src_rect.size.width;
+ instance_data->src_rect[3] = src_rect.size.height;
+
+ instance_data->dst_rect[0] = dst_rect.position.x;
+ instance_data->dst_rect[1] = dst_rect.position.y;
+ instance_data->dst_rect[2] = dst_rect.size.width;
+ instance_data->dst_rect[3] = dst_rect.size.height;
+
+ _add_to_batch(r_index, r_batch_broken, r_current_batch);
+
+ p_item->debug_redraw_time -= RSG::rasterizer->get_frame_delta_time();
+
+ RenderingServerDefault::redraw_request();
+
+ r_batch_broken = false;
+ }
+#endif
+
if (r_current_clip && reclip) {
// will make it re-enable clipping if needed afterwards
r_current_clip = nullptr;
}
}
-void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasShaderData *p_shader_data, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info) {
- UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
- ERR_FAIL_NULL(uniform_set_cache);
+void RendererCanvasRenderRD::_before_evict(RendererCanvasRenderRD::RIDSetKey &p_key, RID &p_rid) {
+ RD::get_singleton()->uniform_set_set_invalidation_callback(p_rid, nullptr, nullptr);
+ RD::get_singleton()->free(p_rid);
+}
- ERR_FAIL_NULL(p_batch->command);
+void RendererCanvasRenderRD::_uniform_set_invalidation_callback(void *p_userdata) {
+ const RIDSetKey *key = static_cast<RIDSetKey *>(p_userdata);
+ static_cast<RendererCanvasRenderRD *>(singleton)->rid_set_to_uniform_set.erase(*key);
+}
+void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasShaderData *p_shader_data, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info) {
{
- RD::Uniform u_diffuse(RD::UNIFORM_TYPE_TEXTURE, 0, p_batch->tex_info.diffuse);
- RD::Uniform u_normal(RD::UNIFORM_TYPE_TEXTURE, 1, p_batch->tex_info.normal);
- RD::Uniform u_specular(RD::UNIFORM_TYPE_TEXTURE, 2, p_batch->tex_info.specular);
- RD::Uniform u_sampler(RD::UNIFORM_TYPE_SAMPLER, 3, p_batch->tex_info.sampler);
- RD::Uniform u_instance_data(RD::UNIFORM_TYPE_STORAGE_BUFFER, 4, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]);
-
- RID uniform_set = uniform_set_cache->get_cache(shader.default_version_rd_shader, BATCH_UNIFORM_SET, u_diffuse, u_normal, u_specular, u_sampler, u_instance_data);
+ RIDSetKey key(
+ p_batch->tex_info->state,
+ state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]);
+
+ const RID *uniform_set = rid_set_to_uniform_set.getptr(key);
+ if (uniform_set == nullptr) {
+ state.batch_texture_uniforms.write[0] = RD::Uniform(RD::UNIFORM_TYPE_TEXTURE, 0, p_batch->tex_info->diffuse);
+ state.batch_texture_uniforms.write[1] = RD::Uniform(RD::UNIFORM_TYPE_TEXTURE, 1, p_batch->tex_info->normal);
+ state.batch_texture_uniforms.write[2] = RD::Uniform(RD::UNIFORM_TYPE_TEXTURE, 2, p_batch->tex_info->specular);
+ state.batch_texture_uniforms.write[3] = RD::Uniform(RD::UNIFORM_TYPE_SAMPLER, 3, p_batch->tex_info->sampler);
+ state.batch_texture_uniforms.write[4] = RD::Uniform(RD::UNIFORM_TYPE_STORAGE_BUFFER, 4, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[p_batch->instance_buffer_index]);
+
+ RID rid = RD::get_singleton()->uniform_set_create(state.batch_texture_uniforms, shader.default_version_rd_shader, BATCH_UNIFORM_SET);
+ ERR_FAIL_COND_MSG(rid.is_null(), "Failed to create uniform set for batch.");
+
+ const RIDCache::Pair *iter = rid_set_to_uniform_set.insert(key, rid);
+ uniform_set = &iter->data;
+ RD::get_singleton()->uniform_set_set_invalidation_callback(rid, RendererCanvasRenderRD::_uniform_set_invalidation_callback, (void *)&iter->key);
+ }
- if (state.current_batch_uniform_set != uniform_set) {
- state.current_batch_uniform_set = uniform_set;
- RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, BATCH_UNIFORM_SET);
+ if (state.current_batch_uniform_set != *uniform_set) {
+ state.current_batch_uniform_set = *uniform_set;
+ RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, *uniform_set, BATCH_UNIFORM_SET);
}
}
+ PushConstant push_constant;
+ push_constant.base_instance_index = p_batch->start;
+ push_constant.specular_shininess = p_batch->tex_info->specular_shininess;
RID pipeline;
PipelineKey pipeline_key;
- PushConstant push_constant;
pipeline_key.framebuffer_format_id = p_framebuffer_format;
pipeline_key.variant = p_batch->shader_variant;
pipeline_key.render_primitive = p_batch->render_primitive;
@@ -2792,7 +2938,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha
RD::get_singleton()->draw_list_set_blend_constants(p_draw_list, p_batch->modulate);
}
- push_constant.base_instance_index = p_batch->start;
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);
RD::get_singleton()->draw_list_draw(p_draw_list, true, p_batch->instance_count);
@@ -2805,6 +2950,8 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha
} break;
case Item::Command::TYPE_POLYGON: {
+ ERR_FAIL_NULL(p_batch->command);
+
const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(p_batch->command);
PolygonBuffers *pb = polygon_buffers.polygons.getptr(polygon->polygon.polygon_id);
@@ -2814,7 +2961,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha
pipeline = _get_pipeline_specialization_or_ubershader(p_shader_data, pipeline_key, push_constant);
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
- push_constant.base_instance_index = p_batch->start;
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, pb->vertex_array);
if (pb->indices.is_valid()) {
@@ -2830,12 +2976,13 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha
} break;
case Item::Command::TYPE_PRIMITIVE: {
+ ERR_FAIL_NULL(p_batch->command);
+
const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(p_batch->command);
pipeline = _get_pipeline_specialization_or_ubershader(p_shader_data, pipeline_key, push_constant);
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
- push_constant.base_instance_index = p_batch->start;
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, primitive_arrays.index_array[MIN(3u, primitive->point_count) - 1]);
uint32_t instance_count = p_batch->instance_count;
@@ -2852,6 +2999,8 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha
case Item::Command::TYPE_MESH:
case Item::Command::TYPE_MULTIMESH:
case Item::Command::TYPE_PARTICLES: {
+ ERR_FAIL_NULL(p_batch->command);
+
RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
RendererRD::ParticlesStorage *particles_storage = RendererRD::ParticlesStorage::get_singleton();
@@ -2912,7 +3061,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha
pipeline = _get_pipeline_specialization_or_ubershader(p_shader_data, pipeline_key, push_constant, mesh_instance, surface, j, &vertex_array);
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
- push_constant.base_instance_index = p_batch->start;
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
RID index_array = mesh_storage->mesh_surface_get_index_array(surface, 0);
@@ -2994,7 +3142,7 @@ void RendererCanvasRenderRD::_allocate_instance_buffer() {
state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers.push_back(buf);
}
-void RendererCanvasRenderRD::_prepare_batch_texture_info(Batch *p_current_batch, RID p_texture) const {
+void RendererCanvasRenderRD::_prepare_batch_texture_info(RID p_texture, TextureState &p_state, TextureInfo *p_info) {
if (p_texture.is_null()) {
p_texture = default_canvas_texture;
}
@@ -3002,38 +3150,38 @@ void RendererCanvasRenderRD::_prepare_batch_texture_info(Batch *p_current_batch,
RendererRD::TextureStorage::CanvasTextureInfo info =
RendererRD::TextureStorage::get_singleton()->canvas_texture_get_info(
p_texture,
- p_current_batch->tex_info.state.texture_filter(),
- p_current_batch->tex_info.state.texture_repeat(),
- p_current_batch->tex_info.state.linear_colors(),
- p_current_batch->tex_info.state.texture_is_data());
-
+ p_state.texture_filter(),
+ p_state.texture_repeat(),
+ p_state.linear_colors(),
+ p_state.texture_is_data());
// something odd happened
if (info.is_null()) {
- _prepare_batch_texture_info(p_current_batch, default_canvas_texture);
+ _prepare_batch_texture_info(default_canvas_texture, p_state, p_info);
return;
}
- p_current_batch->tex_info.diffuse = info.diffuse;
- p_current_batch->tex_info.normal = info.normal;
- p_current_batch->tex_info.specular = info.specular;
- p_current_batch->tex_info.sampler = info.sampler;
+ p_info->state = p_state;
+ p_info->diffuse = info.diffuse;
+ p_info->normal = info.normal;
+ p_info->specular = info.specular;
+ p_info->sampler = info.sampler;
// cache values to be copied to instance data
if (info.specular_color.a < 0.999) {
- p_current_batch->tex_info.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
+ p_info->flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
}
if (info.use_normal) {
- p_current_batch->tex_info.flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
+ p_info->flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
}
uint8_t a = uint8_t(CLAMP(info.specular_color.a * 255.0, 0.0, 255.0));
uint8_t b = uint8_t(CLAMP(info.specular_color.b * 255.0, 0.0, 255.0));
uint8_t g = uint8_t(CLAMP(info.specular_color.g * 255.0, 0.0, 255.0));
uint8_t r = uint8_t(CLAMP(info.specular_color.r * 255.0, 0.0, 255.0));
- p_current_batch->tex_info.specular_shininess = uint32_t(a) << 24 | uint32_t(b) << 16 | uint32_t(g) << 8 | uint32_t(r);
+ p_info->specular_shininess = uint32_t(a) << 24 | uint32_t(b) << 16 | uint32_t(g) << 8 | uint32_t(r);
- p_current_batch->tex_info.texpixel_size = Vector2(1.0 / float(info.size.width), 1.0 / float(info.size.height));
+ p_info->texpixel_size = Vector2(1.0 / float(info.size.width), 1.0 / float(info.size.height));
}
RendererCanvasRenderRD::~RendererCanvasRenderRD() {
@@ -3075,7 +3223,7 @@ RendererCanvasRenderRD::~RendererCanvasRenderRD() {
RD::get_singleton()->free(state.shadow_texture);
memdelete_arr(state.instance_data_array);
- for (uint32_t i = 0; i < state.canvas_instance_data_buffers.size(); i++) {
+ for (uint32_t i = 0; i < BATCH_DATA_BUFFER_COUNT; i++) {
for (uint32_t j = 0; j < state.canvas_instance_data_buffers[i].instance_buffers.size(); j++) {
RD::get_singleton()->free(state.canvas_instance_data_buffers[i].instance_buffers[j]);
}
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 07445b5c53..1bdc5076c5 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -31,6 +31,7 @@
#ifndef RENDERER_CANVAS_RENDER_RD_H
#define RENDERER_CANVAS_RENDER_RD_H
+#include "core/templates/lru.h"
#include "servers/rendering/renderer_canvas_render.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
@@ -50,6 +51,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
};
const int SAMPLERS_BINDING_FIRST_INDEX = 10;
+ // The size of the ring buffer to store GPU buffers. Triple-buffering the max expected frames in flight.
+ static const uint32_t BATCH_DATA_BUFFER_COUNT = 3;
enum ShaderVariant {
SHADER_VARIANT_QUAD,
@@ -339,7 +342,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
struct InstanceData {
float world[6];
uint32_t flags;
- uint32_t specular_shininess;
+ uint32_t pad1;
union {
//rect
struct {
@@ -366,8 +369,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
struct PushConstant {
uint32_t base_instance_index;
ShaderSpecialization shader_specialization;
- uint32_t pad2;
- uint32_t pad3;
+ uint32_t specular_shininess;
+ uint32_t pad;
};
// TextureState is used to determine when a new batch is required due to a change of texture state.
@@ -398,50 +401,91 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
(((uint32_t)p_use_linear_colors & LINEAR_COLORS_MASK) << LINEAR_COLORS_SHIFT);
}
- _FORCE_INLINE_ RS::CanvasItemTextureFilter texture_filter() const {
+ _ALWAYS_INLINE_ RS::CanvasItemTextureFilter texture_filter() const {
return (RS::CanvasItemTextureFilter)((other >> FILTER_SHIFT) & FILTER_MASK);
}
- _FORCE_INLINE_ RS::CanvasItemTextureRepeat texture_repeat() const {
+ _ALWAYS_INLINE_ RS::CanvasItemTextureRepeat texture_repeat() const {
return (RS::CanvasItemTextureRepeat)((other >> REPEAT_SHIFT) & REPEAT_MASK);
}
- _FORCE_INLINE_ bool linear_colors() const {
+ _ALWAYS_INLINE_ bool linear_colors() const {
return (other >> LINEAR_COLORS_SHIFT) & LINEAR_COLORS_MASK;
}
- _FORCE_INLINE_ bool texture_is_data() const {
+ _ALWAYS_INLINE_ bool texture_is_data() const {
return (other >> TEXTURE_IS_DATA_SHIFT) & TEXTURE_IS_DATA_MASK;
}
- bool operator==(const TextureState &p_val) const {
+ _ALWAYS_INLINE_ bool operator==(const TextureState &p_val) const {
return (texture == p_val.texture) && (other == p_val.other);
}
- bool operator!=(const TextureState &p_val) const {
+ _ALWAYS_INLINE_ bool operator!=(const TextureState &p_val) const {
return (texture != p_val.texture) || (other != p_val.other);
}
+
+ _ALWAYS_INLINE_ bool is_valid() const { return texture.is_valid(); }
+ _ALWAYS_INLINE_ bool is_null() const { return texture.is_null(); }
+
+ uint32_t hash() const {
+ uint32_t hash = hash_murmur3_one_64(texture.get_id());
+ return hash_murmur3_one_32(other, hash);
+ }
};
struct TextureInfo {
TextureState state;
- uint32_t specular_shininess = 0;
- uint32_t flags = 0;
- Vector2 texpixel_size;
-
RID diffuse;
RID normal;
RID specular;
RID sampler;
+ Vector2 texpixel_size;
+ uint32_t specular_shininess = 0;
+ uint32_t flags = 0;
+ };
+
+ /// A key used to uniquely identify a distinct BATCH_UNIFORM_SET
+ struct RIDSetKey {
+ TextureState state;
+ RID instance_data;
+
+ RIDSetKey() {
+ }
+
+ RIDSetKey(TextureState p_state, RID p_instance_data) :
+ state(p_state),
+ instance_data(p_instance_data) {
+ }
+
+ _ALWAYS_INLINE_ bool operator==(const RIDSetKey &p_val) const {
+ return state == p_val.state && instance_data == p_val.instance_data;
+ }
+
+ _ALWAYS_INLINE_ bool operator!=(const RIDSetKey &p_val) const {
+ return !(*this == p_val);
+ }
+
+ _ALWAYS_INLINE_ uint32_t hash() const {
+ uint32_t h = state.hash();
+ h = hash_murmur3_one_64(instance_data.get_id(), h);
+ return hash_fmix32(h);
+ }
};
+ static void _before_evict(RendererCanvasRenderRD::RIDSetKey &p_key, RID &p_rid);
+ static void _uniform_set_invalidation_callback(void *p_userdata);
+
+ typedef LRUCache<RIDSetKey, RID, HashableHasher<RIDSetKey>, HashMapComparatorDefault<RIDSetKey>, _before_evict> RIDCache;
+ RIDCache rid_set_to_uniform_set;
+
struct Batch {
// Position in the UBO measured in bytes
uint32_t start = 0;
uint32_t instance_count = 0;
uint32_t instance_buffer_index = 0;
- TextureInfo tex_info;
+ TextureInfo *tex_info;
Color modulate = Color(1.0, 1.0, 1.0, 1.0);
@@ -466,6 +510,9 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
bool has_blend = false;
};
+ HashMap<TextureState, TextureInfo, HashableHasher<TextureState>> texture_info_map;
+
+ // per-frame buffers
struct DataBuffer {
LocalVector<RID> instance_buffers;
};
@@ -492,7 +539,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
uint32_t pad2;
};
- LocalVector<DataBuffer> canvas_instance_data_buffers;
+ DataBuffer canvas_instance_data_buffers[BATCH_DATA_BUFFER_COUNT];
LocalVector<Batch> canvas_instance_batches;
uint32_t current_data_buffer_index = 0;
uint32_t current_instance_buffer_index = 0;
@@ -503,6 +550,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
uint32_t max_instances_per_buffer = 16384;
uint32_t max_instance_buffer_size = 16384 * sizeof(InstanceData);
+ Vector<RD::Uniform> batch_texture_uniforms;
RID current_batch_uniform_set;
LightUniform *light_uniforms = nullptr;
@@ -518,7 +566,6 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
RID default_transforms_uniform_set;
uint32_t max_lights_per_render;
- uint32_t max_lights_per_item;
double time;
@@ -558,7 +605,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
void _render_batch_items(RenderTarget p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false, RenderingMethod::RenderInfo *r_render_info = nullptr);
void _record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, Batch *&r_current_batch);
void _render_batch(RD::DrawListID p_draw_list, CanvasShaderData *p_shader_data, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info = nullptr);
- void _prepare_batch_texture_info(Batch *p_current_batch, RID p_texture) const;
+ void _prepare_batch_texture_info(RID p_texture, TextureState &p_state, TextureInfo *p_info);
+ InstanceData *new_instance_data(float *p_world, uint32_t *p_lights, uint32_t p_base_flags, uint32_t p_index, TextureInfo *p_info);
[[nodiscard]] Batch *_new_batch(bool &r_batch_broken);
void _add_to_batch(uint32_t &r_index, bool &r_batch_broken, Batch *&r_current_batch);
void _allocate_instance_buffer();
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index 84ea6a5da2..ba47508700 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -66,6 +66,16 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID
RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.array);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_target_descriptors[rd_texture], 0);
+ // We need to invert the phone rotation.
+ const int screen_rotation_degrees = -RD::get_singleton()->screen_get_pre_rotation_degrees(p_screen);
+ float screen_rotation = Math::deg_to_rad((float)screen_rotation_degrees);
+
+ blit.push_constant.rotation_cos = Math::cos(screen_rotation);
+ blit.push_constant.rotation_sin = Math::sin(screen_rotation);
+ // Swap width and height when the orientation is not the native one.
+ if (screen_rotation_degrees % 180 != 0) {
+ SWAP(screen_size.width, screen_size.height);
+ }
blit.push_constant.src_rect[0] = p_render_targets[i].src_rect.position.x;
blit.push_constant.src_rect[1] = p_render_targets[i].src_rect.position.y;
blit.push_constant.src_rect[2] = p_render_targets[i].src_rect.size.width;
@@ -228,6 +238,10 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color
RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.array);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uset, 0);
+ const int screen_rotation_degrees = -RD::get_singleton()->screen_get_pre_rotation_degrees(DisplayServer::MAIN_WINDOW_ID);
+ float screen_rotation = Math::deg_to_rad((float)screen_rotation_degrees);
+ blit.push_constant.rotation_cos = Math::cos(screen_rotation);
+ blit.push_constant.rotation_sin = Math::sin(screen_rotation);
blit.push_constant.src_rect[0] = 0.0;
blit.push_constant.src_rect[1] = 0.0;
blit.push_constant.src_rect[2] = 1.0;
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h
index 2547f08715..6821fa737e 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.h
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h
@@ -74,6 +74,10 @@ protected:
float src_rect[4];
float dst_rect[4];
+ float rotation_sin;
+ float rotation_cos;
+ float pad[2];
+
float eye_center[2];
float k1;
float k2;
@@ -103,7 +107,7 @@ protected:
static RendererCompositorRD *singleton;
public:
- RendererUtilities *get_utilities() { return utilities; };
+ RendererUtilities *get_utilities() { return utilities; }
RendererLightStorage *get_light_storage() { return light_storage; }
RendererMaterialStorage *get_material_storage() { return material_storage; }
RendererMeshStorage *get_mesh_storage() { return mesh_storage; }
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index dc2605b670..4417f6832c 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -1130,6 +1130,7 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
scene_data.cam_transform = p_camera_data->main_transform;
scene_data.cam_projection = p_camera_data->main_projection;
scene_data.cam_orthogonal = p_camera_data->is_orthogonal;
+ scene_data.cam_frustum = p_camera_data->is_frustum;
scene_data.camera_visible_layers = p_camera_data->visible_layers;
scene_data.taa_jitter = p_camera_data->taa_jitter;
scene_data.taa_frame_count = p_camera_data->taa_frame_count;
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index b82d50378e..631ad21247 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -78,7 +78,7 @@ protected:
////////////////////////////////
- virtual RendererRD::ForwardIDStorage *create_forward_id_storage() { return memnew(RendererRD::ForwardIDStorage); };
+ virtual RendererRD::ForwardIDStorage *create_forward_id_storage() { return memnew(RendererRD::ForwardIDStorage); }
void _update_vrs(Ref<RenderSceneBuffersRD> p_render_buffers);
diff --git a/servers/rendering/renderer_rd/shaders/blit.glsl b/servers/rendering/renderer_rd/shaders/blit.glsl
index d451647bec..fe6416f03c 100644
--- a/servers/rendering/renderer_rd/shaders/blit.glsl
+++ b/servers/rendering/renderer_rd/shaders/blit.glsl
@@ -8,6 +8,10 @@ layout(push_constant, std140) uniform Pos {
vec4 src_rect;
vec4 dst_rect;
+ float rotation_sin;
+ float rotation_cos;
+ vec2 pad;
+
vec2 eye_center;
float k1;
float k2;
@@ -15,17 +19,23 @@ layout(push_constant, std140) uniform Pos {
float upscale;
float aspect_ratio;
uint layer;
- uint pad1;
+ bool convert_to_srgb;
}
data;
layout(location = 0) out vec2 uv;
void main() {
+ mat4 swapchain_transform = mat4(1.0);
+ swapchain_transform[0][0] = data.rotation_cos;
+ swapchain_transform[0][1] = -data.rotation_sin;
+ swapchain_transform[1][0] = data.rotation_sin;
+ swapchain_transform[1][1] = data.rotation_cos;
+
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 = data.src_rect.xy + base_arr[gl_VertexIndex] * data.src_rect.zw;
vec2 vtx = data.dst_rect.xy + base_arr[gl_VertexIndex] * data.dst_rect.zw;
- gl_Position = vec4(vtx * 2.0 - 1.0, 0.0, 1.0);
+ gl_Position = swapchain_transform * vec4(vtx * 2.0 - 1.0, 0.0, 1.0);
}
#[fragment]
@@ -38,6 +48,10 @@ layout(push_constant, std140) uniform Pos {
vec4 src_rect;
vec4 dst_rect;
+ float rotation_sin;
+ float rotation_cos;
+ vec2 pad;
+
vec2 eye_center;
float k1;
float k2;
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index dafcce37ad..f665bc24a4 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -28,7 +28,7 @@ layout(location = 11) in vec4 weight_attrib;
layout(location = 4) out flat uint instance_index_interp;
-#endif // USE_ATTRIBUTES
+#endif // !USE_ATTRIBUTES
layout(location = 0) out vec2 uv_interp;
layout(location = 1) out vec4 color_interp;
@@ -322,11 +322,7 @@ vec4 light_compute(
#ifdef USE_NINEPATCH
float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, float margin_begin, float margin_end, int np_repeat, inout int draw_center) {
-#ifdef USE_ATTRIBUTES
- const InstanceData draw_data = instances.data[params.base_instance_index];
-#else
const InstanceData draw_data = instances.data[instance_index];
-#endif // USE_ATTRIBUTES
float tex_size = 1.0 / tex_pixel_size;
@@ -567,7 +563,7 @@ void main() {
if (specular_shininess_used || (using_light && normal_used && bool(draw_data.flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
specular_shininess = texture(sampler2D(specular_texture, texture_sampler), uv);
- specular_shininess *= unpackUnorm4x8(draw_data.specular_shininess);
+ specular_shininess *= unpackUnorm4x8(params.specular_shininess);
specular_shininess_used = true;
} else {
specular_shininess = vec4(1.0);
diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
index ead8c459a4..84017a1fe1 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
@@ -37,7 +37,7 @@ struct InstanceData {
vec2 world_y;
vec2 world_ofs;
uint flags;
- uint specular_shininess;
+ uint pad2;
#ifdef USE_PRIMITIVE
vec2 points[3];
vec2 uvs[3];
@@ -57,8 +57,8 @@ struct InstanceData {
layout(push_constant, std430) uniform Params {
uint base_instance_index; // base index to instance data
uint sc_packed_0;
- uint pad2;
- uint pad3;
+ uint specular_shininess;
+ uint pad;
}
params;
@@ -68,7 +68,7 @@ params;
// Pull the constants from the draw call's push constants.
uint sc_packed_0() {
- return draw_call.sc_packed_0;
+ return params.sc_packed_0;
}
#else
diff --git a/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl
index 3fb93dda35..b45e310b61 100644
--- a/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl
@@ -8,7 +8,6 @@ layout(push_constant, std430) uniform Params {
float z_far;
float z_near;
vec2 texel_size;
- vec4 screen_rect;
}
params;
@@ -17,8 +16,7 @@ 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);
+ gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
}
#[fragment]
@@ -35,7 +33,6 @@ layout(push_constant, std430) uniform Params {
float z_far;
float z_near;
vec2 texel_size;
- vec4 screen_rect;
}
params;
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
index 72236dcd9f..81d3d87a22 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
@@ -211,6 +211,13 @@ vec3 double_add_vec3(vec3 base_a, vec3 prec_a, vec3 base_b, vec3 prec_b, out vec
}
#endif
+uint multimesh_stride() {
+ uint stride = sc_multimesh_format_2d() ? 2 : 3;
+ stride += sc_multimesh_has_color() ? 1 : 0;
+ stride += sc_multimesh_has_custom_data() ? 1 : 0;
+ return stride;
+}
+
void vertex_shader(vec3 vertex_input,
#ifdef NORMAL_USED
in vec3 normal_input,
@@ -219,7 +226,7 @@ void vertex_shader(vec3 vertex_input,
in vec3 tangent_input,
in vec3 binormal_input,
#endif
- in uint instance_index, in bool is_multimesh, in uint multimesh_offset, in SceneData scene_data, in mat4 model_matrix, out vec4 screen_pos) {
+ in uint instance_index, in uint multimesh_offset, in SceneData scene_data, in mat4 model_matrix, out vec4 screen_pos) {
vec4 instance_custom = vec4(0.0);
#if defined(COLOR_USED)
color_interp = color_attrib;
@@ -248,7 +255,7 @@ void vertex_shader(vec3 vertex_input,
mat4 matrix;
mat4 read_model_matrix = model_matrix;
- if (is_multimesh) {
+ if (sc_multimesh()) {
//multimesh, instances are for it
#ifdef USE_PARTICLE_TRAILS
@@ -296,25 +303,10 @@ void vertex_shader(vec3 vertex_input,
#endif
#else
- uint stride = 0;
- {
- //TODO implement a small lookup table for the stride
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
- stride += 2;
- } else {
- stride += 3;
- }
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
- stride += 1;
- }
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
- stride += 1;
- }
- }
-
+ uint stride = multimesh_stride();
uint offset = stride * (gl_InstanceIndex + multimesh_offset);
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
+ if (sc_multimesh_format_2d()) {
matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
offset += 2;
} else {
@@ -322,14 +314,14 @@ void vertex_shader(vec3 vertex_input,
offset += 3;
}
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
+ if (sc_multimesh_has_color()) {
#ifdef COLOR_USED
color_interp *= transforms.data[offset];
#endif
offset += 1;
}
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
+ if (sc_multimesh_has_custom_data()) {
instance_custom = transforms.data[offset];
}
@@ -427,7 +419,7 @@ void vertex_shader(vec3 vertex_input,
// Then we combine the translations from the model matrix and the view matrix using emulated doubles.
// We add the result to the vertex and ignore the final lost precision.
vec3 model_origin = model_matrix[3].xyz;
- if (is_multimesh) {
+ if (sc_multimesh()) {
vertex = mat3(matrix) * vertex;
model_origin = double_add_vec3(model_origin, model_precision, matrix[3].xyz, vec3(0.0), model_precision);
}
@@ -708,9 +700,7 @@ void _unpack_vertex_attributes(vec4 p_vertex_in, vec3 p_compressed_aabb_position
void main() {
uint instance_index = draw_call.instance_index;
-
- bool is_multimesh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH);
- if (!is_multimesh) {
+ if (!sc_multimesh()) {
instance_index += gl_InstanceIndex;
}
@@ -753,7 +743,7 @@ void main() {
prev_tangent,
prev_binormal,
#endif
- instance_index, is_multimesh, draw_call.multimesh_motion_vectors_previous_offset, scene_data_block.prev_data, instances.data[instance_index].prev_transform, prev_screen_position);
+ instance_index, draw_call.multimesh_motion_vectors_previous_offset, scene_data_block.prev_data, instances.data[instance_index].prev_transform, prev_screen_position);
#else
// Unused output.
vec4 screen_position;
@@ -792,7 +782,7 @@ void main() {
tangent,
binormal,
#endif
- instance_index, is_multimesh, draw_call.multimesh_motion_vectors_current_offset, scene_data_block.data, model_matrix, screen_position);
+ instance_index, draw_call.multimesh_motion_vectors_current_offset, scene_data_block.data, model_matrix, screen_position);
}
#[fragment]
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
index 9f68d59be2..8f153f7ed5 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
@@ -59,6 +59,10 @@ uint sc_packed_0() {
return draw_call.sc_packed_0;
}
+uint sc_packed_1() {
+ return draw_call.sc_packed_1;
+}
+
uint uc_cull_mode() {
return (draw_call.uc_packed_0 >> 0) & 3U;
}
@@ -67,11 +71,16 @@ uint uc_cull_mode() {
// Pull the constants from the pipeline's specialization constants.
layout(constant_id = 0) const uint pso_sc_packed_0 = 0;
+layout(constant_id = 1) const uint pso_sc_packed_1 = 0;
uint sc_packed_0() {
return pso_sc_packed_0;
}
+uint sc_packed_1() {
+ return pso_sc_packed_1;
+}
+
#endif
bool sc_use_forward_gi() {
@@ -107,19 +116,35 @@ bool sc_use_lightmap_bicubic_filter() {
}
uint sc_soft_shadow_samples() {
- return (sc_packed_0() >> 8) & 15U;
+ return (sc_packed_0() >> 8) & 63U;
}
uint sc_penumbra_shadow_samples() {
- return (sc_packed_0() >> 12) & 15U;
+ return (sc_packed_0() >> 14) & 63U;
}
uint sc_directional_soft_shadow_samples() {
- return (sc_packed_0() >> 16) & 15U;
+ return (sc_packed_0() >> 20) & 63U;
}
uint sc_directional_penumbra_shadow_samples() {
- return (sc_packed_0() >> 20) & 15U;
+ return (sc_packed_0() >> 26) & 63U;
+}
+
+bool sc_multimesh() {
+ return ((sc_packed_1() >> 0) & 1U) != 0;
+}
+
+bool sc_multimesh_format_2d() {
+ return ((sc_packed_1() >> 1) & 1U) != 0;
+}
+
+bool sc_multimesh_has_color() {
+ return ((sc_packed_1() >> 2) & 1U) != 0;
+}
+
+bool sc_multimesh_has_custom_data() {
+ return ((sc_packed_1() >> 3) & 1U) != 0;
}
float sc_luminance_multiplier() {
@@ -144,10 +169,6 @@ layout(set = 0, binding = 2) uniform sampler shadow_sampler;
#define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 9)
#define INSTANCE_FLAGS_USE_VOXEL_GI (1 << 10)
#define INSTANCE_FLAGS_PARTICLES (1 << 11)
-#define INSTANCE_FLAGS_MULTIMESH (1 << 12)
-#define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13)
-#define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14)
-#define INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA (1 << 15)
#define INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT 16
#define INSTANCE_FLAGS_FADE_SHIFT 24
//3 bits of stride
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
index 2f0e4e0bea..404f658fa6 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
@@ -178,6 +178,13 @@ vec3 double_add_vec3(vec3 base_a, vec3 prec_a, vec3 base_b, vec3 prec_b, out vec
}
#endif
+uint multimesh_stride() {
+ uint stride = sc_multimesh_format_2d() ? 2 : 3;
+ stride += sc_multimesh_has_color() ? 1 : 0;
+ stride += sc_multimesh_has_custom_data() ? 1 : 0;
+ return stride;
+}
+
void main() {
vec4 instance_custom = vec4(0.0);
#if defined(COLOR_USED)
@@ -208,7 +215,7 @@ void main() {
mat4 matrix;
mat4 read_model_matrix = model_matrix;
- if (sc_is_multimesh()) {
+ if (sc_multimesh()) {
//multimesh, instances are for it
#ifdef USE_PARTICLE_TRAILS
@@ -256,25 +263,10 @@ void main() {
#endif
#else
- uint stride = 0;
- {
- //TODO implement a small lookup table for the stride
- if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
- stride += 2;
- } else {
- stride += 3;
- }
- if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
- stride += 1;
- }
- if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
- stride += 1;
- }
- }
-
+ uint stride = multimesh_stride();
uint offset = stride * gl_InstanceIndex;
- if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
+ if (sc_multimesh_format_2d()) {
matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
offset += 2;
} else {
@@ -282,14 +274,14 @@ void main() {
offset += 3;
}
- if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
+ if (sc_multimesh_has_color()) {
#ifdef COLOR_USED
color_interp *= transforms.data[offset];
#endif
offset += 1;
}
- if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
+ if (sc_multimesh_has_custom_data()) {
instance_custom = transforms.data[offset];
}
@@ -404,7 +396,7 @@ void main() {
// Then we combine the translations from the model matrix and the view matrix using emulated doubles.
// We add the result to the vertex and ignore the final lost precision.
vec3 model_origin = model_matrix[3].xyz;
- if (sc_is_multimesh()) {
+ if (sc_multimesh()) {
vertex = mat3(matrix) * vertex;
model_origin = double_add_vec3(model_origin, model_precision, matrix[3].xyz, vec3(0.0), model_precision);
}
@@ -461,50 +453,24 @@ void main() {
diffuse_light_interp = vec4(0.0);
specular_light_interp = vec4(0.0);
- if (!sc_disable_omni_lights()) {
- uint light_indices = instances.data[draw_call.instance_index].omni_lights.x;
- for (uint i = 0; i < 8; i++) {
- uint light_index = light_indices & 0xFF;
- if (i == 3) {
- light_indices = instances.data[draw_call.instance_index].omni_lights.y;
- } else {
- light_indices = light_indices >> 8;
- }
-
- if (light_index == 0xFF) {
- break;
- }
-
- light_process_omni_vertex(light_index, vertex, view, normal, roughness,
- diffuse_light_interp.rgb, specular_light_interp.rgb);
- }
+ uvec2 omni_light_indices = instances.data[draw_call.instance_index].omni_lights;
+ for (uint i = 0; i < sc_omni_lights(); i++) {
+ uint light_index = (i > 3) ? ((omni_light_indices.y >> ((i - 4) * 8)) & 0xFF) : ((omni_light_indices.x >> (i * 8)) & 0xFF);
+ light_process_omni_vertex(light_index, vertex, view, normal, roughness, diffuse_light_interp.rgb, specular_light_interp.rgb);
}
- if (!sc_disable_spot_lights()) {
- uint light_indices = instances.data[draw_call.instance_index].spot_lights.x;
- for (uint i = 0; i < 8; i++) {
- uint light_index = light_indices & 0xFF;
- if (i == 3) {
- light_indices = instances.data[draw_call.instance_index].spot_lights.y;
- } else {
- light_indices = light_indices >> 8;
- }
-
- if (light_index == 0xFF) {
- break;
- }
-
- light_process_spot_vertex(light_index, vertex, view, normal, roughness,
- diffuse_light_interp.rgb, specular_light_interp.rgb);
- }
+ uvec2 spot_light_indices = instances.data[draw_call.instance_index].spot_lights;
+ for (uint i = 0; i < sc_spot_lights(); i++) {
+ uint light_index = (i > 3) ? ((spot_light_indices.y >> ((i - 4) * 8)) & 0xFF) : ((spot_light_indices.x >> (i * 8)) & 0xFF);
+ light_process_spot_vertex(light_index, vertex, view, normal, roughness, diffuse_light_interp.rgb, specular_light_interp.rgb);
}
- if (!sc_disable_directional_lights()) {
+ if (sc_directional_lights() > 0) {
// We process the first directional light separately as it may have shadows.
vec3 directional_diffuse = vec3(0.0);
vec3 directional_specular = vec3(0.0);
- for (uint i = 0; i < scene_data.directional_light_count; i++) {
+ for (uint i = 0; i < sc_directional_lights(); i++) {
if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) {
continue; // Not masked, skip.
}
@@ -823,7 +789,7 @@ vec4 fog_process(vec3 vertex) {
float sun_total = 0.0;
vec3 view = normalize(vertex);
- for (uint i = 0; i < scene_data_block.data.directional_light_count; i++) {
+ for (uint i = 0; i < sc_directional_lights(); i++) {
vec3 light_color = directional_lights.data[i].color * directional_lights.data[i].energy;
float light_amount = pow(max(dot(view, directional_lights.data[i].direction), 0.0), 8.0);
fog_color += light_color * light_amount * scene_data_block.data.fog_sun_scatter;
@@ -1110,97 +1076,83 @@ void main() {
vec3 vertex_ddx = dFdx(vertex);
vec3 vertex_ddy = dFdy(vertex);
- if (!sc_disable_decals()) { //Decals
- // must implement
-
- uint decal_indices = instances.data[draw_call.instance_index].decals.x;
- for (uint i = 0; i < 8; i++) {
- uint decal_index = decal_indices & 0xFF;
- if (i == 3) {
- decal_indices = instances.data[draw_call.instance_index].decals.y;
- } else {
- decal_indices = decal_indices >> 8;
- }
+ uvec2 decal_indices = instances.data[draw_call.instance_index].decals;
+ for (uint i = 0; i < sc_decals(); i++) {
+ uint decal_index = (i > 3) ? ((decal_indices.y >> ((i - 4) * 8)) & 0xFF) : ((decal_indices.x >> (i * 8)) & 0xFF);
+ if (!bool(decals.data[decal_index].mask & instances.data[draw_call.instance_index].layer_mask)) {
+ continue; //not masked
+ }
- if (decal_index == 0xFF) {
- break;
- }
+ 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 (!bool(decals.data[decal_index].mask & instances.data[draw_call.instance_index].layer_mask)) {
- continue; //not masked
- }
+ 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);
- 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].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);
+ }
- 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);
+ //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;
- 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;
+ if (sc_decal_use_mipmaps()) {
+ decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), 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);
+ } else {
+ decal_albedo = textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, 0.0);
}
+ 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);
- //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;
-
- if (decals.data[decal_index].albedo_rect != vec4(0.0)) {
- //has albedo
- vec4 decal_albedo;
+ if (decals.data[decal_index].normal_rect != vec4(0.0)) {
+ vec3 decal_normal;
if (sc_decal_use_mipmaps()) {
- decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), 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_normal = textureGrad(sampler2D(decal_atlas, decal_sampler), 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;
} else {
- decal_albedo = textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, 0.0);
- }
- 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;
- if (sc_decal_use_mipmaps()) {
- decal_normal = textureGrad(sampler2D(decal_atlas, decal_sampler), 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;
- } else {
- decal_normal = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, 0.0).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));
+ decal_normal = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, 0.0).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;
- if (decals.data[decal_index].orm_rect != vec4(0.0)) {
- vec3 decal_orm;
- if (sc_decal_use_mipmaps()) {
- decal_orm = textureGrad(sampler2D(decal_atlas, decal_sampler), 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;
- } else {
- decal_orm = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, 0.0).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);
- }
+ normal = normalize(mix(normal, decal_normal, decal_albedo.a));
}
- if (decals.data[decal_index].emission_rect != vec4(0.0)) {
- //emission is additive, so its independent from albedo
+ if (decals.data[decal_index].orm_rect != vec4(0.0)) {
+ vec3 decal_orm;
if (sc_decal_use_mipmaps()) {
- emission += textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), 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;
+ decal_orm = textureGrad(sampler2D(decal_atlas, decal_sampler), 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;
} else {
- emission += textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, 0.0).xyz * decals.data[decal_index].emission_energy * fade;
+ decal_orm = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, 0.0).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
+ if (sc_decal_use_mipmaps()) {
+ emission += textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), 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;
+ } else {
+ emission += textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, 0.0).xyz * decals.data[decal_index].emission_energy * fade;
}
}
- } //Decals
+ }
#endif //!MODE_RENDER_DEPTH
/////////////////////// LIGHTING //////////////////////////////
#ifdef NORMAL_USED
- if (scene_data.roughness_limiter_enabled) {
+ if (sc_scene_roughness_limiter_enabled()) {
//https://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
float roughness2 = roughness * roughness;
vec3 dndu = dFdx(normal), dndv = dFdy(normal);
@@ -1225,7 +1177,7 @@ void main() {
#ifndef AMBIENT_LIGHT_DISABLED
- if (scene_data.use_reflection_cubemap) {
+ if (sc_scene_use_reflection_cubemap()) {
#ifdef LIGHT_ANISOTROPY_USED
// https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy
vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent;
@@ -1266,7 +1218,7 @@ void main() {
if (scene_data.use_ambient_light) {
ambient_light = scene_data.ambient_light_color_energy.rgb;
- if (scene_data.use_ambient_cubemap) {
+ if (sc_scene_use_ambient_cubemap()) {
vec3 ambient_dir = scene_data.radiance_inverse_xform * normal;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb;
@@ -1285,7 +1237,7 @@ void main() {
#endif // CUSTOM_IRRADIANCE_USED
#ifdef LIGHT_CLEARCOAT_USED
- if (scene_data.use_reflection_cubemap) {
+ if (sc_scene_use_reflection_cubemap()) {
vec3 n = normalize(normal_interp); // We want to use geometric normal, not normal_map
float NoV = max(dot(n, view), 0.0001);
vec3 ref_vec = reflect(-view, n);
@@ -1393,12 +1345,10 @@ void main() {
// skipping ssao, do we remove ssao totally?
- if (!sc_disable_reflection_probes()) { //Reflection probes
+ if (sc_reflection_probes() > 0) {
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_indices = instances.data[draw_call.instance_index].reflection_probes.x;
-
#ifdef LIGHT_ANISOTROPY_USED
// https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy
vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent;
@@ -1411,18 +1361,9 @@ void main() {
vec3 ref_vec = normalize(reflect(-view, bent_normal));
ref_vec = mix(ref_vec, bent_normal, roughness * roughness);
- for (uint i = 0; i < 8; i++) {
- uint reflection_index = reflection_indices & 0xFF;
- if (i == 3) {
- reflection_indices = instances.data[draw_call.instance_index].reflection_probes.y;
- } else {
- reflection_indices = reflection_indices >> 8;
- }
-
- if (reflection_index == 0xFF) {
- break;
- }
-
+ uvec2 reflection_indices = instances.data[draw_call.instance_index].reflection_probes;
+ for (uint i = 0; i < sc_reflection_probes(); i++) {
+ uint reflection_index = (i > 3) ? ((reflection_indices.y >> ((i - 4) * 8)) & 0xFF) : ((reflection_indices.x >> (i * 8)) & 0xFF);
reflection_process(reflection_index, vertex, ref_vec, bent_normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum);
}
@@ -1487,7 +1428,7 @@ void main() {
specular_light += specular_light_interp.rgb * f0;
#endif
- if (!sc_disable_directional_lights()) { //directional light
+ if (sc_directional_lights() > 0) {
#ifndef SHADOWS_DISABLED
// Do shadow and lighting in two passes to reduce register pressure
uint shadow0 = 0;
@@ -1497,7 +1438,7 @@ void main() {
// Only process the first light's shadow for vertex lighting.
for (uint i = 0; i < 1; i++) {
#else
- for (uint i = 0; i < scene_data.directional_light_count; i++) {
+ for (uint i = 0; i < sc_directional_lights(); i++) {
#endif
if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) {
@@ -1612,7 +1553,7 @@ void main() {
#endif // SHADOWS_DISABLED
#ifndef USE_VERTEX_LIGHTING
- for (uint i = 0; i < scene_data.directional_light_count; i++) {
+ for (uint i = 0; i < sc_directional_lights(); i++) {
if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) {
continue; //not masked
}
@@ -1678,95 +1619,72 @@ void main() {
} //directional light
#ifndef USE_VERTEX_LIGHTING
- if (!sc_disable_omni_lights()) { //omni lights
- uint light_indices = instances.data[draw_call.instance_index].omni_lights.x;
- for (uint i = 0; i < 8; i++) {
- uint light_index = light_indices & 0xFF;
- if (i == 3) {
- light_indices = instances.data[draw_call.instance_index].omni_lights.y;
- } else {
- light_indices = light_indices >> 8;
- }
-
- if (light_index == 0xFF) {
- break;
- }
+ uvec2 omni_indices = instances.data[draw_call.instance_index].omni_lights;
+ for (uint i = 0; i < sc_omni_lights(); i++) {
+ uint light_index = (i > 3) ? ((omni_indices.y >> ((i - 4) * 8)) & 0xFF) : ((omni_indices.x >> (i * 8)) & 0xFF);
- float shadow = light_process_omni_shadow(light_index, vertex, normal, scene_data.taa_frame_count);
+ float shadow = light_process_omni_shadow(light_index, vertex, normal, scene_data.taa_frame_count);
- shadow = blur_shadow(shadow);
+ shadow = blur_shadow(shadow);
- // Fragment lighting
- light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
+ // Fragment lighting
+ light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
- backlight,
+ backlight,
#endif
/*
#ifdef LIGHT_TRANSMITTANCE_USED
- transmittance_color,
- transmittance_depth,
- transmittance_boost,
+ transmittance_color,
+ transmittance_depth,
+ transmittance_boost,
#endif
*/
#ifdef LIGHT_RIM_USED
- rim,
- rim_tint,
+ rim,
+ rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
- clearcoat, clearcoat_roughness, normalize(normal_interp),
+ clearcoat, clearcoat_roughness, normalize(normal_interp),
#endif
#ifdef LIGHT_ANISOTROPY_USED
- tangent,
- binormal, anisotropy,
+ tangent,
+ binormal, anisotropy,
#endif
- diffuse_light, specular_light);
- }
- } //omni lights
-
- if (!sc_disable_spot_lights()) { //spot lights
-
- uint light_indices = instances.data[draw_call.instance_index].spot_lights.x;
- for (uint i = 0; i < 8; i++) {
- uint light_index = light_indices & 0xFF;
- if (i == 3) {
- light_indices = instances.data[draw_call.instance_index].spot_lights.y;
- } else {
- light_indices = light_indices >> 8;
- }
+ diffuse_light, specular_light);
+ }
- if (light_index == 0xFF) {
- break;
- }
+ uvec2 spot_indices = instances.data[draw_call.instance_index].spot_lights;
+ for (uint i = 0; i < sc_spot_lights(); i++) {
+ uint light_index = (i > 3) ? ((spot_indices.y >> ((i - 4) * 8)) & 0xFF) : ((spot_indices.x >> (i * 8)) & 0xFF);
- float shadow = light_process_spot_shadow(light_index, vertex, normal, scene_data.taa_frame_count);
+ float shadow = light_process_spot_shadow(light_index, vertex, normal, scene_data.taa_frame_count);
- shadow = blur_shadow(shadow);
+ shadow = blur_shadow(shadow);
- light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
+ light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
- backlight,
+ backlight,
#endif
/*
#ifdef LIGHT_TRANSMITTANCE_USED
- transmittance_color,
- transmittance_depth,
- transmittance_boost,
+ transmittance_color,
+ transmittance_depth,
+ transmittance_boost,
#endif
*/
#ifdef LIGHT_RIM_USED
- rim,
- rim_tint,
+ rim,
+ rim_tint,
#endif
#ifdef LIGHT_CLEARCOAT_USED
- clearcoat, clearcoat_roughness, normalize(normal_interp),
+ clearcoat, clearcoat_roughness, normalize(normal_interp),
#endif
#ifdef LIGHT_ANISOTROPY_USED
- tangent,
- binormal, anisotropy,
+ tangent,
+ binormal, anisotropy,
#endif
- diffuse_light, specular_light);
- }
- } //spot lights
+ diffuse_light, specular_light);
+ }
#endif // !VERTEX_LIGHTING
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
index 495e52a29e..2cc86482f6 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
@@ -22,8 +22,8 @@ layout(push_constant, std430) uniform DrawCall {
uint pad;
#ifdef UBERSHADER
uint sc_packed_0;
- float sc_packed_1;
- uint sc_packed_2;
+ uint sc_packed_1;
+ float sc_packed_2;
uint uc_packed_0;
#endif
}
@@ -42,10 +42,14 @@ uint sc_packed_0() {
return draw_call.sc_packed_0;
}
-float sc_packed_1() {
+uint sc_packed_1() {
return draw_call.sc_packed_1;
}
+float sc_packed_2() {
+ return draw_call.sc_packed_2;
+}
+
uint uc_cull_mode() {
return (draw_call.uc_packed_0 >> 0) & 3U;
}
@@ -54,16 +58,21 @@ uint uc_cull_mode() {
// Pull the constants from the pipeline's specialization constants.
layout(constant_id = 0) const uint pso_sc_packed_0 = 0;
-layout(constant_id = 1) const float pso_sc_packed_1 = 2.0;
+layout(constant_id = 1) const uint pso_sc_packed_1 = 0;
+layout(constant_id = 2) const float pso_sc_packed_2 = 2.0;
uint sc_packed_0() {
return pso_sc_packed_0;
}
-float sc_packed_1() {
+uint sc_packed_1() {
return pso_sc_packed_1;
}
+float sc_packed_2() {
+ return pso_sc_packed_2;
+}
+
#endif
bool sc_use_light_projector() {
@@ -86,60 +95,84 @@ bool sc_projector_use_mipmaps() {
return ((sc_packed_0() >> 4) & 1U) != 0;
}
-bool sc_disable_omni_lights() {
+bool sc_disable_fog() {
return ((sc_packed_0() >> 5) & 1U) != 0;
}
-bool sc_disable_spot_lights() {
+bool sc_use_depth_fog() {
return ((sc_packed_0() >> 6) & 1U) != 0;
}
-bool sc_disable_reflection_probes() {
+bool sc_use_lightmap_bicubic_filter() {
return ((sc_packed_0() >> 7) & 1U) != 0;
}
-bool sc_disable_directional_lights() {
+bool sc_multimesh() {
return ((sc_packed_0() >> 8) & 1U) != 0;
}
-bool sc_disable_decals() {
+bool sc_multimesh_format_2d() {
return ((sc_packed_0() >> 9) & 1U) != 0;
}
-bool sc_disable_fog() {
+bool sc_multimesh_has_color() {
return ((sc_packed_0() >> 10) & 1U) != 0;
}
-bool sc_use_depth_fog() {
+bool sc_multimesh_has_custom_data() {
return ((sc_packed_0() >> 11) & 1U) != 0;
}
-bool sc_is_multimesh() {
+bool sc_scene_use_ambient_cubemap() {
return ((sc_packed_0() >> 12) & 1U) != 0;
}
-bool sc_use_lightmap_bicubic_filter() {
+bool sc_scene_use_reflection_cubemap() {
return ((sc_packed_0() >> 13) & 1U) != 0;
}
+bool sc_scene_roughness_limiter_enabled() {
+ return ((sc_packed_0() >> 14) & 1U) != 0;
+}
+
uint sc_soft_shadow_samples() {
- return (sc_packed_0() >> 16) & 15U;
+ return (sc_packed_0() >> 20) & 63U;
}
uint sc_penumbra_shadow_samples() {
- return (sc_packed_0() >> 20) & 15U;
+ return (sc_packed_0() >> 26) & 63U;
}
uint sc_directional_soft_shadow_samples() {
- return (sc_packed_0() >> 24) & 15U;
+ return (sc_packed_1() >> 0) & 63U;
}
uint sc_directional_penumbra_shadow_samples() {
- return (sc_packed_0() >> 28) & 15U;
+ return (sc_packed_1() >> 6) & 63U;
+}
+
+uint sc_omni_lights() {
+ return (sc_packed_1() >> 12) & 15U;
+}
+
+uint sc_spot_lights() {
+ return (sc_packed_1() >> 16) & 15U;
+}
+
+uint sc_reflection_probes() {
+ return (sc_packed_1() >> 20) & 15U;
+}
+
+uint sc_directional_lights() {
+ return (sc_packed_1() >> 24) & 15U;
+}
+
+uint sc_decals() {
+ return (sc_packed_1() >> 28) & 15U;
}
float sc_luminance_multiplier() {
- return sc_packed_1();
+ return sc_packed_2();
}
/* Set 0: Base Pass (never changes) */
@@ -157,10 +190,6 @@ layout(set = 0, binding = 2) uniform sampler shadow_sampler;
#define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 9)
#define INSTANCE_FLAGS_USE_VOXEL_GI (1 << 10)
#define INSTANCE_FLAGS_PARTICLES (1 << 11)
-#define INSTANCE_FLAGS_MULTIMESH (1 << 12)
-#define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13)
-#define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14)
-#define INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA (1 << 15)
#define INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT 16
//3 bits of stride
#define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
index 8f71909154..9de37050f0 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
@@ -285,6 +285,23 @@ void LightStorage::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled)
light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT);
}
+void LightStorage::light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) {
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_NULL(light);
+
+ light->shadow_caster_mask = p_caster_mask;
+
+ light->version++;
+ light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT);
+}
+
+uint32_t LightStorage::light_get_shadow_caster_mask(RID p_light) const {
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_NULL_V(light, 0);
+
+ return light->shadow_caster_mask;
+}
+
void LightStorage::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) {
Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_NULL(light);
@@ -1032,7 +1049,7 @@ void LightStorage::reflection_probe_free(RID p_rid) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_rid);
reflection_probe->dependency.deleted_notify(p_rid);
reflection_probe_owner.free(p_rid);
-};
+}
void LightStorage::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) {
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h
index 59303e8a73..1a92c5470d 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h
@@ -72,6 +72,7 @@ private:
RS::LightBakeMode bake_mode = RS::LIGHT_BAKE_DYNAMIC;
uint32_t max_sdfgi_cascade = 2;
uint32_t cull_mask = 0xFFFFFFFF;
+ uint32_t shadow_caster_mask = 0xFFFFFFFF;
bool distance_fade = false;
real_t distance_fade_begin = 40.0;
real_t distance_fade_shadow = 50.0;
@@ -480,6 +481,8 @@ public:
virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) override;
virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) override;
virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) override;
+ virtual void light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) override;
+ virtual uint32_t light_get_shadow_caster_mask(RID p_light) const override;
virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) override;
virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) override;
@@ -587,7 +590,7 @@ public:
/* LIGHT INSTANCE API */
- bool owns_light_instance(RID p_rid) { return light_instance_owner.owns(p_rid); };
+ bool owns_light_instance(RID p_rid) { return light_instance_owner.owns(p_rid); }
virtual RID light_instance_create(RID p_light) override;
virtual void light_instance_free(RID p_light) override;
@@ -808,7 +811,7 @@ public:
/* REFLECTION PROBE */
- bool owns_reflection_probe(RID p_rid) { return reflection_probe_owner.owns(p_rid); };
+ bool owns_reflection_probe(RID p_rid) { return reflection_probe_owner.owns(p_rid); }
virtual RID reflection_probe_allocate() override;
virtual void reflection_probe_initialize(RID p_reflection_probe) override;
@@ -950,7 +953,7 @@ public:
/* LIGHTMAP */
- bool owns_lightmap(RID p_rid) { return lightmap_owner.owns(p_rid); };
+ bool owns_lightmap(RID p_rid) { return lightmap_owner.owns(p_rid); }
virtual RID lightmap_allocate() override;
virtual void lightmap_initialize(RID p_lightmap) override;
@@ -1016,7 +1019,7 @@ public:
/* LIGHTMAP INSTANCE */
- bool owns_lightmap_instance(RID p_rid) { return lightmap_instance_owner.owns(p_rid); };
+ bool owns_lightmap_instance(RID p_rid) { return lightmap_instance_owner.owns(p_rid); }
virtual RID lightmap_instance_create(RID p_lightmap) override;
virtual void lightmap_instance_free(RID p_lightmap) override;
@@ -1036,7 +1039,7 @@ public:
/* SHADOW ATLAS API */
- bool owns_shadow_atlas(RID p_rid) { return shadow_atlas_owner.owns(p_rid); };
+ bool owns_shadow_atlas(RID p_rid) { return shadow_atlas_owner.owns(p_rid); }
virtual RID shadow_atlas_create() override;
virtual void shadow_atlas_free(RID p_atlas) override;
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h
index 08c1064dcb..89a8b36853 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h
@@ -254,7 +254,7 @@ private:
MaterialDataRequestFunction material_data_request_func[SHADER_TYPE_MAX];
mutable RID_Owner<Material, true> material_owner;
- Material *get_material(RID p_rid) { return material_owner.get_or_null(p_rid); };
+ Material *get_material(RID p_rid) { return material_owner.get_or_null(p_rid); }
SelfList<Material>::List material_update_list;
Mutex material_update_list_mutex;
@@ -403,7 +403,7 @@ public:
/* SHADER API */
- bool owns_shader(RID p_rid) { return shader_owner.owns(p_rid); };
+ bool owns_shader(RID p_rid) { return shader_owner.owns(p_rid); }
virtual RID shader_allocate() override;
virtual void shader_initialize(RID p_shader) override;
@@ -423,7 +423,7 @@ public:
/* MATERIAL API */
- bool owns_material(RID p_rid) { return material_owner.owns(p_rid); };
+ bool owns_material(RID p_rid) { return material_owner.owns(p_rid); }
void _material_queue_update(Material *material, bool p_uniform, bool p_texture);
void _update_queued_materials();
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
index 322f3cc6f4..c14c2945bd 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
@@ -351,7 +351,7 @@ public:
/* MESH API */
- bool owns_mesh(RID p_rid) { return mesh_owner.owns(p_rid); };
+ bool owns_mesh(RID p_rid) { return mesh_owner.owns(p_rid); }
virtual RID mesh_allocate() override;
virtual void mesh_initialize(RID p_mesh) override;
@@ -616,7 +616,7 @@ public:
/* MESH INSTANCE API */
- bool owns_mesh_instance(RID p_rid) const { return mesh_instance_owner.owns(p_rid); };
+ bool owns_mesh_instance(RID p_rid) const { return mesh_instance_owner.owns(p_rid); }
virtual RID mesh_instance_create(RID p_base) override;
virtual void mesh_instance_free(RID p_rid) override;
@@ -628,7 +628,7 @@ public:
/* MULTIMESH API */
- bool owns_multimesh(RID p_rid) { return multimesh_owner.owns(p_rid); };
+ bool owns_multimesh(RID p_rid) { return multimesh_owner.owns(p_rid); }
virtual RID _multimesh_allocate() override;
virtual void _multimesh_initialize(RID p_multimesh) override;
@@ -737,7 +737,7 @@ public:
/* SKELETON API */
- bool owns_skeleton(RID p_rid) const { return skeleton_owner.owns(p_rid); };
+ bool owns_skeleton(RID p_rid) const { return skeleton_owner.owns(p_rid); }
virtual RID skeleton_allocate() override;
virtual void skeleton_initialize(RID p_skeleton) override;
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
index 314cbf9aa9..6efb8c176f 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
@@ -306,9 +306,14 @@ void ParticlesStorage::_particles_free_data(Particles *particles) {
particles->emission_storage_buffer = RID();
}
- if (particles->unused_storage_buffer.is_valid()) {
- RD::get_singleton()->free(particles->unused_storage_buffer);
- particles->unused_storage_buffer = RID();
+ if (particles->unused_emission_storage_buffer.is_valid()) {
+ RD::get_singleton()->free(particles->unused_emission_storage_buffer);
+ particles->unused_emission_storage_buffer = RID();
+ }
+
+ if (particles->unused_trail_storage_buffer.is_valid()) {
+ RD::get_singleton()->free(particles->unused_trail_storage_buffer);
+ particles->unused_trail_storage_buffer = RID();
}
if (RD::get_singleton()->uniform_set_is_valid(particles->particles_material_uniform_set)) {
@@ -534,9 +539,15 @@ void ParticlesStorage::_particles_allocate_emission_buffer(Particles *particles)
}
}
-void ParticlesStorage::_particles_ensure_unused_buffer(Particles *particles) {
- if (particles->unused_storage_buffer.is_null()) {
- particles->unused_storage_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4);
+void ParticlesStorage::_particles_ensure_unused_emission_buffer(Particles *particles) {
+ if (particles->unused_emission_storage_buffer.is_null()) {
+ particles->unused_emission_storage_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4);
+ }
+}
+
+void ParticlesStorage::_particles_ensure_unused_trail_buffer(Particles *particles) {
+ if (particles->unused_trail_storage_buffer.is_null()) {
+ particles->unused_trail_storage_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4);
}
}
@@ -763,8 +774,8 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
if (p_particles->emission_storage_buffer.is_valid()) {
u.append_id(p_particles->emission_storage_buffer);
} else {
- _particles_ensure_unused_buffer(p_particles);
- u.append_id(p_particles->unused_storage_buffer);
+ _particles_ensure_unused_emission_buffer(p_particles);
+ u.append_id(p_particles->unused_emission_storage_buffer);
}
uniforms.push_back(u);
}
@@ -779,8 +790,8 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
}
u.append_id(sub_emitter->emission_storage_buffer);
} else {
- _particles_ensure_unused_buffer(p_particles);
- u.append_id(p_particles->unused_storage_buffer);
+ _particles_ensure_unused_emission_buffer(p_particles);
+ u.append_id(p_particles->unused_emission_storage_buffer);
}
uniforms.push_back(u);
}
@@ -1481,8 +1492,8 @@ void ParticlesStorage::update_particles() {
if (particles->trail_bind_pose_buffer.is_valid()) {
u.append_id(particles->trail_bind_pose_buffer);
} else {
- _particles_ensure_unused_buffer(particles);
- u.append_id(particles->unused_storage_buffer);
+ _particles_ensure_unused_trail_buffer(particles);
+ u.append_id(particles->unused_trail_storage_buffer);
}
uniforms.push_back(u);
}
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
index 33f44f3045..ec897c4ea9 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
@@ -247,7 +247,8 @@ private:
ParticleEmissionBuffer *emission_buffer = nullptr;
RID emission_storage_buffer;
- RID unused_storage_buffer;
+ RID unused_emission_storage_buffer;
+ RID unused_trail_storage_buffer;
HashSet<RID> collisions;
@@ -265,7 +266,8 @@ private:
void _particles_process(Particles *p_particles, double p_delta);
void _particles_allocate_emission_buffer(Particles *particles);
- void _particles_ensure_unused_buffer(Particles *particles);
+ void _particles_ensure_unused_emission_buffer(Particles *particles);
+ void _particles_ensure_unused_trail_buffer(Particles *particles);
void _particles_free_data(Particles *particles);
void _particles_update_buffers(Particles *particles);
@@ -509,7 +511,7 @@ public:
_FORCE_INLINE_ bool particles_has_collision(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_NULL_V(particles, 0);
+ ERR_FAIL_NULL_V(particles, false);
return particles->has_collision_cache;
}
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h
index 4a70482d72..59671c3a13 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h
@@ -51,6 +51,7 @@ public:
float taa_frame_count = 0.0f;
uint32_t camera_visible_layers;
bool cam_orthogonal = false;
+ bool cam_frustum = false;
bool flip_y = false;
// For billboards to cast correct shadows.
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index 42fce65b2d..8a9499dfc9 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -1666,7 +1666,9 @@ void TextureStorage::texture_rd_initialize(RID p_texture, const RID &p_rd_textur
ERR_FAIL_COND(tf.array_layers != 1);
texture.type = TextureStorage::TYPE_2D;
} break;
- case RD::TEXTURE_TYPE_2D_ARRAY: {
+ case RD::TEXTURE_TYPE_2D_ARRAY:
+ case RD::TEXTURE_TYPE_CUBE:
+ case RD::TEXTURE_TYPE_CUBE_ARRAY: {
// RenderingDevice doesn't distinguish between Array textures and Cube textures
// this condition covers TextureArrays, TextureCube, and TextureCubeArray.
ERR_FAIL_COND(tf.array_layers == 1);
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
index 866fdd50ac..3d281cf98a 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
@@ -102,9 +102,9 @@ private:
/* Canvas Texture API */
struct CanvasTextureCache {
- RID diffuse = RID();
- RID normal = RID();
- RID specular = RID();
+ RID diffuse;
+ RID normal;
+ RID specular;
};
class CanvasTexture {
@@ -122,7 +122,6 @@ private:
Size2i size_cache = Size2i(1, 1);
bool use_normal_cache = false;
bool use_specular_cache = false;
- bool cleared_cache = true;
void clear_cache();
~CanvasTexture();
@@ -195,7 +194,7 @@ private:
// Textures can be created from threads, so this RID_Owner is thread safe.
mutable RID_Owner<Texture, true> texture_owner;
- Texture *get_texture(RID p_rid) { return texture_owner.get_or_null(p_rid); };
+ Texture *get_texture(RID p_rid) { return texture_owner.get_or_null(p_rid); }
struct TextureToRDFormat {
RD::DataFormat format;
@@ -439,7 +438,7 @@ private:
};
mutable RID_Owner<RenderTarget> render_target_owner;
- RenderTarget *get_render_target(RID p_rid) const { return render_target_owner.get_or_null(p_rid); };
+ RenderTarget *get_render_target(RID p_rid) const { return render_target_owner.get_or_null(p_rid); }
void _clear_render_target(RenderTarget *rt);
void _update_render_target(RenderTarget *rt);
@@ -486,7 +485,7 @@ public:
/* Canvas Texture API */
- bool owns_canvas_texture(RID p_rid) { return canvas_texture_owner.owns(p_rid); };
+ bool owns_canvas_texture(RID p_rid) { return canvas_texture_owner.owns(p_rid); }
virtual RID canvas_texture_allocate() override;
virtual void canvas_texture_initialize(RID p_rid) override;
@@ -502,7 +501,7 @@ public:
/* Texture API */
- bool owns_texture(RID p_rid) const { return texture_owner.owns(p_rid); };
+ bool owns_texture(RID p_rid) const { return texture_owner.owns(p_rid); }
virtual RID texture_allocate() override;
virtual void texture_free(RID p_rid) override;
@@ -591,7 +590,7 @@ public:
void update_decal_atlas();
- bool owns_decal(RID p_rid) const { return decal_owner.owns(p_rid); };
+ bool owns_decal(RID p_rid) const { return decal_owner.owns(p_rid); }
RID decal_atlas_get_texture() const;
RID decal_atlas_get_texture_srgb() const;
@@ -731,7 +730,7 @@ public:
/* RENDER TARGET API */
- bool owns_render_target(RID p_rid) const { return render_target_owner.owns(p_rid); };
+ bool owns_render_target(RID p_rid) const { return render_target_owner.owns(p_rid); }
virtual RID render_target_create() override;
virtual void render_target_free(RID p_rid) override;
diff --git a/servers/rendering/renderer_rd/storage_rd/utilities.h b/servers/rendering/renderer_rd/storage_rd/utilities.h
index 2ba3da7515..96508fd3ff 100644
--- a/servers/rendering/renderer_rd/storage_rd/utilities.h
+++ b/servers/rendering/renderer_rd/storage_rd/utilities.h
@@ -77,8 +77,8 @@ public:
/* VISIBILITY NOTIFIER */
- VisibilityNotifier *get_visibility_notifier(RID p_rid) { return visibility_notifier_owner.get_or_null(p_rid); };
- bool owns_visibility_notifier(RID p_rid) const { return visibility_notifier_owner.owns(p_rid); };
+ VisibilityNotifier *get_visibility_notifier(RID p_rid) { return visibility_notifier_owner.get_or_null(p_rid); }
+ bool owns_visibility_notifier(RID p_rid) const { return visibility_notifier_owner.owns(p_rid); }
virtual RID visibility_notifier_allocate() override;
virtual void visibility_notifier_initialize(RID p_notifier) override;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index ca07444465..11ca7de44f 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -2299,6 +2299,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
cull.shadow_count = p_shadow_index + 1;
cull.shadows[p_shadow_index].cascade_count = splits;
cull.shadows[p_shadow_index].light_instance = light->instance;
+ cull.shadows[p_shadow_index].caster_mask = RSG::light_storage->light_get_shadow_caster_mask(p_instance->base);
for (int i = 0; i < splits; i++) {
RENDER_TIMESTAMP("Cull DirectionalLight3D, Split " + itos(i));
@@ -2529,7 +2530,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
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 || !(p_visible_layers & instance->layer_mask)) {
+ if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask & RSG::light_storage->light_get_shadow_caster_mask(p_instance->base))) {
continue;
} else {
if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) {
@@ -2611,7 +2612,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
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 || !(p_visible_layers & instance->layer_mask)) {
+ if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask & RSG::light_storage->light_get_shadow_caster_mask(p_instance->base))) {
continue;
} else {
if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) {
@@ -2678,7 +2679,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
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 || !(p_visible_layers & instance->layer_mask)) {
+ if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask & RSG::light_storage->light_get_shadow_caster_mask(p_instance->base))) {
continue;
} else {
if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) {
@@ -2737,6 +2738,7 @@ void RendererSceneCull::render_camera(const Ref<RenderSceneBuffers> &p_render_bu
Projection projection;
bool vaspect = camera->vaspect;
bool is_orthogonal = false;
+ bool is_frustum = false;
switch (camera->type) {
case Camera::ORTHOGONAL: {
@@ -2765,10 +2767,11 @@ void RendererSceneCull::render_camera(const Ref<RenderSceneBuffers> &p_render_bu
camera->znear,
camera->zfar,
camera->vaspect);
+ is_frustum = true;
} break;
}
- camera_data.set_camera(transform, projection, is_orthogonal, vaspect, jitter, taa_frame_count, camera->visible_layers);
+ camera_data.set_camera(transform, projection, is_orthogonal, is_frustum, vaspect, jitter, taa_frame_count, camera->visible_layers);
} else {
// Setup our camera for our XR interface.
// We can support multiple views here each with their own camera
@@ -2790,9 +2793,9 @@ void RendererSceneCull::render_camera(const Ref<RenderSceneBuffers> &p_render_bu
}
if (view_count == 1) {
- camera_data.set_camera(transforms[0], projections[0], false, camera->vaspect, jitter, p_jitter_phase_count, camera->visible_layers);
+ camera_data.set_camera(transforms[0], projections[0], false, false, camera->vaspect, jitter, p_jitter_phase_count, camera->visible_layers);
} else if (view_count == 2) {
- camera_data.set_multiview_camera(view_count, transforms, projections, false, camera->vaspect);
+ camera_data.set_multiview_camera(view_count, transforms, projections, false, false, camera->vaspect);
} else {
// this won't be called (see fail check above) but keeping this comment to indicate we may support more then 2 views in the future...
}
@@ -3036,6 +3039,10 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
for (const Instance *E : geom->lights) {
InstanceLightData *light = static_cast<InstanceLightData *>(E->base_data);
+ if (!(RSG::light_storage->light_get_cull_mask(E->base) & idata.layer_mask)) {
+ continue;
+ }
+
instance_pair_buffer[idx++] = light->instance;
if (idx == MAX_INSTANCE_PAIRS) {
break;
@@ -3140,7 +3147,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
if (IN_FRUSTUM(cull_data.cull->shadows[j].cascades[k].frustum) && VIS_CHECK) {
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 && LAYER_CHECK) {
+ if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS && (LAYER_CHECK & cull_data.cull->shadows[j].caster_mask)) {
cull_result.directional_shadows[j].cascade_geometry_instances[k].push_back(idata.instance_geometry);
mesh_visible = true;
}
@@ -3636,7 +3643,7 @@ void RendererSceneCull::render_empty_scene(const Ref<RenderSceneBuffers> &p_rend
RENDER_TIMESTAMP("Render Empty 3D Scene");
RendererSceneRender::CameraData camera_data;
- camera_data.set_camera(Transform3D(), Projection(), true, false);
+ camera_data.set_camera(Transform3D(), Projection(), true, false, false);
scene_render->render_scene(p_render_buffers, &camera_data, &camera_data, PagedArray<RenderGeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), environment, RID(), compositor, p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr);
#endif
@@ -3714,7 +3721,7 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
RENDER_TIMESTAMP("Render ReflectionProbe, Step " + itos(p_step));
RendererSceneRender::CameraData camera_data;
- camera_data.set_camera(xform, cm, false, false);
+ camera_data.set_camera(xform, cm, false, false, false);
Ref<RenderSceneBuffers> render_buffers = RSG::light_storage->reflection_probe_atlas_get_render_buffers(scenario->reflection_atlas);
_render_scene(&camera_data, render_buffers, environment, RID(), RID(), RSG::light_storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, p_step, mesh_lod_threshold, use_shadows);
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index 5aae59eb51..82523fd4ef 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -1121,6 +1121,7 @@ public:
struct Cull {
struct Shadow {
RID light_instance;
+ uint32_t caster_mask;
struct Cascade {
Frustum frustum;
@@ -1255,6 +1256,7 @@ public:
PASS3(environment_set_bg_energy, RID, float, float)
PASS2(environment_set_canvas_max_layer, RID, int)
PASS6(environment_set_ambient_light, RID, const Color &, RS::EnvironmentAmbientSource, float, float, RS::EnvironmentReflectionSource)
+ PASS2(environment_set_camera_feed_id, RID, int)
PASS1RC(RS::EnvironmentBG, environment_get_background, RID)
PASS1RC(RID, environment_get_sky, RID)
diff --git a/servers/rendering/renderer_scene_occlusion_cull.h b/servers/rendering/renderer_scene_occlusion_cull.h
index df403c5484..14b97918ec 100644
--- a/servers/rendering/renderer_scene_occlusion_cull.h
+++ b/servers/rendering/renderer_scene_occlusion_cull.h
@@ -72,7 +72,7 @@ public:
return false;
}
- float min_depth = -closest_point_view.z * 0.95f;
+ float min_depth = (closest_point - p_cam_position).length();
Vector2 rect_min = Vector2(FLT_MAX, FLT_MAX);
Vector2 rect_max = Vector2(FLT_MIN, FLT_MIN);
@@ -83,6 +83,10 @@ public:
Vector3 corner = Vector3(p_bounds[0] * c.x + p_bounds[3] * nc.x, p_bounds[1] * c.y + p_bounds[4] * nc.y, p_bounds[2] * c.z + p_bounds[5] * nc.z);
Vector3 view = p_cam_inv_transform.xform(corner);
+ if (p_cam_projection.is_orthogonal()) {
+ min_depth = MIN(min_depth, -view.z);
+ }
+
Plane vp = Plane(view, 1.0);
Plane projected = p_cam_projection.xform4(vp);
@@ -230,11 +234,11 @@ public:
RendererSceneOcclusionCull() {
singleton = this;
- };
+ }
virtual ~RendererSceneOcclusionCull() {
singleton = nullptr;
- };
+ }
};
#endif // RENDERER_SCENE_OCCLUSION_CULL_H
diff --git a/servers/rendering/renderer_scene_render.cpp b/servers/rendering/renderer_scene_render.cpp
index 797ba7eaf7..07259f73d2 100644
--- a/servers/rendering/renderer_scene_render.cpp
+++ b/servers/rendering/renderer_scene_render.cpp
@@ -33,9 +33,10 @@
/////////////////////////////////////////////////////////////////////////////
// CameraData
-void RendererSceneRender::CameraData::set_camera(const Transform3D p_transform, const Projection p_projection, bool p_is_orthogonal, bool p_vaspect, const Vector2 &p_taa_jitter, float p_taa_frame_count, const uint32_t p_visible_layers) {
+void RendererSceneRender::CameraData::set_camera(const Transform3D p_transform, const Projection p_projection, bool p_is_orthogonal, bool p_is_frustum, bool p_vaspect, const Vector2 &p_taa_jitter, float p_taa_frame_count, const uint32_t p_visible_layers) {
view_count = 1;
is_orthogonal = p_is_orthogonal;
+ is_frustum = p_is_frustum;
vaspect = p_vaspect;
main_transform = p_transform;
@@ -48,12 +49,13 @@ void RendererSceneRender::CameraData::set_camera(const Transform3D p_transform,
taa_frame_count = p_taa_frame_count;
}
-void RendererSceneRender::CameraData::set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const Projection *p_projections, bool p_is_orthogonal, bool p_vaspect) {
+void RendererSceneRender::CameraData::set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const Projection *p_projections, bool p_is_orthogonal, bool p_is_frustum, bool p_vaspect) {
ERR_FAIL_COND_MSG(p_view_count != 2, "Incorrect view count for stereoscopic view");
visible_layers = 0xFFFFFFFF;
view_count = p_view_count;
is_orthogonal = p_is_orthogonal;
+ is_frustum = p_is_frustum;
vaspect = p_vaspect;
Vector<Plane> planes[2];
@@ -349,6 +351,14 @@ RS::EnvironmentReflectionSource RendererSceneRender::environment_get_reflection_
return environment_storage.environment_get_reflection_source(p_env);
}
+void RendererSceneRender::environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) {
+ environment_storage.environment_set_camera_feed_id(p_env, p_camera_feed_id);
+}
+
+int RendererSceneRender::environment_get_camera_feed_id(RID p_env) const {
+ return environment_storage.environment_get_camera_feed_id(p_env);
+}
+
// Tonemap
void RendererSceneRender::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white) {
diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h
index 4d81a9b6a3..99418e0411 100644
--- a/servers/rendering/renderer_scene_render.h
+++ b/servers/rendering/renderer_scene_render.h
@@ -118,10 +118,7 @@ public:
void environment_set_bg_energy(RID p_env, float p_multiplier, float p_exposure_value);
void environment_set_canvas_max_layer(RID p_env, int p_max_layer);
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);
-// FIXME: Disabled during Vulkan refactoring, should be ported.
-#if 0
void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id);
-#endif
RS::EnvironmentBG environment_get_background(RID p_env) const;
RID environment_get_sky(RID p_env) const;
@@ -136,6 +133,7 @@ public:
float environment_get_ambient_light_energy(RID p_env) const;
float environment_get_ambient_sky_contribution(RID p_env) const;
RS::EnvironmentReflectionSource environment_get_reflection_source(RID p_env) const;
+ int environment_get_camera_feed_id(RID p_env) const;
// Tonemap
void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white);
@@ -302,6 +300,7 @@ public:
// flags
uint32_t view_count;
bool is_orthogonal;
+ bool is_frustum;
uint32_t visible_layers;
bool vaspect;
@@ -314,8 +313,8 @@ public:
Vector2 taa_jitter;
float taa_frame_count = 0.0f;
- void set_camera(const Transform3D p_transform, const Projection p_projection, bool p_is_orthogonal, bool p_vaspect, const Vector2 &p_taa_jitter = Vector2(), float p_taa_frame_count = 0.0f, uint32_t p_visible_layers = 0xFFFFFFFF);
- void set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const Projection *p_projections, bool p_is_orthogonal, bool p_vaspect);
+ void set_camera(const Transform3D p_transform, const Projection p_projection, bool p_is_orthogonal, bool p_is_frustum, bool p_vaspect, const Vector2 &p_taa_jitter = Vector2(), float p_taa_frame_count = 0.0f, uint32_t p_visible_layers = 0xFFFFFFFF);
+ void set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const Projection *p_projections, bool p_is_orthogonal, bool p_is_frustum, bool p_vaspect);
};
virtual void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_compositor, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_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, RenderingMethod::RenderInfo *r_render_info = nullptr) = 0;
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 942d5631e4..cc67873b24 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -1260,8 +1260,6 @@ Error RenderingDevice::_texture_initialize(RID p_texture, uint32_t p_layer, cons
write_ptr = driver->buffer_map(transfer_worker->staging_buffer);
ERR_FAIL_NULL_V(write_ptr, ERR_CANT_CREATE);
- write_ptr += staging_worker_offset;
-
if (driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
// Transition the texture to the optimal layout.
RDD::TextureBarrier tb;
@@ -1303,11 +1301,12 @@ Error RenderingDevice::_texture_initialize(RID p_texture, uint32_t p_layer, cons
if (copy_pass) {
const uint8_t *read_ptr_mipmap_layer = read_ptr_mipmap + (tight_mip_size / depth) * z;
- _copy_region_block_or_regular(read_ptr_mipmap_layer, write_ptr, 0, 0, width, width, height, block_w, block_h, pitch, pixel_size, block_size);
- write_ptr += to_allocate;
+ uint64_t staging_buffer_offset = staging_worker_offset + staging_local_offset;
+ uint8_t *write_ptr_mipmap_layer = write_ptr + staging_buffer_offset;
+ _copy_region_block_or_regular(read_ptr_mipmap_layer, write_ptr_mipmap_layer, 0, 0, width, width, height, block_w, block_h, pitch, pixel_size, block_size);
RDD::BufferTextureCopyRegion copy_region;
- copy_region.buffer_offset = staging_worker_offset + staging_local_offset;
+ copy_region.buffer_offset = staging_buffer_offset;
copy_region.texture_subresources.aspect = texture->read_aspect_flags;
copy_region.texture_subresources.mipmap = mm_i;
copy_region.texture_subresources.base_layer = p_layer;
@@ -3758,6 +3757,15 @@ int RenderingDevice::screen_get_height(DisplayServer::WindowID p_screen) const {
return context->surface_get_height(surface);
}
+int RenderingDevice::screen_get_pre_rotation_degrees(DisplayServer::WindowID p_screen) const {
+ _THREAD_SAFE_METHOD_
+
+ HashMap<DisplayServer::WindowID, RDD::SwapChainID>::ConstIterator it = screen_swap_chains.find(p_screen);
+ ERR_FAIL_COND_V_MSG(it == screen_swap_chains.end(), ERR_CANT_CREATE, "A swap chain was not created for the screen.");
+
+ return driver->swap_chain_get_pre_rotation_degrees(it->value);
+}
+
RenderingDevice::FramebufferFormatID RenderingDevice::screen_get_framebuffer_format(DisplayServer::WindowID p_screen) const {
_THREAD_SAFE_METHOD_
@@ -4441,6 +4449,117 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint
dl->state.draw_count++;
}
+void RenderingDevice::draw_list_draw_indirect(DrawListID p_list, bool p_use_indices, RID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {
+ ERR_RENDER_THREAD_GUARD();
+
+ DrawList *dl = _get_draw_list_ptr(p_list);
+ ERR_FAIL_NULL(dl);
+
+ Buffer *buffer = storage_buffer_owner.get_or_null(p_buffer);
+ ERR_FAIL_NULL(buffer);
+
+ ERR_FAIL_COND_MSG(!buffer->usage.has_flag(RDD::BUFFER_USAGE_INDIRECT_BIT), "Buffer provided was not created to do indirect dispatch.");
+
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
+#endif
+
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_MSG(!dl->validation.pipeline_active,
+ "No render pipeline was set before attempting to draw.");
+ if (dl->validation.pipeline_vertex_format != INVALID_ID) {
+ // Pipeline uses vertices, validate format.
+ ERR_FAIL_COND_MSG(dl->validation.vertex_format == INVALID_ID,
+ "No vertex array was bound, and render pipeline expects vertices.");
+ // Make sure format is right.
+ ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format != dl->validation.vertex_format,
+ "The vertex format used to create the pipeline does not match the vertex format bound.");
+ }
+
+ if (dl->validation.pipeline_push_constant_size > 0) {
+ // Using push constants, check that they were supplied.
+ ERR_FAIL_COND_MSG(!dl->validation.pipeline_push_constant_supplied,
+ "The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
+ }
+#endif
+
+#ifdef DEBUG_ENABLED
+ for (uint32_t i = 0; i < dl->state.set_count; i++) {
+ if (dl->state.sets[i].pipeline_expected_format == 0) {
+ // Nothing expected by this pipeline.
+ continue;
+ }
+
+ if (dl->state.sets[i].pipeline_expected_format != dl->state.sets[i].uniform_set_format) {
+ if (dl->state.sets[i].uniform_set_format == 0) {
+ ERR_FAIL_MSG(vformat("Uniforms were never supplied for set (%d) at the time of drawing, which are required by the pipeline.", i));
+ } else if (uniform_set_owner.owns(dl->state.sets[i].uniform_set)) {
+ UniformSet *us = uniform_set_owner.get_or_null(dl->state.sets[i].uniform_set);
+ ERR_FAIL_MSG(vformat("Uniforms supplied for set (%d):\n%s\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n%s", i, _shader_uniform_debug(us->shader_id, us->shader_set), _shader_uniform_debug(dl->state.pipeline_shader)));
+ } else {
+ ERR_FAIL_MSG(vformat("Uniforms supplied for set (%s, which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n%s", i, _shader_uniform_debug(dl->state.pipeline_shader)));
+ }
+ }
+ }
+#endif
+
+ // Prepare descriptor sets if the API doesn't use pipeline barriers.
+ if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
+ for (uint32_t i = 0; i < dl->state.set_count; i++) {
+ if (dl->state.sets[i].pipeline_expected_format == 0) {
+ // Nothing expected by this pipeline.
+ continue;
+ }
+
+ draw_graph.add_draw_list_uniform_set_prepare_for_use(dl->state.pipeline_shader_driver_id, dl->state.sets[i].uniform_set_driver_id, i);
+ }
+ }
+
+ // Bind descriptor sets.
+ for (uint32_t i = 0; i < dl->state.set_count; i++) {
+ if (dl->state.sets[i].pipeline_expected_format == 0) {
+ continue; // Nothing expected by this pipeline.
+ }
+ if (!dl->state.sets[i].bound) {
+ // All good, see if this requires re-binding.
+ draw_graph.add_draw_list_bind_uniform_set(dl->state.pipeline_shader_driver_id, dl->state.sets[i].uniform_set_driver_id, i);
+
+ UniformSet *uniform_set = uniform_set_owner.get_or_null(dl->state.sets[i].uniform_set);
+ _uniform_set_update_shared(uniform_set);
+
+ draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);
+
+ dl->state.sets[i].bound = true;
+ }
+ }
+
+ if (p_use_indices) {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_MSG(!dl->validation.index_array_count,
+ "Draw command requested indices, but no index buffer was set.");
+
+ ERR_FAIL_COND_MSG(dl->validation.pipeline_uses_restart_indices != dl->validation.index_buffer_uses_restart_indices,
+ "The usage of restart indices in index buffer does not match the render primitive in the pipeline.");
+#endif
+
+ ERR_FAIL_COND_MSG(p_offset + 20 > buffer->size, "Offset provided (+20) is past the end of buffer.");
+
+ draw_graph.add_draw_list_draw_indexed_indirect(buffer->driver_id, p_offset, p_draw_count, p_stride);
+ } else {
+ ERR_FAIL_COND_MSG(p_offset + 16 > buffer->size, "Offset provided (+16) is past the end of buffer.");
+
+ draw_graph.add_draw_list_draw_indirect(buffer->driver_id, p_offset, p_draw_count, p_stride);
+ }
+
+ dl->state.draw_count++;
+
+ if (buffer->draw_tracker != nullptr) {
+ draw_graph.add_draw_list_usage(buffer->draw_tracker, RDG::RESOURCE_USAGE_INDIRECT_BUFFER_READ);
+ }
+
+ _check_transfer_worker_buffer(buffer);
+}
+
void RenderingDevice::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) {
ERR_RENDER_THREAD_GUARD();
@@ -6553,6 +6672,12 @@ void RenderingDevice::finalize() {
ERR_FAIL_COND(reverse_dependency_map.size());
}
+void RenderingDevice::_set_max_fps(int p_max_fps) {
+ for (const KeyValue<DisplayServer::WindowID, RDD::SwapChainID> &it : screen_swap_chains) {
+ driver->swap_chain_set_max_fps(it.value, p_max_fps);
+ }
+}
+
RenderingDevice *RenderingDevice::create_local_device() {
RenderingDevice *rd = memnew(RenderingDevice);
rd->initialize(context);
@@ -6651,6 +6776,7 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_list_set_push_constant", "draw_list", "buffer", "size_bytes"), &RenderingDevice::_draw_list_set_push_constant);
ClassDB::bind_method(D_METHOD("draw_list_draw", "draw_list", "use_indices", "instances", "procedural_vertex_count"), &RenderingDevice::draw_list_draw, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("draw_list_draw_indirect", "draw_list", "use_indices", "buffer", "offset", "draw_count", "stride"), &RenderingDevice::draw_list_draw_indirect, DEFVAL(0), DEFVAL(1), DEFVAL(0));
ClassDB::bind_method(D_METHOD("draw_list_enable_scissor", "draw_list", "rect"), &RenderingDevice::draw_list_enable_scissor, DEFVAL(Rect2()));
ClassDB::bind_method(D_METHOD("draw_list_disable_scissor", "draw_list"), &RenderingDevice::draw_list_disable_scissor);
@@ -7260,6 +7386,10 @@ void RenderingDevice::_bind_methods() {
BIND_ENUM_CONSTANT(DEBUG_PASS);
}
+void RenderingDevice::make_current() {
+ render_thread_id = Thread::get_caller_id();
+}
+
RenderingDevice::~RenderingDevice() {
finalize();
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 71ffbfbd88..9939df976f 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -1083,6 +1083,7 @@ public:
Error screen_prepare_for_drawing(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID);
int screen_get_width(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) const;
int screen_get_height(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) const;
+ int screen_get_pre_rotation_degrees(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) const;
FramebufferFormatID screen_get_framebuffer_format(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) const;
Error screen_free(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID);
@@ -1186,6 +1187,7 @@ public:
void draw_list_set_push_constant(DrawListID p_list, const void *p_data, uint32_t p_data_size);
void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1, uint32_t p_procedural_vertices = 0);
+ void draw_list_draw_indirect(DrawListID p_list, bool p_use_indices, RID p_buffer, uint32_t p_offset = 0, uint32_t p_draw_count = 1, uint32_t p_stride = 0);
void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect);
void draw_list_disable_scissor(DrawListID p_list);
@@ -1427,6 +1429,8 @@ public:
Error initialize(RenderingContextDriver *p_context, DisplayServer::WindowID p_main_window = DisplayServer::INVALID_WINDOW_ID);
void finalize();
+ void _set_max_fps(int p_max_fps);
+
void free(RID p_id);
/****************/
@@ -1496,6 +1500,8 @@ public:
static RenderingDevice *get_singleton();
+ void make_current();
+
RenderingDevice();
~RenderingDevice();
diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp
index d9ca286b15..e41a56b0a3 100644
--- a/servers/rendering/rendering_device_binds.cpp
+++ b/servers/rendering/rendering_device_binds.cpp
@@ -31,7 +31,10 @@
#include "rendering_device_binds.h"
Error RDShaderFile::parse_versions_from_text(const String &p_text, const String p_defines, OpenIncludeFunction p_include_func, void *p_include_func_userdata) {
- ERR_FAIL_NULL_V(RenderingDevice::get_singleton(), ERR_UNAVAILABLE);
+ ERR_FAIL_NULL_V_MSG(
+ RenderingDevice::get_singleton(),
+ ERR_UNAVAILABLE,
+ "Cannot import custom .glsl shaders when running without a RenderingDevice. This can happen if you are using the headless more or the Compatibility backend.");
Vector<String> lines = p_text.split("\n");
diff --git a/servers/rendering/rendering_device_driver.cpp b/servers/rendering/rendering_device_driver.cpp
index 9ff7b83215..c1a3f34af8 100644
--- a/servers/rendering/rendering_device_driver.cpp
+++ b/servers/rendering/rendering_device_driver.cpp
@@ -376,6 +376,8 @@ uint64_t RenderingDeviceDriver::api_trait_get(ApiTrait p_trait) {
return true;
case API_TRAIT_USE_GENERAL_IN_COPY_QUEUES:
return false;
+ case API_TRAIT_BUFFERS_REQUIRE_TRANSITIONS:
+ return false;
default:
ERR_FAIL_V(0);
}
diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h
index 637d52c060..d2d14676db 100644
--- a/servers/rendering/rendering_device_driver.h
+++ b/servers/rendering/rendering_device_driver.h
@@ -120,9 +120,9 @@ struct VersatileResourceTemplate {
class RenderingDeviceDriver : public RenderingDeviceCommons {
public:
struct ID {
- size_t id = 0;
+ uint64_t id = 0;
_ALWAYS_INLINE_ ID() = default;
- _ALWAYS_INLINE_ ID(size_t p_id) :
+ _ALWAYS_INLINE_ ID(uint64_t p_id) :
id(p_id) {}
};
@@ -138,11 +138,9 @@ public:
_ALWAYS_INLINE_ bool operator!=(const m_name##ID &p_other) const { return id != p_other.id; } \
_ALWAYS_INLINE_ m_name##ID(const m_name##ID &p_other) : ID(p_other.id) {} \
_ALWAYS_INLINE_ explicit m_name##ID(uint64_t p_int) : ID(p_int) {} \
- _ALWAYS_INLINE_ explicit m_name##ID(void *p_ptr) : ID((size_t)p_ptr) {} \
+ _ALWAYS_INLINE_ explicit m_name##ID(void *p_ptr) : ID((uint64_t)p_ptr) {} \
_ALWAYS_INLINE_ m_name##ID() = default; \
- }; \
- /* Ensure type-punnable to pointer. Makes some things easier.*/ \
- static_assert(sizeof(m_name##ID) == sizeof(void *));
+ };
// Id types declared before anything else to prevent cyclic dependencies between the different concerns.
DEFINE_ID(Buffer);
@@ -454,9 +452,16 @@ public:
// Retrieve the render pass that can be used to draw on the swap chain's framebuffers.
virtual RenderPassID swap_chain_get_render_pass(SwapChainID p_swap_chain) = 0;
+ // Retrieve the rotation in degrees to apply as a pre-transform. Usually 0 on PC. May be 0, 90, 180 & 270 on Android.
+ virtual int swap_chain_get_pre_rotation_degrees(SwapChainID p_swap_chain) { return 0; }
+
// Retrieve the format used by the swap chain's framebuffers.
virtual DataFormat swap_chain_get_format(SwapChainID p_swap_chain) = 0;
+ // Tells the swapchain the max_fps so it can use the proper frame pacing.
+ // Android uses this with Swappy library. Some implementations or platforms may ignore this hint.
+ virtual void swap_chain_set_max_fps(SwapChainID p_swap_chain, int p_max_fps) {}
+
// Wait until all rendering associated to the swap chain is finished before deleting it.
virtual void swap_chain_free(SwapChainID p_swap_chain) = 0;
@@ -752,6 +757,7 @@ public:
API_TRAIT_SECONDARY_VIEWPORT_SCISSOR,
API_TRAIT_CLEARS_WITH_COPY_ENGINE,
API_TRAIT_USE_GENERAL_IN_COPY_QUEUES,
+ API_TRAIT_BUFFERS_REQUIRE_TRANSITIONS,
};
enum ShaderChangeInvalidation {
diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp
index 0ecd818805..ec2f336f3c 100644
--- a/servers/rendering/rendering_device_graph.cpp
+++ b/servers/rendering/rendering_device_graph.cpp
@@ -34,7 +34,6 @@
#define FORCE_FULL_ACCESS_BITS 0
#define PRINT_RESOURCE_TRACKER_TOTAL 0
#define PRINT_COMMAND_RECORDING 0
-#define INSERT_BREADCRUMBS 1
RenderingDeviceGraph::RenderingDeviceGraph() {
driver_honors_barriers = false;
@@ -141,6 +140,25 @@ RDD::BarrierAccessBits RenderingDeviceGraph::_usage_to_access_bits(ResourceUsage
#endif
}
+bool RenderingDeviceGraph::_check_command_intersection(ResourceTracker *p_resource_tracker, int32_t p_previous_command_index, int32_t p_command_index) const {
+ if (p_resource_tracker->usage != RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE && p_resource_tracker->usage != RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE) {
+ // We don't check possible intersections for usages that aren't consecutive color or depth writes.
+ return true;
+ }
+
+ const uint32_t previous_command_data_offset = command_data_offsets[p_previous_command_index];
+ const uint32_t current_command_data_offset = command_data_offsets[p_command_index];
+ const RecordedDrawListCommand &previous_draw_list_command = *reinterpret_cast<const RecordedDrawListCommand *>(&command_data[previous_command_data_offset]);
+ const RecordedDrawListCommand &current_draw_list_command = *reinterpret_cast<const RecordedDrawListCommand *>(&command_data[current_command_data_offset]);
+ if (previous_draw_list_command.type != RecordedCommand::TYPE_DRAW_LIST || current_draw_list_command.type != RecordedCommand::TYPE_DRAW_LIST) {
+ // We don't check possible intersections if both commands aren't draw lists.
+ return true;
+ }
+
+ // We check if the region used by both draw lists have an intersection.
+ return previous_draw_list_command.region.intersects(current_draw_list_command.region);
+}
+
int32_t RenderingDeviceGraph::_add_to_command_list(int32_t p_command_index, int32_t p_list_index) {
DEV_ASSERT(p_command_index < int32_t(command_count));
DEV_ASSERT(p_list_index < int32_t(command_list_nodes.size()));
@@ -426,11 +444,9 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
#if USE_BUFFER_BARRIERS
_add_buffer_barrier_to_command(resource_tracker->buffer_driver_id, resource_tracker->usage_access, new_usage_access, r_command->buffer_barrier_index, r_command->buffer_barrier_count);
#endif
- // FIXME: Memory barriers are currently pushed regardless of whether buffer barriers are being used or not. Refer to the comment on the
- // definition of USE_BUFFER_BARRIERS for the reason behind this. This can be fixed to be one case or the other once it's been confirmed
- // the buffer and memory barrier behavior discrepancy has been solved.
- r_command->memory_barrier.src_access = resource_tracker->usage_access;
- r_command->memory_barrier.dst_access = new_usage_access;
+ // Memory barriers are pushed regardless of buffer barriers being used or not.
+ r_command->memory_barrier.src_access = r_command->memory_barrier.src_access | resource_tracker->usage_access;
+ r_command->memory_barrier.dst_access = r_command->memory_barrier.dst_access | new_usage_access;
} else {
DEV_ASSERT(false && "Resource tracker does not contain a valid buffer or texture ID.");
}
@@ -450,10 +466,12 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
if (different_usage) {
// Even if the usage of the resource isn't a write usage explicitly, a different usage implies a transition and it should therefore be considered a write.
- write_usage = true;
+ // In the case of buffers however, this is not exactly necessary if the driver does not consider different buffer usages as different states.
+ write_usage = write_usage || bool(resource_tracker->texture_driver_id) || driver_buffers_require_transitions;
resource_tracker->usage = new_resource_usage;
}
+ bool command_intersection_failed = false;
if (search_tracker->write_command_or_list_index >= 0) {
if (search_tracker->write_command_list_enabled) {
// Make this command adjacent to any commands that wrote to this resource and intersect with the slice if it applies.
@@ -465,7 +483,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
if (!resource_has_parent || search_tracker_rect.intersects(write_list_node.subresources)) {
if (write_list_node.command_index == p_command_index) {
ERR_FAIL_COND_MSG(!resource_has_parent, "Command can't have itself as a dependency.");
- } else {
+ } else if (_check_command_intersection(resource_tracker, write_list_node.command_index, p_command_index)) {
// Command is dependent on this command. Add this command to the adjacency list of the write command.
_add_adjacent_command(write_list_node.command_index, p_command_index, r_command);
@@ -481,6 +499,8 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
write_list_index = write_list_node.next_list_index;
continue;
}
+ } else {
+ command_intersection_failed = true;
}
}
@@ -491,14 +511,16 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
// The index is just the latest command index that wrote to the resource.
if (search_tracker->write_command_or_list_index == p_command_index) {
ERR_FAIL_MSG("Command can't have itself as a dependency.");
- } else {
+ } else if (_check_command_intersection(resource_tracker, search_tracker->write_command_or_list_index, p_command_index)) {
_add_adjacent_command(search_tracker->write_command_or_list_index, p_command_index, r_command);
+ } else {
+ command_intersection_failed = true;
}
}
}
if (write_usage) {
- if (resource_has_parent) {
+ if (resource_has_parent || command_intersection_failed) {
if (!search_tracker->write_command_list_enabled && search_tracker->write_command_or_list_index >= 0) {
// Write command list was not being used but there was a write command recorded. Add a new node with the entire parent resource's subresources and the recorded command index to the list.
const RDD::TextureSubresourceRange &tracker_subresources = search_tracker->texture_subresources;
@@ -709,6 +731,16 @@ void RenderingDeviceGraph::_run_draw_list_command(RDD::CommandBufferID p_command
driver->command_render_draw_indexed(p_command_buffer, draw_indexed_instruction->index_count, draw_indexed_instruction->instance_count, draw_indexed_instruction->first_index, 0, 0);
instruction_data_cursor += sizeof(DrawListDrawIndexedInstruction);
} break;
+ case DrawListInstruction::TYPE_DRAW_INDIRECT: {
+ const DrawListDrawIndirectInstruction *draw_indirect_instruction = reinterpret_cast<const DrawListDrawIndirectInstruction *>(instruction);
+ driver->command_render_draw_indirect(p_command_buffer, draw_indirect_instruction->buffer, draw_indirect_instruction->offset, draw_indirect_instruction->draw_count, draw_indirect_instruction->stride);
+ instruction_data_cursor += sizeof(DrawListDrawIndirectInstruction);
+ } break;
+ case DrawListInstruction::TYPE_DRAW_INDEXED_INDIRECT: {
+ const DrawListDrawIndexedIndirectInstruction *draw_indexed_indirect_instruction = reinterpret_cast<const DrawListDrawIndexedIndirectInstruction *>(instruction);
+ driver->command_render_draw_indexed_indirect(p_command_buffer, draw_indexed_indirect_instruction->buffer, draw_indexed_indirect_instruction->offset, draw_indexed_indirect_instruction->draw_count, draw_indexed_indirect_instruction->stride);
+ instruction_data_cursor += sizeof(DrawListDrawIndexedIndirectInstruction);
+ } break;
case DrawListInstruction::TYPE_EXECUTE_COMMANDS: {
const DrawListExecuteCommandsInstruction *execute_commands_instruction = reinterpret_cast<const DrawListExecuteCommandsInstruction *>(instruction);
driver->command_buffer_execute_secondary(p_command_buffer, execute_commands_instruction->command_buffer);
@@ -833,7 +865,7 @@ void RenderingDeviceGraph::_run_render_commands(int32_t p_level, const RecordedC
const RecordedDrawListCommand *draw_list_command = reinterpret_cast<const RecordedDrawListCommand *>(command);
const VectorView clear_values(draw_list_command->clear_values(), draw_list_command->clear_values_count);
-#if INSERT_BREADCRUMBS
+#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
driver->command_insert_breadcrumb(r_command_buffer, draw_list_command->breadcrumb);
#endif
driver->command_begin_render_pass(r_command_buffer, draw_list_command->render_pass, draw_list_command->framebuffer, draw_list_command->command_buffer_type, draw_list_command->region, clear_values);
@@ -1190,6 +1222,16 @@ void RenderingDeviceGraph::_print_draw_list(const uint8_t *p_instruction_data, u
print_line("\tDRAW INDICES", draw_indexed_instruction->index_count, "INSTANCES", draw_indexed_instruction->instance_count, "FIRST INDEX", draw_indexed_instruction->first_index);
instruction_data_cursor += sizeof(DrawListDrawIndexedInstruction);
} break;
+ case DrawListInstruction::TYPE_DRAW_INDIRECT: {
+ const DrawListDrawIndirectInstruction *draw_indirect_instruction = reinterpret_cast<const DrawListDrawIndirectInstruction *>(instruction);
+ print_line("\tDRAW INDIRECT BUFFER ID", itos(draw_indirect_instruction->buffer.id), "OFFSET", draw_indirect_instruction->offset, "DRAW COUNT", draw_indirect_instruction->draw_count, "STRIDE", draw_indirect_instruction->stride);
+ instruction_data_cursor += sizeof(DrawListDrawIndirectInstruction);
+ } break;
+ case DrawListInstruction::TYPE_DRAW_INDEXED_INDIRECT: {
+ const DrawListDrawIndexedIndirectInstruction *draw_indexed_indirect_instruction = reinterpret_cast<const DrawListDrawIndexedIndirectInstruction *>(instruction);
+ print_line("\tDRAW INDEXED INDIRECT BUFFER ID", itos(draw_indexed_indirect_instruction->buffer.id), "OFFSET", draw_indexed_indirect_instruction->offset, "DRAW COUNT", draw_indexed_indirect_instruction->draw_count, "STRIDE", draw_indexed_indirect_instruction->stride);
+ instruction_data_cursor += sizeof(DrawListDrawIndexedIndirectInstruction);
+ } break;
case DrawListInstruction::TYPE_EXECUTE_COMMANDS: {
print_line("\tEXECUTE COMMANDS");
instruction_data_cursor += sizeof(DrawListExecuteCommandsInstruction);
@@ -1299,6 +1341,7 @@ void RenderingDeviceGraph::initialize(RDD *p_driver, RenderingContextDriver::Dev
driver_honors_barriers = driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS);
driver_clears_with_copy_engine = driver->api_trait_get(RDD::API_TRAIT_CLEARS_WITH_COPY_ENGINE);
+ driver_buffers_require_transitions = driver->api_trait_get(RDD::API_TRAIT_BUFFERS_REQUIRE_TRANSITIONS);
}
void RenderingDeviceGraph::finalize() {
@@ -1416,7 +1459,9 @@ void RenderingDeviceGraph::add_buffer_update(RDD::BufferID p_dst, ResourceTracke
void RenderingDeviceGraph::add_compute_list_begin(RDD::BreadcrumbMarker p_phase, uint32_t p_breadcrumb_data) {
compute_instruction_list.clear();
+#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
compute_instruction_list.breadcrumb = p_breadcrumb_data | (p_phase & ((1 << 16) - 1));
+#endif
compute_instruction_list.index++;
}
@@ -1512,7 +1557,9 @@ void RenderingDeviceGraph::add_draw_list_begin(RDD::RenderPassID p_render_pass,
draw_instruction_list.render_pass = p_render_pass;
draw_instruction_list.framebuffer = p_framebuffer;
draw_instruction_list.region = p_region;
+#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
draw_instruction_list.breadcrumb = p_breadcrumb;
+#endif
draw_instruction_list.clear_values.resize(p_clear_values.size());
for (uint32_t i = 0; i < p_clear_values.size(); i++) {
draw_instruction_list.clear_values[i] = p_clear_values[i];
@@ -1608,6 +1655,26 @@ void RenderingDeviceGraph::add_draw_list_draw_indexed(uint32_t p_index_count, ui
instruction->first_index = p_first_index;
}
+void RenderingDeviceGraph::add_draw_list_draw_indirect(RDD::BufferID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {
+ DrawListDrawIndirectInstruction *instruction = reinterpret_cast<DrawListDrawIndirectInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListDrawIndirectInstruction)));
+ instruction->type = DrawListInstruction::TYPE_DRAW_INDIRECT;
+ instruction->buffer = p_buffer;
+ instruction->offset = p_offset;
+ instruction->draw_count = p_draw_count;
+ instruction->stride = p_stride;
+ draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
+}
+
+void RenderingDeviceGraph::add_draw_list_draw_indexed_indirect(RDD::BufferID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {
+ DrawListDrawIndexedIndirectInstruction *instruction = reinterpret_cast<DrawListDrawIndexedIndirectInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListDrawIndexedIndirectInstruction)));
+ instruction->type = DrawListInstruction::TYPE_DRAW_INDEXED_INDIRECT;
+ instruction->buffer = p_buffer;
+ instruction->offset = p_offset;
+ instruction->draw_count = p_draw_count;
+ instruction->stride = p_stride;
+ draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
+}
+
void RenderingDeviceGraph::add_draw_list_execute_commands(RDD::CommandBufferID p_command_buffer) {
DrawListExecuteCommandsInstruction *instruction = reinterpret_cast<DrawListExecuteCommandsInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListExecuteCommandsInstruction)));
instruction->type = DrawListInstruction::TYPE_EXECUTE_COMMANDS;
@@ -1723,7 +1790,9 @@ void RenderingDeviceGraph::add_draw_list_end() {
command->framebuffer = draw_instruction_list.framebuffer;
command->command_buffer_type = command_buffer_type;
command->region = draw_instruction_list.region;
+#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
command->breadcrumb = draw_instruction_list.breadcrumb;
+#endif
command->clear_values_count = draw_instruction_list.clear_values.size();
RDD::RenderPassClearValue *clear_values = command->clear_values();
diff --git a/servers/rendering/rendering_device_graph.h b/servers/rendering/rendering_device_graph.h
index 0534d4ee1e..9ddd70bc80 100644
--- a/servers/rendering/rendering_device_graph.h
+++ b/servers/rendering/rendering_device_graph.h
@@ -69,6 +69,8 @@ public:
TYPE_CLEAR_ATTACHMENTS,
TYPE_DRAW,
TYPE_DRAW_INDEXED,
+ TYPE_DRAW_INDIRECT,
+ TYPE_DRAW_INDEXED_INDIRECT,
TYPE_EXECUTE_COMMANDS,
TYPE_NEXT_SUBPASS,
TYPE_SET_BLEND_CONSTANTS,
@@ -221,14 +223,18 @@ private:
};
struct ComputeInstructionList : InstructionList {
+#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
uint32_t breadcrumb;
+#endif
};
struct DrawInstructionList : InstructionList {
RDD::RenderPassID render_pass;
RDD::FramebufferID framebuffer;
Rect2i region;
+#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
uint32_t breadcrumb;
+#endif
LocalVector<RDD::RenderPassClearValue> clear_values;
};
@@ -317,7 +323,9 @@ private:
RDD::FramebufferID framebuffer;
RDD::CommandBufferType command_buffer_type;
Rect2i region;
+#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
uint32_t breadcrumb = 0;
+#endif
uint32_t clear_values_count = 0;
_FORCE_INLINE_ RDD::RenderPassClearValue *clear_values() {
@@ -466,6 +474,20 @@ private:
uint32_t first_index = 0;
};
+ struct DrawListDrawIndirectInstruction : DrawListInstruction {
+ RDD::BufferID buffer;
+ uint32_t offset = 0;
+ uint32_t draw_count = 0;
+ uint32_t stride = 0;
+ };
+
+ struct DrawListDrawIndexedIndirectInstruction : DrawListInstruction {
+ RDD::BufferID buffer;
+ uint32_t offset = 0;
+ uint32_t draw_count = 0;
+ uint32_t stride = 0;
+ };
+
struct DrawListEndRenderPassInstruction : DrawListInstruction {
// No contents.
};
@@ -615,6 +637,7 @@ private:
BarrierGroup barrier_group;
bool driver_honors_barriers : 1;
bool driver_clears_with_copy_engine : 1;
+ bool driver_buffers_require_transitions : 1;
WorkaroundsState workarounds_state;
TightLocalVector<Frame> frames;
uint32_t frame = 0;
@@ -626,6 +649,7 @@ private:
static bool _is_write_usage(ResourceUsage p_usage);
static RDD::TextureLayout _usage_to_image_layout(ResourceUsage p_usage);
static RDD::BarrierAccessBits _usage_to_access_bits(ResourceUsage p_usage);
+ bool _check_command_intersection(ResourceTracker *p_resource_tracker, int32_t p_previous_command_index, int32_t p_command_index) const;
int32_t _add_to_command_list(int32_t p_command_index, int32_t p_list_index);
void _add_adjacent_command(int32_t p_previous_command_index, int32_t p_command_index, RecordedCommand *r_command);
int32_t _add_to_slice_read_list(int32_t p_command_index, Rect2i p_subresources, int32_t p_list_index);
@@ -678,6 +702,8 @@ public:
void add_draw_list_clear_attachments(VectorView<RDD::AttachmentClear> p_attachments_clear, VectorView<Rect2i> p_attachments_clear_rect);
void add_draw_list_draw(uint32_t p_vertex_count, uint32_t p_instance_count);
void add_draw_list_draw_indexed(uint32_t p_index_count, uint32_t p_instance_count, uint32_t p_first_index);
+ void add_draw_list_draw_indirect(RDD::BufferID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride);
+ void add_draw_list_draw_indexed_indirect(RDD::BufferID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride);
void add_draw_list_execute_commands(RDD::CommandBufferID p_command_buffer);
void add_draw_list_next_subpass(RDD::CommandBufferType p_command_buffer_type);
void add_draw_list_set_blend_constants(const Color &p_color);
diff --git a/servers/rendering/rendering_method.h b/servers/rendering/rendering_method.h
index 4c277ac215..34f11924ce 100644
--- a/servers/rendering/rendering_method.h
+++ b/servers/rendering/rendering_method.h
@@ -168,6 +168,7 @@ public:
virtual void environment_set_bg_energy(RID p_env, float p_multiplier, float p_exposure_value) = 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) = 0;
+ virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) = 0;
virtual RS::EnvironmentBG environment_get_background(RID p_Env) const = 0;
virtual RID environment_get_sky(RID p_env) const = 0;
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index 20f1f9ad6f..2ec693cbbf 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -370,6 +370,8 @@ Size2i RenderingServerDefault::get_maximum_viewport_size() const {
void RenderingServerDefault::_assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id) {
server_thread = Thread::get_caller_id();
server_task_id = p_pump_task_id;
+ // This is needed because the main RD is created on the main thread.
+ RenderingDevice::get_singleton()->make_current();
}
void RenderingServerDefault::_thread_exit() {
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 225a67fb52..5c3ee513c7 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -443,6 +443,7 @@ public:
FUNC2(light_set_cull_mask, RID, uint32_t)
FUNC5(light_set_distance_fade, RID, bool, float, float, float)
FUNC2(light_set_reverse_cull_face_mode, RID, bool)
+ FUNC2(light_set_shadow_caster_mask, RID, uint32_t)
FUNC2(light_set_bake_mode, RID, LightBakeMode)
FUNC2(light_set_max_sdfgi_cascade, RID, uint32_t)
@@ -785,10 +786,8 @@ public:
FUNC2(environment_set_canvas_max_layer, RID, int)
FUNC6(environment_set_ambient_light, RID, const Color &, EnvironmentAmbientSource, float, float, EnvironmentReflectionSource)
-// FIXME: Disabled during Vulkan refactoring, should be ported.
-#if 0
FUNC2(environment_set_camera_feed_id, RID, int)
-#endif
+
FUNC6(environment_set_ssr, RID, bool, int, float, float, float)
FUNC1(environment_set_ssr_roughness_quality, EnvironmentSSRRoughnessQuality)
diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp
index 119ac677eb..f52963f98f 100644
--- a/servers/rendering/shader_compiler.cpp
+++ b/servers/rendering/shader_compiler.cpp
@@ -489,7 +489,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
struct_code += _typestr(m->datatype);
}
struct_code += " ";
- struct_code += m->name;
+ struct_code += _mkid(m->name);
if (m->array_size > 0) {
struct_code += "[";
struct_code += itos(m->array_size);
@@ -1448,7 +1448,13 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
} break;
case SL::Node::NODE_TYPE_MEMBER: {
SL::MemberNode *mnode = (SL::MemberNode *)p_node;
- code = _dump_node_code(mnode->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + "." + mnode->name;
+ String name;
+ if (mnode->basetype == SL::TYPE_STRUCT) {
+ name = _mkid(mnode->name);
+ } else {
+ name = mnode->name;
+ }
+ code = _dump_node_code(mnode->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + "." + name;
if (mnode->index_expression != nullptr) {
code += "[";
code += _dump_node_code(mnode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index b6770c773c..7c4128b0e3 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -356,7 +356,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
{ TK_CF_BREAK, "break", CF_BLOCK, {}, {} },
{ TK_CF_CONTINUE, "continue", CF_BLOCK, {}, {} },
{ TK_CF_RETURN, "return", CF_BLOCK, {}, {} },
- { TK_CF_DISCARD, "discard", CF_BLOCK, { "particles", "sky", "fog" }, { "fragment" } },
+ { TK_CF_DISCARD, "discard", CF_BLOCK, { "particles", "sky", "fog" }, { "vertex" } },
// function specifier keywords
@@ -3565,28 +3565,33 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
int argcount = args.size();
- if (p_function_info.stage_functions.has(name)) {
- //stage based function
- const StageFunctionInfo &sf = p_function_info.stage_functions[name];
- if (argcount != sf.arguments.size()) {
- _set_error(vformat(RTR("Invalid number of arguments when calling stage function '%s', which expects %d arguments."), String(name), sf.arguments.size()));
- return false;
- }
- //validate arguments
- for (int i = 0; i < argcount; i++) {
- if (args[i] != sf.arguments[i].type) {
- _set_error(vformat(RTR("Invalid argument type when calling stage function '%s', type expected is '%s'."), String(name), get_datatype_name(sf.arguments[i].type)));
- return false;
- }
- }
+ if (stages) {
+ // Stage functions can be used in custom functions as well, that why need to check them all.
+ for (const KeyValue<StringName, FunctionInfo> &E : *stages) {
+ if (E.value.stage_functions.has(name)) {
+ // Stage-based function.
+ const StageFunctionInfo &sf = E.value.stage_functions[name];
+ if (argcount != sf.arguments.size()) {
+ _set_error(vformat(RTR("Invalid number of arguments when calling stage function '%s', which expects %d arguments."), String(name), sf.arguments.size()));
+ return false;
+ }
+ // Validate arguments.
+ for (int i = 0; i < argcount; i++) {
+ if (args[i] != sf.arguments[i].type) {
+ _set_error(vformat(RTR("Invalid argument type when calling stage function '%s', type expected is '%s'."), String(name), get_datatype_name(sf.arguments[i].type)));
+ return false;
+ }
+ }
- if (r_ret_type) {
- *r_ret_type = sf.return_type;
- }
- if (r_ret_type_str) {
- *r_ret_type_str = "";
+ if (r_ret_type) {
+ *r_ret_type = sf.return_type;
+ }
+ if (r_ret_type_str) {
+ *r_ret_type_str = "";
+ }
+ return true;
+ }
}
- return true;
}
bool failed_builtin = false;
@@ -5937,22 +5942,35 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
calls_info[current_function].calls.push_back(&calls_info[name]);
}
- int idx = 0;
bool is_builtin = false;
- while (frag_only_func_defs[idx].name) {
- if (frag_only_func_defs[idx].name == name) {
- // If a built-in function not found for the current shader type, then it shouldn't be parsed further.
- if (!is_supported_frag_only_funcs) {
- _set_error(vformat(RTR("Built-in function '%s' is not supported for the '%s' shader type."), name, shader_type_identifier));
- return nullptr;
+ if (is_supported_frag_only_funcs && stages) {
+ for (const KeyValue<StringName, FunctionInfo> &E : *stages) {
+ if (E.value.stage_functions.has(name)) {
+ // Register usage of the restricted stage function.
+ calls_info[current_function].uses_restricted_items.push_back(Pair<StringName, CallInfo::Item>(name, CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, _get_tkpos())));
+ is_builtin = true;
+ break;
}
- // Register usage of the restricted function.
- calls_info[current_function].uses_restricted_items.push_back(Pair<StringName, CallInfo::Item>(name, CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, _get_tkpos())));
- is_builtin = true;
- break;
}
- idx++;
+ }
+
+ if (!is_builtin) {
+ int idx = 0;
+ while (frag_only_func_defs[idx].name) {
+ if (frag_only_func_defs[idx].name == name) {
+ // If a built-in function not found for the current shader type, then it shouldn't be parsed further.
+ if (!is_supported_frag_only_funcs) {
+ _set_error(vformat(RTR("Built-in function '%s' is not supported for the '%s' shader type."), name, shader_type_identifier));
+ return nullptr;
+ }
+ // Register usage of the restricted function.
+ calls_info[current_function].uses_restricted_items.push_back(Pair<StringName, CallInfo::Item>(name, CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, _get_tkpos())));
+ is_builtin = true;
+ break;
+ }
+ idx++;
+ }
}
// Recursively checks for the restricted function call.
@@ -8581,6 +8599,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
block = block->parent_block;
}
} else if (tk.type == TK_CF_DISCARD) {
+ if (!is_discard_supported) {
+ _set_error(vformat(RTR("Use of '%s' is not supported for the '%s' shader type."), "discard", shader_type_identifier));
+ return ERR_PARSE_ERROR;
+ }
+
//check return type
BlockNode *b = p_block;
while (b && !b->parent_function) {
@@ -8592,7 +8615,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
if (!b->parent_function->can_discard) {
- _set_error(vformat(RTR("Use of '%s' is not allowed here."), "discard"));
+ _set_error(vformat(RTR("'%s' cannot be used within the '%s' processor function."), "discard", b->parent_function->name));
return ERR_PARSE_ERROR;
}
@@ -8601,6 +8624,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
pos = _get_tkpos();
tk = _get_token();
+
+ calls_info[b->parent_function->name].uses_restricted_items.push_back(Pair<StringName, CallInfo::Item>("discard", CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, pos)));
+
if (tk.type != TK_SEMICOLON) {
_set_expected_after_error(";", "discard");
return ERR_PARSE_ERROR;
@@ -8838,7 +8864,9 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;
stages = &p_functions;
- is_supported_frag_only_funcs = shader_type_identifier == "canvas_item" || shader_type_identifier == "spatial" || shader_type_identifier == "sky";
+
+ is_discard_supported = shader_type_identifier == "canvas_item" || shader_type_identifier == "spatial";
+ is_supported_frag_only_funcs = is_discard_supported || shader_type_identifier == "sky";
const FunctionInfo &constants = p_functions.has("constants") ? p_functions["constants"] : FunctionInfo();
@@ -10332,6 +10360,8 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
if (p_functions.has(name)) {
func_node->can_discard = p_functions[name].can_discard;
+ } else {
+ func_node->can_discard = is_discard_supported; // Allow use it for custom functions (in supported shader types).
}
if (!function_overload_count.has(name)) {
@@ -10922,10 +10952,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
break; // Ignore hint keywords (parsed below).
}
if (keyword_list[i].flags & keyword_completion_context) {
- if (keyword_list[i].excluded_shader_types.has(shader_type_identifier)) {
- continue;
- }
- if (!keyword_list[i].functions.is_empty() && !keyword_list[i].functions.has(current_function)) {
+ if (keyword_list[i].excluded_shader_types.has(shader_type_identifier) || keyword_list[i].excluded_functions.has(current_function)) {
continue;
}
ScriptLanguage::CodeCompletionOption option(keyword_list[i].text, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
@@ -11160,9 +11187,15 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
int idx = 0;
bool low_end = RenderingServer::get_singleton()->is_low_end();
- if (stages && stages->has(skip_function)) {
- for (const KeyValue<StringName, StageFunctionInfo> &E : (*stages)[skip_function].stage_functions) {
- matches.insert(String(E.key), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
+ if (stages) {
+ // Stage functions can be used in custom functions as well, that why need to check them all.
+ for (const KeyValue<StringName, FunctionInfo> &E : *stages) {
+ for (const KeyValue<StringName, StageFunctionInfo> &F : E.value.stage_functions) {
+ if (F.value.skip_function == skip_function && stages->has(skip_function)) {
+ continue;
+ }
+ matches.insert(String(F.key), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
+ }
}
}
@@ -11292,9 +11325,15 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
return OK;
}
- if (stages && stages->has(block_function)) {
- for (const KeyValue<StringName, StageFunctionInfo> &E : (*stages)[block_function].stage_functions) {
- if (completion_function == E.key) {
+ if (stages) {
+ // Stage functions can be used in custom functions as well, that why need to check them all.
+ for (const KeyValue<StringName, FunctionInfo> &S : *stages) {
+ for (const KeyValue<StringName, StageFunctionInfo> &E : S.value.stage_functions) {
+ // No need to check for the skip function here.
+ if (completion_function != E.key) {
+ continue;
+ }
+
calltip += get_datatype_name(E.value.return_type);
calltip += " ";
calltip += E.key;
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index fb0a526230..4dade4d79f 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -859,6 +859,7 @@ public:
Vector<Argument> arguments;
DataType return_type = TYPE_VOID;
+ String skip_function;
};
struct ModeInfo {
@@ -934,7 +935,7 @@ private:
const char *text;
uint32_t flags;
const Vector<String> excluded_shader_types;
- const Vector<String> functions;
+ const Vector<String> excluded_functions;
};
static const KeyWord keyword_list[];
@@ -1150,6 +1151,7 @@ private:
const HashMap<StringName, FunctionInfo> *stages = nullptr;
bool is_supported_frag_only_funcs = false;
+ bool is_discard_supported = false;
bool _get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier);
static const BuiltinFuncDef builtin_func_defs[];
@@ -1211,7 +1213,7 @@ public:
struct ShaderCompileInfo {
HashMap<StringName, FunctionInfo> functions;
Vector<ModeInfo> render_modes;
- VaryingFunctionNames varying_function_names = VaryingFunctionNames();
+ VaryingFunctionNames varying_function_names;
HashSet<String> shader_types;
GlobalShaderUniformGetTypeFunc global_shader_uniform_type_func = nullptr;
bool is_include = false;
diff --git a/servers/rendering/shader_preprocessor.cpp b/servers/rendering/shader_preprocessor.cpp
index 0e41a178b5..88ea74cdfc 100644
--- a/servers/rendering/shader_preprocessor.cpp
+++ b/servers/rendering/shader_preprocessor.cpp
@@ -816,6 +816,11 @@ void ShaderPreprocessor::process_undef(Tokenizer *p_tokenizer) {
}
if (state->defines.has(label)) {
+ if (state->defines[label]->is_builtin) {
+ set_error(vformat(RTR("Cannot use '%s' on built-in define."), "undef"), line);
+ return;
+ }
+
memdelete(state->defines[label]);
state->defines.erase(label);
}
@@ -1324,6 +1329,35 @@ Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filen
pp_state.current_filename = p_filename;
pp_state.save_regions = r_regions != nullptr;
}
+
+ // Built-in defines.
+ {
+ static HashMap<StringName, String> defines;
+
+ if (defines.is_empty()) {
+ const String rendering_method = OS::get_singleton()->get_current_rendering_method();
+
+ if (rendering_method == "forward_plus") {
+ defines["CURRENT_RENDERER"] = _MKSTR(2);
+ } else if (rendering_method == "mobile") {
+ defines["CURRENT_RENDERER"] = _MKSTR(1);
+ } else { // gl_compatibility
+ defines["CURRENT_RENDERER"] = _MKSTR(0);
+ }
+
+ defines["RENDERER_COMPATIBILITY"] = _MKSTR(0);
+ defines["RENDERER_MOBILE"] = _MKSTR(1);
+ defines["RENDERER_FORWARD_PLUS"] = _MKSTR(2);
+ }
+
+ for (const KeyValue<StringName, String> &E : defines) {
+ Define *define = memnew(Define);
+ define->is_builtin = true;
+ define->body = E.value;
+ pp_state.defines[E.key] = define;
+ }
+ }
+
Error err = preprocess(&pp_state, p_code, r_result);
if (err != OK) {
if (r_error_text) {
diff --git a/servers/rendering/shader_preprocessor.h b/servers/rendering/shader_preprocessor.h
index 0a90aec958..b3d9594bcb 100644
--- a/servers/rendering/shader_preprocessor.h
+++ b/servers/rendering/shader_preprocessor.h
@@ -132,6 +132,7 @@ private:
struct Define {
Vector<String> arguments;
String body;
+ bool is_builtin = false;
};
struct Branch {
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index f498c0bf93..821009f07c 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -63,6 +63,8 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["constants"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_SPATIAL].functions["constants"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_SPATIAL].functions["constants"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SPATIAL].functions["constants"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_SPATIAL].functions["constants"].built_ins["CLIP_SPACE_FAR"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC3;
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3;
@@ -96,8 +98,6 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["MODELVIEW_MATRIX"] = ShaderLanguage::TYPE_MAT4;
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["MODELVIEW_NORMAL_MATRIX"] = ShaderLanguage::TYPE_MAT3;
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CLIP_SPACE_FAR"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["MAIN_CAM_INV_VIEW_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NODE_POSITION_WORLD"] = constt(ShaderLanguage::TYPE_VEC3);
@@ -159,9 +159,6 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_RIGHT"] = constt(ShaderLanguage::TYPE_INT);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["EYE_OFFSET"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CLIP_SPACE_FAR"] = constt(ShaderLanguage::TYPE_FLOAT);
-
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["MODEL_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["MODEL_NORMAL_MATRIX"] = constt(ShaderLanguage::TYPE_MAT3);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
@@ -203,8 +200,6 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ROUGHNESS"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["DIFFUSE_LIGHT"] = ShaderLanguage::TYPE_VEC3;
shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["SPECULAR_LIGHT"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["CLIP_SPACE_FAR"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["light"].can_discard = true;
@@ -284,6 +279,7 @@ ShaderTypes::ShaderTypes() {
{
ShaderLanguage::StageFunctionInfo func;
+ func.skip_function = "vertex";
func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("sdf_pos", ShaderLanguage::TYPE_VEC2));
func.return_type = ShaderLanguage::TYPE_FLOAT; //whether it could emit
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].stage_functions["texture_sdf"] = func;
@@ -297,6 +293,7 @@ ShaderTypes::ShaderTypes() {
{
ShaderLanguage::StageFunctionInfo func;
+ func.skip_function = "vertex";
func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("uv", ShaderLanguage::TYPE_VEC2));
func.return_type = ShaderLanguage::TYPE_VEC2; //whether it could emit
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].stage_functions["screen_uv_to_sdf"] = func;
diff --git a/servers/rendering/storage/camera_attributes_storage.h b/servers/rendering/storage/camera_attributes_storage.h
index 6fbcd3da7d..afb8ad23cf 100644
--- a/servers/rendering/storage/camera_attributes_storage.h
+++ b/servers/rendering/storage/camera_attributes_storage.h
@@ -72,8 +72,8 @@ public:
RendererCameraAttributes();
~RendererCameraAttributes();
- CameraAttributes *get_camera_attributes(RID p_rid) { return camera_attributes_owner.get_or_null(p_rid); };
- bool owns_camera_attributes(RID p_rid) { return camera_attributes_owner.owns(p_rid); };
+ CameraAttributes *get_camera_attributes(RID p_rid) { return camera_attributes_owner.get_or_null(p_rid); }
+ bool owns_camera_attributes(RID p_rid) { return camera_attributes_owner.owns(p_rid); }
RID camera_attributes_allocate();
void camera_attributes_initialize(RID p_rid);
diff --git a/servers/rendering/storage/environment_storage.cpp b/servers/rendering/storage/environment_storage.cpp
index 1bbb5da6bb..e7556f9000 100644
--- a/servers/rendering/storage/environment_storage.cpp
+++ b/servers/rendering/storage/environment_storage.cpp
@@ -189,6 +189,18 @@ RS::EnvironmentReflectionSource RendererEnvironmentStorage::environment_get_refl
return env->reflection_source;
}
+void RendererEnvironmentStorage::environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) {
+ Environment *env = environment_owner.get_or_null(p_env);
+ ERR_FAIL_NULL(env);
+ env->camera_feed_id = p_camera_feed_id;
+}
+
+int RendererEnvironmentStorage::environment_get_camera_feed_id(RID p_env) const {
+ Environment *env = environment_owner.get_or_null(p_env);
+ ERR_FAIL_NULL_V(env, -1);
+ return env->camera_feed_id;
+}
+
// Tonemap
void RendererEnvironmentStorage::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white) {
diff --git a/servers/rendering/storage/environment_storage.h b/servers/rendering/storage/environment_storage.h
index 9f78808ff7..6fdc047ba2 100644
--- a/servers/rendering/storage/environment_storage.h
+++ b/servers/rendering/storage/environment_storage.h
@@ -57,6 +57,7 @@ private:
float ambient_light_energy = 1.0;
float ambient_sky_contribution = 1.0;
RS::EnvironmentReflectionSource reflection_source = RS::ENV_REFLECTION_SOURCE_BG;
+ int camera_feed_id = 0;
// Tonemap
RS::EnvironmentToneMapper tone_mapper;
@@ -181,10 +182,8 @@ public:
void environment_set_bg_energy(RID p_env, float p_multiplier, float p_exposure_value);
void environment_set_canvas_max_layer(RID p_env, int p_max_layer);
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);
-// FIXME: Disabled during Vulkan refactoring, should be ported.
-#if 0
void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id);
-#endif
+ int environment_get_camera_feed_id(RID p_env) const;
RS::EnvironmentBG environment_get_background(RID p_env) const;
RID environment_get_sky(RID p_env) const;
diff --git a/servers/rendering/storage/light_storage.h b/servers/rendering/storage/light_storage.h
index 6a0adfa596..1e149e3a97 100644
--- a/servers/rendering/storage/light_storage.h
+++ b/servers/rendering/storage/light_storage.h
@@ -59,6 +59,8 @@ public:
virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0;
virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) = 0;
virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0;
+ virtual void light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) = 0;
+ virtual uint32_t light_get_shadow_caster_mask(RID p_light) const = 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;
diff --git a/servers/rendering/storage/render_scene_buffers.cpp b/servers/rendering/storage/render_scene_buffers.cpp
index 96e6492854..6d18ae2f77 100644
--- a/servers/rendering/storage/render_scene_buffers.cpp
+++ b/servers/rendering/storage/render_scene_buffers.cpp
@@ -81,7 +81,7 @@ void RenderSceneBuffersExtension::_bind_methods() {
void RenderSceneBuffersExtension::configure(const RenderSceneBuffersConfiguration *p_config) {
GDVIRTUAL_CALL(_configure, p_config);
-};
+}
void RenderSceneBuffersExtension::set_fsr_sharpness(float p_fsr_sharpness) {
GDVIRTUAL_CALL(_set_fsr_sharpness, p_fsr_sharpness);
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 32ef5261f3..c0c6f1e904 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -309,7 +309,7 @@ RID RenderingServer::get_white_texture() {
w[i] = 255;
}
}
- Ref<Image> white = memnew(Image(4, 4, 0, Image::FORMAT_RGB8, wt));
+ Ref<Image> white = memnew(Image(4, 4, false, Image::FORMAT_RGB8, wt));
white_texture = texture_2d_create(white);
return white_texture;
}
@@ -2067,6 +2067,16 @@ void RenderingServer::_particles_set_trail_bind_poses(RID p_particles, const Typ
particles_set_trail_bind_poses(p_particles, tbposes);
}
+String RenderingServer::get_current_rendering_driver_name() const {
+ // Needs to remain in OS, since it's actually OS that interacts with it, but it's better exposed here.
+ return ::OS::get_singleton()->get_current_rendering_driver_name();
+}
+
+String RenderingServer::get_current_rendering_method() const {
+ // Needs to remain in OS, since it's actually OS that interacts with it, but it's better exposed here.
+ return ::OS::get_singleton()->get_current_rendering_method();
+}
+
Vector<uint8_t> _convert_surface_version_1_to_surface_version_2(uint64_t p_format, Vector<uint8_t> p_vertex_data, uint32_t p_vertex_count, uint32_t p_old_stride, uint32_t p_vertex_size, uint32_t p_normal_size, uint32_t p_position_stride, uint32_t p_normal_tangent_stride) {
Vector<uint8_t> new_vertex_data;
new_vertex_data.resize(p_vertex_data.size());
@@ -2479,6 +2489,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("light_set_cull_mask", "light", "mask"), &RenderingServer::light_set_cull_mask);
ClassDB::bind_method(D_METHOD("light_set_distance_fade", "decal", "enabled", "begin", "shadow", "length"), &RenderingServer::light_set_distance_fade);
ClassDB::bind_method(D_METHOD("light_set_reverse_cull_face_mode", "light", "enabled"), &RenderingServer::light_set_reverse_cull_face_mode);
+ ClassDB::bind_method(D_METHOD("light_set_shadow_caster_mask", "light", "mask"), &RenderingServer::light_set_shadow_caster_mask);
ClassDB::bind_method(D_METHOD("light_set_bake_mode", "light", "bake_mode"), &RenderingServer::light_set_bake_mode);
ClassDB::bind_method(D_METHOD("light_set_max_sdfgi_cascade", "light", "cascade"), &RenderingServer::light_set_max_sdfgi_cascade);
@@ -2979,6 +2990,7 @@ void RenderingServer::_bind_methods() {
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_camera_id", "env", "id"), &RenderingServer::environment_set_camera_feed_id);
ClassDB::bind_method(D_METHOD("environment_set_sky", "env", "sky"), &RenderingServer::environment_set_sky);
ClassDB::bind_method(D_METHOD("environment_set_sky_custom_fov", "env", "scale"), &RenderingServer::environment_set_sky_custom_fov);
ClassDB::bind_method(D_METHOD("environment_set_sky_orientation", "env", "orientation"), &RenderingServer::environment_set_sky_orientation);
@@ -3421,6 +3433,9 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_video_adapter_type"), &RenderingServer::get_video_adapter_type);
ClassDB::bind_method(D_METHOD("get_video_adapter_api_version"), &RenderingServer::get_video_adapter_api_version);
+ ClassDB::bind_method(D_METHOD("get_current_rendering_driver_name"), &RenderingServer::get_current_rendering_driver_name);
+ ClassDB::bind_method(D_METHOD("get_current_rendering_method"), &RenderingServer::get_current_rendering_method);
+
ClassDB::bind_method(D_METHOD("make_sphere_mesh", "latitudes", "longitudes", "radius"), &RenderingServer::make_sphere_mesh);
ClassDB::bind_method(D_METHOD("get_test_cube"), &RenderingServer::get_test_cube);
@@ -3568,6 +3583,7 @@ void RenderingServer::init() {
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/2d/shadow_atlas/size", PROPERTY_HINT_RANGE, "128,16384"), 2048);
GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/2d/batching/item_buffer_size", PROPERTY_HINT_RANGE, "128,1048576,1"), 16384);
+ GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/2d/batching/uniform_set_cache_size", PROPERTY_HINT_RANGE, "256,1048576,1"), 256);
// Number of commands that can be drawn per frame.
GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/gl_compatibility/item_buffer_size", PROPERTY_HINT_RANGE, "128,1048576,1"), 16384);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 0208a640a5..6de934aaeb 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -542,6 +542,7 @@ public:
virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0;
virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) = 0;
virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0;
+ virtual void light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) = 0;
enum LightBakeMode {
LIGHT_BAKE_DISABLED,
@@ -1179,6 +1180,7 @@ public:
virtual void environment_set_bg_energy(RID p_env, float p_multiplier, float p_exposure_value) = 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, EnvironmentAmbientSource p_ambient = ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, EnvironmentReflectionSource p_reflection_source = ENV_REFLECTION_SOURCE_BG) = 0;
+ virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) = 0;
enum EnvironmentGlowBlendMode {
ENV_GLOW_BLEND_MODE_ADDITIVE,
@@ -1785,6 +1787,9 @@ public:
virtual bool is_on_render_thread() = 0;
virtual void call_on_render_thread(const Callable &p_callable) = 0;
+ String get_current_rendering_driver_name() const;
+ String get_current_rendering_method() const;
+
#ifdef TOOLS_ENABLED
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
#endif
diff --git a/servers/text/text_server_dummy.h b/servers/text/text_server_dummy.h
index 1a945ac221..10fe3b4595 100644
--- a/servers/text/text_server_dummy.h
+++ b/servers/text/text_server_dummy.h
@@ -88,7 +88,7 @@ public:
virtual int64_t font_get_char_from_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_glyph_index) const override { return 0; }
virtual bool font_has_char(const RID &p_font_rid, int64_t p_char) const override { return false; }
virtual String font_get_supported_chars(const RID &p_font_rid) const override { return String(); }
- virtual PackedInt32Array font_get_supported_glyphs(const RID &p_font_rid) const override { return PackedInt32Array(); };
+ virtual PackedInt32Array font_get_supported_glyphs(const RID &p_font_rid) const override { return PackedInt32Array(); }
virtual void font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const override {}
virtual void font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const override {}
diff --git a/servers/text_server.h b/servers/text_server.h
index 7dd9669818..f448d62cb2 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -544,8 +544,8 @@ public:
virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "", int64_t p_chars_per_line = 0) const = 0;
virtual PackedInt32Array string_get_character_breaks(const String &p_string, const String &p_language = "") const;
- virtual int64_t is_confusable(const String &p_string, const PackedStringArray &p_dict) const { return -1; };
- virtual bool spoof_check(const String &p_string) const { return false; };
+ virtual int64_t is_confusable(const String &p_string, const PackedStringArray &p_dict) const { return -1; }
+ virtual bool spoof_check(const String &p_string) const { return false; }
virtual String strip_diacritics(const String &p_string) const;
virtual bool is_valid_identifier(const String &p_string) const;
diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp
index 26f315a454..e9d2fc8520 100644
--- a/servers/xr/xr_interface.cpp
+++ b/servers/xr/xr_interface.cpp
@@ -108,7 +108,7 @@ void XRInterface::_bind_methods() {
BIND_ENUM_CONSTANT(XR_ENV_BLEND_MODE_OPAQUE);
BIND_ENUM_CONSTANT(XR_ENV_BLEND_MODE_ADDITIVE);
BIND_ENUM_CONSTANT(XR_ENV_BLEND_MODE_ALPHA_BLEND);
-};
+}
bool XRInterface::is_primary() {
XRServer *xr_server = XRServer::get_singleton();
@@ -155,7 +155,7 @@ PackedVector3Array XRInterface::get_play_area() const {
// Note implementation is responsible for applying our reference frame and world scale to the raw data.
// `play_area_changed` should be emitted if play area data is available and either the reference frame or world scale changes.
return PackedVector3Array();
-};
+}
/** these will only be implemented on AR interfaces, so we want dummies for VR **/
bool XRInterface::get_anchor_detection_is_enabled() const {
diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h
index 55495731c5..abd5476fc9 100644
--- a/servers/xr/xr_interface.h
+++ b/servers/xr/xr_interface.h
@@ -138,7 +138,7 @@ public:
virtual RID get_depth_texture(); /* obtain depth output texture (if applicable, used for reprojection) */
virtual RID get_velocity_texture(); /* obtain velocity output texture (if applicable, used for spacewarp) */
virtual void pre_render() {}
- virtual bool pre_draw_viewport(RID p_render_target) { return true; }; /* inform XR interface we are about to start our viewport draw process */
+ virtual bool pre_draw_viewport(RID p_render_target) { return true; } /* inform XR interface we are about to start our viewport draw process */
virtual Vector<BlitToScreen> post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) = 0; /* inform XR interface we finished our viewport draw process */
virtual void end_frame() {}
diff --git a/servers/xr/xr_positional_tracker.cpp b/servers/xr/xr_positional_tracker.cpp
index b479237730..225dab272f 100644
--- a/servers/xr/xr_positional_tracker.cpp
+++ b/servers/xr/xr_positional_tracker.cpp
@@ -61,7 +61,7 @@ void XRPositionalTracker::_bind_methods() {
ADD_SIGNAL(MethodInfo("input_float_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "value")));
ADD_SIGNAL(MethodInfo("input_vector2_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::VECTOR2, "vector")));
ADD_SIGNAL(MethodInfo("profile_changed", PropertyInfo(Variant::STRING, "role")));
-};
+}
void XRPositionalTracker::set_tracker_profile(const String &p_profile) {
if (profile != p_profile) {
@@ -77,12 +77,12 @@ String XRPositionalTracker::get_tracker_profile() const {
XRPositionalTracker::TrackerHand XRPositionalTracker::get_tracker_hand() const {
return tracker_hand;
-};
+}
void XRPositionalTracker::set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand) {
ERR_FAIL_INDEX(p_hand, TRACKER_HAND_MAX);
tracker_hand = p_hand;
-};
+}
bool XRPositionalTracker::has_pose(const StringName &p_action_name) const {
return poses.has(p_action_name);
diff --git a/servers/xr/xr_tracker.cpp b/servers/xr/xr_tracker.cpp
index 0b917a5dc3..b0b2f3f30a 100644
--- a/servers/xr/xr_tracker.cpp
+++ b/servers/xr/xr_tracker.cpp
@@ -42,24 +42,24 @@ void XRTracker::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tracker_desc"), &XRTracker::get_tracker_desc);
ClassDB::bind_method(D_METHOD("set_tracker_desc", "description"), &XRTracker::set_tracker_desc);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "description"), "set_tracker_desc", "get_tracker_desc");
-};
+}
void XRTracker::set_tracker_type(XRServer::TrackerType p_type) {
type = p_type;
-};
+}
XRServer::TrackerType XRTracker::get_tracker_type() const {
return type;
-};
+}
void XRTracker::set_tracker_name(const StringName &p_name) {
// Note: this should not be changed after the tracker is registered with the XRServer!
name = p_name;
-};
+}
StringName XRTracker::get_tracker_name() const {
return name;
-};
+}
void XRTracker::set_tracker_desc(const String &p_desc) {
description = p_desc;