diff options
Diffstat (limited to 'servers')
266 files changed, 23025 insertions, 13247 deletions
diff --git a/servers/audio/audio_driver_dummy.cpp b/servers/audio/audio_driver_dummy.cpp index ff0d2cad65..12cadb9301 100644 --- a/servers/audio/audio_driver_dummy.cpp +++ b/servers/audio/audio_driver_dummy.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,8 +30,8 @@ #include "audio_driver_dummy.h" +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" Error AudioDriverDummy::init() { active = false; diff --git a/servers/audio/audio_driver_dummy.h b/servers/audio/audio_driver_dummy.h index 84a566e420..617ffb2c79 100644 --- a/servers/audio/audio_driver_dummy.h +++ b/servers/audio/audio_driver_dummy.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/audio_effect.cpp b/servers/audio/audio_effect.cpp index d7279cdf48..3035828c95 100644 --- a/servers/audio/audio_effect.cpp +++ b/servers/audio/audio_effect.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/audio_effect.h b/servers/audio/audio_effect.h index 76cb8a209c..4556db9b93 100644 --- a/servers/audio/audio_effect.h +++ b/servers/audio/audio_effect.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,8 +31,8 @@ #ifndef AUDIOEFFECT_H #define AUDIOEFFECT_H +#include "core/io/resource.h" #include "core/math/audio_frame.h" -#include "core/resource.h" class AudioEffectInstance : public Reference { GDCLASS(AudioEffectInstance, Reference); diff --git a/servers/audio/audio_filter_sw.cpp b/servers/audio/audio_filter_sw.cpp index f5eafb7e60..580e061496 100644 --- a/servers/audio/audio_filter_sw.cpp +++ b/servers/audio/audio_filter_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/audio_filter_sw.h b/servers/audio/audio_filter_sw.h index a7f570fbb4..540d6368e3 100644 --- a/servers/audio/audio_filter_sw.h +++ b/servers/audio/audio_filter_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/audio_rb_resampler.cpp b/servers/audio/audio_rb_resampler.cpp index 7613e70e64..efdcb916ed 100644 --- a/servers/audio/audio_rb_resampler.cpp +++ b/servers/audio/audio_rb_resampler.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/audio_rb_resampler.h b/servers/audio/audio_rb_resampler.h index 12ec526adb..7b74e3a2a1 100644 --- a/servers/audio/audio_rb_resampler.h +++ b/servers/audio/audio_rb_resampler.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 2cc2f5c291..91fce5d34e 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,8 +30,8 @@ #include "audio_stream.h" +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" ////////////////////////////// diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index 9720196cc2..93566783be 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,8 +31,8 @@ #ifndef AUDIO_STREAM_H #define AUDIO_STREAM_H -#include "core/image.h" -#include "core/resource.h" +#include "core/io/image.h" +#include "core/io/resource.h" #include "servers/audio/audio_filter_sw.h" #include "servers/audio_server.h" diff --git a/servers/audio/effects/audio_effect_amplify.cpp b/servers/audio/effects/audio_effect_amplify.cpp index 74fdcbc67a..c5c1174670 100644 --- a/servers/audio/effects/audio_effect_amplify.cpp +++ b/servers/audio/effects/audio_effect_amplify.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_amplify.h b/servers/audio/effects/audio_effect_amplify.h index 7245bbdcbe..2ece57854c 100644 --- a/servers/audio/effects/audio_effect_amplify.h +++ b/servers/audio/effects/audio_effect_amplify.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_chorus.cpp b/servers/audio/effects/audio_effect_chorus.cpp index 2b530475f0..1542273a24 100644 --- a/servers/audio/effects/audio_effect_chorus.cpp +++ b/servers/audio/effects/audio_effect_chorus.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_chorus.h b/servers/audio/effects/audio_effect_chorus.h index 81af948530..f5b023734a 100644 --- a/servers/audio/effects/audio_effect_chorus.h +++ b/servers/audio/effects/audio_effect_chorus.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -60,7 +60,6 @@ class AudioEffectChorus : public AudioEffect { public: enum { - MAX_DELAY_MS = 50, MAX_DEPTH_MS = 20, MAX_WIDTH_MS = 50, diff --git a/servers/audio/effects/audio_effect_compressor.cpp b/servers/audio/effects/audio_effect_compressor.cpp index 4b0b4dabea..bb4a90f3d6 100644 --- a/servers/audio/effects/audio_effect_compressor.cpp +++ b/servers/audio/effects/audio_effect_compressor.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_compressor.h b/servers/audio/effects/audio_effect_compressor.h index be187605c5..33c60680fc 100644 --- a/servers/audio/effects/audio_effect_compressor.h +++ b/servers/audio/effects/audio_effect_compressor.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_delay.cpp b/servers/audio/effects/audio_effect_delay.cpp index d6ab14be89..f04ab45ec1 100644 --- a/servers/audio/effects/audio_effect_delay.cpp +++ b/servers/audio/effects/audio_effect_delay.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_delay.h b/servers/audio/effects/audio_effect_delay.h index a55000af4b..ff267d5023 100644 --- a/servers/audio/effects/audio_effect_delay.h +++ b/servers/audio/effects/audio_effect_delay.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -62,7 +62,6 @@ class AudioEffectDelay : public AudioEffect { friend class AudioEffectDelayInstance; enum { - MAX_DELAY_MS = 3000, MAX_TAPS = 2 }; diff --git a/servers/audio/effects/audio_effect_distortion.cpp b/servers/audio/effects/audio_effect_distortion.cpp index dc5c2cc16f..8f713ace22 100644 --- a/servers/audio/effects/audio_effect_distortion.cpp +++ b/servers/audio/effects/audio_effect_distortion.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_distortion.h b/servers/audio/effects/audio_effect_distortion.h index 8149fc3f0a..9da800b79f 100644 --- a/servers/audio/effects/audio_effect_distortion.h +++ b/servers/audio/effects/audio_effect_distortion.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_eq.cpp b/servers/audio/effects/audio_effect_eq.cpp index ed4e7122b5..01ac605bd7 100644 --- a/servers/audio/effects/audio_effect_eq.cpp +++ b/servers/audio/effects/audio_effect_eq.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_eq.h b/servers/audio/effects/audio_effect_eq.h index 5a639f64d4..38c63a7d4f 100644 --- a/servers/audio/effects/audio_effect_eq.h +++ b/servers/audio/effects/audio_effect_eq.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_filter.cpp b/servers/audio/effects/audio_effect_filter.cpp index a5135ee1a6..c2d6074825 100644 --- a/servers/audio/effects/audio_effect_filter.cpp +++ b/servers/audio/effects/audio_effect_filter.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_filter.h b/servers/audio/effects/audio_effect_filter.h index 16940173ba..9a48ccf70b 100644 --- a/servers/audio/effects/audio_effect_filter.h +++ b/servers/audio/effects/audio_effect_filter.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_limiter.cpp b/servers/audio/effects/audio_effect_limiter.cpp index 27f1aaf71f..1a4b01d947 100644 --- a/servers/audio/effects/audio_effect_limiter.cpp +++ b/servers/audio/effects/audio_effect_limiter.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_limiter.h b/servers/audio/effects/audio_effect_limiter.h index 5204c42759..8f3092c0e2 100644 --- a/servers/audio/effects/audio_effect_limiter.h +++ b/servers/audio/effects/audio_effect_limiter.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_panner.cpp b/servers/audio/effects/audio_effect_panner.cpp index 32b7921d1f..238e979e13 100644 --- a/servers/audio/effects/audio_effect_panner.cpp +++ b/servers/audio/effects/audio_effect_panner.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_panner.h b/servers/audio/effects/audio_effect_panner.h index b4aa7a58b9..0938824c64 100644 --- a/servers/audio/effects/audio_effect_panner.h +++ b/servers/audio/effects/audio_effect_panner.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_phaser.cpp b/servers/audio/effects/audio_effect_phaser.cpp index ffeaa7d25e..5e4e183ccf 100644 --- a/servers/audio/effects/audio_effect_phaser.cpp +++ b/servers/audio/effects/audio_effect_phaser.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_phaser.h b/servers/audio/effects/audio_effect_phaser.h index dbf014dbac..563927c678 100644 --- a/servers/audio/effects/audio_effect_phaser.h +++ b/servers/audio/effects/audio_effect_phaser.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_pitch_shift.cpp b/servers/audio/effects/audio_effect_pitch_shift.cpp index fb6b56d984..2123fe8548 100644 --- a/servers/audio/effects/audio_effect_pitch_shift.cpp +++ b/servers/audio/effects/audio_effect_pitch_shift.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -95,14 +95,12 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff expct = 2.*Math_PI*(double)stepSize/(double)fftFrameSize; inFifoLatency = fftFrameSize-stepSize; if (gRover == 0) { gRover = inFifoLatency; - } /* initialize our static arrays */ /* main processing loop */ for (i = 0; i < numSampsToProcess; i++){ - /* As long as we have not yet collected enough data just read in */ gInFIFO[gRover] = indata[i*stride]; outdata[i*stride] = gOutFIFO[gRover-inFifoLatency]; @@ -126,7 +124,6 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff /* this is the analysis step */ for (k = 0; k <= fftFrameSize2; k++) { - /* de-interlace FFT buffer */ real = gFFTworksp[2*k]; imag = gFFTworksp[2*k+1]; @@ -146,7 +143,6 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff qpd = tmp/Math_PI; if (qpd >= 0) { qpd += qpd&1; } else { qpd -= qpd&1; - } tmp -= Math_PI*(double)qpd; @@ -177,7 +173,6 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff /* ***************** SYNTHESIS ******************* */ /* this is the synthesis step */ for (k = 0; k <= fftFrameSize2; k++) { - /* get magnitude and true frequency from synthesis arrays */ magn = gSynMagn[k]; tmp = gSynFreq[k]; @@ -205,7 +200,6 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff /* zero negative frequencies */ for (k = fftFrameSize+2; k < 2*fftFrameSize; k++) { gFFTworksp[k] = 0.; - } /* do inverse transform */ @@ -217,7 +211,6 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff gOutputAccum[k] += 2.*window*gFFTworksp[2*k]/(fftFrameSize2*osamp); } for (k = 0; k < stepSize; k++) { gOutFIFO[k] = gOutputAccum[k]; - } /* shift accumulator */ @@ -225,13 +218,9 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff /* move input FIFO */ for (k = 0; k < inFifoLatency; k++) { gInFIFO[k] = gInFIFO[k+stepSize]; - } } } - - - } @@ -256,7 +245,6 @@ void SMBPitchShift::smbFft(float *fftBuffer, long fftFrameSize, long sign) for (i = 2; i < 2*fftFrameSize-2; i += 2) { for (bitm = 2, j = 0; bitm < 2*fftFrameSize; bitm <<= 1) { if (i & bitm) { j++; - } j <<= 1; } diff --git a/servers/audio/effects/audio_effect_pitch_shift.h b/servers/audio/effects/audio_effect_pitch_shift.h index 0fa4de6b5b..18a9c33968 100644 --- a/servers/audio/effects/audio_effect_pitch_shift.h +++ b/servers/audio/effects/audio_effect_pitch_shift.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_record.cpp b/servers/audio/effects/audio_effect_record.cpp index 79388b2dc7..e8832c92a3 100644 --- a/servers/audio/effects/audio_effect_record.cpp +++ b/servers/audio/effects/audio_effect_record.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_record.h b/servers/audio/effects/audio_effect_record.h index 55080539d3..14e646e29d 100644 --- a/servers/audio/effects/audio_effect_record.h +++ b/servers/audio/effects/audio_effect_record.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_reverb.cpp b/servers/audio/effects/audio_effect_reverb.cpp index f6465abfaf..b8d812680e 100644 --- a/servers/audio/effects/audio_effect_reverb.cpp +++ b/servers/audio/effects/audio_effect_reverb.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_reverb.h b/servers/audio/effects/audio_effect_reverb.h index 3a1922bc1d..141ba48e29 100644 --- a/servers/audio/effects/audio_effect_reverb.h +++ b/servers/audio/effects/audio_effect_reverb.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp index 3f4f11ee8d..7f73f2e880 100644 --- a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp +++ b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_spectrum_analyzer.h b/servers/audio/effects/audio_effect_spectrum_analyzer.h index 0eacd43b57..fba276e2bb 100644 --- a/servers/audio/effects/audio_effect_spectrum_analyzer.h +++ b/servers/audio/effects/audio_effect_spectrum_analyzer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_stereo_enhance.cpp b/servers/audio/effects/audio_effect_stereo_enhance.cpp index 4f9bee83e4..dfdf154aa4 100644 --- a/servers/audio/effects/audio_effect_stereo_enhance.cpp +++ b/servers/audio/effects/audio_effect_stereo_enhance.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_effect_stereo_enhance.h b/servers/audio/effects/audio_effect_stereo_enhance.h index 7fb32bd8ec..f99256470b 100644 --- a/servers/audio/effects/audio_effect_stereo_enhance.h +++ b/servers/audio/effects/audio_effect_stereo_enhance.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -41,7 +41,6 @@ class AudioEffectStereoEnhanceInstance : public AudioEffectInstance { Ref<AudioEffectStereoEnhance> base; enum { - MAX_DELAY_MS = 50 }; diff --git a/servers/audio/effects/audio_stream_generator.cpp b/servers/audio/effects/audio_stream_generator.cpp index aba04550db..d1a05ccf2a 100644 --- a/servers/audio/effects/audio_stream_generator.cpp +++ b/servers/audio/effects/audio_stream_generator.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/audio/effects/audio_stream_generator.h b/servers/audio/effects/audio_stream_generator.h index c90983a66f..5d46771f4d 100644 --- a/servers/audio/effects/audio_stream_generator.h +++ b/servers/audio/effects/audio_stream_generator.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,7 +31,7 @@ #ifndef AUDIO_STREAM_GENERATOR_H #define AUDIO_STREAM_GENERATOR_H -#include "core/ring_buffer.h" +#include "core/templates/ring_buffer.h" #include "servers/audio/audio_stream.h" class AudioStreamGenerator : public AudioStream { diff --git a/servers/audio/effects/eq.cpp b/servers/audio/effects/eq.cpp index 08a6cf55fa..2181411b9e 100644 --- a/servers/audio/effects/eq.cpp +++ b/servers/audio/effects/eq.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,7 +31,7 @@ // Author: reduzio@gmail.com (C) 2006 #include "eq.h" -#include "core/error_macros.h" +#include "core/error/error_macros.h" #include "core/math/math_funcs.h" #include <math.h> diff --git a/servers/audio/effects/eq.h b/servers/audio/effects/eq.h index 391a7aa24b..afd5bf5334 100644 --- a/servers/audio/effects/eq.h +++ b/servers/audio/effects/eq.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,8 +33,8 @@ #ifndef EQ_FILTER_H #define EQ_FILTER_H +#include "core/templates/vector.h" #include "core/typedefs.h" -#include "core/vector.h" /** @author Juan Linietsky @@ -43,7 +43,6 @@ class EQ { public: enum Preset { - PRESET_6_BANDS, PRESET_8_BANDS, PRESET_10_BANDS, diff --git a/servers/audio/effects/reverb.cpp b/servers/audio/effects/reverb.cpp index 7c35d88ced..eb96e21659 100644 --- a/servers/audio/effects/reverb.cpp +++ b/servers/audio/effects/reverb.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -127,13 +127,11 @@ void Reverb::process(float *p_src, float *p_dst, int p_frames) { int ap_size_limit[MAX_ALLPASS]; for (int i=0;i<MAX_ALLPASS;i++) { - AllPass &a=allpass[i]; ap_size_limit[i]=a.size-lrintf((float)a.extra_spread_frames*(1.0-params.extra_spread)); } for (int i=0;i<p_frames;i++) { - float sample=p_dst[i]; float aux,in; float AllPass*ap; diff --git a/servers/audio/effects/reverb.h b/servers/audio/effects/reverb.h index 614de0c534..e7ce55098d 100644 --- a/servers/audio/effects/reverb.h +++ b/servers/audio/effects/reverb.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -46,7 +46,6 @@ public: private: enum { - MAX_COMBS = 8, MAX_ALLPASS = 4, MAX_ECHO_MS = 500 diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 6b70f41e57..d4f7876b4b 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,11 +30,11 @@ #include "audio_server.h" +#include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" #include "core/io/resource_loader.h" #include "core/os/file_access.h" #include "core/os/os.h" -#include "core/project_settings.h" #include "scene/resources/audio_stream_sample.h" #include "servers/audio/audio_driver_dummy.h" #include "servers/audio/effects/audio_effect_compressor.h" @@ -71,13 +71,20 @@ void AudioDriver::update_mix_time(int p_frames) { } } -double AudioDriver::get_time_since_last_mix() const { - return (OS::get_singleton()->get_ticks_usec() - _last_mix_time) / 1000000.0; +double AudioDriver::get_time_since_last_mix() { + lock(); + uint64_t last_mix_time = _last_mix_time; + unlock(); + return (OS::get_singleton()->get_ticks_usec() - last_mix_time) / 1000000.0; } -double AudioDriver::get_time_to_next_mix() const { - double total = (OS::get_singleton()->get_ticks_usec() - _last_mix_time) / 1000000.0; - double mix_buffer = _last_mix_frames / (double)get_mix_rate(); +double AudioDriver::get_time_to_next_mix() { + lock(); + uint64_t last_mix_time = _last_mix_time; + uint64_t last_mix_frames = _last_mix_frames; + unlock(); + double total = (OS::get_singleton()->get_ticks_usec() - last_mix_time) / 1000000.0; + double mix_buffer = last_mix_frames / (double)get_mix_rate(); return mix_buffer - total; } @@ -905,6 +912,8 @@ bool AudioServer::is_bus_channel_active(int p_bus, int p_channel) const { } void AudioServer::set_global_rate_scale(float p_scale) { + ERR_FAIL_COND(p_scale <= 0); + global_rate_scale = p_scale; } diff --git a/servers/audio_server.h b/servers/audio_server.h index 31537e8326..51fbc59851 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,10 +31,10 @@ #ifndef AUDIO_SERVER_H #define AUDIO_SERVER_H -#include "core/class_db.h" #include "core/math/audio_frame.h" +#include "core/object/class_db.h" #include "core/os/os.h" -#include "core/variant.h" +#include "core/variant/variant.h" #include "servers/audio/audio_effect.h" class AudioDriverDummy; @@ -70,8 +70,8 @@ protected: #endif public: - double get_time_since_last_mix() const; //useful for video -> audio sync - double get_time_to_next_mix() const; + double get_time_since_last_mix(); //useful for video -> audio sync + double get_time_to_next_mix(); enum SpeakerMode { SPEAKER_MODE_STEREO, @@ -122,7 +122,6 @@ public: class AudioDriverManager { enum { - MAX_DRIVERS = 10 }; diff --git a/servers/camera/SCsub b/servers/camera/SCsub index c949f3bb25..86681f9c74 100644 --- a/servers/camera/SCsub +++ b/servers/camera/SCsub @@ -3,5 +3,3 @@ Import("env") env.add_source_files(env.servers_sources, "*.cpp") - -Export("env") diff --git a/servers/camera/camera_feed.cpp b/servers/camera/camera_feed.cpp index 41f44abae8..be812cf62d 100644 --- a/servers/camera/camera_feed.cpp +++ b/servers/camera/camera_feed.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/camera/camera_feed.h b/servers/camera/camera_feed.h index 52a737cd8d..fc02af4249 100644 --- a/servers/camera/camera_feed.h +++ b/servers/camera/camera_feed.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,7 +31,7 @@ #ifndef CAMERA_FEED_H #define CAMERA_FEED_H -#include "core/image.h" +#include "core/io/image.h" #include "core/math/transform_2d.h" #include "servers/camera_server.h" #include "servers/rendering_server.h" diff --git a/servers/camera_server.cpp b/servers/camera_server.cpp index 3caea6b7c3..b06f32417c 100644 --- a/servers/camera_server.cpp +++ b/servers/camera_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/camera_server.h b/servers/camera_server.h index 7723e30974..97aa8f74ba 100644 --- a/servers/camera_server.h +++ b/servers/camera_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,11 +31,11 @@ #ifndef CAMERA_SERVER_H #define CAMERA_SERVER_H -#include "core/class_db.h" +#include "core/object/class_db.h" +#include "core/object/reference.h" #include "core/os/thread_safe.h" -#include "core/reference.h" -#include "core/rid.h" -#include "core/variant.h" +#include "core/templates/rid.h" +#include "core/variant/variant.h" /** @author Bastiaan Olij <mux213@gmail.com> @@ -95,15 +95,16 @@ public: int get_feed_index(int p_id); Ref<CameraFeed> get_feed_by_id(int p_id); - // add and remove feeds + // Add and remove feeds. void add_feed(const Ref<CameraFeed> &p_feed); void remove_feed(const Ref<CameraFeed> &p_feed); - // get our feeds + // Get our feeds. Ref<CameraFeed> get_feed(int p_index); int get_feed_count(); Array get_feeds(); + // Intended for use with custom CameraServer implementation. RID feed_texture(int p_id, FeedImage p_texture); CameraServer(); diff --git a/servers/display_server.cpp b/servers/display_server.cpp index e678c6919b..29c1c9fc60 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/display_server.h b/servers/display_server.h index 3ee0da709b..fc34a2a228 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,10 +31,10 @@ #ifndef DISPLAY_SERVER_H #define DISPLAY_SERVER_H -#include "core/callable.h" #include "core/input/input.h" +#include "core/io/resource.h" #include "core/os/os.h" -#include "core/resource.h" +#include "core/variant/callable.h" class Texture2D; @@ -83,7 +83,7 @@ protected: static DisplayServerCreate server_create_functions[MAX_SERVERS]; static int server_create_count; - friend class RenderingServerRaster; + friend class RenderingServerDefault; virtual void _set_use_vsync(bool p_enable); public: @@ -177,7 +177,6 @@ public: } virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const; enum ScreenOrientation { - SCREEN_LANDSCAPE, SCREEN_PORTRAIT, SCREEN_REVERSE_LANDSCAPE, diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp index b20f6865cd..df348d2add 100644 --- a/servers/navigation_server_2d.cpp +++ b/servers/navigation_server_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h index 6575426e73..7be5a74cb3 100644 --- a/servers/navigation_server_2d.h +++ b/servers/navigation_server_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -35,8 +35,8 @@ #ifndef NAVIGATION_2D_SERVER_H #define NAVIGATION_2D_SERVER_H -#include "core/class_db.h" -#include "core/rid.h" +#include "core/object/class_db.h" +#include "core/templates/rid.h" #include "scene/2d/navigation_region_2d.h" // This server exposes the `NavigationServer3D` features in the 2D world. diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index 8f9b5df589..0e5ae82b0d 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h index 7a3e4f5f8f..3761c3871a 100644 --- a/servers/navigation_server_3d.h +++ b/servers/navigation_server_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -35,8 +35,8 @@ #ifndef NAVIGATION_SERVER_H #define NAVIGATION_SERVER_H -#include "core/class_db.h" -#include "core/rid.h" +#include "core/object/class_db.h" +#include "core/templates/rid.h" #include "scene/3d/navigation_region_3d.h" /// This server uses the concept of internal mutability. diff --git a/servers/physics_2d/area_2d_sw.cpp b/servers/physics_2d/area_2d_sw.cpp index 7485f31afc..6485c8d1e9 100644 --- a/servers/physics_2d/area_2d_sw.cpp +++ b/servers/physics_2d/area_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -199,7 +199,7 @@ void Area2DSW::set_monitorable(bool p_monitorable) { } void Area2DSW::call_queries() { - if (monitor_callback_id.is_valid() && !monitored_bodies.empty()) { + if (monitor_callback_id.is_valid() && !monitored_bodies.is_empty()) { Variant res[5]; Variant *resptr[5]; for (int i = 0; i < 5; i++) { @@ -234,7 +234,7 @@ void Area2DSW::call_queries() { } } - if (area_monitor_callback_id.is_valid() && !monitored_areas.empty()) { + if (area_monitor_callback_id.is_valid() && !monitored_areas.is_empty()) { Variant res[5]; Variant *resptr[5]; for (int i = 0; i < 5; i++) { diff --git a/servers/physics_2d/area_2d_sw.h b/servers/physics_2d/area_2d_sw.h index f14466f582..3bf603b30d 100644 --- a/servers/physics_2d/area_2d_sw.h +++ b/servers/physics_2d/area_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,7 +32,7 @@ #define AREA_2D_SW_H #include "collision_object_2d_sw.h" -#include "core/self_list.h" +#include "core/templates/self_list.h" #include "servers/physics_server_2d.h" //#include "servers/physics_3d/query_sw.h" diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/area_pair_2d_sw.cpp index d7bceb9f02..21ad57e344 100644 --- a/servers/physics_2d/area_pair_2d_sw.cpp +++ b/servers/physics_2d/area_pair_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -89,7 +89,7 @@ AreaPair2DSW::~AreaPair2DSW() { area->remove_body_from_query(body, body_shape, area_shape); } } - body->remove_constraint(this); + body->remove_constraint(this, 0); area->remove_constraint(this); } diff --git a/servers/physics_2d/area_pair_2d_sw.h b/servers/physics_2d/area_pair_2d_sw.h index 5e8670b464..4015aad5d1 100644 --- a/servers/physics_2d/area_pair_2d_sw.h +++ b/servers/physics_2d/area_pair_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp index 75c9a95739..d0636047b7 100644 --- a/servers/physics_2d/body_2d_sw.cpp +++ b/servers/physics_2d/body_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -562,13 +562,13 @@ void Body2DSW::integrate_velocities(real_t p_step) { } void Body2DSW::wakeup_neighbours() { - for (Map<Constraint2DSW *, int>::Element *E = constraint_map.front(); E; E = E->next()) { - const Constraint2DSW *c = E->key(); + for (List<Pair<Constraint2DSW *, int>>::Element *E = constraint_list.front(); E; E = E->next()) { + const Constraint2DSW *c = E->get().first; Body2DSW **n = c->get_body_ptr(); int bc = c->get_body_count(); for (int i = 0; i < bc; i++) { - if (i == E->get()) { + if (i == E->get().second) { continue; } Body2DSW *b = n[i]; diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h index 4a3ef718ec..60d55ab8bd 100644 --- a/servers/physics_2d/body_2d_sw.h +++ b/servers/physics_2d/body_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,7 +33,9 @@ #include "area_2d_sw.h" #include "collision_object_2d_sw.h" -#include "core/vset.h" +#include "core/templates/list.h" +#include "core/templates/pair.h" +#include "core/templates/vset.h" class Constraint2DSW; @@ -83,7 +85,7 @@ class Body2DSW : public CollisionObject2DSW { virtual void _shapes_changed(); Transform2D new_transform; - Map<Constraint2DSW *, int> constraint_map; + List<Pair<Constraint2DSW *, int>> constraint_list; struct AreaCMP { Area2DSW *area; @@ -162,7 +164,7 @@ public: _FORCE_INLINE_ int get_max_contacts_reported() const { return contacts.size(); } - _FORCE_INLINE_ bool can_report_contacts() const { return !contacts.empty(); } + _FORCE_INLINE_ bool can_report_contacts() const { return !contacts.is_empty(); } _FORCE_INLINE_ void add_contact(const Vector2 &p_local_pos, const Vector2 &p_local_normal, real_t p_depth, int p_local_shape, const Vector2 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector2 &p_collider_velocity_at_pos); _FORCE_INLINE_ void add_exception(const RID &p_exception) { exceptions.insert(p_exception); } @@ -179,10 +181,10 @@ public: _FORCE_INLINE_ Body2DSW *get_island_list_next() const { return island_list_next; } _FORCE_INLINE_ void set_island_list_next(Body2DSW *p_next) { island_list_next = p_next; } - _FORCE_INLINE_ void add_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_map[p_constraint] = p_pos; } - _FORCE_INLINE_ void remove_constraint(Constraint2DSW *p_constraint) { constraint_map.erase(p_constraint); } - const Map<Constraint2DSW *, int> &get_constraint_map() const { return constraint_map; } - _FORCE_INLINE_ void clear_constraint_map() { constraint_map.clear(); } + _FORCE_INLINE_ void add_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_list.push_back({ p_constraint, p_pos }); } + _FORCE_INLINE_ void remove_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_list.erase({ p_constraint, p_pos }); } + const List<Pair<Constraint2DSW *, int>> &get_constraint_list() const { return constraint_list; } + _FORCE_INLINE_ void clear_constraint_list() { constraint_list.clear(); } _FORCE_INLINE_ void set_omit_force_integration(bool p_omit_force_integration) { omit_force_integration = p_omit_force_integration; } _FORCE_INLINE_ bool get_omit_force_integration() const { return omit_force_integration; } diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp index 2021aab17c..feced36a2b 100644 --- a/servers/physics_2d/body_pair_2d_sw.cpp +++ b/servers/physics_2d/body_pair_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -288,21 +288,17 @@ bool BodyPair2DSW::setup(real_t p_step) { if (A->is_shape_set_as_one_way_collision(shape_A)) { Vector2 direction = xform_A.get_axis(1).normalized(); bool valid = false; - if (B->get_linear_velocity().dot(direction) >= 0) { - for (int i = 0; i < contact_count; i++) { - Contact &c = contacts[i]; - if (!c.reused) { - continue; - } - if (c.normal.dot(direction) > 0) { //greater (normal inverted) - continue; - } - - valid = true; - break; + for (int i = 0; i < contact_count; i++) { + Contact &c = contacts[i]; + if (!c.reused) { + continue; } + if (c.normal.dot(direction) > -CMP_EPSILON) { //greater (normal inverted) + continue; + } + valid = true; + break; } - if (!valid) { collided = false; oneway_disabled = true; @@ -313,19 +309,16 @@ bool BodyPair2DSW::setup(real_t p_step) { if (B->is_shape_set_as_one_way_collision(shape_B)) { Vector2 direction = xform_B.get_axis(1).normalized(); bool valid = false; - if (A->get_linear_velocity().dot(direction) >= 0) { - for (int i = 0; i < contact_count; i++) { - Contact &c = contacts[i]; - if (!c.reused) { - continue; - } - if (c.normal.dot(direction) < 0) { //less (normal ok) - continue; - } - - valid = true; - break; + for (int i = 0; i < contact_count; i++) { + Contact &c = contacts[i]; + if (!c.reused) { + continue; + } + if (c.normal.dot(direction) < CMP_EPSILON) { //less (normal ok) + continue; } + valid = true; + break; } if (!valid) { collided = false; @@ -409,7 +402,7 @@ bool BodyPair2DSW::setup(real_t p_step) { kNormal += A->get_inv_inertia() * (c.rA.dot(c.rA) - rnA * rnA) + B->get_inv_inertia() * (c.rB.dot(c.rB) - rnB * rnB); c.mass_normal = 1.0f / kNormal; - Vector2 tangent = c.normal.tangent(); + Vector2 tangent = c.normal.orthogonal(); real_t rtA = c.rA.dot(tangent); real_t rtB = c.rB.dot(tangent); real_t kTangent = A->get_inv_mass() + B->get_inv_mass(); @@ -469,7 +462,7 @@ void BodyPair2DSW::solve(real_t p_step) { real_t vn = dv.dot(c.normal); real_t vbn = dbv.dot(c.normal); - Vector2 tangent = c.normal.tangent(); + Vector2 tangent = c.normal.orthogonal(); real_t vt = dv.dot(tangent); real_t jbn = (c.bias - vbn) * c.mass_normal; @@ -514,6 +507,6 @@ BodyPair2DSW::BodyPair2DSW(Body2DSW *p_A, int p_shape_A, Body2DSW *p_B, int p_sh } BodyPair2DSW::~BodyPair2DSW() { - A->remove_constraint(this); - B->remove_constraint(this); + A->remove_constraint(this, 0); + B->remove_constraint(this, 1); } diff --git a/servers/physics_2d/body_pair_2d_sw.h b/servers/physics_2d/body_pair_2d_sw.h index ea4d55841a..31ab9b9017 100644 --- a/servers/physics_2d/body_pair_2d_sw.h +++ b/servers/physics_2d/body_pair_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/broad_phase_2d_basic.cpp b/servers/physics_2d/broad_phase_2d_basic.cpp index 3bdfc1a973..17424629a9 100644 --- a/servers/physics_2d/broad_phase_2d_basic.cpp +++ b/servers/physics_2d/broad_phase_2d_basic.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/broad_phase_2d_basic.h b/servers/physics_2d/broad_phase_2d_basic.h index ec5cfdbf1d..ca1db360fb 100644 --- a/servers/physics_2d/broad_phase_2d_basic.h +++ b/servers/physics_2d/broad_phase_2d_basic.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,7 +31,7 @@ #ifndef BROAD_PHASE_2D_BASIC_H #define BROAD_PHASE_2D_BASIC_H -#include "core/map.h" +#include "core/templates/map.h" #include "space_2d_sw.h" class BroadPhase2DBasic : public BroadPhase2DSW { struct Element { diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp index ec74507e03..6cfe6908d1 100644 --- a/servers/physics_2d/broad_phase_2d_hash_grid.cpp +++ b/servers/physics_2d/broad_phase_2d_hash_grid.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,7 +30,7 @@ #include "broad_phase_2d_hash_grid.h" #include "collision_object_2d_sw.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h" #define LARGE_ELEMENT_FI 1.01239812 @@ -261,7 +261,7 @@ void BroadPhase2DHashGrid::_exit_grid(Element *p_elem, const Rect2 &p_rect, bool } } - if (pb->object_set.empty() && pb->static_object_set.empty()) { + if (pb->object_set.is_empty() && pb->static_object_set.is_empty()) { if (hash_table[idx] == pb) { hash_table[idx] = pb->next; } else { diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.h b/servers/physics_2d/broad_phase_2d_hash_grid.h index de1ada0932..eb7c8879ac 100644 --- a/servers/physics_2d/broad_phase_2d_hash_grid.h +++ b/servers/physics_2d/broad_phase_2d_hash_grid.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,7 +32,7 @@ #define BROAD_PHASE_2D_HASH_GRID_H #include "broad_phase_2d_sw.h" -#include "core/map.h" +#include "core/templates/map.h" class BroadPhase2DHashGrid : public BroadPhase2DSW { struct PairData { diff --git a/servers/physics_2d/broad_phase_2d_sw.cpp b/servers/physics_2d/broad_phase_2d_sw.cpp index 5ba557e70a..7f0af48b1f 100644 --- a/servers/physics_2d/broad_phase_2d_sw.cpp +++ b/servers/physics_2d/broad_phase_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/broad_phase_2d_sw.h b/servers/physics_2d/broad_phase_2d_sw.h index e4444cd180..d17ee6e2d6 100644 --- a/servers/physics_2d/broad_phase_2d_sw.h +++ b/servers/physics_2d/broad_phase_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp index 6931d96fe4..7a2f312263 100644 --- a/servers/physics_2d/collision_object_2d_sw.cpp +++ b/servers/physics_2d/collision_object_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h index 8caa53680d..2939b4b99f 100644 --- a/servers/physics_2d/collision_object_2d_sw.h +++ b/servers/physics_2d/collision_object_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,7 +32,7 @@ #define COLLISION_OBJECT_2D_SW_H #include "broad_phase_2d_sw.h" -#include "core/self_list.h" +#include "core/templates/self_list.h" #include "servers/physics_server_2d.h" #include "shape_2d_sw.h" diff --git a/servers/physics_2d/collision_solver_2d_sat.cpp b/servers/physics_2d/collision_solver_2d_sat.cpp index d993754fee..29242a554b 100644 --- a/servers/physics_2d/collision_solver_2d_sat.cpp +++ b/servers/physics_2d/collision_solver_2d_sat.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -88,7 +88,7 @@ _FORCE_INLINE_ static void _generate_contacts_edge_edge(const Vector2 *p_points_ #endif Vector2 n = p_collector->normal; - Vector2 t = n.tangent(); + Vector2 t = n.orthogonal(); real_t dA = n.dot(p_points_A[0]); real_t dB = n.dot(p_points_B[0]); @@ -209,7 +209,7 @@ public: if (!test_axis(na)) { return false; } - if (!test_axis(na.tangent())) { + if (!test_axis(na.orthogonal())) { return false; } } @@ -219,7 +219,7 @@ public: if (!test_axis(nb)) { return false; } - if (!test_axis(nb.tangent())) { + if (!test_axis(nb.orthogonal())) { return false; } } @@ -450,7 +450,7 @@ static void _collision_segment_circle(const Shape2DSW *p_a, const Transform2D &p //segment normal if (!separator.test_axis( - (p_transform_a.xform(segment_A->get_b()) - p_transform_a.xform(segment_A->get_a())).normalized().tangent())) { + (p_transform_a.xform(segment_A->get_b()) - p_transform_a.xform(segment_A->get_a())).normalized().orthogonal())) { return; } diff --git a/servers/physics_2d/collision_solver_2d_sat.h b/servers/physics_2d/collision_solver_2d_sat.h index 6bb485f561..49cc5176f9 100644 --- a/servers/physics_2d/collision_solver_2d_sat.h +++ b/servers/physics_2d/collision_solver_2d_sat.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/collision_solver_2d_sw.cpp b/servers/physics_2d/collision_solver_2d_sw.cpp index 0e056691c7..5bd4d498c6 100644 --- a/servers/physics_2d/collision_solver_2d_sw.cpp +++ b/servers/physics_2d/collision_solver_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/collision_solver_2d_sw.h b/servers/physics_2d/collision_solver_2d_sw.h index f39cfee0a9..4f12ca9e88 100644 --- a/servers/physics_2d/collision_solver_2d_sw.h +++ b/servers/physics_2d/collision_solver_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/constraint_2d_sw.h b/servers/physics_2d/constraint_2d_sw.h index d8751f588e..49ae4dd848 100644 --- a/servers/physics_2d/constraint_2d_sw.h +++ b/servers/physics_2d/constraint_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp index e7d26645e9..3558848dac 100644 --- a/servers/physics_2d/joints_2d_sw.cpp +++ b/servers/physics_2d/joints_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -75,9 +75,9 @@ static inline real_t k_scalar(Body2DSW *a, Body2DSW *b, const Vector2 &rA, const static inline Vector2 relative_velocity(Body2DSW *a, Body2DSW *b, Vector2 rA, Vector2 rB) { - Vector2 sum = a->get_linear_velocity() - rA.tangent() * a->get_angular_velocity(); + Vector2 sum = a->get_linear_velocity() - rA.orthogonal() * a->get_angular_velocity(); if (b) { - return (b->get_linear_velocity() - rB.tangent() * b->get_angular_velocity()) - sum; + return (b->get_linear_velocity() - rB.orthogonal() * b->get_angular_velocity()) - sum; } else { return -sum; } @@ -199,10 +199,10 @@ PinJoint2DSW::PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p PinJoint2DSW::~PinJoint2DSW() { if (A) { - A->remove_constraint(this); + A->remove_constraint(this, 0); } if (B) { - B->remove_constraint(this); + B->remove_constraint(this, 1); } } @@ -264,7 +264,7 @@ bool GrooveJoint2DSW::setup(real_t p_step) { Space2DSW *space = A->get_space(); // calculate axis - Vector2 n = -(tb - ta).tangent().normalized(); + Vector2 n = -(tb - ta).orthogonal().normalized(); real_t d = ta.dot(n); xf_normal = n; @@ -282,7 +282,7 @@ bool GrooveJoint2DSW::setup(real_t p_step) { } else { clamp = 0.0f; //joint->r1 = cpvsub(cpvadd(cpvmult(cpvperp(n), -td), cpvmult(n, d)), a->p); - rA = ((-n.tangent() * -td) + n * d) - A->get_transform().get_origin(); + rA = ((-n.orthogonal() * -td) + n * d) - A->get_transform().get_origin(); } // Calculate mass tensor @@ -332,15 +332,15 @@ GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_ A_groove_1 = A->get_inv_transform().xform(p_a_groove1); A_groove_2 = A->get_inv_transform().xform(p_a_groove2); B_anchor = B->get_inv_transform().xform(p_b_anchor); - A_groove_normal = -(A_groove_2 - A_groove_1).normalized().tangent(); + A_groove_normal = -(A_groove_2 - A_groove_1).normalized().orthogonal(); A->add_constraint(this, 0); B->add_constraint(this, 1); } GrooveJoint2DSW::~GrooveJoint2DSW() { - A->remove_constraint(this); - B->remove_constraint(this); + A->remove_constraint(this, 0); + B->remove_constraint(this, 1); } ////////////////////////////////////////////// @@ -436,6 +436,6 @@ DampedSpringJoint2DSW::DampedSpringJoint2DSW(const Vector2 &p_anchor_a, const Ve } DampedSpringJoint2DSW::~DampedSpringJoint2DSW() { - A->remove_constraint(this); - B->remove_constraint(this); + A->remove_constraint(this, 0); + B->remove_constraint(this, 1); } diff --git a/servers/physics_2d/joints_2d_sw.h b/servers/physics_2d/joints_2d_sw.h index 3c8aab77c8..53e436b539 100644 --- a/servers/physics_2d/joints_2d_sw.h +++ b/servers/physics_2d/joints_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp index 1b396190e9..c4e2489bef 100644 --- a/servers/physics_2d/physics_server_2d_sw.cpp +++ b/servers/physics_2d/physics_server_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,9 +33,9 @@ #include "broad_phase_2d_basic.h" #include "broad_phase_2d_hash_grid.h" #include "collision_solver_2d_sw.h" +#include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" #include "core/os/os.h" -#include "core/project_settings.h" #define FLUSH_QUERY_CHECK(m_object) \ ERR_FAIL_COND_MSG(m_object->get_space() && flushing_queries, "Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead."); @@ -149,24 +149,19 @@ void PhysicsServer2DSW::_shape_col_cbk(const Vector2 &p_point_A, const Vector2 & return; } + Vector2 rel_dir = (p_point_A - p_point_B); + real_t rel_length2 = rel_dir.length_squared(); if (cbk->valid_dir != Vector2()) { - if (p_point_A.distance_squared_to(p_point_B) > cbk->valid_depth * cbk->valid_depth) { - cbk->invalid_by_dir++; - return; - } - Vector2 rel_dir = (p_point_A - p_point_B).normalized(); - - if (cbk->valid_dir.dot(rel_dir) < Math_SQRT12) { //sqrt(2)/2.0 - 45 degrees - cbk->invalid_by_dir++; - - /* - print_line("A: "+p_point_A); - print_line("B: "+p_point_B); - print_line("discard too angled "+rtos(cbk->valid_dir.dot((p_point_A-p_point_B)))); - print_line("resnorm: "+(p_point_A-p_point_B).normalized()); - print_line("distance: "+rtos(p_point_A.distance_to(p_point_B))); - */ - return; + if (cbk->valid_depth < 10e20) { + if (rel_length2 > cbk->valid_depth * cbk->valid_depth || + (rel_length2 > CMP_EPSILON && cbk->valid_dir.dot(rel_dir.normalized()) < CMP_EPSILON)) { + cbk->invalid_by_dir++; + return; + } + } else { + if (rel_length2 > 0 && cbk->valid_dir.dot(rel_dir.normalized()) < CMP_EPSILON) { + return; + } } } @@ -182,8 +177,7 @@ void PhysicsServer2DSW::_shape_col_cbk(const Vector2 &p_point_A, const Vector2 & } } - real_t d = p_point_A.distance_squared_to(p_point_B); - if (d < min_depth) { + if (rel_length2 < min_depth) { return; } cbk->ptr[min_depth_idx * 2 + 0] = p_point_A; @@ -554,7 +548,7 @@ void PhysicsServer2DSW::body_set_space(RID p_body, RID p_space) { return; //pointless } - body->clear_constraint_map(); + body->clear_constraint_list(); body->set_space(space); }; @@ -1230,8 +1224,6 @@ void PhysicsServer2DSW::step(real_t p_step) { _update_shapes(); - doing_sync = false; - last_step = p_step; PhysicsDirectBodyState2DSW::singleton->step = p_step; island_count = 0; diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/physics_server_2d_sw.h index e88db28056..3305c0bd3d 100644 --- a/servers/physics_2d/physics_server_2d_sw.h +++ b/servers/physics_2d/physics_server_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,7 +31,7 @@ #ifndef PHYSICS_2D_SERVER_SW #define PHYSICS_2D_SERVER_SW -#include "core/rid_owner.h" +#include "core/templates/rid_owner.h" #include "joints_2d_sw.h" #include "servers/physics_server_2d.h" #include "shape_2d_sw.h" diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.cpp b/servers/physics_2d/physics_server_2d_wrap_mt.cpp index 49c38c6ce0..15d875b3b7 100644 --- a/servers/physics_2d/physics_server_2d_wrap_mt.cpp +++ b/servers/physics_2d/physics_server_2d_wrap_mt.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h index 586dbe9e12..9207081a51 100644 --- a/servers/physics_2d/physics_server_2d_wrap_mt.h +++ b/servers/physics_2d/physics_server_2d_wrap_mt.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,9 +31,9 @@ #ifndef PHYSICS2DSERVERWRAPMT_H #define PHYSICS2DSERVERWRAPMT_H -#include "core/command_queue_mt.h" +#include "core/config/project_settings.h" #include "core/os/thread.h" -#include "core/project_settings.h" +#include "core/templates/command_queue_mt.h" #include "servers/physics_server_2d.h" #ifdef DEBUG_SYNC diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp index 87e22ef1c9..24c73314d8 100644 --- a/servers/physics_2d/shape_2d_sw.cpp +++ b/servers/physics_2d/shape_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,7 +31,7 @@ #include "shape_2d_sw.h" #include "core/math/geometry_2d.h" -#include "core/sort_array.h" +#include "core/templates/sort_array.h" void Shape2DSW::configure(const Rect2 &p_aabb) { aabb = p_aabb; @@ -228,7 +228,7 @@ void SegmentShape2DSW::set_data(const Variant &p_data) { Rect2 r = p_data; a = r.position; b = r.size; - n = (b - a).tangent(); + n = (b - a).orthogonal(); Rect2 aabb; aabb.position = a; @@ -612,7 +612,7 @@ void ConvexPolygonShape2DSW::set_data(const Variant &p_data) { for (int i = 0; i < point_count; i++) { Vector2 p = points[i].pos; Vector2 pn = points[(i + 1) % point_count].pos; - points[i].normal = (pn - p).tangent().normalized(); + points[i].normal = (pn - p).orthogonal().normalized(); } } else { Vector<real_t> dvr = p_data; @@ -740,7 +740,7 @@ bool ConcavePolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Ve if (nd < d) { d = nd; r_point = res; - r_normal = (b - a).tangent().normalized(); + r_normal = (b - a).orthogonal().normalized(); inters = true; } } @@ -960,7 +960,7 @@ void ConcavePolygonShape2DSW::cull(const Rect2 &p_local_aabb, Callback p_callbac Vector2 a = pointptr[s.points[0]]; Vector2 b = pointptr[s.points[1]]; - SegmentShape2DSW ss(a, b, (b - a).tangent().normalized()); + SegmentShape2DSW ss(a, b, (b - a).orthogonal().normalized()); p_callback(p_userdata, &ss); stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; diff --git a/servers/physics_2d/shape_2d_sw.h b/servers/physics_2d/shape_2d_sw.h index eca284f7a4..ee2730ebb5 100644 --- a/servers/physics_2d/shape_2d_sw.h +++ b/servers/physics_2d/shape_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -237,7 +237,7 @@ public: virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_SEGMENT; } _FORCE_INLINE_ Vector2 get_xformed_normal(const Transform2D &p_xform) const { - return (p_xform.xform(b) - p_xform.xform(a)).normalized().tangent(); + return (p_xform.xform(b) - p_xform.xform(a)).normalized().orthogonal(); } virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); } virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const; @@ -431,7 +431,7 @@ public: Vector2 a = points[p_idx].pos; p_idx++; Vector2 b = points[p_idx == point_count ? 0 : p_idx].pos; - return (p_xform.xform(b) - p_xform.xform(a)).normalized().tangent(); + return (p_xform.xform(b) - p_xform.xform(a)).normalized().orthogonal(); } virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_CONVEX_POLYGON; } diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index 966dcbd651..068bc7fc0a 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,7 +32,7 @@ #include "collision_solver_2d_sw.h" #include "core/os/os.h" -#include "core/pair.h" +#include "core/templates/pair.h" #include "physics_server_2d_sw.h" _FORCE_INLINE_ static bool _can_collide_with(CollisionObject2DSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { if (!(p_object->get_collision_layer() & p_collision_mask)) { @@ -278,9 +278,9 @@ bool PhysicsDirectSpaceState2DSW::cast_motion(const RID &p_shape, const Transfor continue; } - //test initial overlap + //test initial overlap, ignore objects it's inside of. if (CollisionSolver2DSW::solve(shape, p_xform, Vector2(), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, nullptr, p_margin)) { - return false; + continue; } //just do kinematic solving @@ -376,25 +376,25 @@ struct _RestCallbackData2D { Vector2 best_normal; real_t best_len; Vector2 valid_dir; - real_t valid_depth; real_t min_allowed_depth; }; static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata) { _RestCallbackData2D *rd = (_RestCallbackData2D *)p_userdata; - if (rd->valid_dir != Vector2()) { - if (p_point_A.distance_squared_to(p_point_B) > rd->valid_depth * rd->valid_depth) { - return; - } - if (rd->valid_dir.dot((p_point_A - p_point_B).normalized()) < Math_PI * 0.25) { - return; - } - } - Vector2 contact_rel = p_point_B - p_point_A; real_t len = contact_rel.length(); + if (len == 0) { + return; + } + + Vector2 normal = contact_rel / len; + + if (rd->valid_dir != Vector2() && rd->valid_dir.dot(normal) > -CMP_EPSILON) { + return; + } + if (len < rd->min_allowed_depth) { return; } @@ -405,7 +405,7 @@ static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B, rd->best_len = len; rd->best_contact = p_point_B; - rd->best_normal = contact_rel / len; + rd->best_normal = normal; rd->best_object = rd->object; rd->best_shape = rd->shape; rd->best_local_shape = rd->local_shape; @@ -440,7 +440,6 @@ bool PhysicsDirectSpaceState2DSW::rest_info(RID p_shape, const Transform2D &p_sh } rcd.valid_dir = Vector2(); - rcd.valid_depth = 0; rcd.object = col_obj; rcd.shape = shape_idx; rcd.local_shape = 0; @@ -603,7 +602,6 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t * direction. Use a short ray shape if you want to achieve a similar effect. * if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { - cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized(); cbk.valid_depth = p_margin; //only valid depth is the collision margin cbk.invalid_by_dir = 0; @@ -644,7 +642,7 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t Vector2 a = sr[k * 2 + 0]; Vector2 b = sr[k * 2 + 1]; - recover_motion += (b - a) * 0.4; + recover_motion += (b - a) / cbk.amount; float depth = a.distance_to(b); if (depth > result.collision_depth) { @@ -851,7 +849,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co for (int i = 0; i < cbk.amount; i++) { Vector2 a = sr[i * 2 + 0]; Vector2 b = sr[i * 2 + 1]; - recover_motion += (b - a) * 0.4; + recover_motion += (b - a) / cbk.amount; } if (recover_motion == Vector2()) { @@ -1003,7 +1001,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co best_shape = -1; //no best shape with cast, reset to -1 } - { + if (safe < 1) { //it collided, let's get the rest info in unsafe advance Transform2D ugt = body_transform; ugt.elements[2] += p_motion * unsafe; @@ -1062,10 +1060,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { rcd.valid_dir = col_obj_shape_xform.get_axis(1).normalized(); - rcd.valid_depth = 10e20; } else { rcd.valid_dir = Vector2(); - rcd.valid_depth = 0; } rcd.object = col_obj; diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h index 1eee83dfe9..4d737d622f 100644 --- a/servers/physics_2d/space_2d_sw.h +++ b/servers/physics_2d/space_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -37,8 +37,8 @@ #include "body_pair_2d_sw.h" #include "broad_phase_2d_sw.h" #include "collision_object_2d_sw.h" -#include "core/hash_map.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h" +#include "core/templates/hash_map.h" #include "core/typedefs.h" class PhysicsDirectSpaceState2DSW : public PhysicsDirectSpaceState2D { @@ -105,7 +105,6 @@ private: real_t test_motion_min_contact_depth; enum { - INTERSECTION_QUERY_MAX = 2048 }; @@ -188,7 +187,7 @@ public: int test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, PhysicsServer2D::SeparationResult *r_results, int p_result_max, real_t p_margin); void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); } - _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.empty(); } + _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.is_empty(); } _FORCE_INLINE_ void add_debug_contact(const Vector2 &p_contact) { if (contact_debug_count < contact_debug.size()) { contact_debug.write[contact_debug_count++] = p_contact; diff --git a/servers/physics_2d/step_2d_sw.cpp b/servers/physics_2d/step_2d_sw.cpp index c7711bcd1d..6613d19729 100644 --- a/servers/physics_2d/step_2d_sw.cpp +++ b/servers/physics_2d/step_2d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -36,8 +36,8 @@ void Step2DSW::_populate_island(Body2DSW *p_body, Body2DSW **p_island, Constrain p_body->set_island_next(*p_island); *p_island = p_body; - for (Map<Constraint2DSW *, int>::Element *E = p_body->get_constraint_map().front(); E; E = E->next()) { - Constraint2DSW *c = (Constraint2DSW *)E->key(); + for (const List<Pair<Constraint2DSW *, int>>::Element *E = p_body->get_constraint_list().front(); E; E = E->next()) { + Constraint2DSW *c = (Constraint2DSW *)E->get().first; if (c->get_island_step() == _step) { continue; //already processed } @@ -46,7 +46,7 @@ void Step2DSW::_populate_island(Body2DSW *p_body, Body2DSW **p_island, Constrain *p_constraint_island = c; for (int i = 0; i < c->get_body_count(); i++) { - if (i == E->get()) { + if (i == E->get().second) { continue; } Body2DSW *b = c->get_body_ptr()[i]; diff --git a/servers/physics_2d/step_2d_sw.h b/servers/physics_2d/step_2d_sw.h index c1b2d01fb4..83b9130608 100644 --- a/servers/physics_2d/step_2d_sw.h +++ b/servers/physics_2d/step_2d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/area_3d_sw.cpp b/servers/physics_3d/area_3d_sw.cpp index 571f1435de..b6c5b3003c 100644 --- a/servers/physics_3d/area_3d_sw.cpp +++ b/servers/physics_3d/area_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -199,7 +199,7 @@ void Area3DSW::set_monitorable(bool p_monitorable) { } void Area3DSW::call_queries() { - if (monitor_callback_id.is_valid() && !monitored_bodies.empty()) { + if (monitor_callback_id.is_valid() && !monitored_bodies.is_empty()) { Variant res[5]; Variant *resptr[5]; for (int i = 0; i < 5; i++) { @@ -234,7 +234,7 @@ void Area3DSW::call_queries() { } } - if (area_monitor_callback_id.is_valid() && !monitored_areas.empty()) { + if (area_monitor_callback_id.is_valid() && !monitored_areas.is_empty()) { Variant res[5]; Variant *resptr[5]; for (int i = 0; i < 5; i++) { diff --git a/servers/physics_3d/area_3d_sw.h b/servers/physics_3d/area_3d_sw.h index 6af3976167..8a0a1e963b 100644 --- a/servers/physics_3d/area_3d_sw.h +++ b/servers/physics_3d/area_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,7 +32,7 @@ #define AREA_SW_H #include "collision_object_3d_sw.h" -#include "core/self_list.h" +#include "core/templates/self_list.h" #include "servers/physics_server_3d.h" //#include "servers/physics_3d/query_sw.h" diff --git a/servers/physics_3d/area_pair_3d_sw.cpp b/servers/physics_3d/area_pair_3d_sw.cpp index a5fb20fe2b..4de5f1ba47 100644 --- a/servers/physics_3d/area_pair_3d_sw.cpp +++ b/servers/physics_3d/area_pair_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/area_pair_3d_sw.h b/servers/physics_3d/area_pair_3d_sw.h index 992d4747b9..fbdaa25cbb 100644 --- a/servers/physics_3d/area_pair_3d_sw.h +++ b/servers/physics_3d/area_pair_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp index d1f16cb4ae..82356e77ef 100644 --- a/servers/physics_3d/body_3d_sw.cpp +++ b/servers/physics_3d/body_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -628,7 +628,6 @@ void Body3DSW::integrate_velocities(real_t p_step) { /* void BodySW::simulate_motion(const Transform& p_xform,real_t p_step) { - Transform inv_xform = p_xform.affine_inverse(); if (!get_space()) { _set_transform(p_xform); @@ -655,8 +654,6 @@ void BodySW::simulate_motion(const Transform& p_xform,real_t p_step) { get_space()->body_add_to_state_query_list(&direct_state_query_list); simulated_motion=true; _set_transform(p_xform); - - } */ diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h index b642729404..41578778f6 100644 --- a/servers/physics_3d/body_3d_sw.h +++ b/servers/physics_3d/body_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,7 +33,7 @@ #include "area_3d_sw.h" #include "collision_object_3d_sw.h" -#include "core/vset.h" +#include "core/templates/vset.h" class Constraint3DSW; @@ -178,7 +178,7 @@ public: } _FORCE_INLINE_ int get_max_contacts_reported() const { return contacts.size(); } - _FORCE_INLINE_ bool can_report_contacts() const { return !contacts.empty(); } + _FORCE_INLINE_ bool can_report_contacts() const { return !contacts.is_empty(); } _FORCE_INLINE_ void add_contact(const Vector3 &p_local_pos, const Vector3 &p_local_normal, real_t p_depth, int p_local_shape, const Vector3 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector3 &p_collider_velocity_at_pos); _FORCE_INLINE_ void add_exception(const RID &p_exception) { exceptions.insert(p_exception); } diff --git a/servers/physics_3d/body_pair_3d_sw.cpp b/servers/physics_3d/body_pair_3d_sw.cpp index 848138940e..6012ff1522 100644 --- a/servers/physics_3d/body_pair_3d_sw.cpp +++ b/servers/physics_3d/body_pair_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -367,8 +367,8 @@ void BodyPair3DSW::solve(real_t p_step) { Vector3 jb = c.normal * (c.acc_bias_impulse - jbnOld); - A->apply_bias_impulse(c.rA + A->get_center_of_mass(), -jb, MAX_BIAS_ROTATION / p_step); - B->apply_bias_impulse(c.rB + B->get_center_of_mass(), jb, MAX_BIAS_ROTATION / p_step); + A->apply_bias_impulse(-jb, c.rA + A->get_center_of_mass(), MAX_BIAS_ROTATION / p_step); + B->apply_bias_impulse(jb, c.rB + B->get_center_of_mass(), MAX_BIAS_ROTATION / p_step); crbA = A->get_biased_angular_velocity().cross(c.rA); crbB = B->get_biased_angular_velocity().cross(c.rB); @@ -383,8 +383,8 @@ void BodyPair3DSW::solve(real_t p_step) { Vector3 jb_com = c.normal * (c.acc_bias_impulse_center_of_mass - jbnOld_com); - A->apply_bias_impulse(A->get_center_of_mass(), -jb_com, 0.0f); - B->apply_bias_impulse(B->get_center_of_mass(), jb_com, 0.0f); + A->apply_bias_impulse(-jb_com, A->get_center_of_mass(), 0.0f); + B->apply_bias_impulse(jb_com, B->get_center_of_mass(), 0.0f); } c.active = true; diff --git a/servers/physics_3d/body_pair_3d_sw.h b/servers/physics_3d/body_pair_3d_sw.h index 59e36e7ea5..4d049eafdc 100644 --- a/servers/physics_3d/body_pair_3d_sw.h +++ b/servers/physics_3d/body_pair_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -36,7 +36,6 @@ class BodyPair3DSW : public Constraint3DSW { enum { - MAX_CONTACTS = 4 }; diff --git a/servers/physics_3d/broad_phase_3d_basic.cpp b/servers/physics_3d/broad_phase_3d_basic.cpp index f5ea1897a9..b41c2530da 100644 --- a/servers/physics_3d/broad_phase_3d_basic.cpp +++ b/servers/physics_3d/broad_phase_3d_basic.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,8 +29,8 @@ /*************************************************************************/ #include "broad_phase_3d_basic.h" -#include "core/list.h" -#include "core/print_string.h" +#include "core/string/print_string.h" +#include "core/templates/list.h" BroadPhase3DSW::ID BroadPhase3DBasic::create(CollisionObject3DSW *p_object, int p_subindex) { ERR_FAIL_COND_V(p_object == nullptr, 0); diff --git a/servers/physics_3d/broad_phase_3d_basic.h b/servers/physics_3d/broad_phase_3d_basic.h index 4b644bf818..54d34e005f 100644 --- a/servers/physics_3d/broad_phase_3d_basic.h +++ b/servers/physics_3d/broad_phase_3d_basic.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,7 +32,7 @@ #define BROAD_PHASE_BASIC_H #include "broad_phase_3d_sw.h" -#include "core/map.h" +#include "core/templates/map.h" class BroadPhase3DBasic : public BroadPhase3DSW { struct Element { diff --git a/servers/physics_3d/broad_phase_3d_sw.cpp b/servers/physics_3d/broad_phase_3d_sw.cpp index 1a20fdd0cb..8aa64034ec 100644 --- a/servers/physics_3d/broad_phase_3d_sw.cpp +++ b/servers/physics_3d/broad_phase_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/broad_phase_3d_sw.h b/servers/physics_3d/broad_phase_3d_sw.h index 081e75810f..283c087b96 100644 --- a/servers/physics_3d/broad_phase_3d_sw.h +++ b/servers/physics_3d/broad_phase_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/broad_phase_octree.cpp b/servers/physics_3d/broad_phase_octree.cpp index 1ace1a4fcf..11324fa4e4 100644 --- a/servers/physics_3d/broad_phase_octree.cpp +++ b/servers/physics_3d/broad_phase_octree.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/broad_phase_octree.h b/servers/physics_3d/broad_phase_octree.h index 761a90a051..ee681dda96 100644 --- a/servers/physics_3d/broad_phase_octree.h +++ b/servers/physics_3d/broad_phase_octree.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/collision_object_3d_sw.cpp b/servers/physics_3d/collision_object_3d_sw.cpp index e12f0659e2..b06ade5ed3 100644 --- a/servers/physics_3d/collision_object_3d_sw.cpp +++ b/servers/physics_3d/collision_object_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/collision_object_3d_sw.h b/servers/physics_3d/collision_object_3d_sw.h index a3a5787ced..3847b81381 100644 --- a/servers/physics_3d/collision_object_3d_sw.h +++ b/servers/physics_3d/collision_object_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,7 +32,7 @@ #define COLLISION_OBJECT_SW_H #include "broad_phase_3d_sw.h" -#include "core/self_list.h" +#include "core/templates/self_list.h" #include "servers/physics_server_3d.h" #include "shape_3d_sw.h" diff --git a/servers/physics_3d/collision_solver_3d_sat.cpp b/servers/physics_3d/collision_solver_3d_sat.cpp index 85f55ad66d..b8e056f1f4 100644 --- a/servers/physics_3d/collision_solver_3d_sat.cpp +++ b/servers/physics_3d/collision_solver_3d_sat.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/collision_solver_3d_sat.h b/servers/physics_3d/collision_solver_3d_sat.h index 5eccfda9ac..97454c0b4a 100644 --- a/servers/physics_3d/collision_solver_3d_sat.h +++ b/servers/physics_3d/collision_solver_3d_sat.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/collision_solver_3d_sw.cpp b/servers/physics_3d/collision_solver_3d_sw.cpp index e2bfaf990d..1150696b84 100644 --- a/servers/physics_3d/collision_solver_3d_sw.cpp +++ b/servers/physics_3d/collision_solver_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/collision_solver_3d_sw.h b/servers/physics_3d/collision_solver_3d_sw.h index 13f54ca8fb..81d87e9773 100644 --- a/servers/physics_3d/collision_solver_3d_sw.h +++ b/servers/physics_3d/collision_solver_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/constraint_3d_sw.h b/servers/physics_3d/constraint_3d_sw.h index 081ddb0382..2571335c43 100644 --- a/servers/physics_3d/constraint_3d_sw.h +++ b/servers/physics_3d/constraint_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/gjk_epa.cpp b/servers/physics_3d/gjk_epa.cpp index d99a2532f8..dafd2feb8b 100644 --- a/servers/physics_3d/gjk_epa.cpp +++ b/servers/physics_3d/gjk_epa.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -102,7 +102,6 @@ typedef unsigned char U1; // MinkowskiDiff struct MinkowskiDiff { - const Shape3DSW* m_shapes[2]; Transform transform_A; @@ -127,7 +126,6 @@ struct MinkowskiDiff { return ( Support1 ( d ) ); } else { return ( Support0 ( d ) ); - } } }; @@ -281,7 +279,6 @@ struct GJK } } if(mask==15) { m_status=eStatus::Inside; - } } else @@ -312,12 +309,10 @@ struct GJK axis[i]=1; appendvertice(*m_simplex, axis); if(EncloseOrigin()) { return(true); - } removevertice(*m_simplex); appendvertice(*m_simplex,-axis); if(EncloseOrigin()) { return(true); - } removevertice(*m_simplex); } @@ -335,12 +330,10 @@ struct GJK { appendvertice(*m_simplex, p); if(EncloseOrigin()) { return(true); - } removevertice(*m_simplex); appendvertice(*m_simplex,-p); if(EncloseOrigin()) { return(true); - } removevertice(*m_simplex); } @@ -355,12 +348,10 @@ struct GJK { appendvertice(*m_simplex,n); if(EncloseOrigin()) { return(true); - } removevertice(*m_simplex); appendvertice(*m_simplex,-n); if(EncloseOrigin()) { return(true); - } removevertice(*m_simplex); } @@ -372,7 +363,6 @@ struct GJK m_simplex->c[1]->w-m_simplex->c[3]->w, m_simplex->c[2]->w-m_simplex->c[3]->w))>0) { return(true); - } } break; @@ -580,7 +570,6 @@ struct GJK face->l[0] = nullptr; face->l[1] = list.root; if(list.root) { list.root->l[0]=face; - } list.root = face; ++list.count; @@ -588,13 +577,10 @@ struct GJK static inline void remove(sList& list,sFace* face) { if(face->l[1]) { face->l[1]->l[0]=face->l[0]; - } if(face->l[0]) { face->l[0]->l[1]=face->l[1]; - } if(face==list.root) { list.root=face->l[1]; - } --list.count; } @@ -616,7 +602,6 @@ struct GJK GJK::sSimplex& simplex=*gjk.m_simplex; if((simplex.rank>1)&&gjk.EncloseOrigin()) { - /* Clean up */ while(m_hull.root) { @@ -677,7 +662,6 @@ struct GJK append(m_stock,best); best=findbest(); if(best->p>=outer.p) { outer=*best; - } } else { m_status=eStatus::InvalidHull;break; } } else { m_status=eStatus::AccuraryReached;break; } @@ -711,7 +695,6 @@ struct GJK m_normal = m_normal/nl; } else { m_normal = Vector3(1,0,0); - } m_depth = 0; m_result.rank=1; @@ -747,10 +730,8 @@ struct GJK { return(face); } else { m_status=eStatus::NonConvex; - } } else { m_status=eStatus::Degenerated; - } remove(m_hull,face); append(m_stock,face); @@ -793,7 +774,6 @@ struct GJK { bind(nf,0,f,e); if(horizon.cf) { bind(horizon.cf,1,nf,2); } else { horizon.ff=nf; - } horizon.cf=nf; ++horizon.nf; @@ -917,7 +897,6 @@ bool Penetration( const Shape3DSW* shape0, results.distance = -epa.m_depth; return(true); } else { results.status=sResults::EPA_Failed; - } } break; @@ -948,8 +927,6 @@ bool Penetration( const Shape3DSW* shape0, #undef EPA_FALLBACK #undef EPA_PLANE_EPS #undef EPA_INSIDE_EPS - - } // end of namespace /* clang-format on */ diff --git a/servers/physics_3d/gjk_epa.h b/servers/physics_3d/gjk_epa.h index dec0f269e1..be3ba4e664 100644 --- a/servers/physics_3d/gjk_epa.h +++ b/servers/physics_3d/gjk_epa.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp index 789d6687a4..7b10257157 100644 --- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h b/servers/physics_3d/joints/cone_twist_joint_3d_sw.h index c713d8cf17..c38edc5737 100644 --- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h +++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp index fede40ca65..13b389251f 100644 --- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -132,7 +132,7 @@ real_t G6DOFRotationalLimitMotor3DSW::solveAngularLimits( real_t oldaccumImpulse = m_accumulatedImpulse; real_t sum = oldaccumImpulse + clippedMotorImpulse; - m_accumulatedImpulse = sum > hi ? real_t(0.) : sum < lo ? real_t(0.) : sum; + m_accumulatedImpulse = sum > hi ? real_t(0.) : (sum < lo ? real_t(0.) : sum); clippedMotorImpulse = m_accumulatedImpulse - oldaccumImpulse; @@ -201,7 +201,7 @@ real_t G6DOFTranslationalLimitMotor3DSW::solveLinearAxis( real_t oldNormalImpulse = m_accumulatedImpulse[limit_index]; real_t sum = oldNormalImpulse + normalImpulse; - m_accumulatedImpulse[limit_index] = sum > hi ? real_t(0.) : sum < lo ? real_t(0.) : sum; + m_accumulatedImpulse[limit_index] = sum > hi ? real_t(0.) : (sum < lo ? real_t(0.) : sum); normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse; Vector3 impulse_vector = axis_normal_on_a * normalImpulse; @@ -253,7 +253,6 @@ void Generic6DOFJoint3DSW::calculateAngleInfo() { /* if(m_debugDrawer) { - char buff[300]; sprintf(buff,"\n X: %.2f ; Y: %.2f ; Z: %.2f ", m_calculatedAxisAngleDiff[0], diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h index cc1423a1cb..2ae6fe85fa 100644 --- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h +++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -103,19 +103,6 @@ public: m_enableLimit = false; } - G6DOFRotationalLimitMotor3DSW(const G6DOFRotationalLimitMotor3DSW &limot) { - m_targetVelocity = limot.m_targetVelocity; - m_maxMotorForce = limot.m_maxMotorForce; - m_limitSoftness = limot.m_limitSoftness; - m_loLimit = limot.m_loLimit; - m_hiLimit = limot.m_hiLimit; - m_ERP = limot.m_ERP; - m_bounce = limot.m_bounce; - m_currentLimit = limot.m_currentLimit; - m_currentLimitError = limot.m_currentLimitError; - m_enableMotor = limot.m_enableMotor; - } - //! Is limited bool isLimited() { return (m_loLimit < m_hiLimit); @@ -163,16 +150,6 @@ public: enable_limit[2] = true; } - G6DOFTranslationalLimitMotor3DSW(const G6DOFTranslationalLimitMotor3DSW &other) { - m_lowerLimit = other.m_lowerLimit; - m_upperLimit = other.m_upperLimit; - m_accumulatedImpulse = other.m_accumulatedImpulse; - - m_limitSoftness = other.m_limitSoftness; - m_damping = other.m_damping; - m_restitution = other.m_restitution; - } - //! Test limit /*! - free means upper < lower, @@ -242,11 +219,8 @@ protected: //!@} - Generic6DOFJoint3DSW &operator=(Generic6DOFJoint3DSW &other) { - ERR_PRINT("pito"); - (void)other; - return *this; - } + Generic6DOFJoint3DSW(Generic6DOFJoint3DSW const &) = delete; + void operator=(Generic6DOFJoint3DSW const &) = delete; void buildLinearJacobian( JacobianEntry3DSW &jacLinear, const Vector3 &normalWorld, diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp index 52c7389e1f..2b9f0038b4 100644 --- a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -365,7 +365,6 @@ void HingeJoint3DSW::solve(real_t p_step) { void HingeJointSW::updateRHS(real_t timeStep) { (void)timeStep; - } */ diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.h b/servers/physics_3d/joints/hinge_joint_3d_sw.h index c5af888eca..028a8b8c72 100644 --- a/servers/physics_3d/joints/hinge_joint_3d_sw.h +++ b/servers/physics_3d/joints/hinge_joint_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/joints/jacobian_entry_3d_sw.h b/servers/physics_3d/joints/jacobian_entry_3d_sw.h index 1737c21b3d..2829a5caf7 100644 --- a/servers/physics_3d/joints/jacobian_entry_3d_sw.h +++ b/servers/physics_3d/joints/jacobian_entry_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.cpp b/servers/physics_3d/joints/pin_joint_3d_sw.cpp index f028ad88f9..9f708ce151 100644 --- a/servers/physics_3d/joints/pin_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/pin_joint_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.h b/servers/physics_3d/joints/pin_joint_3d_sw.h index 0181a4455b..e28fbec6cd 100644 --- a/servers/physics_3d/joints/pin_joint_3d_sw.h +++ b/servers/physics_3d/joints/pin_joint_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.cpp b/servers/physics_3d/joints/slider_joint_3d_sw.cpp index 43bd49b4b5..0adc471797 100644 --- a/servers/physics_3d/joints/slider_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/slider_joint_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -105,7 +105,6 @@ void SliderJoint3DSW::initParams() { m_targetAngMotorVelocity = real_t(0.); m_maxAngMotorForce = real_t(0.); m_accumulatedAngMotorImpulse = real_t(0.0); - } // SliderJointSW::initParams() //----------------------------------------------------------------------------- diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.h b/servers/physics_3d/joints/slider_joint_3d_sw.h index 37394a1580..196e60d19d 100644 --- a/servers/physics_3d/joints/slider_joint_3d_sw.h +++ b/servers/physics_3d/joints/slider_joint_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/joints_3d_sw.h b/servers/physics_3d/joints_3d_sw.h index 6a010ee771..cad05b6702 100644 --- a/servers/physics_3d/joints_3d_sw.h +++ b/servers/physics_3d/joints_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp index 143cc9ebbd..274de8411c 100644 --- a/servers/physics_3d/physics_server_3d_sw.cpp +++ b/servers/physics_3d/physics_server_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -174,7 +174,7 @@ real_t PhysicsServer3DSW::space_get_param(RID p_space, SpaceParameter p_param) c PhysicsDirectSpaceState3D *PhysicsServer3DSW::space_get_direct_state(RID p_space) { Space3DSW *space = space_owner.getornull(p_space); ERR_FAIL_COND_V(!space, nullptr); - ERR_FAIL_COND_V_MSG(!doing_sync || space->is_locked(), nullptr, "Space state is inaccessible right now, wait for iteration or physics process notification."); + ERR_FAIL_COND_V_MSG(space->is_locked(), nullptr, "Space state is inaccessible right now, wait for iteration or physics process notification."); return space->get_direct_state(); } @@ -888,7 +888,7 @@ int PhysicsServer3DSW::body_test_ray_separation(RID p_body, const Transform &p_t PhysicsDirectBodyState3D *PhysicsServer3DSW::body_get_direct_state(RID p_body) { Body3DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, nullptr); - ERR_FAIL_COND_V_MSG(!doing_sync || body->get_space()->is_locked(), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification."); + ERR_FAIL_COND_V_MSG(body->get_space()->is_locked(), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification."); direct_state->body = body; return direct_state; @@ -1287,7 +1287,6 @@ void PhysicsServer3DSW::set_active(bool p_active) { }; void PhysicsServer3DSW::init() { - doing_sync = true; last_step = 0.001; iterations = 8; // 8? stepper = memnew(Step3DSW); @@ -1303,8 +1302,6 @@ void PhysicsServer3DSW::step(real_t p_step) { _update_shapes(); - doing_sync = false; - last_step = p_step; PhysicsDirectBodyState3DSW::singleton->step = p_step; @@ -1327,8 +1324,6 @@ void PhysicsServer3DSW::flush_queries() { return; } - doing_sync = true; - flushing_queries = true; uint64_t time_beg = OS::get_singleton()->get_ticks_usec(); diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h index d9c86312cc..9b6b113677 100644 --- a/servers/physics_3d/physics_server_3d_sw.h +++ b/servers/physics_3d/physics_server_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,7 +31,7 @@ #ifndef PHYSICS_SERVER_SW #define PHYSICS_SERVER_SW -#include "core/rid_owner.h" +#include "core/templates/rid_owner.h" #include "joints_3d_sw.h" #include "servers/physics_server_3d.h" #include "shape_3d_sw.h" @@ -44,7 +44,6 @@ class PhysicsServer3DSW : public PhysicsServer3D { friend class PhysicsDirectSpaceState3DSW; bool active; int iterations; - bool doing_sync; real_t last_step; int island_count; @@ -347,9 +346,6 @@ public: virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag, bool p_enable) override; virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) override; - virtual void generic_6dof_joint_set_precision(RID p_joint, int precision) override {} - virtual int generic_6dof_joint_get_precision(RID p_joint) override { return 0; } - virtual JointType joint_get_type(RID p_joint) const override; virtual void joint_set_solver_priority(RID p_joint, int p_priority) override; @@ -365,7 +361,6 @@ public: virtual void set_active(bool p_active) override; virtual void init() override; virtual void step(real_t p_step) override; - virtual void sync() override {} virtual void flush_queries() override; virtual void finish() override; diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp index ca33241d29..f2adcc1072 100644 --- a/servers/physics_3d/shape_3d_sw.cpp +++ b/servers/physics_3d/shape_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,7 +32,7 @@ #include "core/math/geometry_3d.h" #include "core/math/quick_hull.h" -#include "core/sort_array.h" +#include "core/templates/sort_array.h" #define _POINT_SNAP 0.001953125 #define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.0002 @@ -333,7 +333,6 @@ void BoxShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_s int i_n2 = next2[i]; static const real_t sign[4][2] = { - { -1.0, 1.0 }, { 1.0, 1.0 }, { 1.0, -1.0 }, diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/shape_3d_sw.h index 2a2cd42255..851c0d9443 100644 --- a/servers/physics_3d/shape_3d_sw.h +++ b/servers/physics_3d/shape_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp index 48f250ba35..6cc7ad2676 100644 --- a/servers/physics_3d/space_3d_sw.cpp +++ b/servers/physics_3d/space_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,7 +31,7 @@ #include "space_3d_sw.h" #include "collision_solver_3d_sw.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h" #include "physics_server_3d_sw.h" _FORCE_INLINE_ static bool _can_collide_with(CollisionObject3DSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { @@ -274,11 +274,11 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor continue; } - //test initial overlap + //test initial overlap, ignore objects it's inside of. sep_axis = p_motion.normalized(); if (!CollisionSolver3DSW::solve_distance(shape, p_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, aabb, &sep_axis)) { - return false; + continue; } //just do kinematic solving @@ -649,7 +649,7 @@ int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform &p_tra Vector3 a = sr[k * 2 + 0]; Vector3 b = sr[k * 2 + 1]; - recover_motion += (b - a) * 0.4; + recover_motion += (b - a) / cbk.amount; float depth = a.distance_to(b); if (depth > result.collision_depth) { @@ -791,7 +791,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons for (int i = 0; i < cbk.amount; i++) { Vector3 a = sr[i * 2 + 0]; Vector3 b = sr[i * 2 + 1]; - recover_motion += (b - a) * 0.4; + recover_motion += (b - a) / cbk.amount; } if (recover_motion == Vector3()) { diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/space_3d_sw.h index 4aba80c8f3..eed3d86a72 100644 --- a/servers/physics_3d/space_3d_sw.h +++ b/servers/physics_3d/space_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -37,8 +37,8 @@ #include "body_pair_3d_sw.h" #include "broad_phase_3d_sw.h" #include "collision_object_3d_sw.h" -#include "core/hash_map.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h" +#include "core/templates/hash_map.h" #include "core/typedefs.h" class PhysicsDirectSpaceState3DSW : public PhysicsDirectSpaceState3D { @@ -97,7 +97,6 @@ private: real_t test_motion_min_contact_depth; enum { - INTERSECTION_QUERY_MAX = 2048 }; @@ -183,7 +182,7 @@ public: PhysicsDirectSpaceState3DSW *get_direct_state(); void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); } - _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.empty(); } + _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.is_empty(); } _FORCE_INLINE_ void add_debug_contact(const Vector3 &p_contact) { if (contact_debug_count < contact_debug.size()) { contact_debug.write[contact_debug_count++] = p_contact; diff --git a/servers/physics_3d/step_3d_sw.cpp b/servers/physics_3d/step_3d_sw.cpp index 9a2a0073a1..d9370de6a3 100644 --- a/servers/physics_3d/step_3d_sw.cpp +++ b/servers/physics_3d/step_3d_sw.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_3d/step_3d_sw.h b/servers/physics_3d/step_3d_sw.h index 9dbb61308f..55c48ec0eb 100644 --- a/servers/physics_3d/step_3d_sw.h +++ b/servers/physics_3d/step_3d_sw.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index 4338a6938a..a6f64f5848 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,8 +30,8 @@ #include "physics_server_2d.h" -#include "core/print_string.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h" +#include "core/string/print_string.h" PhysicsServer2D *PhysicsServer2D::singleton = nullptr; @@ -245,11 +245,11 @@ void PhysicsShapeQueryParameters2D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &PhysicsShapeQueryParameters2D::is_collide_with_areas_enabled); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer"); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_NONE, itos(Variant::_RID) + ":"), "set_exclude", "get_exclude"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_NONE, itos(Variant::RID) + ":"), "set_exclude", "get_exclude"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_margin", "get_margin"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion"), "set_motion", "get_motion"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape"); - ADD_PROPERTY(PropertyInfo(Variant::_RID, "shape_rid"), "set_shape_rid", "get_shape_rid"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "shape_rid"), "set_shape_rid", "get_shape_rid"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies"), "set_collide_with_bodies", "is_collide_with_bodies_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled"); @@ -504,7 +504,7 @@ void PhysicsTestMotionResult2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collision_normal"), "", "get_collision_normal"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collider_velocity"), "", "get_collider_velocity"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id", PROPERTY_HINT_OBJECT_ID), "", "get_collider_id"); - ADD_PROPERTY(PropertyInfo(Variant::_RID, "collider_rid"), "", "get_collider_rid"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "collider_rid"), "", "get_collider_rid"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape"), "", "get_collider_shape"); } diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index 40773e4ced..dd38855199 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,9 +31,9 @@ #ifndef PHYSICS_2D_SERVER_H #define PHYSICS_2D_SERVER_H -#include "core/class_db.h" -#include "core/reference.h" -#include "core/resource.h" +#include "core/io/resource.h" +#include "core/object/class_db.h" +#include "core/object/reference.h" class PhysicsDirectSpaceState2D; @@ -276,7 +276,6 @@ public: virtual bool space_is_active(RID p_space) const = 0; enum SpaceParameter { - SPACE_PARAM_CONTACT_RECYCLE_RADIUS, SPACE_PARAM_CONTACT_MAX_SEPARATION, SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION, @@ -526,7 +525,6 @@ public: /* JOINT API */ enum JointType { - JOINT_PIN, JOINT_GROOVE, JOINT_DAMPED_SPRING @@ -587,7 +585,6 @@ public: virtual bool is_flushing_queries() const = 0; enum ProcessInfo { - INFO_ACTIVE_OBJECTS, INFO_COLLISION_PAIRS, INFO_ISLAND_COUNT diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index d0266f95b5..702b35f8d1 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,8 +30,8 @@ #include "physics_server_3d.h" -#include "core/print_string.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h" +#include "core/string/print_string.h" PhysicsServer3D *PhysicsServer3D::singleton = nullptr; @@ -128,7 +128,7 @@ void PhysicsDirectBodyState3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity"), "set_angular_velocity", "get_angular_velocity"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleep_state", "is_sleeping"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "transform"), "set_transform", "get_transform"); } PhysicsDirectBodyState3D::PhysicsDirectBodyState3D() {} @@ -238,10 +238,10 @@ void PhysicsShapeQueryParameters3D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &PhysicsShapeQueryParameters3D::is_collide_with_areas_enabled); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_NONE, itos(Variant::_RID) + ":"), "set_exclude", "get_exclude"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_NONE, itos(Variant::RID) + ":"), "set_exclude", "get_exclude"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_margin", "get_margin"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape3D"), "set_shape", "get_shape"); - ADD_PROPERTY(PropertyInfo(Variant::_RID, "shape_rid"), "set_shape_rid", "get_shape_rid"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "shape_rid"), "set_shape_rid", "get_shape_rid"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "transform"), "set_transform", "get_transform"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies"), "set_collide_with_bodies", "is_collide_with_bodies_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled"); diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index d79dc6fec0..303825f37c 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,8 +31,8 @@ #ifndef PHYSICS_SERVER_H #define PHYSICS_SERVER_H -#include "core/class_db.h" -#include "core/resource.h" +#include "core/io/resource.h" +#include "core/object/class_db.h" class PhysicsDirectSpaceState3D; @@ -259,7 +259,6 @@ public: virtual bool space_is_active(RID p_space) const = 0; enum SpaceParameter { - SPACE_PARAM_CONTACT_RECYCLE_RADIUS, SPACE_PARAM_CONTACT_MAX_SEPARATION, SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION, @@ -578,7 +577,6 @@ public: /* JOINT API */ enum JointType { - JOINT_PIN, JOINT_HINGE, JOINT_SLIDER, @@ -613,7 +611,6 @@ public: virtual Vector3 pin_joint_get_local_b(RID p_joint) const = 0; enum HingeJointParam { - HINGE_JOINT_BIAS, HINGE_JOINT_LIMIT_UPPER, HINGE_JOINT_LIMIT_LOWER, @@ -714,7 +711,6 @@ public: }; enum G6DOFJointAxisFlag { - G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING, @@ -732,9 +728,6 @@ public: virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag, bool p_enable) = 0; virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) = 0; - virtual void generic_6dof_joint_set_precision(RID p_joint, int precision) = 0; - virtual int generic_6dof_joint_get_precision(RID p_joint) = 0; - /* QUERY API */ enum AreaBodyStatus { @@ -749,14 +742,12 @@ public: virtual void set_active(bool p_active) = 0; virtual void init() = 0; virtual void step(float p_step) = 0; - virtual void sync() = 0; virtual void flush_queries() = 0; virtual void finish() = 0; virtual bool is_flushing_queries() const = 0; enum ProcessInfo { - INFO_ACTIVE_OBJECTS, INFO_COLLISION_PAIRS, INFO_ISLAND_COUNT diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index adca7b8055..58bcdf5802 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,8 +30,8 @@ #include "register_server_types.h" -#include "core/engine.h" -#include "core/project_settings.h" +#include "core/config/engine.h" +#include "core/config/project_settings.h" #include "audio/audio_effect.h" #include "audio/audio_stream.h" @@ -62,12 +62,12 @@ #include "physics_3d/physics_server_3d_sw.h" #include "physics_server_2d.h" #include "physics_server_3d.h" -#include "rendering/rasterizer.h" +#include "rendering/renderer_compositor.h" #include "rendering/rendering_device.h" #include "rendering/rendering_device_binds.h" - #include "rendering_server.h" #include "servers/rendering/shader_types.h" +#include "text_server.h" #include "xr/xr_interface.h" #include "xr/xr_positional_tracker.h" #include "xr_server.h" @@ -102,6 +102,11 @@ void register_server_types() { ClassDB::register_virtual_class<DisplayServer>(); ClassDB::register_virtual_class<RenderingServer>(); ClassDB::register_class<AudioServer>(); + + ClassDB::register_class<TextServerManager>(); + ClassDB::register_virtual_class<TextServer>(); + TextServer::initialize_hex_code_box_fonts(); + ClassDB::register_virtual_class<PhysicsServer2D>(); ClassDB::register_virtual_class<PhysicsServer3D>(); ClassDB::register_virtual_class<NavigationServer2D>(); @@ -209,6 +214,7 @@ void register_server_types() { void unregister_server_types() { memdelete(shader_types); + TextServer::finish_hex_code_box_fonts(); } void register_server_singletons() { @@ -219,6 +225,7 @@ void register_server_singletons() { Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3D", PhysicsServer3D::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer2D", NavigationServer2D::get_singleton_mut())); Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3D", NavigationServer3D::get_singleton_mut())); + Engine::get_singleton()->add_singleton(Engine::Singleton("TextServerManager", TextServerManager::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("XRServer", XRServer::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("CameraServer", CameraServer::get_singleton())); } diff --git a/servers/register_server_types.h b/servers/register_server_types.h index 7d1dad37af..f6a65cb653 100644 --- a/servers/register_server_types.h +++ b/servers/register_server_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/SCsub b/servers/rendering/SCsub index 5ea0d40486..0939b68482 100644 --- a/servers/rendering/SCsub +++ b/servers/rendering/SCsub @@ -4,4 +4,4 @@ Import("env") env.add_source_files(env.servers_sources, "*.cpp") -SConscript("rasterizer_rd/SCsub") +SConscript("renderer_rd/SCsub") diff --git a/servers/rendering/rasterizer.h b/servers/rendering/rasterizer.h deleted file mode 100644 index b2b2b4977b..0000000000 --- a/servers/rendering/rasterizer.h +++ /dev/null @@ -1,1403 +0,0 @@ -/*************************************************************************/ -/* rasterizer.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RASTERIZER_H -#define RASTERIZER_H - -#include "core/math/camera_matrix.h" -#include "core/pair.h" -#include "core/self_list.h" -#include "servers/rendering_server.h" - -class RasterizerScene { -public: - /* SHADOW ATLAS API */ - - virtual RID shadow_atlas_create() = 0; - virtual void shadow_atlas_set_size(RID p_atlas, int p_size) = 0; - virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0; - virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) = 0; - - virtual void directional_shadow_atlas_set_size(int p_size) = 0; - virtual int get_directional_light_shadow_size(RID p_light_intance) = 0; - virtual void set_directional_shadow_count(int p_count) = 0; - - /* SDFGI UPDATE */ - - struct InstanceBase; - - virtual void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) = 0; - virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const = 0; - virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const = 0; - virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const = 0; - virtual void sdfgi_update_probes(RID p_render_buffers, RID p_environment, const RID *p_directional_light_instances, uint32_t p_directional_light_count, const RID *p_positional_light_instances, uint32_t p_positional_light_count) = 0; - - /* SKY API */ - - virtual RID sky_create() = 0; - virtual void sky_set_radiance_size(RID p_sky, int p_radiance_size) = 0; - virtual void sky_set_mode(RID p_sky, RS::SkyMode p_samples) = 0; - virtual void sky_set_material(RID p_sky, RID p_material) = 0; - virtual Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) = 0; - - /* ENVIRONMENT API */ - - virtual RID environment_create() = 0; - - virtual void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) = 0; - virtual void environment_set_sky(RID p_env, RID p_sky) = 0; - virtual void environment_set_sky_custom_fov(RID p_env, float p_scale) = 0; - virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) = 0; - virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0; - virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0; - virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0; - virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) = 0; -// FIXME: Disabled during Vulkan refactoring, should be ported. -#if 0 - virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) = 0; -#endif - - virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0; - virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0; - virtual void environment_glow_set_use_high_quality(bool p_enable) = 0; - - virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter) = 0; - - virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0; - virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0; - virtual void environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size) = 0; - virtual void environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size) = 0; - - virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) = 0; - virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) = 0; - - virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) = 0; - - virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size) = 0; - - virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; - - virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) = 0; - virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) = 0; - - virtual void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) = 0; - - virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) = 0; - - virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) = 0; - - virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) = 0; - - virtual bool is_environment(RID p_env) const = 0; - virtual RS::EnvironmentBG environment_get_background(RID p_env) const = 0; - virtual int environment_get_canvas_max_layer(RID p_env) const = 0; - - virtual RID camera_effects_create() = 0; - - virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) = 0; - virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) = 0; - - virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0; - virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0; - - virtual void shadows_quality_set(RS::ShadowQuality p_quality) = 0; - virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) = 0; - - struct InstanceDependency { - void instance_notify_changed(bool p_aabb, bool p_dependencies); - void instance_notify_deleted(RID p_deleted); - - ~InstanceDependency(); - - private: - friend struct InstanceBase; - Map<InstanceBase *, uint32_t> instances; - }; - - struct InstanceBase { - RS::InstanceType base_type; - RID base; - - RID skeleton; - RID material_override; - - RID instance_data; - - Transform transform; - - int depth_layer; - uint32_t layer_mask; - uint32_t instance_version; - - //RID sampled_light; - - Vector<RID> materials; - Vector<RID> light_instances; - Vector<RID> reflection_probe_instances; - Vector<RID> gi_probe_instances; - - Vector<float> blend_values; - - RS::ShadowCastingSetting cast_shadows; - - //fit in 32 bits - bool mirror : 8; - bool receive_shadows : 8; - bool visible : 8; - bool baked_light : 2; //this flag is only to know if it actually did use baked light - bool dynamic_gi : 2; //this flag is only to know if it actually did use baked light - bool redraw_if_visible : 4; - - float depth; //used for sorting - - SelfList<InstanceBase> dependency_item; - - InstanceBase *lightmap; - Rect2 lightmap_uv_scale; - int lightmap_slice_index; - uint32_t lightmap_cull_index; - Vector<Color> lightmap_sh; //spherical harmonic - - AABB aabb; - AABB transformed_aabb; - - struct InstanceShaderParameter { - int32_t index = -1; - Variant value; - Variant default_value; - PropertyInfo info; - }; - - Map<StringName, InstanceShaderParameter> instance_shader_parameters; - bool instance_allocated_shader_parameters = false; - int32_t instance_allocated_shader_parameters_offset = -1; - - virtual void dependency_deleted(RID p_dependency) {} - virtual void dependency_changed(bool p_aabb, bool p_dependencies) {} - - Set<InstanceDependency *> dependencies; - - void instance_increase_version() { - instance_version++; - } - - void update_dependency(InstanceDependency *p_dependency) { - dependencies.insert(p_dependency); - p_dependency->instances[this] = instance_version; - } - - void clean_up_dependencies() { - List<Pair<InstanceDependency *, Map<InstanceBase *, uint32_t>::Element *>> to_clean_up; - for (Set<InstanceDependency *>::Element *E = dependencies.front(); E; E = E->next()) { - InstanceDependency *dep = E->get(); - Map<InstanceBase *, uint32_t>::Element *F = dep->instances.find(this); - ERR_CONTINUE(!F); - if (F->get() != instance_version) { - Pair<InstanceDependency *, Map<InstanceBase *, uint32_t>::Element *> p; - p.first = dep; - p.second = F; - to_clean_up.push_back(p); - } - } - - while (to_clean_up.size()) { - to_clean_up.front()->get().first->instances.erase(to_clean_up.front()->get().second); - to_clean_up.pop_front(); - } - } - - void clear_dependencies() { - for (Set<InstanceDependency *>::Element *E = dependencies.front(); E; E = E->next()) { - InstanceDependency *dep = E->get(); - dep->instances.erase(this); - } - dependencies.clear(); - } - - InstanceBase() : - dependency_item(this) { - base_type = RS::INSTANCE_NONE; - cast_shadows = RS::SHADOW_CASTING_SETTING_ON; - receive_shadows = true; - visible = true; - depth_layer = 0; - layer_mask = 1; - instance_version = 0; - baked_light = false; - dynamic_gi = false; - redraw_if_visible = false; - lightmap_slice_index = 0; - lightmap = nullptr; - lightmap_cull_index = 0; - } - - virtual ~InstanceBase() { - clear_dependencies(); - } - }; - - virtual RID light_instance_create(RID p_light) = 0; - virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) = 0; - virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) = 0; - virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) = 0; - virtual void light_instance_mark_visible(RID p_light_instance) = 0; - virtual bool light_instances_can_render_shadow_cube() const { - return true; - } - - virtual RID reflection_atlas_create() = 0; - virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) = 0; - - virtual RID reflection_probe_instance_create(RID p_probe) = 0; - virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) = 0; - virtual void reflection_probe_release_atlas_index(RID p_instance) = 0; - virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0; - virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0; - virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0; - virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0; - - virtual RID decal_instance_create(RID p_decal) = 0; - virtual void decal_instance_set_transform(RID p_decal, const Transform &p_transform) = 0; - - virtual RID gi_probe_instance_create(RID p_gi_probe) = 0; - virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) = 0; - virtual bool gi_probe_needs_update(RID p_probe) const = 0; - virtual void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) = 0; - - virtual void gi_probe_set_quality(RS::GIProbeQuality) = 0; - - virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0; - - virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) = 0; - virtual void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0; - virtual void render_sdfgi(RID p_render_buffers, int p_region, InstanceBase **p_cull_result, int p_cull_count) = 0; - virtual void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const RID **p_positional_light_cull_result, const uint32_t *p_positional_light_cull_count) = 0; - virtual void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, InstanceBase **p_cull_result, int p_cull_count) = 0; - - virtual void set_scene_pass(uint64_t p_pass) = 0; - virtual void set_time(double p_time, double p_step) = 0; - virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0; - - virtual RID render_buffers_create() = 0; - virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) = 0; - - virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) = 0; - virtual bool screen_space_roughness_limiter_is_active() const = 0; - - virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) = 0; - virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) = 0; - - virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) = 0; - - virtual bool free(RID p_rid) = 0; - - virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0; - - virtual void update() = 0; - virtual ~RasterizerScene() {} -}; - -class RasterizerStorage { - Color default_clear_color; - -public: - /* TEXTURE API */ - - virtual RID texture_2d_create(const Ref<Image> &p_image) = 0; - virtual RID texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) = 0; - virtual RID texture_3d_create(Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) = 0; - virtual RID texture_proxy_create(RID p_base) = 0; //all slices, then all the mipmaps, must be coherent - - virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; //mostly used for video and streaming - virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; - virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) = 0; - virtual void texture_proxy_update(RID p_proxy, RID p_base) = 0; - - //these two APIs can be used together or in combination with the others. - virtual RID texture_2d_placeholder_create() = 0; - virtual RID texture_2d_layered_placeholder_create(RenderingServer::TextureLayeredType p_layered_type) = 0; - virtual RID texture_3d_placeholder_create() = 0; - - virtual Ref<Image> texture_2d_get(RID p_texture) const = 0; - virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const = 0; - virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const = 0; - - virtual void texture_replace(RID p_texture, RID p_by_texture) = 0; - virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) = 0; - - virtual void texture_set_path(RID p_texture, const String &p_path) = 0; - virtual String texture_get_path(RID p_texture) const = 0; - - virtual void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) = 0; - virtual void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) = 0; - virtual void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) = 0; - - virtual void texture_debug_usage(List<RS::TextureInfo> *r_info) = 0; - - virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) = 0; - - virtual Size2 texture_size_with_proxy(RID p_proxy) = 0; - - virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0; - virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0; - - /* CANVAS TEXTURE API */ - - virtual RID canvas_texture_create() = 0; - virtual void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) = 0; - virtual void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) = 0; - - virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) = 0; - virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) = 0; - - /* SHADER API */ - - virtual RID shader_create() = 0; - - virtual void shader_set_code(RID p_shader, const String &p_code) = 0; - virtual String shader_get_code(RID p_shader) const = 0; - virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0; - - virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) = 0; - virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const = 0; - virtual Variant shader_get_param_default(RID p_material, const StringName &p_param) const = 0; - - /* COMMON MATERIAL API */ - - virtual RID material_create() = 0; - - virtual void material_set_render_priority(RID p_material, int priority) = 0; - virtual void material_set_shader(RID p_shader_material, RID p_shader) = 0; - - virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) = 0; - virtual Variant material_get_param(RID p_material, const StringName &p_param) const = 0; - - virtual void material_set_next_pass(RID p_material, RID p_next_material) = 0; - - virtual bool material_is_animated(RID p_material) = 0; - virtual bool material_casts_shadows(RID p_material) = 0; - - struct InstanceShaderParam { - PropertyInfo info; - int index; - Variant default_value; - }; - - virtual void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) = 0; - - virtual void material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) = 0; - - /* MESH API */ - - virtual RID mesh_create() = 0; - - /// Returns stride - virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) = 0; - - virtual int mesh_get_blend_shape_count(RID p_mesh) const = 0; - - virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) = 0; - virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const = 0; - - virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0; - - virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) = 0; - virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const = 0; - - virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const = 0; - - virtual int mesh_get_surface_count(RID p_mesh) const = 0; - - virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0; - virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0; - - virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) = 0; - - virtual void mesh_clear(RID p_mesh) = 0; - - /* MULTIMESH API */ - - virtual RID multimesh_create() = 0; - - virtual void multimesh_allocate(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0; - - virtual int multimesh_get_instance_count(RID p_multimesh) const = 0; - - virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0; - virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) = 0; - virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) = 0; - virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0; - virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0; - - virtual RID multimesh_get_mesh(RID p_multimesh) const = 0; - - virtual Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0; - virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0; - virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0; - virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0; - - virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0; - virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const = 0; - - virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0; - virtual int multimesh_get_visible_instances(RID p_multimesh) const = 0; - - virtual AABB multimesh_get_aabb(RID p_multimesh) const = 0; - - /* IMMEDIATE API */ - - virtual RID immediate_create() = 0; - virtual void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) = 0; - virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) = 0; - virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal) = 0; - virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent) = 0; - virtual void immediate_color(RID p_immediate, const Color &p_color) = 0; - virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv) = 0; - virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) = 0; - virtual void immediate_end(RID p_immediate) = 0; - virtual void immediate_clear(RID p_immediate) = 0; - virtual void immediate_set_material(RID p_immediate, RID p_material) = 0; - virtual RID immediate_get_material(RID p_immediate) const = 0; - virtual AABB immediate_get_aabb(RID p_immediate) const = 0; - - /* SKELETON API */ - - virtual RID skeleton_create() = 0; - virtual void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0; - virtual int skeleton_get_bone_count(RID p_skeleton) const = 0; - virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) = 0; - virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0; - virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0; - virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0; - virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0; - - /* Light API */ - - virtual RID light_create(RS::LightType p_type) = 0; - - RID directional_light_create() { return light_create(RS::LIGHT_DIRECTIONAL); } - RID omni_light_create() { return light_create(RS::LIGHT_OMNI); } - RID spot_light_create() { return light_create(RS::LIGHT_SPOT); } - - virtual void light_set_color(RID p_light, const Color &p_color) = 0; - virtual void light_set_param(RID p_light, RS::LightParam p_param, float p_value) = 0; - virtual void light_set_shadow(RID p_light, bool p_enabled) = 0; - virtual void light_set_shadow_color(RID p_light, const Color &p_color) = 0; - virtual void light_set_projector(RID p_light, RID p_texture) = 0; - virtual void light_set_negative(RID p_light, bool p_enable) = 0; - virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0; - virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0; - virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) = 0; - virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) = 0; - - virtual void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) = 0; - - virtual void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) = 0; - virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0; - virtual bool light_directional_get_blend_splits(RID p_light) const = 0; - virtual void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) = 0; - virtual RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const = 0; - - virtual RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) = 0; - virtual RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) = 0; - - virtual bool light_has_shadow(RID p_light) const = 0; - - virtual RS::LightType light_get_type(RID p_light) const = 0; - virtual AABB light_get_aabb(RID p_light) const = 0; - virtual float light_get_param(RID p_light, RS::LightParam p_param) = 0; - virtual Color light_get_color(RID p_light) = 0; - virtual RS::LightBakeMode light_get_bake_mode(RID p_light) = 0; - virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) = 0; - virtual uint64_t light_get_version(RID p_light) const = 0; - - /* PROBE API */ - - virtual RID reflection_probe_create() = 0; - - virtual void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) = 0; - virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0; - virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity) = 0; - virtual void reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) = 0; - virtual void reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) = 0; - virtual void reflection_probe_set_ambient_energy(RID p_probe, float p_energy) = 0; - virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance) = 0; - virtual void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) = 0; - virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) = 0; - virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable) = 0; - virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) = 0; - virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) = 0; - virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0; - - virtual AABB reflection_probe_get_aabb(RID p_probe) const = 0; - virtual RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const = 0; - virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const = 0; - virtual Vector3 reflection_probe_get_extents(RID p_probe) const = 0; - virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const = 0; - virtual float reflection_probe_get_origin_max_distance(RID p_probe) const = 0; - virtual bool reflection_probe_renders_shadows(RID p_probe) const = 0; - - virtual void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0; - virtual void skeleton_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0; - - /* DECAL API */ - - virtual RID decal_create() = 0; - virtual void decal_set_extents(RID p_decal, const Vector3 &p_extents) = 0; - virtual void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) = 0; - virtual void decal_set_emission_energy(RID p_decal, float p_energy) = 0; - virtual void decal_set_albedo_mix(RID p_decal, float p_mix) = 0; - virtual void decal_set_modulate(RID p_decal, const Color &p_modulate) = 0; - virtual void decal_set_cull_mask(RID p_decal, uint32_t p_layers) = 0; - virtual void decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) = 0; - virtual void decal_set_fade(RID p_decal, float p_above, float p_below) = 0; - virtual void decal_set_normal_fade(RID p_decal, float p_fade) = 0; - - virtual AABB decal_get_aabb(RID p_decal) const = 0; - - /* GI PROBE API */ - - virtual RID gi_probe_create() = 0; - - virtual void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0; - - virtual AABB gi_probe_get_bounds(RID p_gi_probe) const = 0; - virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0; - virtual Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const = 0; - virtual Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const = 0; - virtual Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const = 0; - - virtual Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const = 0; - virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) = 0; - virtual float gi_probe_get_dynamic_range(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_propagation(RID p_gi_probe, float p_range) = 0; - virtual float gi_probe_get_propagation(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_energy(RID p_gi_probe, float p_energy) = 0; - virtual float gi_probe_get_energy(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_ao(RID p_gi_probe, float p_ao) = 0; - virtual float gi_probe_get_ao(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_ao_size(RID p_gi_probe, float p_strength) = 0; - virtual float gi_probe_get_ao_size(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_bias(RID p_gi_probe, float p_bias) = 0; - virtual float gi_probe_get_bias(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) = 0; - virtual float gi_probe_get_normal_bias(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_interior(RID p_gi_probe, bool p_enable) = 0; - virtual bool gi_probe_is_interior(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) = 0; - virtual bool gi_probe_is_using_two_bounces(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) = 0; - virtual float gi_probe_get_anisotropy_strength(RID p_gi_probe) const = 0; - - virtual uint32_t gi_probe_get_version(RID p_probe) = 0; - - /* LIGHTMAP CAPTURE */ - - virtual RID lightmap_create() = 0; - - virtual void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) = 0; - virtual void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) = 0; - virtual void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) = 0; - virtual void lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) = 0; - virtual PackedVector3Array lightmap_get_probe_capture_points(RID p_lightmap) const = 0; - virtual PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const = 0; - virtual PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const = 0; - virtual PackedInt32Array lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const = 0; - virtual AABB lightmap_get_aabb(RID p_lightmap) const = 0; - virtual void lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) = 0; - virtual bool lightmap_is_interior(RID p_lightmap) const = 0; - virtual void lightmap_set_probe_capture_update_speed(float p_speed) = 0; - virtual float lightmap_get_probe_capture_update_speed() const = 0; - - /* PARTICLES */ - - virtual RID particles_create() = 0; - - virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0; - virtual bool particles_get_emitting(RID p_particles) = 0; - - virtual void particles_set_amount(RID p_particles, int p_amount) = 0; - virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0; - virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0; - virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0; - virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0; - virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0; - virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) = 0; - virtual void particles_set_speed_scale(RID p_particles, float p_scale) = 0; - virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0; - virtual void particles_set_process_material(RID p_particles, RID p_material) = 0; - virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0; - virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0; - virtual void particles_set_collision_base_size(RID p_particles, float p_size) = 0; - virtual void particles_restart(RID p_particles) = 0; - virtual void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0; - virtual void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) = 0; - - virtual bool particles_is_inactive(RID p_particles) const = 0; - - virtual void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) = 0; - - virtual void particles_set_draw_passes(RID p_particles, int p_count) = 0; - virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) = 0; - - virtual void particles_request_process(RID p_particles) = 0; - virtual AABB particles_get_current_aabb(RID p_particles) = 0; - virtual AABB particles_get_aabb(RID p_particles) const = 0; - - virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform) = 0; - - virtual int particles_get_draw_passes(RID p_particles) const = 0; - virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const = 0; - - virtual void particles_set_view_axis(RID p_particles, const Vector3 &p_axis) = 0; - - virtual void particles_add_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance) = 0; - virtual void particles_remove_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance) = 0; - - virtual void update_particles() = 0; - - /* PARTICLES COLLISION */ - - virtual RID particles_collision_create() = 0; - virtual void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) = 0; - virtual void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) = 0; - virtual void particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius) = 0; //for spheres - virtual void particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) = 0; //for non-spheres - virtual void particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength) = 0; - virtual void particles_collision_set_attractor_directionality(RID p_particles_collision, float p_directionality) = 0; - virtual void particles_collision_set_attractor_attenuation(RID p_particles_collision, float p_curve) = 0; - virtual void particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) = 0; //for SDF and vector field, heightfield is dynamic - virtual void particles_collision_height_field_update(RID p_particles_collision) = 0; //for SDF and vector field - virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) = 0; //for SDF and vector field - virtual AABB particles_collision_get_aabb(RID p_particles_collision) const = 0; - virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 0; - virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const = 0; - - /* GLOBAL VARIABLES */ - - virtual void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) = 0; - virtual void global_variable_remove(const StringName &p_name) = 0; - virtual Vector<StringName> global_variable_get_list() const = 0; - - virtual void global_variable_set(const StringName &p_name, const Variant &p_value) = 0; - virtual void global_variable_set_override(const StringName &p_name, const Variant &p_value) = 0; - virtual Variant global_variable_get(const StringName &p_name) const = 0; - virtual RS::GlobalVariableType global_variable_get_type(const StringName &p_name) const = 0; - - virtual void global_variables_load_settings(bool p_load_textures = true) = 0; - virtual void global_variables_clear() = 0; - - virtual int32_t global_variables_instance_allocate(RID p_instance) = 0; - virtual void global_variables_instance_free(RID p_instance) = 0; - virtual void global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) = 0; - - /* RENDER TARGET */ - - enum RenderTargetFlags { - RENDER_TARGET_TRANSPARENT, - RENDER_TARGET_DIRECT_TO_SCREEN, - RENDER_TARGET_FLAG_MAX - }; - - virtual RID render_target_create() = 0; - virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) = 0; - virtual void render_target_set_size(RID p_render_target, int p_width, int p_height) = 0; - virtual RID render_target_get_texture(RID p_render_target) = 0; - virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0; - virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0; - virtual bool render_target_was_used(RID p_render_target) = 0; - virtual void render_target_set_as_unused(RID p_render_target) = 0; - - virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) = 0; - virtual bool render_target_is_clear_requested(RID p_render_target) = 0; - virtual Color render_target_get_clear_request_color(RID p_render_target) = 0; - virtual void render_target_disable_clear_request(RID p_render_target) = 0; - virtual void render_target_do_clear_request(RID p_render_target) = 0; - - virtual RS::InstanceType get_base_type(RID p_rid) const = 0; - virtual bool free(RID p_rid) = 0; - - virtual bool has_os_feature(const String &p_feature) const = 0; - - virtual void update_dirty_resources() = 0; - - virtual void set_debug_generate_wireframes(bool p_generate) = 0; - - virtual void render_info_begin_capture() = 0; - virtual void render_info_end_capture() = 0; - virtual int get_captured_render_info(RS::RenderInfo p_info) = 0; - - virtual int get_render_info(RS::RenderInfo p_info) = 0; - virtual String get_video_adapter_name() const = 0; - virtual String get_video_adapter_vendor() const = 0; - - static RasterizerStorage *base_singleton; - - void set_default_clear_color(const Color &p_color) { - default_clear_color = p_color; - } - - Color get_default_clear_color() const { - return default_clear_color; - } -#define TIMESTAMP_BEGIN() \ - { \ - if (RSG::storage->capturing_timestamps) \ - RSG::storage->capture_timestamps_begin(); \ - } - -#define RENDER_TIMESTAMP(m_text) \ - { \ - if (RSG::storage->capturing_timestamps) \ - RSG::storage->capture_timestamp(m_text); \ - } - - bool capturing_timestamps = false; - - virtual void capture_timestamps_begin() = 0; - virtual void capture_timestamp(const String &p_name) = 0; - virtual uint32_t get_captured_timestamps_count() const = 0; - virtual uint64_t get_captured_timestamps_frame() const = 0; - virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const = 0; - virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const = 0; - virtual String get_captured_timestamp_name(uint32_t p_index) const = 0; - - RasterizerStorage(); - virtual ~RasterizerStorage() {} -}; - -class RasterizerCanvas { -public: - static RasterizerCanvas *singleton; - - enum CanvasRectFlags { - - CANVAS_RECT_REGION = 1, - CANVAS_RECT_TILE = 2, - CANVAS_RECT_FLIP_H = 4, - CANVAS_RECT_FLIP_V = 8, - CANVAS_RECT_TRANSPOSE = 16, - CANVAS_RECT_CLIP_UV = 32, - CANVAS_RECT_IS_GROUP = 64, - }; - - struct Light { - bool enabled; - Color color; - Transform2D xform; - float height; - float energy; - float scale; - int z_min; - int z_max; - int layer_min; - int layer_max; - int item_mask; - int item_shadow_mask; - RS::CanvasLightMode mode; - RID texture; - Vector2 texture_offset; - RID canvas; - bool use_shadow; - int shadow_buffer_size; - RS::CanvasLightShadowFilter shadow_filter; - Color shadow_color; - float shadow_smooth; - - //void *texture_cache; // implementation dependent - Rect2 rect_cache; - Transform2D xform_cache; - float radius_cache; //used for shadow far plane - //CameraMatrix shadow_matrix_cache; - - Transform2D light_shader_xform; - //Vector2 light_shader_pos; - - Light *shadows_next_ptr; - Light *filter_next_ptr; - Light *next_ptr; - Light *mask_next_ptr; - - RID light_internal; - uint64_t version; - - int32_t render_index_cache; - - Light() { - version = 0; - enabled = true; - color = Color(1, 1, 1); - shadow_color = Color(0, 0, 0, 0); - height = 0; - z_min = -1024; - z_max = 1024; - layer_min = 0; - layer_max = 0; - item_mask = 1; - scale = 1.0; - energy = 1.0; - item_shadow_mask = 1; - mode = RS::CANVAS_LIGHT_MODE_ADD; - // texture_cache = nullptr; - next_ptr = nullptr; - mask_next_ptr = nullptr; - filter_next_ptr = nullptr; - use_shadow = false; - shadow_buffer_size = 2048; - shadow_filter = RS::CANVAS_LIGHT_FILTER_NONE; - shadow_smooth = 0.0; - render_index_cache = -1; - } - }; - - //easier wrap to avoid mistakes - - struct Item; - - typedef uint64_t PolygonID; - virtual PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) = 0; - virtual void free_polygon(PolygonID p_polygon) = 0; - - //also easier to wrap to avoid mistakes - struct Polygon { - PolygonID polygon_id; - Rect2 rect_cache; - - _FORCE_INLINE_ void create(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) { - ERR_FAIL_COND(polygon_id != 0); - { - uint32_t pc = p_points.size(); - const Vector2 *v2 = p_points.ptr(); - rect_cache.position = *v2; - for (uint32_t i = 1; i < pc; i++) { - rect_cache.expand_to(v2[i]); - } - } - polygon_id = singleton->request_polygon(p_indices, p_points, p_colors, p_uvs, p_bones, p_weights); - } - - _FORCE_INLINE_ Polygon() { polygon_id = 0; } - _FORCE_INLINE_ ~Polygon() { - if (polygon_id) { - singleton->free_polygon(polygon_id); - } - } - }; - - //item - - struct Item { - //commands are allocated in blocks of 4k to improve performance - //and cache coherence. - //blocks always grow but never shrink. - - struct CommandBlock { - enum { - MAX_SIZE = 4096 - }; - uint32_t usage; - uint8_t *memory; - }; - - struct Command { - enum Type { - - TYPE_RECT, - TYPE_NINEPATCH, - TYPE_POLYGON, - TYPE_PRIMITIVE, - TYPE_MESH, - TYPE_MULTIMESH, - TYPE_PARTICLES, - TYPE_TRANSFORM, - TYPE_CLIP_IGNORE, - }; - - Command *next; - Type type; - virtual ~Command() {} - }; - - struct CommandRect : public Command { - Rect2 rect; - Color modulate; - Rect2 source; - uint8_t flags; - - RID texture; - - CommandRect() { - flags = 0; - type = TYPE_RECT; - } - }; - - struct CommandNinePatch : public Command { - Rect2 rect; - Rect2 source; - float margin[4]; - bool draw_center; - Color color; - RS::NinePatchAxisMode axis_x; - RS::NinePatchAxisMode axis_y; - - RID texture; - - CommandNinePatch() { - draw_center = true; - type = TYPE_NINEPATCH; - } - }; - - struct CommandPolygon : public Command { - RS::PrimitiveType primitive; - Polygon polygon; - - RID texture; - - CommandPolygon() { - type = TYPE_POLYGON; - } - }; - - struct CommandPrimitive : public Command { - uint32_t point_count; - Vector2 points[4]; - Vector2 uvs[4]; - Color colors[4]; - - RID texture; - - CommandPrimitive() { - type = TYPE_PRIMITIVE; - } - }; - - struct CommandMesh : public Command { - RID mesh; - Transform2D transform; - Color modulate; - - RID texture; - - CommandMesh() { type = TYPE_MESH; } - }; - - struct CommandMultiMesh : public Command { - RID multimesh; - - RID texture; - - CommandMultiMesh() { type = TYPE_MULTIMESH; } - }; - - struct CommandParticles : public Command { - RID particles; - - RID texture; - - CommandParticles() { type = TYPE_PARTICLES; } - }; - - struct CommandTransform : public Command { - Transform2D xform; - CommandTransform() { type = TYPE_TRANSFORM; } - }; - - struct CommandClipIgnore : public Command { - bool ignore; - CommandClipIgnore() { - type = TYPE_CLIP_IGNORE; - ignore = false; - } - }; - - struct ViewportRender { - RenderingServer *owner; - void *udata; - Rect2 rect; - }; - - Transform2D xform; - bool clip; - bool visible; - bool behind; - bool update_when_visible; - - struct CanvasGroup { - RS::CanvasGroupMode mode; - bool fit_empty; - float fit_margin; - bool blur_mipmaps; - float clear_margin; - }; - - CanvasGroup *canvas_group = nullptr; - int light_mask; - int z_final; - - mutable bool custom_rect; - mutable bool rect_dirty; - mutable Rect2 rect; - RID material; - RID skeleton; - - Item *next; - - struct CopyBackBuffer { - Rect2 rect; - Rect2 screen_rect; - bool full; - }; - CopyBackBuffer *copy_back_buffer; - - Color final_modulate; - Transform2D final_transform; - Rect2 final_clip_rect; - Item *final_clip_owner; - Item *material_owner; - Item *canvas_group_owner; - ViewportRender *vp_render; - bool distance_field; - bool light_masked; - - Rect2 global_rect_cache; - - const Rect2 &get_rect() const { - if (custom_rect || (!rect_dirty && !update_when_visible)) { - return rect; - } - - //must update rect - - if (commands == nullptr) { - rect = Rect2(); - rect_dirty = false; - return rect; - } - - Transform2D xf; - bool found_xform = false; - bool first = true; - - const Item::Command *c = commands; - - while (c) { - Rect2 r; - - switch (c->type) { - case Item::Command::TYPE_RECT: { - const Item::CommandRect *crect = static_cast<const Item::CommandRect *>(c); - r = crect->rect; - - } break; - case Item::Command::TYPE_NINEPATCH: { - const Item::CommandNinePatch *style = static_cast<const Item::CommandNinePatch *>(c); - r = style->rect; - } break; - - case Item::Command::TYPE_POLYGON: { - const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c); - r = polygon->polygon.rect_cache; - } break; - case Item::Command::TYPE_PRIMITIVE: { - const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c); - for (uint32_t j = 0; j < primitive->point_count; j++) { - if (j == 0) { - r.position = primitive->points[0]; - } else { - r.expand_to(primitive->points[j]); - } - } - } break; - case Item::Command::TYPE_MESH: { - const Item::CommandMesh *mesh = static_cast<const Item::CommandMesh *>(c); - AABB aabb = RasterizerStorage::base_singleton->mesh_get_aabb(mesh->mesh, RID()); - - r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); - - } break; - case Item::Command::TYPE_MULTIMESH: { - const Item::CommandMultiMesh *multimesh = static_cast<const Item::CommandMultiMesh *>(c); - AABB aabb = RasterizerStorage::base_singleton->multimesh_get_aabb(multimesh->multimesh); - - r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); - - } break; - case Item::Command::TYPE_PARTICLES: { - const Item::CommandParticles *particles_cmd = static_cast<const Item::CommandParticles *>(c); - if (particles_cmd->particles.is_valid()) { - AABB aabb = RasterizerStorage::base_singleton->particles_get_aabb(particles_cmd->particles); - r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); - } - - } break; - case Item::Command::TYPE_TRANSFORM: { - const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c); - xf = transform->xform; - found_xform = true; - [[fallthrough]]; - } - default: { - c = c->next; - continue; - } - } - - if (found_xform) { - r = xf.xform(r); - found_xform = false; - } - - if (first) { - rect = r; - first = false; - } else { - rect = rect.merge(r); - } - c = c->next; - } - - rect_dirty = false; - return rect; - } - - Command *commands; - Command *last_command; - Vector<CommandBlock> blocks; - uint32_t current_block; - - template <class T> - T *alloc_command() { - T *command; - if (commands == nullptr) { - // As the most common use case of canvas items is to - // use only one command, the first is done with it's - // own allocation. The rest of them use blocks. - command = memnew(T); - command->next = nullptr; - commands = command; - last_command = command; - } else { - //Subsequent commands go into a block. - - while (true) { - if (unlikely(current_block == (uint32_t)blocks.size())) { - // If we need more blocks, we allocate them - // (they won't be freed until this CanvasItem is - // deleted, though). - CommandBlock cb; - cb.memory = (uint8_t *)memalloc(CommandBlock::MAX_SIZE); - cb.usage = 0; - blocks.push_back(cb); - } - - CommandBlock *c = &blocks.write[current_block]; - size_t space_left = CommandBlock::MAX_SIZE - c->usage; - if (space_left < sizeof(T)) { - current_block++; - continue; - } - - //allocate block and add to the linked list - void *memory = c->memory + c->usage; - command = memnew_placement(memory, T); - command->next = nullptr; - last_command->next = command; - last_command = command; - c->usage += sizeof(T); - break; - } - } - - rect_dirty = true; - return command; - } - - void clear() { - // The first one is always allocated on heap - // the rest go in the blocks - Command *c = commands; - while (c) { - Command *n = c->next; - if (c == commands) { - memdelete(commands); - commands = nullptr; - } else { - c->~Command(); - } - c = n; - } - { - uint32_t cbc = MIN((current_block + 1), (uint32_t)blocks.size()); - CommandBlock *blockptr = blocks.ptrw(); - for (uint32_t i = 0; i < cbc; i++) { - blockptr[i].usage = 0; - } - } - - last_command = nullptr; - commands = nullptr; - current_block = 0; - clip = false; - rect_dirty = true; - final_clip_owner = nullptr; - material_owner = nullptr; - light_masked = false; - } - - RS::CanvasItemTextureFilter texture_filter; - RS::CanvasItemTextureRepeat texture_repeat; - - Item() { - commands = nullptr; - last_command = nullptr; - current_block = 0; - light_mask = 1; - vp_render = nullptr; - next = nullptr; - final_clip_owner = nullptr; - canvas_group_owner = nullptr; - clip = false; - final_modulate = Color(1, 1, 1, 1); - visible = true; - rect_dirty = true; - custom_rect = false; - behind = false; - material_owner = nullptr; - copy_back_buffer = nullptr; - distance_field = false; - light_masked = false; - update_when_visible = false; - z_final = 0; - texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT; - texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT; - } - virtual ~Item() { - clear(); - for (int i = 0; i < blocks.size(); i++) { - memfree(blocks[i].memory); - } - if (copy_back_buffer) { - memdelete(copy_back_buffer); - } - } - }; - - virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) = 0; - virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) = 0; - - struct LightOccluderInstance { - bool enabled; - RID canvas; - RID polygon; - RID occluder; - Rect2 aabb_cache; - Transform2D xform; - Transform2D xform_cache; - int light_mask; - RS::CanvasOccluderPolygonCullMode cull_cache; - - LightOccluderInstance *next; - - LightOccluderInstance() { - enabled = true; - next = nullptr; - light_mask = 1; - cull_cache = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; - } - }; - - virtual RID light_create() = 0; - virtual void light_set_texture(RID p_rid, RID p_texture) = 0; - virtual void light_set_use_shadow(RID p_rid, bool p_enable) = 0; - virtual void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) = 0; - - virtual RID occluder_polygon_create() = 0; - virtual void occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines) = 0; - virtual void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) = 0; - virtual void set_shadow_texture_size(int p_size) = 0; - - virtual void draw_window_margins(int *p_margins, RID *p_margin_textures) = 0; - - virtual bool free(RID p_rid) = 0; - virtual void update() = 0; - - RasterizerCanvas() { singleton = this; } - virtual ~RasterizerCanvas() {} -}; - -class Rasterizer { -protected: - static Rasterizer *(*_create_func)(); - -public: - static Rasterizer *create(); - - virtual RasterizerStorage *get_storage() = 0; - virtual RasterizerCanvas *get_canvas() = 0; - virtual RasterizerScene *get_scene() = 0; - - virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) = 0; - - virtual void initialize() = 0; - virtual void begin_frame(double frame_step) = 0; - - struct BlitToScreen { - RID render_target; - Rect2i rect; - //lens distorted parameters for VR should go here - }; - - virtual void prepare_for_blitting_render_targets() = 0; - virtual void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0; - - virtual void end_frame(bool p_swap_buffers) = 0; - virtual void finalize() = 0; - virtual uint64_t get_frame_number() const = 0; - virtual float get_frame_delta_time() const = 0; - - virtual bool is_low_end() const = 0; - - virtual ~Rasterizer() {} -}; - -#endif // RASTERIZER_H diff --git a/servers/rendering/rasterizer_rd/light_cluster_builder.cpp b/servers/rendering/rasterizer_rd/light_cluster_builder.cpp deleted file mode 100644 index efb48e6df7..0000000000 --- a/servers/rendering/rasterizer_rd/light_cluster_builder.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/*************************************************************************/ -/* light_cluster_builder.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "light_cluster_builder.h" - -void LightClusterBuilder::begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection) { - view_xform = p_view_transform; - projection = p_cam_projection; - z_near = -projection.get_z_near(); - z_far = -projection.get_z_far(); - - //reset counts - light_count = 0; - refprobe_count = 0; - decal_count = 0; - item_count = 0; - sort_id_count = 0; -} - -void LightClusterBuilder::bake_cluster() { - float slice_depth = (z_near - z_far) / depth; - - uint8_t *cluster_dataw = cluster_data.ptrw(); - Cell *cluster_data_ptr = (Cell *)cluster_dataw; - //clear the cluster - zeromem(cluster_data_ptr, (width * height * depth * sizeof(Cell))); - - /* Step 1, create cell positions and count them */ - - for (uint32_t i = 0; i < item_count; i++) { - const Item &item = items[i]; - - int from_slice = Math::floor((z_near - (item.aabb.position.z + item.aabb.size.z)) / slice_depth); - int to_slice = Math::floor((z_near - item.aabb.position.z) / slice_depth); - - if (from_slice >= (int)depth || to_slice < 0) { - continue; //sorry no go - } - - from_slice = MAX(0, from_slice); - to_slice = MIN((int)depth - 1, to_slice); - - for (int j = from_slice; j <= to_slice; j++) { - Vector3 min = item.aabb.position; - Vector3 max = item.aabb.position + item.aabb.size; - - float limit_near = MIN((z_near - slice_depth * j), max.z); - float limit_far = MAX((z_near - slice_depth * (j + 1)), min.z); - - max.z = limit_near; - min.z = limit_near; - - Vector3 proj_min = projection.xform(min); - Vector3 proj_max = projection.xform(max); - - int near_from_x = int(Math::floor((proj_min.x * 0.5 + 0.5) * width)); - int near_from_y = int(Math::floor((-proj_max.y * 0.5 + 0.5) * height)); - int near_to_x = int(Math::floor((proj_max.x * 0.5 + 0.5) * width)); - int near_to_y = int(Math::floor((-proj_min.y * 0.5 + 0.5) * height)); - - max.z = limit_far; - min.z = limit_far; - - proj_min = projection.xform(min); - proj_max = projection.xform(max); - - int far_from_x = int(Math::floor((proj_min.x * 0.5 + 0.5) * width)); - int far_from_y = int(Math::floor((-proj_max.y * 0.5 + 0.5) * height)); - int far_to_x = int(Math::floor((proj_max.x * 0.5 + 0.5) * width)); - int far_to_y = int(Math::floor((-proj_min.y * 0.5 + 0.5) * height)); - - //print_line(itos(j) + " near - " + Vector2i(near_from_x, near_from_y) + " -> " + Vector2i(near_to_x, near_to_y)); - //print_line(itos(j) + " far - " + Vector2i(far_from_x, far_from_y) + " -> " + Vector2i(far_to_x, far_to_y)); - - int from_x = MIN(near_from_x, far_from_x); - int from_y = MIN(near_from_y, far_from_y); - int to_x = MAX(near_to_x, far_to_x); - int to_y = MAX(near_to_y, far_to_y); - - if (from_x >= (int)width || to_x < 0 || from_y >= (int)height || to_y < 0) { - continue; - } - - int sx = MAX(0, from_x); - int sy = MAX(0, from_y); - int dx = MIN((int)width - 1, to_x); - int dy = MIN((int)height - 1, to_y); - - //print_line(itos(j) + " - " + Vector2i(sx, sy) + " -> " + Vector2i(dx, dy)); - - for (int x = sx; x <= dx; x++) { - for (int y = sy; y <= dy; y++) { - uint32_t offset = j * (width * height) + y * width + x; - - if (unlikely(sort_id_count == sort_id_max)) { - sort_id_max = nearest_power_of_2_templated(sort_id_max + 1); - sort_ids = (SortID *)memrealloc(sort_ids, sizeof(SortID) * sort_id_max); - if (ids.size()) { - ids.resize(sort_id_max); - RD::get_singleton()->free(items_buffer); - items_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * sort_id_max); - } - } - - sort_ids[sort_id_count].cell_index = offset; - sort_ids[sort_id_count].item_index = item.index; - sort_ids[sort_id_count].item_type = item.type; - - sort_id_count++; - - //for now, only count - cluster_data_ptr[offset].item_pointers[item.type]++; - //print_line("at offset " + itos(offset) + " value: " + itos(cluster_data_ptr[offset].item_pointers[item.type])); - } - } - } - } - - /* Step 2, Assign pointers (and reset counters) */ - - uint32_t offset = 0; - for (uint32_t i = 0; i < (width * height * depth); i++) { - for (int j = 0; j < ITEM_TYPE_MAX; j++) { - uint32_t count = cluster_data_ptr[i].item_pointers[j]; //save count - cluster_data_ptr[i].item_pointers[j] = offset; //replace count by pointer - offset += count; //increase offset by count; - } - } - - //print_line("offset: " + itos(offset)); - /* Step 3, Place item lists */ - - uint32_t *ids_ptr = ids.ptrw(); - - for (uint32_t i = 0; i < sort_id_count; i++) { - const SortID &id = sort_ids[i]; - Cell &cell = cluster_data_ptr[id.cell_index]; - uint32_t pointer = cell.item_pointers[id.item_type] & POINTER_MASK; - uint32_t counter = cell.item_pointers[id.item_type] >> COUNTER_SHIFT; - ids_ptr[pointer + counter] = id.item_index; - - cell.item_pointers[id.item_type] = pointer | ((counter + 1) << COUNTER_SHIFT); - } - - RD::get_singleton()->texture_update(cluster_texture, 0, cluster_data, true); - RD::get_singleton()->buffer_update(items_buffer, 0, offset * sizeof(uint32_t), ids_ptr, true); -} - -void LightClusterBuilder::setup(uint32_t p_width, uint32_t p_height, uint32_t p_depth) { - if (width == p_width && height == p_height && depth == p_depth) { - return; - } - if (cluster_texture.is_valid()) { - RD::get_singleton()->free(cluster_texture); - } - - width = p_width; - height = p_height; - depth = p_depth; - - cluster_data.resize(width * height * depth * sizeof(Cell)); - - { - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R32G32B32A32_UINT; - tf.type = RD::TEXTURE_TYPE_3D; - tf.width = width; - tf.height = height; - tf.depth = depth; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - - cluster_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); - } -} - -RID LightClusterBuilder::get_cluster_texture() const { - return cluster_texture; -} - -RID LightClusterBuilder::get_cluster_indices_buffer() const { - return items_buffer; -} - -LightClusterBuilder::LightClusterBuilder() { - //initialize accumulators to something - lights = (LightData *)memalloc(sizeof(LightData) * 1024); - light_max = 1024; - - refprobes = (OrientedBoxData *)memalloc(sizeof(OrientedBoxData) * 1024); - refprobe_max = 1024; - - decals = (OrientedBoxData *)memalloc(sizeof(OrientedBoxData) * 1024); - decal_max = 1024; - - items = (Item *)memalloc(sizeof(Item) * 1024); - item_max = 1024; - - sort_ids = (SortID *)memalloc(sizeof(SortID) * 1024); - ids.resize(2014); - items_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 1024); - item_max = 1024; -} - -LightClusterBuilder::~LightClusterBuilder() { - if (cluster_data.size()) { - RD::get_singleton()->free(cluster_texture); - } - - if (lights) { - memfree(lights); - } - if (refprobes) { - memfree(refprobes); - } - if (decals) { - memfree(decals); - } - if (items) { - memfree(items); - } - if (sort_ids) { - memfree(sort_ids); - RD::get_singleton()->free(items_buffer); - } -} diff --git a/servers/rendering/rasterizer_rd/light_cluster_builder.h b/servers/rendering/rasterizer_rd/light_cluster_builder.h deleted file mode 100644 index b1da083dad..0000000000 --- a/servers/rendering/rasterizer_rd/light_cluster_builder.h +++ /dev/null @@ -1,290 +0,0 @@ -/*************************************************************************/ -/* light_cluster_builder.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef LIGHT_CLUSTER_BUILDER_H -#define LIGHT_CLUSTER_BUILDER_H - -#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h" - -class LightClusterBuilder { -public: - enum LightType { - LIGHT_TYPE_OMNI, - LIGHT_TYPE_SPOT - }; - - enum ItemType { - ITEM_TYPE_OMNI_LIGHT, - ITEM_TYPE_SPOT_LIGHT, - ITEM_TYPE_REFLECTION_PROBE, - ITEM_TYPE_DECAL, - ITEM_TYPE_MAX //should always be 4 - }; - - enum { - COUNTER_SHIFT = 20, //one million total ids - POINTER_MASK = (1 << COUNTER_SHIFT) - 1, - COUNTER_MASK = 0xfff // 4096 items per cell - }; - -private: - struct LightData { - float position[3]; - uint32_t type; - float radius; - float spot_aperture; - uint32_t pad[2]; - }; - - uint32_t light_count = 0; - uint32_t light_max = 0; - LightData *lights = nullptr; - - struct OrientedBoxData { - float position[3]; - uint32_t pad; - float x_axis[3]; - uint32_t pad2; - float y_axis[3]; - uint32_t pad3; - float z_axis[3]; - uint32_t pad4; - }; - - uint32_t refprobe_count = 0; - uint32_t refprobe_max = 0; - OrientedBoxData *refprobes = nullptr; - - uint32_t decal_count = 0; - uint32_t decal_max = 0; - OrientedBoxData *decals = nullptr; - - struct Item { - AABB aabb; - ItemType type; - uint32_t index; - }; - - Item *items = nullptr; - uint32_t item_count = 0; - uint32_t item_max = 0; - - uint32_t width = 0; - uint32_t height = 0; - uint32_t depth = 0; - - struct Cell { - uint32_t item_pointers[ITEM_TYPE_MAX]; - }; - - Vector<uint8_t> cluster_data; - RID cluster_texture; - - struct SortID { - uint32_t cell_index; - uint32_t item_index; - ItemType item_type; - }; - - SortID *sort_ids = nullptr; - Vector<uint32_t> ids; - uint32_t sort_id_count = 0; - uint32_t sort_id_max = 0; - RID items_buffer; - - Transform view_xform; - CameraMatrix projection; - float z_far = 0; - float z_near = 0; - - _FORCE_INLINE_ void _add_item(const AABB &p_aabb, ItemType p_type, uint32_t p_index) { - if (unlikely(item_count == item_max)) { - item_max = nearest_power_of_2_templated(item_max + 1); - items = (Item *)memrealloc(items, sizeof(Item) * item_max); - } - - Item &item = items[item_count]; - item.aabb = p_aabb; - item.index = p_index; - item.type = p_type; - item_count++; - } - -public: - void begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection); - - _FORCE_INLINE_ void add_light(LightType p_type, const Transform &p_transform, float p_radius, float p_spot_aperture) { - if (unlikely(light_count == light_max)) { - light_max = nearest_power_of_2_templated(light_max + 1); - lights = (LightData *)memrealloc(lights, sizeof(LightData) * light_max); - } - - LightData &ld = lights[light_count]; - ld.type = p_type; - ld.position[0] = p_transform.origin.x; - ld.position[1] = p_transform.origin.y; - ld.position[2] = p_transform.origin.z; - ld.radius = p_radius; - ld.spot_aperture = p_spot_aperture; - - Transform xform = view_xform * p_transform; - - ld.radius *= xform.basis.get_uniform_scale(); - - AABB aabb; - - switch (p_type) { - case LIGHT_TYPE_OMNI: { - aabb.position = xform.origin; - aabb.size = Vector3(ld.radius, ld.radius, ld.radius); - aabb.position -= aabb.size; - aabb.size *= 2.0; - - _add_item(aabb, ITEM_TYPE_OMNI_LIGHT, light_count); - } break; - case LIGHT_TYPE_SPOT: { - float r = ld.radius; - real_t len = Math::tan(Math::deg2rad(ld.spot_aperture)) * r; - - aabb.position = xform.origin; - aabb.expand_to(xform.xform(Vector3(len, len, -r))); - aabb.expand_to(xform.xform(Vector3(-len, len, -r))); - aabb.expand_to(xform.xform(Vector3(-len, -len, -r))); - aabb.expand_to(xform.xform(Vector3(len, -len, -r))); - _add_item(aabb, ITEM_TYPE_SPOT_LIGHT, light_count); - } break; - } - - light_count++; - } - - _FORCE_INLINE_ void add_reflection_probe(const Transform &p_transform, const Vector3 &p_half_extents) { - if (unlikely(refprobe_count == refprobe_max)) { - refprobe_max = nearest_power_of_2_templated(refprobe_max + 1); - refprobes = (OrientedBoxData *)memrealloc(refprobes, sizeof(OrientedBoxData) * refprobe_max); - } - - Transform xform = view_xform * p_transform; - - OrientedBoxData &rp = refprobes[refprobe_count]; - Vector3 origin = xform.origin; - rp.position[0] = origin.x; - rp.position[1] = origin.y; - rp.position[2] = origin.z; - - Vector3 x_axis = xform.basis.get_axis(0) * p_half_extents.x; - rp.x_axis[0] = x_axis.x; - rp.x_axis[1] = x_axis.y; - rp.x_axis[2] = x_axis.z; - - Vector3 y_axis = xform.basis.get_axis(1) * p_half_extents.y; - rp.y_axis[0] = y_axis.x; - rp.y_axis[1] = y_axis.y; - rp.y_axis[2] = y_axis.z; - - Vector3 z_axis = xform.basis.get_axis(2) * p_half_extents.z; - rp.z_axis[0] = z_axis.x; - rp.z_axis[1] = z_axis.y; - rp.z_axis[2] = z_axis.z; - - AABB aabb; - - aabb.position = origin + x_axis + y_axis + z_axis; - aabb.expand_to(origin + x_axis + y_axis - z_axis); - aabb.expand_to(origin + x_axis - y_axis + z_axis); - aabb.expand_to(origin + x_axis - y_axis - z_axis); - aabb.expand_to(origin - x_axis + y_axis + z_axis); - aabb.expand_to(origin - x_axis + y_axis - z_axis); - aabb.expand_to(origin - x_axis - y_axis + z_axis); - aabb.expand_to(origin - x_axis - y_axis - z_axis); - - _add_item(aabb, ITEM_TYPE_REFLECTION_PROBE, refprobe_count); - - refprobe_count++; - } - - _FORCE_INLINE_ void add_decal(const Transform &p_transform, const Vector3 &p_half_extents) { - if (unlikely(decal_count == decal_max)) { - decal_max = nearest_power_of_2_templated(decal_max + 1); - decals = (OrientedBoxData *)memrealloc(decals, sizeof(OrientedBoxData) * decal_max); - } - - Transform xform = view_xform * p_transform; - - OrientedBoxData &dc = decals[decal_count]; - - Vector3 origin = xform.origin; - dc.position[0] = origin.x; - dc.position[1] = origin.y; - dc.position[2] = origin.z; - - Vector3 x_axis = xform.basis.get_axis(0) * p_half_extents.x; - dc.x_axis[0] = x_axis.x; - dc.x_axis[1] = x_axis.y; - dc.x_axis[2] = x_axis.z; - - Vector3 y_axis = xform.basis.get_axis(1) * p_half_extents.y; - dc.y_axis[0] = y_axis.x; - dc.y_axis[1] = y_axis.y; - dc.y_axis[2] = y_axis.z; - - Vector3 z_axis = xform.basis.get_axis(2) * p_half_extents.z; - dc.z_axis[0] = z_axis.x; - dc.z_axis[1] = z_axis.y; - dc.z_axis[2] = z_axis.z; - - AABB aabb; - - aabb.position = origin + x_axis + y_axis + z_axis; - aabb.expand_to(origin + x_axis + y_axis - z_axis); - aabb.expand_to(origin + x_axis - y_axis + z_axis); - aabb.expand_to(origin + x_axis - y_axis - z_axis); - aabb.expand_to(origin - x_axis + y_axis + z_axis); - aabb.expand_to(origin - x_axis + y_axis - z_axis); - aabb.expand_to(origin - x_axis - y_axis + z_axis); - aabb.expand_to(origin - x_axis - y_axis - z_axis); - - _add_item(aabb, ITEM_TYPE_DECAL, decal_count); - - decal_count++; - } - - void bake_cluster(); - - void setup(uint32_t p_width, uint32_t p_height, uint32_t p_depth); - - RID get_cluster_texture() const; - RID get_cluster_indices_buffer() const; - - LightClusterBuilder(); - ~LightClusterBuilder(); -}; - -#endif // LIGHT_CLUSTER_BUILDER_H diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h deleted file mode 100644 index 566022ae5b..0000000000 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h +++ /dev/null @@ -1,594 +0,0 @@ -/*************************************************************************/ -/* rasterizer_scene_high_end_rd.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RASTERIZER_SCENE_HIGHEND_RD_H -#define RASTERIZER_SCENE_HIGHEND_RD_H - -#include "servers/rendering/rasterizer_rd/rasterizer_scene_rd.h" -#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h" -#include "servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h" -#include "servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl.gen.h" - -class RasterizerSceneHighEndRD : public RasterizerSceneRD { - enum { - SCENE_UNIFORM_SET = 0, - RADIANCE_UNIFORM_SET = 1, - VIEW_DEPENDANT_UNIFORM_SET = 2, - RENDER_BUFFERS_UNIFORM_SET = 3, - TRANSFORMS_UNIFORM_SET = 4, - MATERIAL_UNIFORM_SET = 5 - }; - - enum { - SDFGI_MAX_CASCADES = 8, - MAX_GI_PROBES = 8 - }; - - /* Scene Shader */ - - enum ShaderVersion { - SHADER_VERSION_DEPTH_PASS, - SHADER_VERSION_DEPTH_PASS_DP, - SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, - SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, - SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL, - SHADER_VERSION_DEPTH_PASS_WITH_SDF, - SHADER_VERSION_COLOR_PASS, - SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, - SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, - SHADER_VERSION_LIGHTMAP_COLOR_PASS, - SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, - SHADER_VERSION_MAX - }; - - struct { - SceneHighEndShaderRD scene_shader; - ShaderCompilerRD compiler; - } shader; - - RasterizerStorageRD *storage; - - /* Material */ - - struct ShaderData : public RasterizerStorageRD::ShaderData { - enum BlendMode { //used internally - BLEND_MODE_MIX, - BLEND_MODE_ADD, - BLEND_MODE_SUB, - BLEND_MODE_MUL, - }; - - enum DepthDraw { - DEPTH_DRAW_DISABLED, - DEPTH_DRAW_OPAQUE, - DEPTH_DRAW_ALWAYS - }; - - enum DepthTest { - DEPTH_TEST_DISABLED, - DEPTH_TEST_ENABLED - }; - - enum Cull { - CULL_DISABLED, - CULL_FRONT, - CULL_BACK - }; - - enum CullVariant { - CULL_VARIANT_NORMAL, - CULL_VARIANT_REVERSED, - CULL_VARIANT_DOUBLE_SIDED, - CULL_VARIANT_MAX - - }; - - bool valid; - RID version; - uint32_t vertex_input_mask; - RenderPipelineVertexFormatCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX]; - - String path; - - Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; - Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; - - Vector<uint32_t> ubo_offsets; - uint32_t ubo_size; - - String code; - Map<StringName, RID> default_texture_params; - - DepthDraw depth_draw; - DepthTest depth_test; - - bool uses_point_size; - bool uses_alpha; - bool uses_blend_alpha; - bool uses_depth_pre_pass; - bool uses_discard; - bool uses_roughness; - bool uses_normal; - - bool unshaded; - bool uses_vertex; - bool uses_sss; - bool uses_transmittance; - bool uses_screen_texture; - bool uses_depth_texture; - bool uses_normal_texture; - bool uses_time; - bool writes_modelview_or_projection; - bool uses_world_coordinates; - - uint64_t last_pass = 0; - uint32_t index = 0; - - virtual void set_code(const String &p_Code); - virtual void set_default_texture_param(const StringName &p_name, RID p_texture); - virtual void get_param_list(List<PropertyInfo> *p_param_list) const; - void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const; - - virtual bool is_param_texture(const StringName &p_param) const; - virtual bool is_animated() const; - virtual bool casts_shadows() const; - virtual Variant get_default_parameter(const StringName &p_parameter) const; - ShaderData(); - virtual ~ShaderData(); - }; - - RasterizerStorageRD::ShaderData *_create_shader_func(); - static RasterizerStorageRD::ShaderData *_create_shader_funcs() { - return static_cast<RasterizerSceneHighEndRD *>(singleton)->_create_shader_func(); - } - - struct MaterialData : public RasterizerStorageRD::MaterialData { - uint64_t last_frame; - ShaderData *shader_data; - RID uniform_buffer; - RID uniform_set; - Vector<RID> texture_cache; - Vector<uint8_t> ubo_data; - uint64_t last_pass = 0; - uint32_t index = 0; - RID next_pass; - uint8_t priority; - virtual void set_render_priority(int p_priority); - virtual void set_next_pass(RID p_pass); - virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); - virtual ~MaterialData(); - }; - - RasterizerStorageRD::MaterialData *_create_material_func(ShaderData *p_shader); - static RasterizerStorageRD::MaterialData *_create_material_funcs(RasterizerStorageRD::ShaderData *p_shader) { - return static_cast<RasterizerSceneHighEndRD *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader)); - } - - /* Push Constant */ - - struct PushConstant { - uint32_t index; - uint32_t pad; - float bake_uv2_offset[2]; - }; - - /* Framebuffer */ - - struct RenderBufferDataHighEnd : public RenderBufferData { - //for rendering, may be MSAAd - - RID color; - RID depth; - RID specular; - RID normal_roughness_buffer; - RID giprobe_buffer; - - RID ambient_buffer; - RID reflection_buffer; - - RS::ViewportMSAA msaa; - RD::TextureSamples texture_samples; - - RID color_msaa; - RID depth_msaa; - RID specular_msaa; - RID normal_roughness_buffer_msaa; - RID roughness_buffer_msaa; - RID giprobe_buffer_msaa; - - RID depth_fb; - RID depth_normal_roughness_fb; - RID depth_normal_roughness_giprobe_fb; - RID color_fb; - RID color_specular_fb; - RID specular_only_fb; - int width, height; - - RID render_sdfgi_uniform_set; - void ensure_specular(); - void ensure_gi(); - void ensure_giprobe(); - void clear(); - virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa); - - RID uniform_set; - - ~RenderBufferDataHighEnd(); - }; - - virtual RenderBufferData *_create_render_buffer_data(); - void _allocate_normal_roughness_texture(RenderBufferDataHighEnd *rb); - - RID shadow_sampler; - RID render_base_uniform_set; - RID view_dependant_uniform_set; - - uint64_t lightmap_texture_array_version = 0xFFFFFFFF; - - virtual void _base_uniforms_changed(); - void _render_buffers_clear_uniform_set(RenderBufferDataHighEnd *rb); - virtual void _render_buffers_uniform_set_changed(RID p_render_buffers); - virtual RID _render_buffers_get_normal_texture(RID p_render_buffers); - virtual RID _render_buffers_get_ambient_texture(RID p_render_buffers); - virtual RID _render_buffers_get_reflection_texture(RID p_render_buffers); - - void _update_render_base_uniform_set(); - void _setup_view_dependant_uniform_set(RID p_shadow_atlas, RID p_reflection_atlas, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count); - void _update_render_buffers_uniform_set(RID p_render_buffers); - - struct LightmapData { - float normal_xform[12]; - }; - - struct LightmapCaptureData { - float sh[9 * 4]; - }; - - enum { - INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6, - INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7, - INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8, - INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9, - INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10, - INSTANCE_DATA_FLAG_USE_GIPROBE = 1 << 11, - INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12, - INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13, - INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14, - INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15, - INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT = 16, - INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_MASK = 0x7, - INSTANCE_DATA_FLAG_SKELETON = 1 << 19, - }; - - struct InstanceData { - float transform[16]; - float normal_transform[16]; - uint32_t flags; - uint32_t instance_uniforms_ofs; //instance_offset in instancing/skeleton buffer - uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap) - uint32_t mask; - float lightmap_uv_scale[4]; - }; - - struct SceneState { - struct UBO { - float projection_matrix[16]; - float inv_projection_matrix[16]; - - float camera_matrix[16]; - float inv_camera_matrix[16]; - - float viewport_size[2]; - float screen_pixel_size[2]; - - float directional_penumbra_shadow_kernel[128]; //32 vec4s - float directional_soft_shadow_kernel[128]; - float penumbra_shadow_kernel[128]; - float soft_shadow_kernel[128]; - - uint32_t directional_penumbra_shadow_samples; - uint32_t directional_soft_shadow_samples; - uint32_t penumbra_shadow_samples; - uint32_t soft_shadow_samples; - - float ambient_light_color_energy[4]; - - float ambient_color_sky_mix; - uint32_t use_ambient_light; - uint32_t use_ambient_cubemap; - uint32_t use_reflection_cubemap; - - float radiance_inverse_xform[12]; - - float shadow_atlas_pixel_size[2]; - float directional_shadow_pixel_size[2]; - - uint32_t directional_light_count; - float dual_paraboloid_side; - float z_far; - float z_near; - - uint32_t ssao_enabled; - float ssao_light_affect; - float ssao_ao_affect; - uint32_t roughness_limiter_enabled; - - float roughness_limiter_amount; - float roughness_limiter_limit; - uint32_t roughness_limiter_pad[2]; - - float ao_color[4]; - - float sdf_to_bounds[16]; - - int32_t sdf_offset[3]; - uint32_t material_uv2_mode; - - int32_t sdf_size[3]; - uint32_t gi_upscale_for_msaa; - - uint32_t volumetric_fog_enabled; - float volumetric_fog_inv_length; - float volumetric_fog_detail_spread; - uint32_t volumetric_fog_pad; - - // Fog - uint32_t fog_enabled; - float fog_density; - float fog_height; - float fog_height_density; - - float fog_light_color[3]; - float fog_sun_scatter; - - float fog_aerial_perspective; - - float time; - float reflection_multiplier; - - uint32_t pancake_shadows; - }; - - UBO ubo; - - RID uniform_buffer; - - LightmapData *lightmaps; - uint32_t max_lightmaps; - RID lightmap_buffer; - - LightmapCaptureData *lightmap_captures; - uint32_t max_lightmap_captures; - RID lightmap_capture_buffer; - - RID instance_buffer; - InstanceData *instances; - uint32_t max_instances; - - bool used_screen_texture = false; - bool used_normal_texture = false; - bool used_depth_texture = false; - bool used_sss = false; - uint32_t current_shader_index = 0; - uint32_t current_material_index = 0; - - } scene_state; - - /* Render List */ - - struct RenderList { - int max_elements; - - struct Element { - RasterizerScene::InstanceBase *instance; - MaterialData *material; - union { - struct { - //from least significant to most significant in sort, TODO: should be endian swapped on big endian - uint64_t geometry_index : 20; - uint64_t material_index : 15; - uint64_t shader_index : 12; - uint64_t uses_instancing : 1; - uint64_t uses_forward_gi : 1; - uint64_t uses_lightmap : 1; - uint64_t depth_layer : 4; - uint64_t priority : 8; - }; - - uint64_t sort_key; - }; - uint32_t surface_index; - }; - - Element *base_elements; - Element **elements; - - int element_count; - int alpha_element_count; - - void clear() { - element_count = 0; - alpha_element_count = 0; - } - - //should eventually be replaced by radix - - struct SortByKey { - _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - return A->sort_key < B->sort_key; - } - }; - - void sort_by_key(bool p_alpha) { - SortArray<Element *, SortByKey> sorter; - if (p_alpha) { - sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); - } else { - sorter.sort(elements, element_count); - } - } - - struct SortByDepth { - _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - return A->instance->depth < B->instance->depth; - } - }; - - void sort_by_depth(bool p_alpha) { //used for shadows - - SortArray<Element *, SortByDepth> sorter; - if (p_alpha) { - sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); - } else { - sorter.sort(elements, element_count); - } - } - - struct SortByReverseDepthAndPriority { - _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - uint32_t layer_A = uint32_t(A->priority); - uint32_t layer_B = uint32_t(B->priority); - if (layer_A == layer_B) { - return A->instance->depth > B->instance->depth; - } else { - return layer_A < layer_B; - } - } - }; - - void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha - - SortArray<Element *, SortByReverseDepthAndPriority> sorter; - if (p_alpha) { - sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); - } else { - sorter.sort(elements, element_count); - } - } - - _FORCE_INLINE_ Element *add_element() { - if (element_count + alpha_element_count >= max_elements) { - return nullptr; - } - elements[element_count] = &base_elements[element_count]; - return elements[element_count++]; - } - - _FORCE_INLINE_ Element *add_alpha_element() { - if (element_count + alpha_element_count >= max_elements) { - return nullptr; - } - int idx = max_elements - alpha_element_count - 1; - elements[idx] = &base_elements[idx]; - alpha_element_count++; - return elements[idx]; - } - - void init() { - element_count = 0; - alpha_element_count = 0; - elements = memnew_arr(Element *, max_elements); - base_elements = memnew_arr(Element, max_elements); - for (int i = 0; i < max_elements; i++) { - elements[i] = &base_elements[i]; // assign elements - } - } - - RenderList() { - max_elements = 0; - } - - ~RenderList() { - memdelete_arr(elements); - memdelete_arr(base_elements); - } - }; - - RenderList render_list; - - static RasterizerSceneHighEndRD *singleton; - uint64_t render_pass; - double time; - RID default_shader; - RID default_material; - RID overdraw_material_shader; - RID overdraw_material; - RID wireframe_material_shader; - RID wireframe_material; - RID default_shader_rd; - RID default_shader_sdfgi_rd; - RID default_radiance_uniform_set; - RID default_render_buffers_uniform_set; - - RID default_vec4_xform_buffer; - RID default_vec4_xform_uniform_set; - - enum PassMode { - PASS_MODE_COLOR, - PASS_MODE_COLOR_SPECULAR, - PASS_MODE_COLOR_TRANSPARENT, - PASS_MODE_SHADOW, - PASS_MODE_SHADOW_DP, - PASS_MODE_DEPTH, - PASS_MODE_DEPTH_NORMAL_ROUGHNESS, - PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE, - PASS_MODE_DEPTH_MATERIAL, - PASS_MODE_SDF, - }; - - void _setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false); - void _setup_lightmaps(InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, const Transform &p_cam_transform); - - void _fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth, bool p_has_sdfgi = false, bool p_has_opaque_gi = false); - void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_radiance_uniform_set, RID p_render_buffers_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2()); - _FORCE_INLINE_ void _add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode, uint32_t p_geometry_index, bool p_using_sdfgi = false); - _FORCE_INLINE_ void _add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, RID p_material_rid, PassMode p_pass_mode, uint32_t p_geometry_index, bool p_using_sdfgi = false); - - void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, PassMode p_pass_mode, bool p_using_sdfgi = false); - - Map<Size2i, RID> sdfgi_framebuffer_size_cache; - -protected: - virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color); - virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake); - virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region); - virtual void _render_uv2(InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region); - virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, InstanceBase **p_cull_result, int p_cull_count, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture); - virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, InstanceBase **p_cull_result, int p_cull_count); - -public: - virtual void set_time(double p_time, double p_step); - - virtual bool free(RID p_rid); - - RasterizerSceneHighEndRD(RasterizerStorageRD *p_storage); - ~RasterizerSceneHighEndRD(); -}; -#endif // RASTERIZER_SCENE_HIGHEND_RD_H diff --git a/servers/rendering/rasterizer_rd/shaders/resolve.glsl b/servers/rendering/rasterizer_rd/shaders/resolve.glsl deleted file mode 100644 index 9429a66dc9..0000000000 --- a/servers/rendering/rasterizer_rd/shaders/resolve.glsl +++ /dev/null @@ -1,110 +0,0 @@ -#[compute] - -#version 450 - -VERSION_DEFINES - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - -#ifdef MODE_RESOLVE_GI -layout(set = 0, binding = 0) uniform sampler2DMS source_depth; -layout(set = 0, binding = 1) uniform sampler2DMS source_normal_roughness; - -layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D dest_depth; -layout(rgba8, set = 1, binding = 1) uniform restrict writeonly image2D dest_normal_roughness; - -#ifdef GIPROBE_RESOLVE -layout(set = 2, binding = 0) uniform usampler2DMS source_giprobe; -layout(rg8ui, set = 3, binding = 0) uniform restrict writeonly uimage2D dest_giprobe; -#endif - -#endif - -layout(push_constant, binding = 16, std430) uniform Params { - ivec2 screen_size; - int sample_count; - uint pad; -} -params; - -void main() { - // Pixel being shaded - ivec2 pos = ivec2(gl_GlobalInvocationID.xy); - if (any(greaterThanEqual(pos, params.screen_size))) { //too large, do nothing - return; - } - -#ifdef MODE_RESOLVE_GI - - float best_depth = 1e20; - vec4 best_normal_roughness = vec4(0.0); -#ifdef GIPROBE_RESOLVE - uvec2 best_giprobe; -#endif - -#if 0 - - for(int i=0;i<params.sample_count;i++) { - float depth = texelFetch(source_depth,pos,i).r; - if (depth < best_depth) { //use the depth closest to camera - best_depth = depth; - best_normal_roughness = texelFetch(source_normal_roughness,pos,i); - -#ifdef GIPROBE_RESOLVE - best_giprobe = texelFetch(source_giprobe,pos,i).rg; -#endif - } - } - -#else - - float depths[16]; - int depth_indices[16]; - int depth_amount[16]; - int depth_count = 0; - - for (int i = 0; i < params.sample_count; i++) { - float depth = texelFetch(source_depth, pos, i).r; - int depth_index = -1; - for (int j = 0; j < depth_count; j++) { - if (abs(depths[j] - depth) < 0.000001) { - depth_index = j; - break; - } - } - - if (depth_index == -1) { - depths[depth_count] = depth; - depth_indices[depth_count] = i; - depth_amount[depth_count] = 1; - depth_count += 1; - } else { - depth_amount[depth_index] += 1; - } - } - - int depth_least = 0xFFFF; - int best_index = 0; - for (int j = 0; j < depth_count; j++) { - if (depth_amount[j] < depth_least) { - best_index = depth_indices[j]; - depth_least = depth_amount[j]; - } - } - - best_depth = texelFetch(source_depth, pos, best_index).r; - best_normal_roughness = texelFetch(source_normal_roughness, pos, best_index); -#ifdef GIPROBE_RESOLVE - best_giprobe = texelFetch(source_giprobe, pos, best_index).rg; -#endif - -#endif - - imageStore(dest_depth, pos, vec4(best_depth)); - imageStore(dest_normal_roughness, pos, vec4(best_normal_roughness)); -#ifdef GIPROBE_RESOLVE - imageStore(dest_giprobe, pos, uvec4(best_giprobe, 0, 0)); -#endif - -#endif -} diff --git a/servers/rendering/rasterizer_rd/shaders/ssao.glsl b/servers/rendering/rasterizer_rd/shaders/ssao.glsl deleted file mode 100644 index 346338181a..0000000000 --- a/servers/rendering/rasterizer_rd/shaders/ssao.glsl +++ /dev/null @@ -1,249 +0,0 @@ -#[compute] - -#version 450 - -VERSION_DEFINES - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - -#define TWO_PI 6.283185307179586476925286766559 - -#ifdef SSAO_QUALITY_HIGH -#define NUM_SAMPLES (20) -#endif - -#ifdef SSAO_QUALITY_ULTRA -#define NUM_SAMPLES (48) -#endif - -#ifdef SSAO_QUALITY_LOW -#define NUM_SAMPLES (8) -#endif - -#if !defined(SSAO_QUALITY_LOW) && !defined(SSAO_QUALITY_HIGH) && !defined(SSAO_QUALITY_ULTRA) -#define NUM_SAMPLES (12) -#endif - -// If using depth mip levels, the log of the maximum pixel offset before we need to switch to a lower -// miplevel to maintain reasonable spatial locality in the cache -// If this number is too small (< 3), too many taps will land in the same pixel, and we'll get bad variance that manifests as flashing. -// If it is too high (> 5), we'll get bad performance because we're not using the MIP levels effectively -#define LOG_MAX_OFFSET (3) - -// This must be less than or equal to the MAX_MIP_LEVEL defined in SSAO.cpp -#define MAX_MIP_LEVEL (4) - -// This is the number of turns around the circle that the spiral pattern makes. This should be prime to prevent -// taps from lining up. This particular choice was tuned for NUM_SAMPLES == 9 - -const int ROTATIONS[] = int[]( - 1, 1, 2, 3, 2, 5, 2, 3, 2, - 3, 3, 5, 5, 3, 4, 7, 5, 5, 7, - 9, 8, 5, 5, 7, 7, 7, 8, 5, 8, - 11, 12, 7, 10, 13, 8, 11, 8, 7, 14, - 11, 11, 13, 12, 13, 19, 17, 13, 11, 18, - 19, 11, 11, 14, 17, 21, 15, 16, 17, 18, - 13, 17, 11, 17, 19, 18, 25, 18, 19, 19, - 29, 21, 19, 27, 31, 29, 21, 18, 17, 29, - 31, 31, 23, 18, 25, 26, 25, 23, 19, 34, - 19, 27, 21, 25, 39, 29, 17, 21, 27); - -//#define NUM_SPIRAL_TURNS (7) -const int NUM_SPIRAL_TURNS = ROTATIONS[NUM_SAMPLES - 1]; - -layout(set = 0, binding = 0) uniform sampler2D source_depth_mipmaps; -layout(r8, set = 1, binding = 0) uniform restrict writeonly image2D dest_image; - -#ifndef USE_HALF_SIZE -layout(set = 2, binding = 0) uniform sampler2D source_depth; -#endif - -layout(set = 3, binding = 0) uniform sampler2D source_normal; - -layout(push_constant, binding = 1, std430) uniform Params { - ivec2 screen_size; - float z_far; - float z_near; - - bool orthogonal; - float intensity_div_r6; - float radius; - float bias; - - vec4 proj_info; - vec2 pixel_size; - float proj_scale; - uint pad; -} -params; - -vec3 reconstructCSPosition(vec2 S, float z) { - if (params.orthogonal) { - return vec3((S.xy * params.proj_info.xy + params.proj_info.zw), z); - } else { - return vec3((S.xy * params.proj_info.xy + params.proj_info.zw) * z, z); - } -} - -vec3 getPosition(ivec2 ssP) { - vec3 P; -#ifdef USE_HALF_SIZE - P.z = texelFetch(source_depth_mipmaps, ssP, 0).r; - P.z = -P.z; -#else - P.z = texelFetch(source_depth, ssP, 0).r; - - P.z = P.z * 2.0 - 1.0; - if (params.orthogonal) { - P.z = ((P.z + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; - } else { - P.z = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - P.z * (params.z_far - params.z_near)); - } - P.z = -P.z; -#endif - // Offset to pixel center - P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); - return P; -} - -/** Returns a unit vector and a screen-space radius for the tap on a unit disk (the caller should scale by the actual disk radius) */ -vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR) { - // Radius relative to ssR - float alpha = (float(sampleNumber) + 0.5) * (1.0 / float(NUM_SAMPLES)); - float angle = alpha * (float(NUM_SPIRAL_TURNS) * 6.28) + spinAngle; - - ssR = alpha; - return vec2(cos(angle), sin(angle)); -} - -/** Read the camera-space position of the point at screen-space pixel ssP + unitOffset * ssR. Assumes length(unitOffset) == 1 */ -vec3 getOffsetPosition(ivec2 ssP, float ssR) { - // Derivation: - // mipLevel = floor(log(ssR / MAX_OFFSET)); - - int mipLevel = clamp(int(floor(log2(ssR))) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); - - vec3 P; - - // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. - // Manually clamp to the texture size because texelFetch bypasses the texture unit - ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), (params.screen_size >> mipLevel) - ivec2(1)); - -#ifdef USE_HALF_SIZE - P.z = texelFetch(source_depth_mipmaps, mipP, mipLevel).r; - P.z = -P.z; -#else - if (mipLevel < 1) { - //read from depth buffer - P.z = texelFetch(source_depth, mipP, 0).r; - P.z = P.z * 2.0 - 1.0; - if (params.orthogonal) { - P.z = ((P.z + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; - } else { - P.z = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - P.z * (params.z_far - params.z_near)); - } - P.z = -P.z; - - } else { - //read from mipmaps - P.z = texelFetch(source_depth_mipmaps, mipP, mipLevel - 1).r; - P.z = -P.z; - } -#endif - - // Offset to pixel center - P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); - - return P; -} - -/** Compute the occlusion due to sample with index \a i about the pixel at \a ssC that corresponds - to camera-space point \a C with unit normal \a n_C, using maximum screen-space sampling radius \a ssDiskRadius - - Note that units of H() in the HPG12 paper are meters, not - unitless. The whole falloff/sampling function is therefore - unitless. In this implementation, we factor out (9 / radius). - - Four versions of the falloff function are implemented below -*/ -float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in float p_radius, in int tapIndex, in float randomPatternRotationAngle) { - // Offset on the unit disk, spun for this pixel - float ssR; - vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR); - ssR *= ssDiskRadius; - - ivec2 ssP = ivec2(ssR * unitOffset) + ssC; - - if (any(lessThan(ssP, ivec2(0))) || any(greaterThanEqual(ssP, params.screen_size))) { - return 0.0; - } - - // The occluding point in camera space - vec3 Q = getOffsetPosition(ssP, ssR); - - vec3 v = Q - C; - - float vv = dot(v, v); - float vn = dot(v, n_C); - - const float epsilon = 0.01; - float radius2 = p_radius * p_radius; - - // A: From the HPG12 paper - // Note large epsilon to avoid overdarkening within cracks - //return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6; - - // B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended] - float f = max(radius2 - vv, 0.0); - return f * f * f * max((vn - params.bias) / (epsilon + vv), 0.0); - - // C: Medium contrast (which looks better at high radii), no division. Note that the - // contribution still falls off with radius^2, but we've adjusted the rate in a way that is - // more computationally efficient and happens to be aesthetically pleasing. - // return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0); - - // D: Low contrast, no division operation - // return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0); -} - -void main() { - // Pixel being shaded - ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); - if (any(greaterThanEqual(ssC, params.screen_size))) { //too large, do nothing - return; - } - - // World space point being shaded - vec3 C = getPosition(ssC); - -#ifdef USE_HALF_SIZE - vec3 n_C = texelFetch(source_normal, ssC << 1, 0).xyz * 2.0 - 1.0; -#else - vec3 n_C = texelFetch(source_normal, ssC, 0).xyz * 2.0 - 1.0; -#endif - n_C = normalize(n_C); - n_C.y = -n_C.y; //because this code reads flipped - - // Hash function used in the HPG12 AlchemyAO paper - float randomPatternRotationAngle = mod(float((3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10), TWO_PI); - - // Reconstruct normals from positions. These will lead to 1-pixel black lines - // at depth discontinuities, however the blur will wipe those out so they are not visible - // in the final image. - - // Choose the screen-space sample radius - // proportional to the projected area of the sphere - - float ssDiskRadius = -params.proj_scale * params.radius; - if (!params.orthogonal) { - ssDiskRadius = -params.proj_scale * params.radius / C.z; - } - float sum = 0.0; - for (int i = 0; i < NUM_SAMPLES; ++i) { - sum += sampleAO(ssC, C, n_C, ssDiskRadius, params.radius, i, randomPatternRotationAngle); - } - - float A = max(0.0, 1.0 - sum * params.intensity_div_r6 * (5.0 / float(NUM_SAMPLES))); - - imageStore(dest_image, ssC, vec4(A)); -} diff --git a/servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl b/servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl deleted file mode 100644 index 3e63e3cb59..0000000000 --- a/servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl +++ /dev/null @@ -1,153 +0,0 @@ -#[compute] - -#version 450 - -VERSION_DEFINES - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - -layout(set = 0, binding = 0) uniform sampler2D source_ssao; -layout(set = 1, binding = 0) uniform sampler2D source_depth; -#ifdef MODE_UPSCALE -layout(set = 2, binding = 0) uniform sampler2D source_depth_mipmaps; -#endif - -layout(r8, set = 3, binding = 0) uniform restrict writeonly image2D dest_image; - -////////////////////////////////////////////////////////////////////////////////////////////// -// Tunable Parameters: - -layout(push_constant, binding = 1, std430) uniform Params { - float edge_sharpness; /** Increase to make depth edges crisper. Decrease to reduce flicker. */ - int filter_scale; - float z_far; - float z_near; - bool orthogonal; - uint pad0; - uint pad1; - uint pad2; - ivec2 axis; /** (1, 0) or (0, 1) */ - ivec2 screen_size; -} -params; - -/** Filter radius in pixels. This will be multiplied by SCALE. */ -#define R (4) - -////////////////////////////////////////////////////////////////////////////////////////////// - -// Gaussian coefficients -const float gaussian[R + 1] = - //float[](0.356642, 0.239400, 0.072410, 0.009869); - //float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0 - float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0 -//float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0 - -void main() { - // Pixel being shaded - ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); - if (any(greaterThanEqual(ssC, params.screen_size))) { //too large, do nothing - return; - } - -#ifdef MODE_UPSCALE - - //closest one should be the same pixel, but check nearby just in case - float depth = texelFetch(source_depth, ssC, 0).r; - - depth = depth * 2.0 - 1.0; - if (params.orthogonal) { - depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; - } else { - depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); - } - - vec2 pixel_size = 1.0 / vec2(params.screen_size); - vec2 closest_uv = vec2(ssC) * pixel_size + pixel_size * 0.5; - vec2 from_uv = closest_uv; - vec2 ps2 = pixel_size; // * 2.0; - - float closest_depth = abs(textureLod(source_depth_mipmaps, closest_uv, 0.0).r - depth); - - vec2 offsets[4] = vec2[](vec2(ps2.x, 0), vec2(-ps2.x, 0), vec2(0, ps2.y), vec2(0, -ps2.y)); - for (int i = 0; i < 4; i++) { - vec2 neighbour = from_uv + offsets[i]; - float neighbour_depth = abs(textureLod(source_depth_mipmaps, neighbour, 0.0).r - depth); - if (neighbour_depth < closest_depth) { - closest_uv = neighbour; - closest_depth = neighbour_depth; - } - } - - float visibility = textureLod(source_ssao, closest_uv, 0.0).r; - imageStore(dest_image, ssC, vec4(visibility)); -#else - - float depth = texelFetch(source_depth, ssC, 0).r; - -#ifdef MODE_FULL_SIZE - depth = depth * 2.0 - 1.0; - - if (params.orthogonal) { - depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; - } else { - depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); - } - -#endif - float depth_divide = 1.0 / params.z_far; - - //depth *= depth_divide; - - /* - if (depth > params.z_far * 0.999) { - discard; //skybox - } - */ - - float sum = texelFetch(source_ssao, ssC, 0).r; - - // Base weight for depth falloff. Increase this for more blurriness, - // decrease it for better edge discrimination - float BASE = gaussian[0]; - float totalWeight = BASE; - sum *= totalWeight; - - ivec2 clamp_limit = params.screen_size - ivec2(1); - - for (int r = -R; r <= R; ++r) { - // We already handled the zero case above. This loop should be unrolled and the static branch optimized out, - // so the IF statement has no runtime cost - if (r != 0) { - ivec2 ppos = ssC + params.axis * (r * params.filter_scale); - float value = texelFetch(source_ssao, clamp(ppos, ivec2(0), clamp_limit), 0).r; - ivec2 rpos = clamp(ppos, ivec2(0), clamp_limit); - - float temp_depth = texelFetch(source_depth, rpos, 0).r; -#ifdef MODE_FULL_SIZE - temp_depth = temp_depth * 2.0 - 1.0; - if (params.orthogonal) { - temp_depth = ((temp_depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; - } else { - temp_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - temp_depth * (params.z_far - params.z_near)); - } - //temp_depth *= depth_divide; -#endif - // spatial domain: offset gaussian tap - float weight = 0.3 + gaussian[abs(r)]; - //weight *= max(0.0, dot(temp_normal, normal)); - - // range domain (the "bilateral" weight). As depth difference increases, decrease weight. - weight *= max(0.0, 1.0 - params.edge_sharpness * abs(temp_depth - depth)); - - sum += value * weight; - totalWeight += weight; - } - } - - const float epsilon = 0.0001; - float visibility = sum / (totalWeight + epsilon); - - imageStore(dest_image, ssC, vec4(visibility)); -#endif -} diff --git a/servers/rendering/rasterizer_rd/shaders/ssao_minify.glsl b/servers/rendering/rasterizer_rd/shaders/ssao_minify.glsl deleted file mode 100644 index 263fca386f..0000000000 --- a/servers/rendering/rasterizer_rd/shaders/ssao_minify.glsl +++ /dev/null @@ -1,45 +0,0 @@ -#[compute] - -#version 450 - -VERSION_DEFINES - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - -layout(push_constant, binding = 1, std430) uniform Params { - vec2 pixel_size; - float z_far; - float z_near; - ivec2 source_size; - bool orthogonal; - uint pad; -} -params; - -#ifdef MINIFY_START -layout(set = 0, binding = 0) uniform sampler2D source_texture; -#else -layout(r32f, set = 0, binding = 0) uniform restrict readonly image2D source_image; -#endif -layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D dest_image; - -void main() { - ivec2 pos = ivec2(gl_GlobalInvocationID.xy); - - if (any(greaterThan(pos, params.source_size >> 1))) { //too large, do nothing - return; - } - -#ifdef MINIFY_START - float depth = texelFetch(source_texture, pos << 1, 0).r * 2.0 - 1.0; - if (params.orthogonal) { - depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; - } else { - depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); - } -#else - float depth = imageLoad(source_image, pos << 1).r; -#endif - - imageStore(dest_image, pos, vec4(depth)); -} diff --git a/servers/rendering/rendering_server_canvas.cpp b/servers/rendering/renderer_canvas_cull.cpp index fd7c022d62..2d2847e6ca 100644 --- a/servers/rendering/rendering_server_canvas.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rendering_server_canvas.cpp */ +/* renderer_canvas_cull.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,20 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rendering_server_canvas.h" +#include "renderer_canvas_cull.h" #include "core/math/geometry_2d.h" +#include "renderer_viewport.h" +#include "rendering_server_default.h" #include "rendering_server_globals.h" -#include "rendering_server_raster.h" -#include "rendering_server_viewport.h" static const int z_range = RS::CANVAS_ITEM_Z_MAX - RS::CANVAS_ITEM_Z_MIN + 1; -void RenderingServerCanvas::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) { +void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) { RENDER_TIMESTAMP("Cull CanvasItem Tree"); - memset(z_list, 0, z_range * sizeof(RasterizerCanvas::Item *)); - memset(z_last_list, 0, z_range * sizeof(RasterizerCanvas::Item *)); + memset(z_list, 0, z_range * sizeof(RendererCanvasRender::Item *)); + memset(z_last_list, 0, z_range * sizeof(RendererCanvasRender::Item *)); for (int i = 0; i < p_child_item_count; i++) { _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr); @@ -50,8 +50,8 @@ void RenderingServerCanvas::_render_canvas_item_tree(RID p_to_render_target, Can _cull_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr); } - RasterizerCanvas::Item *list = nullptr; - RasterizerCanvas::Item *list_end = nullptr; + RendererCanvasRender::Item *list = nullptr; + RendererCanvasRender::Item *list_end = nullptr; for (int i = 0; i < z_range; i++) { if (!z_list[i]) { @@ -68,12 +68,16 @@ void RenderingServerCanvas::_render_canvas_item_tree(RID p_to_render_target, Can RENDER_TIMESTAMP("Render Canvas Items"); - RSG::canvas_render->canvas_render_items(p_to_render_target, list, p_modulate, p_lights, p_transform, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel); + bool sdf_flag; + RSG::canvas_render->canvas_render_items(p_to_render_target, list, p_modulate, p_lights, p_directional_lights, p_transform, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, sdf_flag); + if (sdf_flag) { + sdf_used = true; + } } -void _collect_ysort_children(RenderingServerCanvas::Item *p_canvas_item, Transform2D p_transform, RenderingServerCanvas::Item *p_material_owner, RenderingServerCanvas::Item **r_items, int &r_index) { +void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2D p_transform, RendererCanvasCull::Item *p_material_owner, RendererCanvasCull::Item **r_items, int &r_index) { int child_item_count = p_canvas_item->child_items.size(); - RenderingServerCanvas::Item **child_items = p_canvas_item->child_items.ptrw(); + RendererCanvasCull::Item **child_items = p_canvas_item->child_items.ptrw(); for (int i = 0; i < child_item_count; i++) { if (child_items[i]->visible) { if (r_items) { @@ -93,14 +97,14 @@ void _collect_ysort_children(RenderingServerCanvas::Item *p_canvas_item, Transfo } } -void _mark_ysort_dirty(RenderingServerCanvas::Item *ysort_owner, RID_PtrOwner<RenderingServerCanvas::Item> &canvas_item_owner) { +void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_PtrOwner<RendererCanvasCull::Item> &canvas_item_owner) { do { ysort_owner->ysort_children_count = -1; ysort_owner = canvas_item_owner.owns(ysort_owner->parent) ? canvas_item_owner.getornull(ysort_owner->parent) : nullptr; } while (ysort_owner && ysort_owner->sort_y); } -void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner) { +void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner) { Item *ci = p_canvas_item; if (!ci->visible) { @@ -115,7 +119,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo Rect2 rect = ci->get_rect(); Transform2D xform = ci->xform; if (snapping_2d_transforms_to_pixel) { - xform.elements[2].floor(); + xform.elements[2] = xform.elements[2].floor(); } xform = p_transform * xform; @@ -140,7 +144,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo if (ci->clip) { if (p_canvas_clip != nullptr) { - ci->final_clip_rect = p_canvas_clip->final_clip_rect.clip(global_rect); + ci->final_clip_rect = p_canvas_clip->final_clip_rect.intersection(global_rect); } else { ci->final_clip_rect = global_rect; } @@ -172,7 +176,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo p_z = ci->z_index; } - RasterizerCanvas::Item *canvas_group_from = nullptr; + RendererCanvasRender::Item *canvas_group_from = nullptr; bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr); if (use_canvas_group) { int zidx = p_z - RS::CANVAS_ITEM_Z_MIN; @@ -191,7 +195,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo } if (ci->copy_back_buffer) { - ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).clip(p_clip_rect); + ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect); } if (use_canvas_group) { @@ -209,7 +213,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo //compute a global rect (in global coords) for children in the same z layer Rect2 rect_accum; - RasterizerCanvas::Item *c = canvas_group_from; + RendererCanvasRender::Item *c = canvas_group_from; while (c) { if (c == canvas_group_from) { rect_accum = c->global_rect_cache; @@ -223,7 +227,7 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo // We have two choices now, if user has drawn something, we must assume users wants to draw the "mask", so compute the size based on this. // If nothing has been drawn, we just take it over and draw it ourselves. if (ci->canvas_group->fit_empty && (ci->commands == nullptr || - (ci->commands->next == nullptr && ci->commands->type == Item::Command::TYPE_RECT && (static_cast<Item::CommandRect *>(ci->commands)->flags & RasterizerCanvas::CANVAS_RECT_IS_GROUP)))) { + (ci->commands->next == nullptr && ci->commands->type == Item::Command::TYPE_RECT && (static_cast<Item::CommandRect *>(ci->commands)->flags & RendererCanvasRender::CANVAS_RECT_IS_GROUP)))) { // No commands, or sole command is the one used to draw, so we (re)create the draw command. ci->clear(); @@ -234,9 +238,9 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo rect_accum = rect_accum.grow(ci->canvas_group->fit_margin); //draw it? - RasterizerCanvas::Item::CommandRect *crect = ci->alloc_command<RasterizerCanvas::Item::CommandRect>(); + RendererCanvasRender::Item::CommandRect *crect = ci->alloc_command<RendererCanvasRender::Item::CommandRect>(); - crect->flags = RasterizerCanvas::CANVAS_RECT_IS_GROUP; // so we can recognize it later + crect->flags = RendererCanvasRender::CANVAS_RECT_IS_GROUP; // so we can recognize it later crect->rect = xform.affine_inverse().xform(rect_accum); crect->modulate = Color(1, 1, 1, 1); @@ -252,14 +256,14 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo global_rect.position += p_clip_rect.position; } - // Very important that this is cleared after used in RasterizerCanvas to avoid + // Very important that this is cleared after used in RendererCanvasRender to avoid // potential crashes. canvas_group_from->canvas_group_owner = ci; } } if (ci->update_when_visible) { - RenderingServerRaster::redraw_request(); + RenderingServerDefault::redraw_request(); } if ((ci->commands != nullptr && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) { @@ -298,30 +302,10 @@ void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transfo } } -void RenderingServerCanvas::_light_mask_canvas_items(int p_z, RasterizerCanvas::Item *p_canvas_item, RasterizerCanvas::Light *p_masked_lights) { - if (!p_masked_lights) { - return; - } - - RasterizerCanvas::Item *ci = p_canvas_item; - - while (ci) { - RasterizerCanvas::Light *light = p_masked_lights; - while (light) { - if (ci->light_mask & light->item_mask && p_z >= light->z_min && p_z <= light->z_max && ci->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache)) { - ci->light_masked = true; - } - - light = light->mask_next_ptr; - } - - ci = ci->next; - } -} - -void RenderingServerCanvas::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel) { +void RendererCanvasCull::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, const Rect2 &p_clip_rect, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel) { RENDER_TIMESTAMP(">Render Canvas"); + sdf_used = false; snapping_2d_transforms_to_pixel = p_snap_2d_transforms_to_pixel; if (p_canvas->children_order_dirty) { @@ -341,26 +325,26 @@ void RenderingServerCanvas::render_canvas(RID p_render_target, Canvas *p_canvas, } if (!has_mirror) { - _render_canvas_item_tree(p_render_target, ci, l, nullptr, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel); + _render_canvas_item_tree(p_render_target, ci, l, nullptr, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel); } else { //used for parallaxlayer mirroring for (int i = 0; i < l; i++) { const Canvas::ChildItem &ci2 = p_canvas->child_items[i]; - _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel); + _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel); //mirroring (useful for scrolling backgrounds) if (ci2.mirror.x != 0) { Transform2D xform2 = p_transform * Transform2D(0, Vector2(ci2.mirror.x, 0)); - _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel); + _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel); } if (ci2.mirror.y != 0) { Transform2D xform2 = p_transform * Transform2D(0, Vector2(0, ci2.mirror.y)); - _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel); + _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel); } if (ci2.mirror.y != 0 && ci2.mirror.x != 0) { Transform2D xform2 = p_transform * Transform2D(0, ci2.mirror); - _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel); + _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel); } } } @@ -368,7 +352,11 @@ void RenderingServerCanvas::render_canvas(RID p_render_target, Canvas *p_canvas, RENDER_TIMESTAMP("<End Render Canvas"); } -RID RenderingServerCanvas::canvas_create() { +bool RendererCanvasCull::was_sdf_used() { + return sdf_used; +} + +RID RendererCanvasCull::canvas_create() { Canvas *canvas = memnew(Canvas); ERR_FAIL_COND_V(!canvas, RID()); RID rid = canvas_owner.make_rid(canvas); @@ -376,7 +364,7 @@ RID RenderingServerCanvas::canvas_create() { return rid; } -void RenderingServerCanvas::canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring) { +void RendererCanvasCull::canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring) { Canvas *canvas = canvas_owner.getornull(p_canvas); ERR_FAIL_COND(!canvas); Item *canvas_item = canvas_item_owner.getornull(p_item); @@ -387,17 +375,17 @@ void RenderingServerCanvas::canvas_set_item_mirroring(RID p_canvas, RID p_item, canvas->child_items.write[idx].mirror = p_mirroring; } -void RenderingServerCanvas::canvas_set_modulate(RID p_canvas, const Color &p_color) { +void RendererCanvasCull::canvas_set_modulate(RID p_canvas, const Color &p_color) { Canvas *canvas = canvas_owner.getornull(p_canvas); ERR_FAIL_COND(!canvas); canvas->modulate = p_color; } -void RenderingServerCanvas::canvas_set_disable_scale(bool p_disable) { +void RendererCanvasCull::canvas_set_disable_scale(bool p_disable) { disable_scale = p_disable; } -void RenderingServerCanvas::canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) { +void RendererCanvasCull::canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) { Canvas *canvas = canvas_owner.getornull(p_canvas); ERR_FAIL_COND(!canvas); @@ -405,14 +393,14 @@ void RenderingServerCanvas::canvas_set_parent(RID p_canvas, RID p_parent, float canvas->parent_scale = p_scale; } -RID RenderingServerCanvas::canvas_item_create() { +RID RendererCanvasCull::canvas_item_create() { Item *canvas_item = memnew(Item); ERR_FAIL_COND_V(!canvas_item, RID()); return canvas_item_owner.make_rid(canvas_item); } -void RenderingServerCanvas::canvas_item_set_parent(RID p_item, RID p_parent) { +void RendererCanvasCull::canvas_item_set_parent(RID p_item, RID p_parent) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -456,7 +444,7 @@ void RenderingServerCanvas::canvas_item_set_parent(RID p_item, RID p_parent) { canvas_item->parent = p_parent; } -void RenderingServerCanvas::canvas_item_set_visible(RID p_item, bool p_visible) { +void RendererCanvasCull::canvas_item_set_visible(RID p_item, bool p_visible) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -465,35 +453,35 @@ void RenderingServerCanvas::canvas_item_set_visible(RID p_item, bool p_visible) _mark_ysort_dirty(canvas_item, canvas_item_owner); } -void RenderingServerCanvas::canvas_item_set_light_mask(RID p_item, int p_mask) { +void RendererCanvasCull::canvas_item_set_light_mask(RID p_item, int p_mask) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->light_mask = p_mask; } -void RenderingServerCanvas::canvas_item_set_transform(RID p_item, const Transform2D &p_transform) { +void RendererCanvasCull::canvas_item_set_transform(RID p_item, const Transform2D &p_transform) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->xform = p_transform; } -void RenderingServerCanvas::canvas_item_set_clip(RID p_item, bool p_clip) { +void RendererCanvasCull::canvas_item_set_clip(RID p_item, bool p_clip) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->clip = p_clip; } -void RenderingServerCanvas::canvas_item_set_distance_field_mode(RID p_item, bool p_enable) { +void RendererCanvasCull::canvas_item_set_distance_field_mode(RID p_item, bool p_enable) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->distance_field = p_enable; } -void RenderingServerCanvas::canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect) { +void RendererCanvasCull::canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -501,42 +489,42 @@ void RenderingServerCanvas::canvas_item_set_custom_rect(RID p_item, bool p_custo canvas_item->rect = p_rect; } -void RenderingServerCanvas::canvas_item_set_modulate(RID p_item, const Color &p_color) { +void RendererCanvasCull::canvas_item_set_modulate(RID p_item, const Color &p_color) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->modulate = p_color; } -void RenderingServerCanvas::canvas_item_set_self_modulate(RID p_item, const Color &p_color) { +void RendererCanvasCull::canvas_item_set_self_modulate(RID p_item, const Color &p_color) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->self_modulate = p_color; } -void RenderingServerCanvas::canvas_item_set_draw_behind_parent(RID p_item, bool p_enable) { +void RendererCanvasCull::canvas_item_set_draw_behind_parent(RID p_item, bool p_enable) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->behind = p_enable; } -void RenderingServerCanvas::canvas_item_set_update_when_visible(RID p_item, bool p_update) { +void RendererCanvasCull::canvas_item_set_update_when_visible(RID p_item, bool p_update) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->update_when_visible = p_update; } -void RenderingServerCanvas::canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width) { +void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandPrimitive *line = canvas_item->alloc_command<Item::CommandPrimitive>(); ERR_FAIL_COND(!line); if (p_width > 1.001) { - Vector2 t = (p_from - p_to).tangent().normalized(); + Vector2 t = (p_from - p_to).orthogonal().normalized(); line->points[0] = p_from + t * p_width; line->points[1] = p_from - t * p_width; line->points[2] = p_to - t * p_width; @@ -552,95 +540,146 @@ void RenderingServerCanvas::canvas_item_add_line(RID p_item, const Point2 &p_fro } } -void RenderingServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) { +void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) { ERR_FAIL_COND(p_points.size() < 2); Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); + Color color = Color(1, 1, 1, 1); + + Vector<int> indices; + int pc = p_points.size(); + int pc2 = pc * 2; + + Vector2 prev_t; + int j2; + Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>(); ERR_FAIL_COND(!pline); - if (true || p_width <= 1) { -#define TODO make thick lines possible - Vector<int> indices; - int pc = p_points.size(); - indices.resize((pc - 1) * 2); - { - int *iptr = indices.ptrw(); - for (int i = 0; i < (pc - 1); i++) { - iptr[i * 2 + 0] = i; - iptr[i * 2 + 1] = i + 1; - } - } + PackedColorArray colors; + PackedVector2Array points; - pline->primitive = RS::PRIMITIVE_LINES; - pline->polygon.create(indices, p_points, p_colors); - } else { -#if 0 - //make a trianglestrip for drawing the line... - Vector2 prev_t; - pline->triangles.resize(p_points.size() * 2); - if (p_antialiased) { - pline->lines.resize(p_points.size() * 2); - } + colors.resize(pc2); + points.resize(pc2); - if (p_colors.size() == 0) { - pline->triangle_colors.push_back(Color(1, 1, 1, 1)); - if (p_antialiased) { - pline->line_colors.push_back(Color(1, 1, 1, 1)); - } - } else if (p_colors.size() == 1) { - pline->triangle_colors = p_colors; - pline->line_colors = p_colors; - } else { - if (p_colors.size() != p_points.size()) { - pline->triangle_colors.push_back(p_colors[0]); - pline->line_colors.push_back(p_colors[0]); - } else { - pline->triangle_colors.resize(pline->triangles.size()); - pline->line_colors.resize(pline->lines.size()); - } - } + Vector2 *points_ptr = points.ptrw(); + Color *colors_ptr = colors.ptrw(); + + if (p_antialiased) { + Color color2 = Color(1, 1, 1, 0); + + PackedColorArray colors_top; + PackedVector2Array points_top; + + colors_top.resize(pc2); + points_top.resize(pc2); - for (int i = 0; i < p_points.size(); i++) { + PackedColorArray colors_bottom; + PackedVector2Array points_bottom; + colors_bottom.resize(pc2); + points_bottom.resize(pc2); + + Item::CommandPolygon *pline_top = canvas_item->alloc_command<Item::CommandPolygon>(); + ERR_FAIL_COND(!pline_top); + + Item::CommandPolygon *pline_bottom = canvas_item->alloc_command<Item::CommandPolygon>(); + ERR_FAIL_COND(!pline_bottom); + + //make three trianglestrip's for drawing the antialiased line... + + Vector2 *points_top_ptr = points_top.ptrw(); + Vector2 *points_bottom_ptr = points_bottom.ptrw(); + + Color *colors_top_ptr = colors_top.ptrw(); + Color *colors_bottom_ptr = colors_bottom.ptrw(); + + for (int i = 0, j = 0; i < pc; i++, j += 2) { Vector2 t; - if (i == p_points.size() - 1) { + if (i == pc - 1) { t = prev_t; } else { - t = (p_points[i + 1] - p_points[i]).normalized().tangent(); + t = (p_points[i + 1] - p_points[i]).normalized().orthogonal(); if (i == 0) { prev_t = t; } } + j2 = j + 1; + Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5; + Vector2 pos = p_points[i]; - if (p_antialiased) { - pline->lines.write[i] = p_points[i] + tangent; - pline->lines.write[p_points.size() * 2 - i - 1] = p_points[i] - tangent; - if (pline->line_colors.size() > 1) { - pline->line_colors.write[i] = p_colors[i]; - pline->line_colors.write[p_points.size() * 2 - i - 1] = p_colors[i]; + points_ptr[j] = pos + tangent; + points_ptr[j2] = pos - tangent; + + points_top_ptr[j] = pos + tangent + tangent; + points_top_ptr[j2] = pos + tangent; + + points_bottom_ptr[j] = pos - tangent; + points_bottom_ptr[j2] = pos - tangent - tangent; + + if (i < p_colors.size()) { + color = p_colors[i]; + color2 = Color(color.r, color.g, color.b, 0); + } + + colors_ptr[j] = color; + colors_ptr[j2] = color; + + colors_top_ptr[j] = color2; + colors_top_ptr[j2] = color; + + colors_bottom_ptr[j] = color; + colors_bottom_ptr[j2] = color2; + + prev_t = t; + } + + pline_top->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; + pline_top->polygon.create(indices, points_top, colors_top); + + pline_bottom->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; + pline_bottom->polygon.create(indices, points_bottom, colors_bottom); + } else { + //make a trianglestrip for drawing the line... + + for (int i = 0, j = 0; i < pc; i++, j += 2) { + Vector2 t; + if (i == pc - 1) { + t = prev_t; + } else { + t = (p_points[i + 1] - p_points[i]).normalized().orthogonal(); + if (i == 0) { + prev_t = t; } } - pline->triangles.write[i * 2 + 0] = p_points[i] + tangent; - pline->triangles.write[i * 2 + 1] = p_points[i] - tangent; + j2 = j + 1; - if (pline->triangle_colors.size() > 1) { + Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5; + Vector2 pos = p_points[i]; + + points_ptr[j] = pos + tangent; + points_ptr[j2] = pos - tangent; - pline->triangle_colors.write[i * 2 + 0] = p_colors[i]; - pline->triangle_colors.write[i * 2 + 1] = p_colors[i]; + if (i < p_colors.size()) { + color = p_colors[i]; } + colors_ptr[j] = color; + colors_ptr[j2] = color; + prev_t = t; } -#endif } + + pline->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; + pline->polygon.create(indices, points, colors); } -void RenderingServerCanvas::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) { +void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) { ERR_FAIL_COND(p_points.size() < 2); Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -657,7 +696,7 @@ void RenderingServerCanvas::canvas_item_add_multiline(RID p_item, const Vector<P } } -void RenderingServerCanvas::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) { +void RendererCanvasCull::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -667,7 +706,7 @@ void RenderingServerCanvas::canvas_item_add_rect(RID p_item, const Rect2 &p_rect rect->rect = p_rect; } -void RenderingServerCanvas::canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) { +void RendererCanvasCull::canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -701,7 +740,7 @@ void RenderingServerCanvas::canvas_item_add_circle(RID p_item, const Point2 &p_p circle->polygon.create(indices, points, color); } -void RenderingServerCanvas::canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile, const Color &p_modulate, bool p_transpose) { +void RendererCanvasCull::canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile, const Color &p_modulate, bool p_transpose) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -711,28 +750,28 @@ void RenderingServerCanvas::canvas_item_add_texture_rect(RID p_item, const Rect2 rect->rect = p_rect; rect->flags = 0; if (p_tile) { - rect->flags |= RasterizerCanvas::CANVAS_RECT_TILE; - rect->flags |= RasterizerCanvas::CANVAS_RECT_REGION; + rect->flags |= RendererCanvasRender::CANVAS_RECT_TILE; + rect->flags |= RendererCanvasRender::CANVAS_RECT_REGION; rect->source = Rect2(0, 0, fabsf(p_rect.size.width), fabsf(p_rect.size.height)); } if (p_rect.size.x < 0) { - rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_H; + rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_H; rect->rect.size.x = -rect->rect.size.x; } if (p_rect.size.y < 0) { - rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_V; + rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_V; rect->rect.size.y = -rect->rect.size.y; } if (p_transpose) { - rect->flags |= RasterizerCanvas::CANVAS_RECT_TRANSPOSE; + rect->flags |= RendererCanvasRender::CANVAS_RECT_TRANSPOSE; SWAP(rect->rect.size.x, rect->rect.size.y); } rect->texture = p_texture; } -void RenderingServerCanvas::canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) { +void RendererCanvasCull::canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -744,36 +783,36 @@ void RenderingServerCanvas::canvas_item_add_texture_rect_region(RID p_item, cons rect->texture = p_texture; rect->source = p_src_rect; - rect->flags = RasterizerCanvas::CANVAS_RECT_REGION; + rect->flags = RendererCanvasRender::CANVAS_RECT_REGION; if (p_rect.size.x < 0) { - rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_H; + rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_H; rect->rect.size.x = -rect->rect.size.x; } if (p_src_rect.size.x < 0) { - rect->flags ^= RasterizerCanvas::CANVAS_RECT_FLIP_H; + rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_H; rect->source.size.x = -rect->source.size.x; } if (p_rect.size.y < 0) { - rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_V; + rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_V; rect->rect.size.y = -rect->rect.size.y; } if (p_src_rect.size.y < 0) { - rect->flags ^= RasterizerCanvas::CANVAS_RECT_FLIP_V; + rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_V; rect->source.size.y = -rect->source.size.y; } if (p_transpose) { - rect->flags |= RasterizerCanvas::CANVAS_RECT_TRANSPOSE; + rect->flags |= RendererCanvasRender::CANVAS_RECT_TRANSPOSE; SWAP(rect->rect.size.x, rect->rect.size.y); } if (p_clip_uv) { - rect->flags |= RasterizerCanvas::CANVAS_RECT_CLIP_UV; + rect->flags |= RendererCanvasRender::CANVAS_RECT_CLIP_UV; } } -void RenderingServerCanvas::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode, RS::NinePatchAxisMode p_y_axis_mode, bool p_draw_center, const Color &p_modulate) { +void RendererCanvasCull::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode, RS::NinePatchAxisMode p_y_axis_mode, bool p_draw_center, const Color &p_modulate) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -786,15 +825,15 @@ void RenderingServerCanvas::canvas_item_add_nine_patch(RID p_item, const Rect2 & style->source = p_source; style->draw_center = p_draw_center; style->color = p_modulate; - style->margin[MARGIN_LEFT] = p_topleft.x; - style->margin[MARGIN_TOP] = p_topleft.y; - style->margin[MARGIN_RIGHT] = p_bottomright.x; - style->margin[MARGIN_BOTTOM] = p_bottomright.y; + style->margin[SIDE_LEFT] = p_topleft.x; + style->margin[SIDE_TOP] = p_topleft.y; + style->margin[SIDE_RIGHT] = p_bottomright.x; + style->margin[SIDE_BOTTOM] = p_bottomright.y; style->axis_x = p_x_axis_mode; style->axis_y = p_y_axis_mode; } -void RenderingServerCanvas::canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width) { +void RendererCanvasCull::canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width) { uint32_t pc = p_points.size(); ERR_FAIL_COND(pc == 0 || pc > 4); @@ -823,7 +862,7 @@ void RenderingServerCanvas::canvas_item_add_primitive(RID p_item, const Vector<P prim->texture = p_texture; } -void RenderingServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture) { +void RendererCanvasCull::canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); #ifdef DEBUG_ENABLED @@ -835,7 +874,7 @@ void RenderingServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Poi ERR_FAIL_COND(uv_size != 0 && (uv_size != pointcount)); #endif Vector<int> indices = Geometry2D::triangulate_polygon(p_points); - ERR_FAIL_COND_MSG(indices.empty(), "Invalid polygon data, triangulation failed."); + ERR_FAIL_COND_MSG(indices.is_empty(), "Invalid polygon data, triangulation failed."); Item::CommandPolygon *polygon = canvas_item->alloc_command<Item::CommandPolygon>(); ERR_FAIL_COND(!polygon); @@ -844,16 +883,16 @@ void RenderingServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Poi polygon->polygon.create(indices, p_points, p_colors, p_uvs); } -void RenderingServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights, RID p_texture, int p_count) { +void RendererCanvasCull::canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights, RID p_texture, int p_count) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); int vertex_count = p_points.size(); ERR_FAIL_COND(vertex_count == 0); - ERR_FAIL_COND(!p_colors.empty() && p_colors.size() != vertex_count && p_colors.size() != 1); - ERR_FAIL_COND(!p_uvs.empty() && p_uvs.size() != vertex_count); - ERR_FAIL_COND(!p_bones.empty() && p_bones.size() != vertex_count * 4); - ERR_FAIL_COND(!p_weights.empty() && p_weights.size() != vertex_count * 4); + ERR_FAIL_COND(!p_colors.is_empty() && p_colors.size() != vertex_count && p_colors.size() != 1); + ERR_FAIL_COND(!p_uvs.is_empty() && p_uvs.size() != vertex_count); + ERR_FAIL_COND(!p_bones.is_empty() && p_bones.size() != vertex_count * 4); + ERR_FAIL_COND(!p_weights.is_empty() && p_weights.size() != vertex_count * 4); Vector<int> indices = p_indices; @@ -867,7 +906,7 @@ void RenderingServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vec polygon->primitive = RS::PRIMITIVE_TRIANGLES; } -void RenderingServerCanvas::canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) { +void RendererCanvasCull::canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -876,7 +915,7 @@ void RenderingServerCanvas::canvas_item_add_set_transform(RID p_item, const Tran tr->xform = p_transform; } -void RenderingServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture) { +void RendererCanvasCull::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -890,7 +929,7 @@ void RenderingServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, m->modulate = p_modulate; } -void RenderingServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture) { +void RendererCanvasCull::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -904,7 +943,7 @@ void RenderingServerCanvas::canvas_item_add_particles(RID p_item, RID p_particle RSG::storage->particles_request_process(p_particles); } -void RenderingServerCanvas::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture) { +void RendererCanvasCull::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -915,7 +954,7 @@ void RenderingServerCanvas::canvas_item_add_multimesh(RID p_item, RID p_mesh, RI mm->texture = p_texture; } -void RenderingServerCanvas::canvas_item_add_clip_ignore(RID p_item, bool p_ignore) { +void RendererCanvasCull::canvas_item_add_clip_ignore(RID p_item, bool p_ignore) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -924,7 +963,7 @@ void RenderingServerCanvas::canvas_item_add_clip_ignore(RID p_item, bool p_ignor ci->ignore = p_ignore; } -void RenderingServerCanvas::canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) { +void RendererCanvasCull::canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -933,7 +972,7 @@ void RenderingServerCanvas::canvas_item_set_sort_children_by_y(RID p_item, bool _mark_ysort_dirty(canvas_item, canvas_item_owner); } -void RenderingServerCanvas::canvas_item_set_z_index(RID p_item, int p_z) { +void RendererCanvasCull::canvas_item_set_z_index(RID p_item, int p_z) { ERR_FAIL_COND(p_z < RS::CANVAS_ITEM_Z_MIN || p_z > RS::CANVAS_ITEM_Z_MAX); Item *canvas_item = canvas_item_owner.getornull(p_item); @@ -942,25 +981,25 @@ void RenderingServerCanvas::canvas_item_set_z_index(RID p_item, int p_z) { canvas_item->z_index = p_z; } -void RenderingServerCanvas::canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) { +void RendererCanvasCull::canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->z_relative = p_enable; } -void RenderingServerCanvas::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) { +void RendererCanvasCull::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->skeleton = p_skeleton; } -void RenderingServerCanvas::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) { +void RendererCanvasCull::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); if (p_enable && (canvas_item->copy_back_buffer == nullptr)) { - canvas_item->copy_back_buffer = memnew(RasterizerCanvas::Item::CopyBackBuffer); + canvas_item->copy_back_buffer = memnew(RendererCanvasRender::Item::CopyBackBuffer); } if (!p_enable && (canvas_item->copy_back_buffer != nullptr)) { memdelete(canvas_item->copy_back_buffer); @@ -973,14 +1012,14 @@ void RenderingServerCanvas::canvas_item_set_copy_to_backbuffer(RID p_item, bool } } -void RenderingServerCanvas::canvas_item_clear(RID p_item) { +void RendererCanvasCull::canvas_item_clear(RID p_item) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->clear(); } -void RenderingServerCanvas::canvas_item_set_draw_index(RID p_item, int p_index) { +void RendererCanvasCull::canvas_item_set_draw_index(RID p_item, int p_index) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -999,21 +1038,21 @@ void RenderingServerCanvas::canvas_item_set_draw_index(RID p_item, int p_index) } } -void RenderingServerCanvas::canvas_item_set_material(RID p_item, RID p_material) { +void RendererCanvasCull::canvas_item_set_material(RID p_item, RID p_material) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->material = p_material; } -void RenderingServerCanvas::canvas_item_set_use_parent_material(RID p_item, bool p_enable) { +void RendererCanvasCull::canvas_item_set_use_parent_material(RID p_item, bool p_enable) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->use_parent_material = p_enable; } -void RenderingServerCanvas::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) { +void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -1024,7 +1063,7 @@ void RenderingServerCanvas::canvas_item_set_canvas_group_mode(RID p_item, RS::Ca } } else { if (canvas_item->canvas_group == nullptr) { - canvas_item->canvas_group = memnew(RasterizerCanvas::Item::CanvasGroup); + canvas_item->canvas_group = memnew(RendererCanvasRender::Item::CanvasGroup); } canvas_item->canvas_group->mode = p_mode; canvas_item->canvas_group->fit_empty = p_fit_empty; @@ -1034,19 +1073,44 @@ void RenderingServerCanvas::canvas_item_set_canvas_group_mode(RID p_item, RS::Ca } } -RID RenderingServerCanvas::canvas_light_create() { - RasterizerCanvas::Light *clight = memnew(RasterizerCanvas::Light); +RID RendererCanvasCull::canvas_light_create() { + RendererCanvasRender::Light *clight = memnew(RendererCanvasRender::Light); clight->light_internal = RSG::canvas_render->light_create(); return canvas_light_owner.make_rid(clight); } -void RenderingServerCanvas::canvas_light_attach_to_canvas(RID p_light, RID p_canvas) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + ERR_FAIL_COND(!clight); + + if (clight->mode == p_mode) { + return; + } + + RID canvas = clight->canvas; + + if (canvas.is_valid()) { + canvas_light_attach_to_canvas(p_light, RID()); + } + + clight->mode = p_mode; + + if (canvas.is_valid()) { + canvas_light_attach_to_canvas(p_light, canvas); + } +} + +void RendererCanvasCull::canvas_light_attach_to_canvas(RID p_light, RID p_canvas) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); if (clight->canvas.is_valid()) { Canvas *canvas = canvas_owner.getornull(clight->canvas); - canvas->lights.erase(clight); + if (clight->mode == RS::CANVAS_LIGHT_MODE_POINT) { + canvas->lights.erase(clight); + } else { + canvas->directional_lights.erase(clight); + } } if (!canvas_owner.owns(p_canvas)) { @@ -1057,33 +1121,37 @@ void RenderingServerCanvas::canvas_light_attach_to_canvas(RID p_light, RID p_can if (clight->canvas.is_valid()) { Canvas *canvas = canvas_owner.getornull(clight->canvas); - canvas->lights.insert(clight); + if (clight->mode == RS::CANVAS_LIGHT_MODE_POINT) { + canvas->lights.insert(clight); + } else { + canvas->directional_lights.insert(clight); + } } } -void RenderingServerCanvas::canvas_light_set_enabled(RID p_light, bool p_enabled) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_enabled(RID p_light, bool p_enabled) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->enabled = p_enabled; } -void RenderingServerCanvas::canvas_light_set_scale(RID p_light, float p_scale) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_texture_scale(RID p_light, float p_scale) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->scale = p_scale; } -void RenderingServerCanvas::canvas_light_set_transform(RID p_light, const Transform2D &p_transform) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_transform(RID p_light, const Transform2D &p_transform) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->xform = p_transform; } -void RenderingServerCanvas::canvas_light_set_texture(RID p_light, RID p_texture) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_texture(RID p_light, RID p_texture) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); if (clight->texture == p_texture) { @@ -1094,73 +1162,80 @@ void RenderingServerCanvas::canvas_light_set_texture(RID p_light, RID p_texture) RSG::canvas_render->light_set_texture(clight->light_internal, p_texture); } -void RenderingServerCanvas::canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->texture_offset = p_offset; } -void RenderingServerCanvas::canvas_light_set_color(RID p_light, const Color &p_color) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_color(RID p_light, const Color &p_color) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->color = p_color; } -void RenderingServerCanvas::canvas_light_set_height(RID p_light, float p_height) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_height(RID p_light, float p_height) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->height = p_height; } -void RenderingServerCanvas::canvas_light_set_energy(RID p_light, float p_energy) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_energy(RID p_light, float p_energy) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->energy = p_energy; } -void RenderingServerCanvas::canvas_light_set_z_range(RID p_light, int p_min_z, int p_max_z) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_z_range(RID p_light, int p_min_z, int p_max_z) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->z_min = p_min_z; clight->z_max = p_max_z; } -void RenderingServerCanvas::canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->layer_max = p_max_layer; clight->layer_min = p_min_layer; } -void RenderingServerCanvas::canvas_light_set_item_cull_mask(RID p_light, int p_mask) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_item_cull_mask(RID p_light, int p_mask) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->item_mask = p_mask; } -void RenderingServerCanvas::canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->item_shadow_mask = p_mask; } -void RenderingServerCanvas::canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_directional_distance(RID p_light, float p_distance) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); - clight->mode = p_mode; + clight->directional_distance = p_distance; +} + +void RendererCanvasCull::canvas_light_set_blend_mode(RID p_light, RS::CanvasLightBlendMode p_mode) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + ERR_FAIL_COND(!clight); + + clight->blend_mode = p_mode; } -void RenderingServerCanvas::canvas_light_set_shadow_enabled(RID p_light, bool p_enabled) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_shadow_enabled(RID p_light, bool p_enabled) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); if (clight->use_shadow == p_enabled) { @@ -1171,34 +1246,34 @@ void RenderingServerCanvas::canvas_light_set_shadow_enabled(RID p_light, bool p_ RSG::canvas_render->light_set_use_shadow(clight->light_internal, clight->use_shadow); } -void RenderingServerCanvas::canvas_light_set_shadow_filter(RID p_light, RS::CanvasLightShadowFilter p_filter) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_shadow_filter(RID p_light, RS::CanvasLightShadowFilter p_filter) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->shadow_filter = p_filter; } -void RenderingServerCanvas::canvas_light_set_shadow_color(RID p_light, const Color &p_color) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_shadow_color(RID p_light, const Color &p_color) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->shadow_color = p_color; } -void RenderingServerCanvas::canvas_light_set_shadow_smooth(RID p_light, float p_smooth) { - RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light); +void RendererCanvasCull::canvas_light_set_shadow_smooth(RID p_light, float p_smooth) { + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); ERR_FAIL_COND(!clight); clight->shadow_smooth = p_smooth; } -RID RenderingServerCanvas::canvas_light_occluder_create() { - RasterizerCanvas::LightOccluderInstance *occluder = memnew(RasterizerCanvas::LightOccluderInstance); +RID RendererCanvasCull::canvas_light_occluder_create() { + RendererCanvasRender::LightOccluderInstance *occluder = memnew(RendererCanvasRender::LightOccluderInstance); return canvas_light_occluder_owner.make_rid(occluder); } -void RenderingServerCanvas::canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) { - RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); +void RendererCanvasCull::canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); ERR_FAIL_COND(!occluder); if (occluder->canvas.is_valid()) { @@ -1218,15 +1293,15 @@ void RenderingServerCanvas::canvas_light_occluder_attach_to_canvas(RID p_occlude } } -void RenderingServerCanvas::canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled) { - RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); +void RendererCanvasCull::canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); ERR_FAIL_COND(!occluder); occluder->enabled = p_enabled; } -void RenderingServerCanvas::canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon) { - RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); +void RendererCanvasCull::canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); ERR_FAIL_COND(!occluder); if (occluder->polygon.is_valid()) { @@ -1253,134 +1328,110 @@ void RenderingServerCanvas::canvas_light_occluder_set_polygon(RID p_occluder, RI } } -void RenderingServerCanvas::canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) { - RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); +void RendererCanvasCull::canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); + ERR_FAIL_COND(!occluder); +} + +void RendererCanvasCull::canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); ERR_FAIL_COND(!occluder); occluder->xform = p_xform; } -void RenderingServerCanvas::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) { - RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); +void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); ERR_FAIL_COND(!occluder); occluder->light_mask = p_mask; } -RID RenderingServerCanvas::canvas_occluder_polygon_create() { +RID RendererCanvasCull::canvas_occluder_polygon_create() { LightOccluderPolygon *occluder_poly = memnew(LightOccluderPolygon); occluder_poly->occluder = RSG::canvas_render->occluder_polygon_create(); return canvas_light_occluder_polygon_owner.make_rid(occluder_poly); } -void RenderingServerCanvas::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) { - if (p_shape.size() < 3) { - canvas_occluder_polygon_set_shape_as_lines(p_occluder_polygon, p_shape); - return; - } - - Vector<Vector2> lines; - int lc = p_shape.size() * 2; - - lines.resize(lc - (p_closed ? 0 : 2)); - { - Vector2 *w = lines.ptrw(); - const Vector2 *r = p_shape.ptr(); - - int max = lc / 2; - if (!p_closed) { - max--; - } - for (int i = 0; i < max; i++) { - Vector2 a = r[i]; - Vector2 b = r[(i + 1) % (lc / 2)]; - w[i * 2 + 0] = a; - w[i * 2 + 1] = b; - } - } - - canvas_occluder_polygon_set_shape_as_lines(p_occluder_polygon, lines); -} - -void RenderingServerCanvas::canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon, const Vector<Vector2> &p_shape) { +void RendererCanvasCull::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) { LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_occluder_polygon); ERR_FAIL_COND(!occluder_poly); - ERR_FAIL_COND(p_shape.size() & 1); - int lc = p_shape.size(); + uint32_t pc = p_shape.size(); + ERR_FAIL_COND(pc < 2); + occluder_poly->aabb = Rect2(); - { - const Vector2 *r = p_shape.ptr(); - for (int i = 0; i < lc; i++) { - if (i == 0) { - occluder_poly->aabb.position = r[i]; - } else { - occluder_poly->aabb.expand_to(r[i]); - } + const Vector2 *r = p_shape.ptr(); + for (uint32_t i = 0; i < pc; i++) { + if (i == 0) { + occluder_poly->aabb.position = r[i]; + } else { + occluder_poly->aabb.expand_to(r[i]); } } - RSG::canvas_render->occluder_polygon_set_shape_as_lines(occluder_poly->occluder, p_shape); - for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *E = occluder_poly->owners.front(); E; E = E->next()) { + RSG::canvas_render->occluder_polygon_set_shape(occluder_poly->occluder, p_shape, p_closed); + + for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *E = occluder_poly->owners.front(); E; E = E->next()) { E->get()->aabb_cache = occluder_poly->aabb; } } -void RenderingServerCanvas::canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode) { +void RendererCanvasCull::canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode) { LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_occluder_polygon); ERR_FAIL_COND(!occluder_poly); occluder_poly->cull_mode = p_mode; RSG::canvas_render->occluder_polygon_set_cull_mode(occluder_poly->occluder, p_mode); - for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *E = occluder_poly->owners.front(); E; E = E->next()) { + for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *E = occluder_poly->owners.front(); E; E = E->next()) { E->get()->cull_cache = p_mode; } } -void RenderingServerCanvas::canvas_set_shadow_texture_size(int p_size) { +void RendererCanvasCull::canvas_set_shadow_texture_size(int p_size) { RSG::canvas_render->set_shadow_texture_size(p_size); } -RID RenderingServerCanvas::canvas_texture_create() { +RID RendererCanvasCull::canvas_texture_create() { return RSG::storage->canvas_texture_create(); } -void RenderingServerCanvas::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) { +void RendererCanvasCull::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) { RSG::storage->canvas_texture_set_channel(p_canvas_texture, p_channel, p_texture); } -void RenderingServerCanvas::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) { +void RendererCanvasCull::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) { RSG::storage->canvas_texture_set_shading_parameters(p_canvas_texture, p_base_color, p_shininess); } -void RenderingServerCanvas::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) { +void RendererCanvasCull::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) { RSG::storage->canvas_texture_set_texture_filter(p_canvas_texture, p_filter); } -void RenderingServerCanvas::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) { +void RendererCanvasCull::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) { RSG::storage->canvas_texture_set_texture_repeat(p_canvas_texture, p_repeat); } -void RenderingServerCanvas::canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) { +void RendererCanvasCull::canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) { Item *ci = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!ci); ci->texture_filter = p_filter; } -void RenderingServerCanvas::canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) { +void RendererCanvasCull::canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) { Item *ci = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!ci); ci->texture_repeat = p_repeat; } -bool RenderingServerCanvas::free(RID p_rid) { +bool RendererCanvasCull::free(RID p_rid) { if (canvas_owner.owns(p_rid)) { Canvas *canvas = canvas_owner.getornull(p_rid); ERR_FAIL_COND_V(!canvas, false); while (canvas->viewports.size()) { - RenderingServerViewport::Viewport *vp = RSG::viewport->viewport_owner.getornull(canvas->viewports.front()->get()); + RendererViewport::Viewport *vp = RSG::viewport->viewport_owner.getornull(canvas->viewports.front()->get()); ERR_FAIL_COND_V(!vp, true); - Map<RID, RenderingServerViewport::Viewport::CanvasData>::Element *E = vp->canvas_map.find(p_rid); + Map<RID, RendererViewport::Viewport::CanvasData>::Element *E = vp->canvas_map.find(p_rid); ERR_FAIL_COND_V(!E, true); vp->canvas_map.erase(p_rid); @@ -1391,11 +1442,11 @@ bool RenderingServerCanvas::free(RID p_rid) { canvas->child_items[i].item->parent = RID(); } - for (Set<RasterizerCanvas::Light *>::Element *E = canvas->lights.front(); E; E = E->next()) { + for (Set<RendererCanvasRender::Light *>::Element *E = canvas->lights.front(); E; E = E->next()) { E->get()->canvas = RID(); } - for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *E = canvas->occluders.front(); E; E = E->next()) { + for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *E = canvas->occluders.front(); E; E = E->next()) { E->get()->canvas = RID(); } @@ -1436,7 +1487,7 @@ bool RenderingServerCanvas::free(RID p_rid) { memdelete(canvas_item); } else if (canvas_light_owner.owns(p_rid)) { - RasterizerCanvas::Light *canvas_light = canvas_light_owner.getornull(p_rid); + RendererCanvasRender::Light *canvas_light = canvas_light_owner.getornull(p_rid); ERR_FAIL_COND_V(!canvas_light, true); if (canvas_light->canvas.is_valid()) { @@ -1452,7 +1503,7 @@ bool RenderingServerCanvas::free(RID p_rid) { memdelete(canvas_light); } else if (canvas_light_occluder_owner.owns(p_rid)) { - RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_rid); + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_rid); ERR_FAIL_COND_V(!occluder, true); if (occluder->polygon.is_valid()) { @@ -1489,14 +1540,14 @@ bool RenderingServerCanvas::free(RID p_rid) { return true; } -RenderingServerCanvas::RenderingServerCanvas() { - z_list = (RasterizerCanvas::Item **)memalloc(z_range * sizeof(RasterizerCanvas::Item *)); - z_last_list = (RasterizerCanvas::Item **)memalloc(z_range * sizeof(RasterizerCanvas::Item *)); +RendererCanvasCull::RendererCanvasCull() { + z_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *)); + z_last_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *)); disable_scale = false; } -RenderingServerCanvas::~RenderingServerCanvas() { +RendererCanvasCull::~RendererCanvasCull() { memfree(z_list); memfree(z_last_list); } diff --git a/servers/rendering/rendering_server_canvas.h b/servers/rendering/renderer_canvas_cull.h index a9a81888aa..7496a413ee 100644 --- a/servers/rendering/rendering_server_canvas.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rendering_server_canvas.h */ +/* renderer_canvas_cull.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef VISUALSERVERCANVAS_H -#define VISUALSERVERCANVAS_H +#ifndef RENDERING_SERVER_CANVAS_CULL_H +#define RENDERING_SERVER_CANVAS_CULL_H -#include "rasterizer.h" -#include "rendering_server_viewport.h" +#include "renderer_compositor.h" +#include "renderer_viewport.h" -class RenderingServerCanvas { +class RendererCanvasCull { public: - struct Item : public RasterizerCanvas::Item { + struct Item : public RendererCanvasRender::Item { RID parent; // canvas it belongs to List<Item *>::Element *E; int z_index; @@ -93,7 +93,7 @@ public: Rect2 aabb; RS::CanvasOccluderPolygonCullMode cull_mode; RID occluder; - Set<RasterizerCanvas::LightOccluderInstance *> owners; + Set<RendererCanvasRender::LightOccluderInstance *> owners; LightOccluderPolygon() { active = false; @@ -103,9 +103,9 @@ public: RID_PtrOwner<LightOccluderPolygon> canvas_light_occluder_polygon_owner; - RID_PtrOwner<RasterizerCanvas::LightOccluderInstance> canvas_light_occluder_owner; + RID_PtrOwner<RendererCanvasRender::LightOccluderInstance> canvas_light_occluder_owner; - struct Canvas : public RenderingServerViewport::CanvasBase { + struct Canvas : public RendererViewport::CanvasBase { Set<RID> viewports; struct ChildItem { Point2 mirror; @@ -115,9 +115,10 @@ public: } }; - Set<RasterizerCanvas::Light *> lights; + Set<RendererCanvasRender::Light *> lights; + Set<RendererCanvasRender::Light *> directional_lights; - Set<RasterizerCanvas::LightOccluderInstance *> occluders; + Set<RendererCanvasRender::LightOccluderInstance *> occluders; bool children_order_dirty; Vector<ChildItem> child_items; @@ -149,21 +150,23 @@ public: mutable RID_PtrOwner<Canvas> canvas_owner; RID_PtrOwner<Item> canvas_item_owner; - RID_PtrOwner<RasterizerCanvas::Light> canvas_light_owner; + RID_PtrOwner<RendererCanvasRender::Light> canvas_light_owner; bool disable_scale; + bool sdf_used = false; bool snapping_2d_transforms_to_pixel = false; private: - void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel); - void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner); - void _light_mask_canvas_items(int p_z, RasterizerCanvas::Item *p_canvas_item, RasterizerCanvas::Light *p_masked_lights); + void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel); + void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner); - RasterizerCanvas::Item **z_list; - RasterizerCanvas::Item **z_last_list; + RendererCanvasRender::Item **z_list; + RendererCanvasRender::Item **z_last_list; public: - void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel); + void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, const Rect2 &p_clip_rect, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel); + + bool was_sdf_used(); RID canvas_create(); void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring); @@ -189,7 +192,7 @@ public: void canvas_item_set_update_when_visible(RID p_item, bool p_update); void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0); - void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0); + void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false); void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0); void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color); void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color); @@ -220,9 +223,10 @@ public: void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false); RID canvas_light_create(); + void canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode); void canvas_light_attach_to_canvas(RID p_light, RID p_canvas); void canvas_light_set_enabled(RID p_light, bool p_enabled); - void canvas_light_set_scale(RID p_light, float p_scale); + void canvas_light_set_texture_scale(RID p_light, float p_scale); void canvas_light_set_transform(RID p_light, const Transform2D &p_transform); void canvas_light_set_texture(RID p_light, RID p_texture); void canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset); @@ -233,8 +237,9 @@ public: void canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer); void canvas_light_set_item_cull_mask(RID p_light, int p_mask); void canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask); + void canvas_light_set_directional_distance(RID p_light, float p_distance); - void canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode); + void canvas_light_set_blend_mode(RID p_light, RS::CanvasLightBlendMode p_mode); void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled); void canvas_light_set_shadow_filter(RID p_light, RS::CanvasLightShadowFilter p_filter); @@ -245,12 +250,12 @@ public: void canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas); void canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled); void canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon); + void canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable); void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform); void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask); RID canvas_occluder_polygon_create(); void canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed); - void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon, const Vector<Vector2> &p_shape); void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode); @@ -267,8 +272,8 @@ public: void canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat); bool free(RID p_rid); - RenderingServerCanvas(); - ~RenderingServerCanvas(); + RendererCanvasCull(); + ~RendererCanvasCull(); }; #endif // VISUALSERVERCANVAS_H diff --git a/servers/rendering/renderer_canvas_render.cpp b/servers/rendering/renderer_canvas_render.cpp new file mode 100644 index 0000000000..1945435586 --- /dev/null +++ b/servers/rendering/renderer_canvas_render.cpp @@ -0,0 +1,31 @@ +/*************************************************************************/ +/* renderer_canvas_render.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "renderer_canvas_render.h" diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h new file mode 100644 index 0000000000..f08986b021 --- /dev/null +++ b/servers/rendering/renderer_canvas_render.h @@ -0,0 +1,604 @@ +/*************************************************************************/ +/* renderer_canvas_render.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERINGSERVERCANVASRENDER_H +#define RENDERINGSERVERCANVASRENDER_H + +#include "servers/rendering/renderer_storage.h" + +class RendererCanvasRender { +public: + static RendererCanvasRender *singleton; + + enum CanvasRectFlags { + CANVAS_RECT_REGION = 1, + CANVAS_RECT_TILE = 2, + CANVAS_RECT_FLIP_H = 4, + CANVAS_RECT_FLIP_V = 8, + CANVAS_RECT_TRANSPOSE = 16, + CANVAS_RECT_CLIP_UV = 32, + CANVAS_RECT_IS_GROUP = 64, + }; + + struct Light { + bool enabled; + Color color; + Transform2D xform; + float height; + float energy; + float scale; + int z_min; + int z_max; + int layer_min; + int layer_max; + int item_mask; + int item_shadow_mask; + float directional_distance; + RS::CanvasLightMode mode; + RS::CanvasLightBlendMode blend_mode; + RID texture; + Vector2 texture_offset; + RID canvas; + bool use_shadow; + int shadow_buffer_size; + RS::CanvasLightShadowFilter shadow_filter; + Color shadow_color; + float shadow_smooth; + + //void *texture_cache; // implementation dependent + Rect2 rect_cache; + Transform2D xform_cache; + float radius_cache; //used for shadow far plane + //CameraMatrix shadow_matrix_cache; + + Transform2D light_shader_xform; + //Vector2 light_shader_pos; + + Light *shadows_next_ptr; + Light *filter_next_ptr; + Light *next_ptr; + Light *directional_next_ptr; + + RID light_internal; + uint64_t version; + + int32_t render_index_cache; + + Light() { + version = 0; + enabled = true; + color = Color(1, 1, 1); + shadow_color = Color(0, 0, 0, 0); + height = 0; + z_min = -1024; + z_max = 1024; + layer_min = 0; + layer_max = 0; + item_mask = 1; + scale = 1.0; + energy = 1.0; + item_shadow_mask = 1; + mode = RS::CANVAS_LIGHT_MODE_POINT; + blend_mode = RS::CANVAS_LIGHT_BLEND_MODE_ADD; + // texture_cache = nullptr; + next_ptr = nullptr; + directional_next_ptr = nullptr; + filter_next_ptr = nullptr; + use_shadow = false; + shadow_buffer_size = 2048; + shadow_filter = RS::CANVAS_LIGHT_FILTER_NONE; + shadow_smooth = 0.0; + render_index_cache = -1; + directional_distance = 10000.0; + } + }; + + //easier wrap to avoid mistakes + + struct Item; + + typedef uint64_t PolygonID; + virtual PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) = 0; + virtual void free_polygon(PolygonID p_polygon) = 0; + + //also easier to wrap to avoid mistakes + struct Polygon { + PolygonID polygon_id; + Rect2 rect_cache; + + _FORCE_INLINE_ void create(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) { + ERR_FAIL_COND(polygon_id != 0); + { + uint32_t pc = p_points.size(); + const Vector2 *v2 = p_points.ptr(); + rect_cache.position = *v2; + for (uint32_t i = 1; i < pc; i++) { + rect_cache.expand_to(v2[i]); + } + } + polygon_id = singleton->request_polygon(p_indices, p_points, p_colors, p_uvs, p_bones, p_weights); + } + + _FORCE_INLINE_ Polygon() { polygon_id = 0; } + _FORCE_INLINE_ ~Polygon() { + if (polygon_id) { + singleton->free_polygon(polygon_id); + } + } + }; + + //item + + struct Item { + //commands are allocated in blocks of 4k to improve performance + //and cache coherence. + //blocks always grow but never shrink. + + struct CommandBlock { + enum { + MAX_SIZE = 4096 + }; + uint32_t usage; + uint8_t *memory; + }; + + struct Command { + enum Type { + TYPE_RECT, + TYPE_NINEPATCH, + TYPE_POLYGON, + TYPE_PRIMITIVE, + TYPE_MESH, + TYPE_MULTIMESH, + TYPE_PARTICLES, + TYPE_TRANSFORM, + TYPE_CLIP_IGNORE, + }; + + Command *next; + Type type; + virtual ~Command() {} + }; + + struct CommandRect : public Command { + Rect2 rect; + Color modulate; + Rect2 source; + uint8_t flags; + + RID texture; + + CommandRect() { + flags = 0; + type = TYPE_RECT; + } + }; + + struct CommandNinePatch : public Command { + Rect2 rect; + Rect2 source; + float margin[4]; + bool draw_center; + Color color; + RS::NinePatchAxisMode axis_x; + RS::NinePatchAxisMode axis_y; + + RID texture; + + CommandNinePatch() { + draw_center = true; + type = TYPE_NINEPATCH; + } + }; + + struct CommandPolygon : public Command { + RS::PrimitiveType primitive; + Polygon polygon; + + RID texture; + + CommandPolygon() { + type = TYPE_POLYGON; + } + }; + + struct CommandPrimitive : public Command { + uint32_t point_count; + Vector2 points[4]; + Vector2 uvs[4]; + Color colors[4]; + + RID texture; + + CommandPrimitive() { + type = TYPE_PRIMITIVE; + } + }; + + struct CommandMesh : public Command { + RID mesh; + Transform2D transform; + Color modulate; + + RID texture; + + CommandMesh() { type = TYPE_MESH; } + }; + + struct CommandMultiMesh : public Command { + RID multimesh; + + RID texture; + + CommandMultiMesh() { type = TYPE_MULTIMESH; } + }; + + struct CommandParticles : public Command { + RID particles; + + RID texture; + + CommandParticles() { type = TYPE_PARTICLES; } + }; + + struct CommandTransform : public Command { + Transform2D xform; + CommandTransform() { type = TYPE_TRANSFORM; } + }; + + struct CommandClipIgnore : public Command { + bool ignore; + CommandClipIgnore() { + type = TYPE_CLIP_IGNORE; + ignore = false; + } + }; + + struct ViewportRender { + RenderingServer *owner; + void *udata; + Rect2 rect; + }; + + Transform2D xform; + bool clip; + bool visible; + bool behind; + bool update_when_visible; + + struct CanvasGroup { + RS::CanvasGroupMode mode; + bool fit_empty; + float fit_margin; + bool blur_mipmaps; + float clear_margin; + }; + + CanvasGroup *canvas_group = nullptr; + int light_mask; + int z_final; + + mutable bool custom_rect; + mutable bool rect_dirty; + mutable Rect2 rect; + RID material; + RID skeleton; + + Item *next; + + struct CopyBackBuffer { + Rect2 rect; + Rect2 screen_rect; + bool full; + }; + CopyBackBuffer *copy_back_buffer; + + Color final_modulate; + Transform2D final_transform; + Rect2 final_clip_rect; + Item *final_clip_owner; + Item *material_owner; + Item *canvas_group_owner; + ViewportRender *vp_render; + bool distance_field; + bool light_masked; + + Rect2 global_rect_cache; + + const Rect2 &get_rect() const { + if (custom_rect || (!rect_dirty && !update_when_visible)) { + return rect; + } + + //must update rect + + if (commands == nullptr) { + rect = Rect2(); + rect_dirty = false; + return rect; + } + + Transform2D xf; + bool found_xform = false; + bool first = true; + + const Item::Command *c = commands; + + while (c) { + Rect2 r; + + switch (c->type) { + case Item::Command::TYPE_RECT: { + const Item::CommandRect *crect = static_cast<const Item::CommandRect *>(c); + r = crect->rect; + + } break; + case Item::Command::TYPE_NINEPATCH: { + const Item::CommandNinePatch *style = static_cast<const Item::CommandNinePatch *>(c); + r = style->rect; + } break; + + case Item::Command::TYPE_POLYGON: { + const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c); + r = polygon->polygon.rect_cache; + } break; + case Item::Command::TYPE_PRIMITIVE: { + const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c); + for (uint32_t j = 0; j < primitive->point_count; j++) { + if (j == 0) { + r.position = primitive->points[0]; + } else { + r.expand_to(primitive->points[j]); + } + } + } break; + case Item::Command::TYPE_MESH: { + const Item::CommandMesh *mesh = static_cast<const Item::CommandMesh *>(c); + AABB aabb = RendererStorage::base_singleton->mesh_get_aabb(mesh->mesh, RID()); + + r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); + + } break; + case Item::Command::TYPE_MULTIMESH: { + const Item::CommandMultiMesh *multimesh = static_cast<const Item::CommandMultiMesh *>(c); + AABB aabb = RendererStorage::base_singleton->multimesh_get_aabb(multimesh->multimesh); + + r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); + + } break; + case Item::Command::TYPE_PARTICLES: { + const Item::CommandParticles *particles_cmd = static_cast<const Item::CommandParticles *>(c); + if (particles_cmd->particles.is_valid()) { + AABB aabb = RendererStorage::base_singleton->particles_get_aabb(particles_cmd->particles); + r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); + } + + } break; + case Item::Command::TYPE_TRANSFORM: { + const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c); + xf = transform->xform; + found_xform = true; + [[fallthrough]]; + } + default: { + c = c->next; + continue; + } + } + + if (found_xform) { + r = xf.xform(r); + found_xform = false; + } + + if (first) { + rect = r; + first = false; + } else { + rect = rect.merge(r); + } + c = c->next; + } + + rect_dirty = false; + return rect; + } + + Command *commands; + Command *last_command; + Vector<CommandBlock> blocks; + uint32_t current_block; + + template <class T> + T *alloc_command() { + T *command; + if (commands == nullptr) { + // As the most common use case of canvas items is to + // use only one command, the first is done with it's + // own allocation. The rest of them use blocks. + command = memnew(T); + command->next = nullptr; + commands = command; + last_command = command; + } else { + //Subsequent commands go into a block. + + while (true) { + if (unlikely(current_block == (uint32_t)blocks.size())) { + // If we need more blocks, we allocate them + // (they won't be freed until this CanvasItem is + // deleted, though). + CommandBlock cb; + cb.memory = (uint8_t *)memalloc(CommandBlock::MAX_SIZE); + cb.usage = 0; + blocks.push_back(cb); + } + + CommandBlock *c = &blocks.write[current_block]; + size_t space_left = CommandBlock::MAX_SIZE - c->usage; + if (space_left < sizeof(T)) { + current_block++; + continue; + } + + //allocate block and add to the linked list + void *memory = c->memory + c->usage; + command = memnew_placement(memory, T); + command->next = nullptr; + last_command->next = command; + last_command = command; + c->usage += sizeof(T); + break; + } + } + + rect_dirty = true; + return command; + } + + void clear() { + // The first one is always allocated on heap + // the rest go in the blocks + Command *c = commands; + while (c) { + Command *n = c->next; + if (c == commands) { + memdelete(commands); + commands = nullptr; + } else { + c->~Command(); + } + c = n; + } + { + uint32_t cbc = MIN((current_block + 1), (uint32_t)blocks.size()); + CommandBlock *blockptr = blocks.ptrw(); + for (uint32_t i = 0; i < cbc; i++) { + blockptr[i].usage = 0; + } + } + + last_command = nullptr; + commands = nullptr; + current_block = 0; + clip = false; + rect_dirty = true; + final_clip_owner = nullptr; + material_owner = nullptr; + light_masked = false; + } + + RS::CanvasItemTextureFilter texture_filter; + RS::CanvasItemTextureRepeat texture_repeat; + + Item() { + commands = nullptr; + last_command = nullptr; + current_block = 0; + light_mask = 1; + vp_render = nullptr; + next = nullptr; + final_clip_owner = nullptr; + canvas_group_owner = nullptr; + clip = false; + final_modulate = Color(1, 1, 1, 1); + visible = true; + rect_dirty = true; + custom_rect = false; + behind = false; + material_owner = nullptr; + copy_back_buffer = nullptr; + distance_field = false; + light_masked = false; + update_when_visible = false; + z_final = 0; + texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT; + texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT; + } + virtual ~Item() { + clear(); + for (int i = 0; i < blocks.size(); i++) { + memfree(blocks[i].memory); + } + if (copy_back_buffer) { + memdelete(copy_back_buffer); + } + } + }; + + virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) = 0; + virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) = 0; + + struct LightOccluderInstance { + bool enabled; + RID canvas; + RID polygon; + RID occluder; + Rect2 aabb_cache; + Transform2D xform; + Transform2D xform_cache; + int light_mask; + bool sdf_collision; + RS::CanvasOccluderPolygonCullMode cull_cache; + + LightOccluderInstance *next; + + LightOccluderInstance() { + enabled = true; + sdf_collision = false; + next = nullptr; + light_mask = 1; + cull_cache = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; + } + }; + + virtual RID light_create() = 0; + virtual void light_set_texture(RID p_rid, RID p_texture) = 0; + virtual void light_set_use_shadow(RID p_rid, bool p_enable) = 0; + virtual void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) = 0; + virtual void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) = 0; + + virtual void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) = 0; + + virtual RID occluder_polygon_create() = 0; + virtual void occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) = 0; + virtual void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) = 0; + virtual void set_shadow_texture_size(int p_size) = 0; + + virtual void draw_window_margins(int *p_margins, RID *p_margin_textures) = 0; + + virtual bool free(RID p_rid) = 0; + virtual void update() = 0; + + RendererCanvasRender() { singleton = this; } + virtual ~RendererCanvasRender() {} +}; + +#endif // RENDERINGSERVERCANVASRENDER_H diff --git a/servers/rendering/renderer_compositor.cpp b/servers/rendering/renderer_compositor.cpp new file mode 100644 index 0000000000..8861522d34 --- /dev/null +++ b/servers/rendering/renderer_compositor.cpp @@ -0,0 +1,42 @@ +/*************************************************************************/ +/* renderer_compositor.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "renderer_compositor.h" + +#include "core/os/os.h" +#include "core/string/print_string.h" + +RendererCompositor *(*RendererCompositor::_create_func)() = nullptr; + +RendererCompositor *RendererCompositor::create() { + return _create_func(); +} + +RendererCanvasRender *RendererCanvasRender::singleton = nullptr; diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h new file mode 100644 index 0000000000..919ae2c6da --- /dev/null +++ b/servers/rendering/renderer_compositor.h @@ -0,0 +1,78 @@ +/*************************************************************************/ +/* renderer_compositor.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERING_SERVER_COMPOSITOR_H +#define RENDERING_SERVER_COMPOSITOR_H + +#include "core/math/camera_matrix.h" +#include "core/templates/pair.h" +#include "core/templates/self_list.h" +#include "servers/rendering/renderer_canvas_render.h" +#include "servers/rendering/renderer_scene.h" +#include "servers/rendering/renderer_scene_render.h" +#include "servers/rendering/renderer_storage.h" +#include "servers/rendering_server.h" + +class RendererCompositor { +protected: + static RendererCompositor *(*_create_func)(); + +public: + static RendererCompositor *create(); + + virtual RendererStorage *get_storage() = 0; + virtual RendererCanvasRender *get_canvas() = 0; + virtual RendererSceneRender *get_scene() = 0; + + virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) = 0; + + virtual void initialize() = 0; + virtual void begin_frame(double frame_step) = 0; + + struct BlitToScreen { + RID render_target; + Rect2i rect; + //lens distorted parameters for VR should go here + }; + + virtual void prepare_for_blitting_render_targets() = 0; + virtual void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0; + + virtual void end_frame(bool p_swap_buffers) = 0; + virtual void finalize() = 0; + virtual uint64_t get_frame_number() const = 0; + virtual float get_frame_delta_time() const = 0; + + virtual bool is_low_end() const = 0; + + virtual ~RendererCompositor() {} +}; + +#endif // RASTERIZER_H diff --git a/servers/rendering/rasterizer_rd/SCsub b/servers/rendering/renderer_rd/SCsub index 6a2e682c67..6a2e682c67 100644 --- a/servers/rendering/rasterizer_rd/SCsub +++ b/servers/rendering/renderer_rd/SCsub diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.cpp b/servers/rendering/renderer_rd/cluster_builder_rd.cpp new file mode 100644 index 0000000000..c35e5e1730 --- /dev/null +++ b/servers/rendering/renderer_rd/cluster_builder_rd.cpp @@ -0,0 +1,550 @@ +/*************************************************************************/ +/* cluster_builder_rd.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "cluster_builder_rd.h" +#include "servers/rendering/rendering_device.h" +#include "servers/rendering/rendering_server_globals.h" + +ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() { + RD::VertexFormatID vertex_format; + + { + Vector<RD::VertexAttribute> attributes; + { + RD::VertexAttribute va; + va.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; + va.stride = sizeof(float) * 3; + attributes.push_back(va); + } + vertex_format = RD::get_singleton()->vertex_format_create(attributes); + } + + { + Vector<String> versions; + versions.push_back(""); + cluster_render.cluster_render_shader.initialize(versions); + cluster_render.shader_version = cluster_render.cluster_render_shader.version_create(); + cluster_render.shader = cluster_render.cluster_render_shader.version_get_shader(cluster_render.shader_version, 0); + cluster_render.shader_pipelines[ClusterRender::PIPELINE_NORMAL] = RD::get_singleton()->render_pipeline_create(cluster_render.shader, RD::get_singleton()->framebuffer_format_create_empty(), vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState(), 0); + RD::PipelineMultisampleState ms; + ms.sample_count = RD::TEXTURE_SAMPLES_4; + cluster_render.shader_pipelines[ClusterRender::PIPELINE_MSAA] = RD::get_singleton()->render_pipeline_create(cluster_render.shader, RD::get_singleton()->framebuffer_format_create_empty(), vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), ms, RD::PipelineDepthStencilState(), RD::PipelineColorBlendState(), 0); + } + { + Vector<String> versions; + versions.push_back(""); + cluster_store.cluster_store_shader.initialize(versions); + cluster_store.shader_version = cluster_store.cluster_store_shader.version_create(); + cluster_store.shader = cluster_store.cluster_store_shader.version_get_shader(cluster_store.shader_version, 0); + cluster_store.shader_pipeline = RD::get_singleton()->compute_pipeline_create(cluster_store.shader); + } + { + Vector<String> versions; + versions.push_back(""); + cluster_debug.cluster_debug_shader.initialize(versions); + cluster_debug.shader_version = cluster_debug.cluster_debug_shader.version_create(); + cluster_debug.shader = cluster_debug.cluster_debug_shader.version_get_shader(cluster_debug.shader_version, 0); + cluster_debug.shader_pipeline = RD::get_singleton()->compute_pipeline_create(cluster_debug.shader); + } + + { // SPHERE + static const uint32_t icosphere_vertex_count = 42; + static const float icosphere_vertices[icosphere_vertex_count * 3] = { + 0, 0, -1, 0.7236073, -0.5257253, -0.4472195, -0.276388, -0.8506492, -0.4472199, -0.8944262, 0, -0.4472156, -0.276388, 0.8506492, -0.4472199, 0.7236073, 0.5257253, -0.4472195, 0.276388, -0.8506492, 0.4472199, -0.7236073, -0.5257253, 0.4472195, -0.7236073, 0.5257253, 0.4472195, 0.276388, 0.8506492, 0.4472199, 0.8944262, 0, 0.4472156, 0, 0, 1, -0.1624555, -0.4999952, -0.8506544, 0.4253227, -0.3090114, -0.8506542, 0.2628688, -0.8090116, -0.5257377, 0.8506479, 0, -0.5257359, 0.4253227, 0.3090114, -0.8506542, -0.5257298, 0, -0.8506517, -0.6881894, -0.4999969, -0.5257362, -0.1624555, 0.4999952, -0.8506544, -0.6881894, 0.4999969, -0.5257362, 0.2628688, 0.8090116, -0.5257377, 0.9510579, -0.3090126, 0, 0.9510579, 0.3090126, 0, 0, -1, 0, 0.5877856, -0.8090167, 0, -0.9510579, -0.3090126, 0, -0.5877856, -0.8090167, 0, -0.5877856, 0.8090167, 0, -0.9510579, 0.3090126, 0, 0.5877856, 0.8090167, 0, 0, 1, 0, 0.6881894, -0.4999969, 0.5257362, -0.2628688, -0.8090116, 0.5257377, -0.8506479, 0, 0.5257359, -0.2628688, 0.8090116, 0.5257377, 0.6881894, 0.4999969, 0.5257362, 0.1624555, -0.4999952, 0.8506544, 0.5257298, 0, 0.8506517, -0.4253227, -0.3090114, 0.8506542, -0.4253227, 0.3090114, 0.8506542, 0.1624555, 0.4999952, 0.8506544 + }; + static const uint32_t icosphere_triangle_count = 80; + static const uint32_t icosphere_triangle_indices[icosphere_triangle_count * 3] = { + 0, 13, 12, 1, 13, 15, 0, 12, 17, 0, 17, 19, 0, 19, 16, 1, 15, 22, 2, 14, 24, 3, 18, 26, 4, 20, 28, 5, 21, 30, 1, 22, 25, 2, 24, 27, 3, 26, 29, 4, 28, 31, 5, 30, 23, 6, 32, 37, 7, 33, 39, 8, 34, 40, 9, 35, 41, 10, 36, 38, 38, 41, 11, 38, 36, 41, 36, 9, 41, 41, 40, 11, 41, 35, 40, 35, 8, 40, 40, 39, 11, 40, 34, 39, 34, 7, 39, 39, 37, 11, 39, 33, 37, 33, 6, 37, 37, 38, 11, 37, 32, 38, 32, 10, 38, 23, 36, 10, 23, 30, 36, 30, 9, 36, 31, 35, 9, 31, 28, 35, 28, 8, 35, 29, 34, 8, 29, 26, 34, 26, 7, 34, 27, 33, 7, 27, 24, 33, 24, 6, 33, 25, 32, 6, 25, 22, 32, 22, 10, 32, 30, 31, 9, 30, 21, 31, 21, 4, 31, 28, 29, 8, 28, 20, 29, 20, 3, 29, 26, 27, 7, 26, 18, 27, 18, 2, 27, 24, 25, 6, 24, 14, 25, 14, 1, 25, 22, 23, 10, 22, 15, 23, 15, 5, 23, 16, 21, 5, 16, 19, 21, 19, 4, 21, 19, 20, 4, 19, 17, 20, 17, 3, 20, 17, 18, 3, 17, 12, 18, 12, 2, 18, 15, 16, 5, 15, 13, 16, 13, 0, 16, 12, 14, 2, 12, 13, 14, 13, 1, 14 + }; + + Vector<uint8_t> vertex_data; + vertex_data.resize(sizeof(float) * icosphere_vertex_count * 3); + copymem(vertex_data.ptrw(), icosphere_vertices, vertex_data.size()); + + sphere_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data); + + Vector<uint8_t> index_data; + index_data.resize(sizeof(uint32_t) * icosphere_triangle_count * 3); + copymem(index_data.ptrw(), icosphere_triangle_indices, index_data.size()); + + sphere_index_buffer = RD::get_singleton()->index_buffer_create(icosphere_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data); + + Vector<RID> buffers; + buffers.push_back(sphere_vertex_buffer); + + sphere_vertex_array = RD::get_singleton()->vertex_array_create(icosphere_vertex_count, vertex_format, buffers); + + sphere_index_array = RD::get_singleton()->index_array_create(sphere_index_buffer, 0, icosphere_triangle_count * 3); + + float min_d = 1e20; + for (uint32_t i = 0; i < icosphere_triangle_count; i++) { + Vector3 vertices[3]; + for (uint32_t j = 0; j < 3; j++) { + uint32_t index = icosphere_triangle_indices[i * 3 + j]; + for (uint32_t k = 0; k < 3; k++) { + vertices[j][k] = icosphere_vertices[index * 3 + k]; + } + } + Plane p(vertices[0], vertices[1], vertices[2]); + min_d = MIN(Math::abs(p.d), min_d); + } + sphere_overfit = 1.0 / min_d; + } + + { // CONE + static const uint32_t cone_vertex_count = 99; + static const float cone_vertices[cone_vertex_count * 3] = { + 0, 1, -1, 0.1950903, 0.9807853, -1, 0.3826835, 0.9238795, -1, 0.5555703, 0.8314696, -1, 0.7071068, 0.7071068, -1, 0.8314697, 0.5555702, -1, 0.9238795, 0.3826834, -1, 0.9807853, 0.1950903, -1, 1, 0, -1, 0.9807853, -0.1950902, -1, 0.9238796, -0.3826833, -1, 0.8314697, -0.5555702, -1, 0.7071068, -0.7071068, -1, 0.5555702, -0.8314697, -1, 0.3826833, -0.9238796, -1, 0.1950901, -0.9807853, -1, -3.25841e-7, -1, -1, -0.1950907, -0.9807852, -1, -0.3826839, -0.9238793, -1, -0.5555707, -0.8314693, -1, -0.7071073, -0.7071063, -1, -0.83147, -0.5555697, -1, -0.9238799, -0.3826827, -1, 0, 0, 0, -0.9807854, -0.1950894, -1, -1, 9.65599e-7, -1, -0.9807851, 0.1950913, -1, -0.9238791, 0.3826845, -1, -0.8314689, 0.5555713, -1, -0.7071059, 0.7071077, -1, -0.5555691, 0.8314704, -1, -0.3826821, 0.9238801, -1, -0.1950888, 0.9807856, -1 + }; + static const uint32_t cone_triangle_count = 62; + static const uint32_t cone_triangle_indices[cone_triangle_count * 3] = { + 0, 23, 1, 1, 23, 2, 2, 23, 3, 3, 23, 4, 4, 23, 5, 5, 23, 6, 6, 23, 7, 7, 23, 8, 8, 23, 9, 9, 23, 10, 10, 23, 11, 11, 23, 12, 12, 23, 13, 13, 23, 14, 14, 23, 15, 15, 23, 16, 16, 23, 17, 17, 23, 18, 18, 23, 19, 19, 23, 20, 20, 23, 21, 21, 23, 22, 22, 23, 24, 24, 23, 25, 25, 23, 26, 26, 23, 27, 27, 23, 28, 28, 23, 29, 29, 23, 30, 30, 23, 31, 31, 23, 32, 32, 23, 0, 7, 15, 24, 32, 0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 3, 6, 7, 3, 7, 8, 9, 9, 10, 7, 10, 11, 7, 11, 12, 15, 12, 13, 15, 13, 14, 15, 15, 16, 17, 17, 18, 19, 19, 20, 24, 20, 21, 24, 21, 22, 24, 24, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32, 32, 1, 3, 15, 17, 24, 17, 19, 24, 24, 26, 32, 26, 28, 32, 28, 30, 32, 32, 3, 7, 7, 11, 15, 32, 7, 24 + }; + + Vector<uint8_t> vertex_data; + vertex_data.resize(sizeof(float) * cone_vertex_count * 3); + copymem(vertex_data.ptrw(), cone_vertices, vertex_data.size()); + + cone_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data); + + Vector<uint8_t> index_data; + index_data.resize(sizeof(uint32_t) * cone_triangle_count * 3); + copymem(index_data.ptrw(), cone_triangle_indices, index_data.size()); + + cone_index_buffer = RD::get_singleton()->index_buffer_create(cone_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data); + + Vector<RID> buffers; + buffers.push_back(cone_vertex_buffer); + + cone_vertex_array = RD::get_singleton()->vertex_array_create(cone_vertex_count, vertex_format, buffers); + + cone_index_array = RD::get_singleton()->index_array_create(cone_index_buffer, 0, cone_triangle_count * 3); + + float min_d = 1e20; + for (uint32_t i = 0; i < cone_triangle_count; i++) { + Vector3 vertices[3]; + int32_t zero_index = -1; + for (uint32_t j = 0; j < 3; j++) { + uint32_t index = cone_triangle_indices[i * 3 + j]; + for (uint32_t k = 0; k < 3; k++) { + vertices[j][k] = cone_vertices[index * 3 + k]; + } + if (vertices[j] == Vector3()) { + zero_index = j; + } + } + + if (zero_index != -1) { + Vector3 a = vertices[(zero_index + 1) % 3]; + Vector3 b = vertices[(zero_index + 2) % 3]; + Vector3 c = a + Vector3(0, 0, 1); + Plane p(a, b, c); + min_d = MIN(Math::abs(p.d), min_d); + } + } + cone_overfit = 1.0 / min_d; + } + + { // BOX + static const uint32_t box_vertex_count = 8; + static const float box_vertices[box_vertex_count * 3] = { + -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1 + }; + static const uint32_t box_triangle_count = 12; + static const uint32_t box_triangle_indices[box_triangle_count * 3] = { + 1, 2, 0, 3, 6, 2, 7, 4, 6, 5, 0, 4, 6, 0, 2, 3, 5, 7, 1, 3, 2, 3, 7, 6, 7, 5, 4, 5, 1, 0, 6, 4, 0, 3, 1, 5 + }; + + Vector<uint8_t> vertex_data; + vertex_data.resize(sizeof(float) * box_vertex_count * 3); + copymem(vertex_data.ptrw(), box_vertices, vertex_data.size()); + + box_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data); + + Vector<uint8_t> index_data; + index_data.resize(sizeof(uint32_t) * box_triangle_count * 3); + copymem(index_data.ptrw(), box_triangle_indices, index_data.size()); + + box_index_buffer = RD::get_singleton()->index_buffer_create(box_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data); + + Vector<RID> buffers; + buffers.push_back(box_vertex_buffer); + + box_vertex_array = RD::get_singleton()->vertex_array_create(box_vertex_count, vertex_format, buffers); + + box_index_array = RD::get_singleton()->index_array_create(box_index_buffer, 0, box_triangle_count * 3); + } +} +ClusterBuilderSharedDataRD::~ClusterBuilderSharedDataRD() { + RD::get_singleton()->free(sphere_vertex_buffer); + RD::get_singleton()->free(sphere_index_buffer); + RD::get_singleton()->free(cone_vertex_buffer); + RD::get_singleton()->free(cone_index_buffer); + RD::get_singleton()->free(box_vertex_buffer); + RD::get_singleton()->free(box_index_buffer); + + cluster_render.cluster_render_shader.version_free(cluster_render.shader_version); + cluster_store.cluster_store_shader.version_free(cluster_store.shader_version); + cluster_debug.cluster_debug_shader.version_free(cluster_debug.shader_version); +} + +///////////////////////////// + +void ClusterBuilderRD::_clear() { + if (cluster_buffer.is_null()) { + return; //nothing to clear + } + RD::get_singleton()->free(cluster_buffer); + RD::get_singleton()->free(cluster_render_buffer); + RD::get_singleton()->free(element_buffer); + cluster_buffer = RID(); + cluster_render_buffer = RID(); + element_buffer = RID(); + + memfree(render_elements); + + render_elements = nullptr; + render_element_max = 0; + render_element_count = 0; + + RD::get_singleton()->free(framebuffer); + framebuffer = RID(); + + cluster_render_uniform_set = RID(); + cluster_store_uniform_set = RID(); +} + +void ClusterBuilderRD::setup(Size2i p_screen_size, uint32_t p_max_elements, RID p_depth_buffer, RID p_depth_buffer_sampler, RID p_color_buffer) { + ERR_FAIL_COND(p_max_elements == 0); + ERR_FAIL_COND(p_screen_size.x < 1); + ERR_FAIL_COND(p_screen_size.y < 1); + + _clear(); + + screen_size = p_screen_size; + + cluster_screen_size.width = (p_screen_size.width - 1) / cluster_size + 1; + cluster_screen_size.height = (p_screen_size.height - 1) / cluster_size + 1; + + max_elements_by_type = p_max_elements; + if (max_elements_by_type % 32) { //need to be 32 aligned + max_elements_by_type += 32 - (max_elements_by_type % 32); + } + + cluster_buffer_size = cluster_screen_size.x * cluster_screen_size.y * (max_elements_by_type / 32 + 32) * ELEMENT_TYPE_MAX * 4; + + render_element_max = max_elements_by_type * ELEMENT_TYPE_MAX; + + uint32_t element_tag_bits_size = render_element_max / 32; + uint32_t element_tag_depth_bits_size = render_element_max; + cluster_render_buffer_size = cluster_screen_size.x * cluster_screen_size.y * (element_tag_bits_size + element_tag_depth_bits_size) * 4; // tag bits (element was used) and tag depth (depth range in which it was used) + + cluster_render_buffer = RD::get_singleton()->storage_buffer_create(cluster_render_buffer_size); + cluster_buffer = RD::get_singleton()->storage_buffer_create(cluster_buffer_size); + + render_elements = (RenderElementData *)memalloc(sizeof(RenderElementData *) * render_element_max); + render_element_count = 0; + + element_buffer = RD::get_singleton()->storage_buffer_create(sizeof(RenderElementData) * render_element_max); + + uint32_t div_value = 1 << divisor; + if (use_msaa) { + framebuffer = RD::get_singleton()->framebuffer_create_empty(p_screen_size / div_value, RD::TEXTURE_SAMPLES_4); + } else { + framebuffer = RD::get_singleton()->framebuffer_create_empty(p_screen_size / div_value); + } + + { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 1; + u.ids.push_back(state_uniform); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 2; + u.ids.push_back(element_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 3; + u.ids.push_back(cluster_render_buffer); + uniforms.push_back(u); + } + + cluster_render_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shared->cluster_render.shader, 0); + } + + { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 1; + u.ids.push_back(cluster_render_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 2; + u.ids.push_back(cluster_buffer); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 3; + u.ids.push_back(element_buffer); + uniforms.push_back(u); + } + + cluster_store_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shared->cluster_store.shader, 0); + } + + if (p_color_buffer.is_valid()) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 1; + u.ids.push_back(cluster_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 2; + u.ids.push_back(p_color_buffer); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 3; + u.ids.push_back(p_depth_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 4; + u.ids.push_back(p_depth_buffer_sampler); + uniforms.push_back(u); + } + + debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shared->cluster_debug.shader, 0); + } else { + debug_uniform_set = RID(); + } +} + +void ClusterBuilderRD::begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection, bool p_flip_y) { + view_xform = p_view_transform.affine_inverse(); + projection = p_cam_projection; + z_near = projection.get_z_near(); + z_far = projection.get_z_far(); + orthogonal = p_cam_projection.is_orthogonal(); + adjusted_projection = projection; + if (!orthogonal) { + adjusted_projection.adjust_perspective_znear(0.0001); + } + + CameraMatrix correction; + correction.set_depth_correction(p_flip_y); + projection = correction * projection; + adjusted_projection = correction * adjusted_projection; + + //reset counts + render_element_count = 0; + for (uint32_t i = 0; i < ELEMENT_TYPE_MAX; i++) { + cluster_count_by_type[i] = 0; + } +} + +void ClusterBuilderRD::bake_cluster() { + RENDER_TIMESTAMP(">Bake Cluster"); + + //clear cluster buffer + RD::get_singleton()->buffer_clear(cluster_buffer, 0, cluster_buffer_size); + + if (render_element_count > 0) { + //clear render buffer + RD::get_singleton()->buffer_clear(cluster_render_buffer, 0, cluster_render_buffer_size); + + { //fill state uniform + + StateUniform state; + + RendererStorageRD::store_camera(adjusted_projection, state.projection); + state.inv_z_far = 1.0 / z_far; + state.screen_to_clusters_shift = get_shift_from_power_of_2(cluster_size); + state.screen_to_clusters_shift -= divisor; //screen is smaller, shift one less + + state.cluster_screen_width = cluster_screen_size.x; + state.cluster_depth_offset = (render_element_max / 32); + state.cluster_data_size = state.cluster_depth_offset + render_element_max; + + RD::get_singleton()->buffer_update(state_uniform, 0, sizeof(StateUniform), &state); + } + + //update instances + + RD::get_singleton()->buffer_update(element_buffer, 0, sizeof(RenderElementData) * render_element_count, render_elements); + + RENDER_TIMESTAMP("Render Elements"); + + //render elements + { + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD); + ClusterBuilderSharedDataRD::ClusterRender::PushConstant push_constant = {}; + + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shared->cluster_render.shader_pipelines[use_msaa ? ClusterBuilderSharedDataRD::ClusterRender::PIPELINE_MSAA : ClusterBuilderSharedDataRD::ClusterRender::PIPELINE_NORMAL]); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, cluster_render_uniform_set, 0); + + for (uint32_t i = 0; i < render_element_count;) { + push_constant.base_index = i; + switch (render_elements[i].type) { + case ELEMENT_TYPE_OMNI_LIGHT: { + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, shared->sphere_vertex_array); + RD::get_singleton()->draw_list_bind_index_array(draw_list, shared->sphere_index_array); + } break; + case ELEMENT_TYPE_SPOT_LIGHT: { + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, shared->cone_vertex_array); + RD::get_singleton()->draw_list_bind_index_array(draw_list, shared->cone_index_array); + } break; + case ELEMENT_TYPE_DECAL: + case ELEMENT_TYPE_REFLECTION_PROBE: { + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, shared->box_vertex_array); + RD::get_singleton()->draw_list_bind_index_array(draw_list, shared->box_index_array); + } break; + } + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ClusterBuilderSharedDataRD::ClusterRender::PushConstant)); + + uint32_t instances = 1; +#if 0 + for (uint32_t j = i+1; j < element_count; j++) { + if (elements[i].type!=elements[j].type) { + break; + } + instances++; + } +#endif + RD::get_singleton()->draw_list_draw(draw_list, true, instances); + i += instances; + } + RD::get_singleton()->draw_list_end(); + } + //store elements + RENDER_TIMESTAMP("Pack Elements"); + + { + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shared->cluster_store.shader_pipeline); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cluster_store_uniform_set, 0); + + ClusterBuilderSharedDataRD::ClusterStore::PushConstant push_constant; + push_constant.cluster_render_data_size = render_element_max / 32 + render_element_max; + push_constant.max_render_element_count_div_32 = render_element_max / 32; + push_constant.cluster_screen_size[0] = cluster_screen_size.x; + push_constant.cluster_screen_size[1] = cluster_screen_size.y; + push_constant.render_element_count_div_32 = render_element_count > 0 ? (render_element_count - 1) / 32 + 1 : 0; + push_constant.max_cluster_element_count_div_32 = max_elements_by_type / 32; + push_constant.pad1 = 0; + push_constant.pad2 = 0; + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ClusterBuilderSharedDataRD::ClusterStore::PushConstant)); + + RD::get_singleton()->compute_list_dispatch_threads(compute_list, cluster_screen_size.x, cluster_screen_size.y, 1, 8, 8, 1); + + RD::get_singleton()->compute_list_end(); + } + } + RENDER_TIMESTAMP("<Bake Cluster"); +} + +void ClusterBuilderRD::debug(ElementType p_element) { + ERR_FAIL_COND(debug_uniform_set.is_null()); + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shared->cluster_debug.shader_pipeline); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, debug_uniform_set, 0); + + ClusterBuilderSharedDataRD::ClusterDebug::PushConstant push_constant; + push_constant.screen_size[0] = screen_size.x; + push_constant.screen_size[1] = screen_size.y; + push_constant.cluster_screen_size[0] = cluster_screen_size.x; + push_constant.cluster_screen_size[1] = cluster_screen_size.y; + push_constant.cluster_shift = get_shift_from_power_of_2(cluster_size); + push_constant.cluster_type = p_element; + push_constant.orthogonal = orthogonal; + push_constant.z_far = z_far; + push_constant.z_near = z_near; + push_constant.max_cluster_element_count_div_32 = max_elements_by_type / 32; + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ClusterBuilderSharedDataRD::ClusterDebug::PushConstant)); + + RD::get_singleton()->compute_list_dispatch_threads(compute_list, screen_size.x, screen_size.y, 1, 8, 8, 1); + + RD::get_singleton()->compute_list_end(); +} + +RID ClusterBuilderRD::get_cluster_buffer() const { + return cluster_buffer; +} + +uint32_t ClusterBuilderRD::get_cluster_size() const { + return cluster_size; +} + +uint32_t ClusterBuilderRD::get_max_cluster_elements() const { + return max_elements_by_type; +} + +void ClusterBuilderRD::set_shared(ClusterBuilderSharedDataRD *p_shared) { + shared = p_shared; +} + +ClusterBuilderRD::ClusterBuilderRD() { + state_uniform = RD::get_singleton()->uniform_buffer_create(sizeof(StateUniform)); +} + +ClusterBuilderRD::~ClusterBuilderRD() { + _clear(); + RD::get_singleton()->free(state_uniform); +} diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.h b/servers/rendering/renderer_rd/cluster_builder_rd.h new file mode 100644 index 0000000000..dc1707b534 --- /dev/null +++ b/servers/rendering/renderer_rd/cluster_builder_rd.h @@ -0,0 +1,378 @@ +/*************************************************************************/ +/* cluster_builder_rd.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef CLUSTER_BUILDER_RD_H +#define CLUSTER_BUILDER_RD_H + +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" +#include "servers/rendering/renderer_rd/shaders/cluster_debug.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/cluster_render.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/cluster_store.glsl.gen.h" + +class ClusterBuilderSharedDataRD { + friend class ClusterBuilderRD; + + RID sphere_vertex_buffer; + RID sphere_vertex_array; + RID sphere_index_buffer; + RID sphere_index_array; + float sphere_overfit = 0.0; //because an icosphere is not a perfect sphere, we need to enlarge it to cover the sphere area + + RID cone_vertex_buffer; + RID cone_vertex_array; + RID cone_index_buffer; + RID cone_index_array; + float cone_overfit = 0.0; //because an cone mesh is not a perfect sphere, we need to enlarge it to cover the actual cone area + + RID box_vertex_buffer; + RID box_vertex_array; + RID box_index_buffer; + RID box_index_array; + + enum Divisor { + DIVISOR_1, + DIVISOR_2, + DIVISOR_4, + }; + + struct ClusterRender { + struct PushConstant { + uint32_t base_index; + uint32_t pad0; + uint32_t pad1; + uint32_t pad2; + }; + + ClusterRenderShaderRD cluster_render_shader; + RID shader_version; + RID shader; + enum PipelineVersion { + PIPELINE_NORMAL, + PIPELINE_MSAA, + PIPELINE_MAX + }; + + RID shader_pipelines[PIPELINE_MAX]; + } cluster_render; + + struct ClusterStore { + struct PushConstant { + uint32_t cluster_render_data_size; // how much data for a single cluster takes + uint32_t max_render_element_count_div_32; //divided by 32 + uint32_t cluster_screen_size[2]; + uint32_t render_element_count_div_32; //divided by 32 + uint32_t max_cluster_element_count_div_32; //divided by 32 + uint32_t pad1; + uint32_t pad2; + }; + + ClusterStoreShaderRD cluster_store_shader; + RID shader_version; + RID shader; + RID shader_pipeline; + } cluster_store; + + struct ClusterDebug { + struct PushConstant { + uint32_t screen_size[2]; + uint32_t cluster_screen_size[2]; + + uint32_t cluster_shift; + uint32_t cluster_type; + float z_near; + float z_far; + + uint32_t orthogonal; + uint32_t max_cluster_element_count_div_32; + uint32_t pad1; + uint32_t pad2; + }; + + ClusterDebugShaderRD cluster_debug_shader; + RID shader_version; + RID shader; + RID shader_pipeline; + } cluster_debug; + +public: + ClusterBuilderSharedDataRD(); + ~ClusterBuilderSharedDataRD(); +}; + +class ClusterBuilderRD { +public: + enum LightType { + LIGHT_TYPE_OMNI, + LIGHT_TYPE_SPOT + }; + + enum BoxType { + BOX_TYPE_REFLECTION_PROBE, + BOX_TYPE_DECAL, + }; + + enum ElementType { + ELEMENT_TYPE_OMNI_LIGHT, + ELEMENT_TYPE_SPOT_LIGHT, + ELEMENT_TYPE_DECAL, + ELEMENT_TYPE_REFLECTION_PROBE, + ELEMENT_TYPE_MAX, + + }; + +private: + ClusterBuilderSharedDataRD *shared = nullptr; + + struct RenderElementData { + uint32_t type; //0-4 + uint32_t touches_near; + uint32_t touches_far; + uint32_t original_index; + float transform_inv[12]; //transposed transform for less space + float scale[3]; + uint32_t pad; + }; + + uint32_t cluster_count_by_type[ELEMENT_TYPE_MAX] = {}; + uint32_t max_elements_by_type = 0; + + RenderElementData *render_elements = nullptr; + uint32_t render_element_count = 0; + uint32_t render_element_max = 0; + + Transform view_xform; + CameraMatrix adjusted_projection; + CameraMatrix projection; + float z_far = 0; + float z_near = 0; + bool orthogonal = false; + + enum Divisor { + DIVISOR_1, + DIVISOR_2, + DIVISOR_4, + }; + + uint32_t cluster_size = 32; + bool use_msaa = true; + Divisor divisor = DIVISOR_4; + + Size2i screen_size; + Size2i cluster_screen_size; + + RID framebuffer; + RID cluster_render_buffer; //used for creating + RID cluster_buffer; //used for rendering + RID element_buffer; //used for storing, to hint element touches far plane or near plane + uint32_t cluster_render_buffer_size = 0; + uint32_t cluster_buffer_size = 0; + + RID cluster_render_uniform_set; + RID cluster_store_uniform_set; + + //persistent data + + void _clear(); + + struct StateUniform { + float projection[16]; + float inv_z_far; + uint32_t screen_to_clusters_shift; // shift to obtain coordinates in block indices + uint32_t cluster_screen_width; // + uint32_t cluster_data_size; // how much data for a single cluster takes + uint32_t cluster_depth_offset; + uint32_t pad0; + uint32_t pad1; + uint32_t pad2; + }; + + RID state_uniform; + + RID debug_uniform_set; + +public: + void setup(Size2i p_screen_size, uint32_t p_max_elements, RID p_depth_buffer, RID p_depth_buffer_sampler, RID p_color_buffer); + + void begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection, bool p_flip_y); + + _FORCE_INLINE_ void add_light(LightType p_type, const Transform &p_transform, float p_radius, float p_spot_aperture) { + if (p_type == LIGHT_TYPE_OMNI && cluster_count_by_type[ELEMENT_TYPE_OMNI_LIGHT] == max_elements_by_type) { + return; //max number elements reached + } + if (p_type == LIGHT_TYPE_SPOT && cluster_count_by_type[ELEMENT_TYPE_SPOT_LIGHT] == max_elements_by_type) { + return; //max number elements reached + } + + RenderElementData &e = render_elements[render_element_count]; + + Transform xform = view_xform * p_transform; + + float radius = xform.basis.get_uniform_scale(); + if (radius > 0.98 || radius < 1.02) { + xform.basis.orthonormalize(); + } + + radius *= p_radius; + + if (p_type == LIGHT_TYPE_OMNI) { + radius *= shared->sphere_overfit; // overfit icosphere + + //omni + float depth = -xform.origin.z; + if (orthogonal) { + e.touches_near = (depth - radius) < z_near; + } else { + //contains camera inside light + float radius2 = radius * shared->sphere_overfit; // overfit again for outer size (camera may be outside actual sphere but behind an icosphere vertex) + e.touches_near = xform.origin.length_squared() < radius2 * radius2; + } + + e.touches_far = (depth + radius) > z_far; + e.scale[0] = radius; + e.scale[1] = radius; + e.scale[2] = radius; + e.type = ELEMENT_TYPE_OMNI_LIGHT; + e.original_index = cluster_count_by_type[ELEMENT_TYPE_OMNI_LIGHT]; + + RendererStorageRD::store_transform_transposed_3x4(xform, e.transform_inv); + + cluster_count_by_type[ELEMENT_TYPE_OMNI_LIGHT]++; + + } else { + //spot + radius *= shared->cone_overfit; // overfit icosphere + + real_t len = Math::tan(Math::deg2rad(p_spot_aperture)) * radius; + //approximate, probably better to use a cone support function + float max_d = -1e20; + float min_d = 1e20; +#define CONE_MINMAX(m_x, m_y) \ + { \ + float d = -xform.xform(Vector3(len * m_x, len * m_y, -radius)).z; \ + min_d = MIN(d, min_d); \ + max_d = MAX(d, max_d); \ + } + + CONE_MINMAX(1, 1); + CONE_MINMAX(-1, 1); + CONE_MINMAX(-1, -1); + CONE_MINMAX(1, -1); + + if (orthogonal) { + e.touches_near = min_d < z_near; + } else { + //contains camera inside light + Plane base_plane(xform.origin, -xform.basis.get_axis(Vector3::AXIS_Z)); + float dist = base_plane.distance_to(Vector3()); + if (dist >= 0 && dist < radius) { + //inside, check angle + float angle = Math::rad2deg(Math::acos((-xform.origin.normalized()).dot(-xform.basis.get_axis(Vector3::AXIS_Z)))); + e.touches_near = angle < p_spot_aperture * 1.05; //overfit aperture a little due to cone overfit + } else { + e.touches_near = false; + } + } + + e.touches_far = max_d > z_far; + + e.scale[0] = len * shared->cone_overfit; + e.scale[1] = len * shared->cone_overfit; + e.scale[2] = radius; + + e.type = ELEMENT_TYPE_SPOT_LIGHT; + e.original_index = cluster_count_by_type[ELEMENT_TYPE_SPOT_LIGHT]; //use omni since they share index + + RendererStorageRD::store_transform_transposed_3x4(xform, e.transform_inv); + + cluster_count_by_type[ELEMENT_TYPE_SPOT_LIGHT]++; + } + + render_element_count++; + } + + _FORCE_INLINE_ void add_box(BoxType p_box_type, const Transform &p_transform, const Vector3 &p_half_extents) { + if (p_box_type == BOX_TYPE_DECAL && cluster_count_by_type[ELEMENT_TYPE_DECAL] == max_elements_by_type) { + return; //max number elements reached + } + if (p_box_type == BOX_TYPE_REFLECTION_PROBE && cluster_count_by_type[ELEMENT_TYPE_REFLECTION_PROBE] == max_elements_by_type) { + return; //max number elements reached + } + + RenderElementData &e = render_elements[render_element_count]; + Transform xform = view_xform * p_transform; + + //extract scale and scale the matrix by it, makes things simpler + Vector3 scale = p_half_extents; + for (uint32_t i = 0; i < 3; i++) { + float s = xform.basis.elements[i].length(); + scale[i] *= s; + xform.basis.elements[i] /= s; + }; + + float box_depth = Math::abs(xform.basis.xform_inv(Vector3(0, 0, -1)).dot(scale)); + float depth = -xform.origin.z; + + if (orthogonal) { + e.touches_near = depth - box_depth < z_near; + } else { + //contains camera inside box + Vector3 inside = xform.xform_inv(Vector3(0, 0, 0)).abs(); + e.touches_near = inside.x < scale.x && inside.y < scale.y && inside.z < scale.z; + } + + e.touches_far = depth + box_depth > z_far; + + e.scale[0] = scale.x; + e.scale[1] = scale.y; + e.scale[2] = scale.z; + + e.type = (p_box_type == BOX_TYPE_DECAL) ? ELEMENT_TYPE_DECAL : ELEMENT_TYPE_REFLECTION_PROBE; + e.original_index = cluster_count_by_type[e.type]; + + RendererStorageRD::store_transform_transposed_3x4(xform, e.transform_inv); + + cluster_count_by_type[e.type]++; + render_element_count++; + } + + void bake_cluster(); + void debug(ElementType p_element); + + RID get_cluster_buffer() const; + uint32_t get_cluster_size() const; + uint32_t get_max_cluster_elements() const; + + void set_shared(ClusterBuilderSharedDataRD *p_shared); + + ClusterBuilderRD(); + ~ClusterBuilderRD(); +}; + +#endif // CLUSTER_BUILDER_H diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index d669db1b4b..f1bab19445 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_effects_rd.cpp */ +/* effects_rd.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,10 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rasterizer_effects_rd.h" +#include "effects_rd.h" +#include "core/config/project_settings.h" +#include "core/math/math_defs.h" #include "core/os/os.h" -#include "core/project_settings.h" #include "thirdparty/misc/cubemap_coeffs.h" @@ -58,7 +59,7 @@ static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_arra } } -RID RasterizerEffectsRD::_get_uniform_set_from_image(RID p_image) { +RID EffectsRD::_get_uniform_set_from_image(RID p_image) { if (image_to_uniform_set_cache.has(p_image)) { RID uniform_set = image_to_uniform_set_cache[p_image]; if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { @@ -67,7 +68,7 @@ RID RasterizerEffectsRD::_get_uniform_set_from_image(RID p_image) { } Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; u.ids.push_back(p_image); uniforms.push_back(u); @@ -79,7 +80,7 @@ RID RasterizerEffectsRD::_get_uniform_set_from_image(RID p_image) { return uniform_set; } -RID RasterizerEffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) { +RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) { if (texture_to_uniform_set_cache.has(p_texture)) { RID uniform_set = texture_to_uniform_set_cache[p_texture]; if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { @@ -89,12 +90,12 @@ RID RasterizerEffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 0; u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); u.ids.push_back(p_texture); uniforms.push_back(u); - //any thing with the same configuration (one texture in binding 0 for set 0), is good + //anything with the same configuration (one texture in binding 0 for set 0), is good RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, 0), 0); texture_to_uniform_set_cache[p_texture] = uniform_set; @@ -102,7 +103,7 @@ RID RasterizerEffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use return uniform_set; } -RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) { +RID EffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) { if (texture_to_compute_uniform_set_cache.has(p_texture)) { RID uniform_set = texture_to_compute_uniform_set_cache[p_texture]; if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { @@ -112,7 +113,7 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bo Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 0; u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); u.ids.push_back(p_texture); @@ -125,7 +126,34 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bo return uniform_set; } -RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture_pair(RID p_texture1, RID p_texture2, bool p_use_mipmaps) { +RID EffectsRD::_get_compute_uniform_set_from_texture_and_sampler(RID p_texture, RID p_sampler) { + TextureSamplerPair tsp; + tsp.texture = p_texture; + tsp.sampler = p_sampler; + + if (texture_sampler_to_compute_uniform_set_cache.has(tsp)) { + RID uniform_set = texture_sampler_to_compute_uniform_set_cache[tsp]; + if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + return uniform_set; + } + } + + Vector<RD::Uniform> uniforms; + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 0; + u.ids.push_back(p_sampler); + u.ids.push_back(p_texture); + uniforms.push_back(u); + //any thing with the same configuration (one texture in binding 0 for set 0), is good + RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.blur_shader.version_get_shader(ssao.blur_shader_version, 0), 0); + + texture_sampler_to_compute_uniform_set_cache[tsp] = uniform_set; + + return uniform_set; +} + +RID EffectsRD::_get_compute_uniform_set_from_texture_pair(RID p_texture1, RID p_texture2, bool p_use_mipmaps) { TexturePair tp; tp.texture1 = p_texture1; tp.texture2 = p_texture2; @@ -140,7 +168,7 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture_pair(RID p_textur Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 0; u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); u.ids.push_back(p_texture1); @@ -148,7 +176,7 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture_pair(RID p_textur } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 1; u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); u.ids.push_back(p_texture2); @@ -162,7 +190,7 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture_pair(RID p_textur return uniform_set; } -RID RasterizerEffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1, RID p_texture2) { +RID EffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1, RID p_texture2) { TexturePair tp; tp.texture1 = p_texture1; tp.texture2 = p_texture2; @@ -177,14 +205,14 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1 Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 0; u.ids.push_back(p_texture1); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(p_texture2); uniforms.push_back(u); @@ -197,7 +225,7 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1 return uniform_set; } -void RasterizerEffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y, bool p_panorama) { +void EffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y, bool p_panorama) { zeromem(©_to_fb.push_constant, sizeof(CopyToFbPushConstant)); copy_to_fb.push_constant.use_section = true; @@ -218,7 +246,7 @@ void RasterizerEffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_f RD::get_singleton()->draw_list_draw(draw_list, true); } -void RasterizerEffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary) { +void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary) { zeromem(©_to_fb.push_constant, sizeof(CopyToFbPushConstant)); if (p_flip_y) { @@ -246,7 +274,7 @@ void RasterizerEffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_fr RD::get_singleton()->draw_list_end(); } -void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_all_source, bool p_8_bit_dst, bool p_alpha_to_one) { +void EffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_all_source, bool p_8_bit_dst, bool p_alpha_to_one) { zeromem(©.push_constant, sizeof(CopyPushConstant)); if (p_flip_y) { copy.push_constant.flags |= COPY_FLAG_FLIP_Y; @@ -283,7 +311,7 @@ void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_textu RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array) { +void EffectsRD::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array) { zeromem(©.push_constant, sizeof(CopyPushConstant)); copy.push_constant.section[0] = 0; @@ -306,7 +334,7 @@ void RasterizerEffectsRD::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far) { +void EffectsRD::copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far) { zeromem(©.push_constant, sizeof(CopyPushConstant)); if (p_flip_y) { copy.push_constant.flags |= COPY_FLAG_FLIP_Y; @@ -333,7 +361,7 @@ void RasterizerEffectsRD::copy_depth_to_rect_and_linearize(RID p_source_rd_textu RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y) { +void EffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y) { zeromem(©.push_constant, sizeof(CopyPushConstant)); if (p_flip_y) { copy.push_constant.flags |= COPY_FLAG_FLIP_Y; @@ -358,7 +386,7 @@ void RasterizerEffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst) { +void EffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst) { zeromem(©.push_constant, sizeof(CopyPushConstant)); copy.push_constant.section[0] = 0; @@ -383,7 +411,7 @@ void RasterizerEffectsRD::set_color(RID p_dest_texture, const Color &p_color, co RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst) { +void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst) { zeromem(©.push_constant, sizeof(CopyPushConstant)); uint32_t base_flags = 0; @@ -418,7 +446,7 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { +void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { zeromem(©.push_constant, sizeof(CopyPushConstant)); CopyMode copy_mode = p_first_pass && p_auto_exposure.is_valid() ? COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : COPY_MODE_GAUSSIAN_GLOW; @@ -455,7 +483,7 @@ void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_text RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera) { +void EffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera) { RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); int32_t x_groups = (p_screen_size.width - 1) / 8 + 1; @@ -578,7 +606,7 @@ void RasterizerEffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_ro RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RID p_depth, const CameraMatrix &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RenderingServer::SubSurfaceScatteringQuality p_quality) { +void EffectsRD::sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RID p_depth, const CameraMatrix &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RenderingServer::SubSurfaceScatteringQuality p_quality) { RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); int32_t x_groups = (p_screen_size.width - 1) / 8 + 1; @@ -624,7 +652,7 @@ void RasterizerEffectsRD::sub_surface_scattering(RID p_diffuse, RID p_diffuse2, } } -void RasterizerEffectsRD::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection) { +void EffectsRD::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection) { RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>()); if (p_reflection.is_valid()) { @@ -654,7 +682,7 @@ void RasterizerEffectsRD::merge_specular(RID p_dest_framebuffer, RID p_specular, RD::get_singleton()->draw_list_end(); } -void RasterizerEffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size) { +void EffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size) { zeromem(©.push_constant, sizeof(CopyPushConstant)); copy.push_constant.section[0] = 0; @@ -674,30 +702,27 @@ void RasterizerEffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_textur RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip) { +void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, bool p_dp_flip) { CopyToDPPushConstant push_constant; - push_constant.screen_size[0] = p_rect.size.x; - push_constant.screen_size[1] = p_rect.size.y; - push_constant.dest_offset[0] = p_rect.position.x; - push_constant.dest_offset[1] = p_rect.position.y; - push_constant.bias = p_bias; + push_constant.screen_rect[0] = p_rect.position.x; + push_constant.screen_rect[1] = p_rect.position.y; + push_constant.screen_rect[2] = p_rect.size.width; + push_constant.screen_rect[3] = p_rect.size.height; push_constant.z_far = p_z_far; push_constant.z_near = p_z_near; push_constant.z_flip = p_dp_flip; - int32_t x_groups = (p_rect.size.width - 1) / 8 + 1; - int32_t y_groups = (p_rect.size.height - 1) / 8 + 1; + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cube_to_dp.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cube_to_dp.pipeline); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 1); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(CopyToDPPushConstant)); - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); - RD::get_singleton()->compute_list_end(); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CopyToDPPushConstant)); + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); } -void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) { +void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) { zeromem(&tonemap.push_constant, sizeof(TonemapPushConstant)); tonemap.push_constant.use_bcs = p_settings.use_bcs; @@ -718,7 +743,10 @@ void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, tonemap.push_constant.glow_texture_size[1] = p_settings.glow_texture_size.y; tonemap.push_constant.glow_mode = p_settings.glow_mode; - TonemapMode mode = p_settings.glow_use_bicubic_upscale ? TONEMAP_MODE_BICUBIC_GLOW_FILTER : TONEMAP_MODE_NORMAL; + int mode = p_settings.glow_use_bicubic_upscale ? TONEMAP_MODE_BICUBIC_GLOW_FILTER : TONEMAP_MODE_NORMAL; + if (p_settings.use_1d_color_correction) { + mode += 2; + } tonemap.push_constant.tonemapper = p_settings.tonemap_mode; tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure; @@ -746,7 +774,7 @@ void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, RD::get_singleton()->draw_list_end(); } -void RasterizerEffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) { +void EffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) { luminance_reduce.push_constant.source_size[0] = p_source_size.x; luminance_reduce.push_constant.source_size[1] = p_source_size.y; luminance_reduce.push_constant.max_luminance = p_max_luminance; @@ -788,7 +816,7 @@ void RasterizerEffectsRD::luminance_reduction(RID p_source_texture, const Size2i RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_halfsize_texture1, RID p_halfsize_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) { +void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_halfsize_texture1, RID p_halfsize_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) { bokeh.push_constant.blur_far_active = p_dof_far; bokeh.push_constant.blur_far_begin = p_dof_far_begin; bokeh.push_constant.blur_far_end = p_dof_far_begin + p_dof_far_size; @@ -948,160 +976,358 @@ void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, con RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, const Size2i &p_depth_buffer_size, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao1, bool p_half_size, RID p_ao2, RID p_upscale_buffer, float p_intensity, float p_radius, float p_bias, const CameraMatrix &p_projection, RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOBlur p_blur, float p_edge_sharpness) { - //minify first - ssao.minify_push_constant.orthogonal = p_projection.is_orthogonal(); - ssao.minify_push_constant.z_near = p_projection.get_z_near(); - ssao.minify_push_constant.z_far = p_projection.get_z_far(); - ssao.minify_push_constant.pixel_size[0] = 1.0 / p_depth_buffer_size.x; - ssao.minify_push_constant.pixel_size[1] = 1.0 / p_depth_buffer_size.y; - ssao.minify_push_constant.source_size[0] = p_depth_buffer_size.x; - ssao.minify_push_constant.source_size[1] = p_depth_buffer_size.y; - - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - - /* FIRST PASS */ - // Minify the depth buffer. - - for (int i = 0; i < depth_mipmaps.size(); i++) { - if (i == 0) { - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_MINIFY_FIRST]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 0); - } else { - if (i == 1) { - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_MINIFY_MIPMAP]); - } +void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass) { + RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, ssao.gather_uniform_set, 0); + if ((p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) && !p_adaptive_base_pass) { + RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, ssao.importance_map_uniform_set, 1); + } - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(depth_mipmaps[i - 1]), 0); + for (int i = 0; i < 4; i++) { + if ((p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { + continue; } - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(depth_mipmaps[i]), 1); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.minify_push_constant, sizeof(SSAOMinifyPushConstant)); - // shrink after set - ssao.minify_push_constant.source_size[0] = MAX(1, ssao.minify_push_constant.source_size[0] >> 1); - ssao.minify_push_constant.source_size[1] = MAX(1, ssao.minify_push_constant.source_size[1] >> 1); + ssao.gather_push_constant.pass_coord_offset[0] = i % 2; + ssao.gather_push_constant.pass_coord_offset[1] = i / 2; + ssao.gather_push_constant.pass_uv_offset[0] = ((i % 2) - 0.0) / p_settings.full_screen_size.x; + ssao.gather_push_constant.pass_uv_offset[1] = ((i / 2) - 0.0) / p_settings.full_screen_size.y; + ssao.gather_push_constant.pass = i; + RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, _get_uniform_set_from_image(p_ao_slices[i]), 2); + RD::get_singleton()->compute_list_set_push_constant(p_compute_list, &ssao.gather_push_constant, sizeof(SSAOGatherPushConstant)); - int x_groups = (ssao.minify_push_constant.source_size[0] - 1) / 8 + 1; - int y_groups = (ssao.minify_push_constant.source_size[1] - 1) / 8 + 1; + int x_groups = ((p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1)) - 1) / 8 + 1; + int y_groups = ((p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1)) - 1) / 8 + 1; - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); - RD::get_singleton()->compute_list_add_barrier(compute_list); + RD::get_singleton()->compute_list_dispatch(p_compute_list, x_groups, y_groups, 1); } + RD::get_singleton()->compute_list_add_barrier(p_compute_list); +} - /* SECOND PASS */ - // Gather samples +void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &p_depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets) { + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->draw_command_begin_label("SSAO"); + /* FIRST PASS */ + // Downsample and deinterleave the depth buffer. + { + RD::get_singleton()->draw_command_begin_label("Downsample Depth"); + if (p_invalidate_uniform_sets) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 0; + u.ids.push_back(p_depth_mipmaps[1]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 1; + u.ids.push_back(p_depth_mipmaps[2]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 2; + u.ids.push_back(p_depth_mipmaps[3]); + uniforms.push_back(u); + } + ssao.downsample_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.downsample_shader.version_get_shader(ssao.downsample_shader_version, 2), 2); + } - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[(SSAO_GATHER_LOW + p_quality) + (p_half_size ? 4 : 0)]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_mipmaps_texture), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao1), 1); - if (!p_half_size) { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 2); - } - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_normal_buffer), 3); + float depth_linearize_mul = -p_projection.matrix[3][2]; + float depth_linearize_add = p_projection.matrix[2][2]; + if (depth_linearize_mul * depth_linearize_add < 0) { + depth_linearize_add = -depth_linearize_add; + } - ssao.gather_push_constant.screen_size[0] = p_depth_buffer_size.x; - ssao.gather_push_constant.screen_size[1] = p_depth_buffer_size.y; - if (p_half_size) { - ssao.gather_push_constant.screen_size[0] >>= 1; - ssao.gather_push_constant.screen_size[1] >>= 1; - } - ssao.gather_push_constant.z_far = p_projection.get_z_far(); - ssao.gather_push_constant.z_near = p_projection.get_z_near(); - ssao.gather_push_constant.orthogonal = p_projection.is_orthogonal(); + ssao.downsample_push_constant.orthogonal = p_projection.is_orthogonal(); + ssao.downsample_push_constant.z_near = depth_linearize_mul; + ssao.downsample_push_constant.z_far = depth_linearize_add; + if (ssao.downsample_push_constant.orthogonal) { + ssao.downsample_push_constant.z_near = p_projection.get_z_near(); + ssao.downsample_push_constant.z_far = p_projection.get_z_far(); + } + ssao.downsample_push_constant.pixel_size[0] = 1.0 / p_settings.full_screen_size.x; + ssao.downsample_push_constant.pixel_size[1] = 1.0 / p_settings.full_screen_size.y; + ssao.downsample_push_constant.radius_sq = p_settings.radius * p_settings.radius; + + int downsample_pipeline = SSAO_DOWNSAMPLE; + if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { + downsample_pipeline = SSAO_DOWNSAMPLE_HALF; + } else if (p_settings.quality > RS::ENV_SSAO_QUALITY_MEDIUM) { + downsample_pipeline = SSAO_DOWNSAMPLE_MIPMAP; + } - ssao.gather_push_constant.proj_info[0] = -2.0f / (ssao.gather_push_constant.screen_size[0] * p_projection.matrix[0][0]); - ssao.gather_push_constant.proj_info[1] = -2.0f / (ssao.gather_push_constant.screen_size[1] * p_projection.matrix[1][1]); - ssao.gather_push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0]; - ssao.gather_push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1]; - //ssao.gather_push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0]; - //ssao.gather_push_constant.proj_info[3] = -(1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1]; + if (p_settings.half_size) { + downsample_pipeline++; + } - ssao.gather_push_constant.radius = p_radius; + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[downsample_pipeline]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_depth_mipmaps[0]), 1); + if (p_settings.quality > RS::ENV_SSAO_QUALITY_MEDIUM) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ssao.downsample_uniform_set, 2); + } + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.downsample_push_constant, sizeof(SSAODownsamplePushConstant)); - ssao.gather_push_constant.proj_scale = float(p_projection.get_pixels_per_meter(ssao.gather_push_constant.screen_size[0])); - ssao.gather_push_constant.bias = p_bias; - ssao.gather_push_constant.intensity_div_r6 = p_intensity / pow(p_radius, 6.0f); + int x_groups = (MAX(1, p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1)) - 1) / 8 + 1; + int y_groups = (MAX(1, p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1)) - 1) / 8 + 1; - ssao.gather_push_constant.pixel_size[0] = 1.0 / p_depth_buffer_size.x; - ssao.gather_push_constant.pixel_size[1] = 1.0 / p_depth_buffer_size.y; + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + RD::get_singleton()->draw_command_end_label(); // Downsample SSAO + } - RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.gather_push_constant, sizeof(SSAOGatherPushConstant)); + /* SECOND PASS */ + // Sample SSAO + { + RD::get_singleton()->draw_command_begin_label("Gather Samples"); + ssao.gather_push_constant.screen_size[0] = p_settings.full_screen_size.x; + ssao.gather_push_constant.screen_size[1] = p_settings.full_screen_size.y; + + ssao.gather_push_constant.half_screen_pixel_size[0] = 1.0 / p_settings.half_screen_size.x; + ssao.gather_push_constant.half_screen_pixel_size[1] = 1.0 / p_settings.half_screen_size.y; + float tan_half_fov_x = 1.0 / p_projection.matrix[0][0]; + float tan_half_fov_y = 1.0 / p_projection.matrix[1][1]; + ssao.gather_push_constant.NDC_to_view_mul[0] = tan_half_fov_x * 2.0; + ssao.gather_push_constant.NDC_to_view_mul[1] = tan_half_fov_y * -2.0; + ssao.gather_push_constant.NDC_to_view_add[0] = tan_half_fov_x * -1.0; + ssao.gather_push_constant.NDC_to_view_add[1] = tan_half_fov_y; + ssao.gather_push_constant.is_orthogonal = p_projection.is_orthogonal(); + + ssao.gather_push_constant.half_screen_pixel_size_x025[0] = ssao.gather_push_constant.half_screen_pixel_size[0] * 0.25; + ssao.gather_push_constant.half_screen_pixel_size_x025[1] = ssao.gather_push_constant.half_screen_pixel_size[1] * 0.25; + + float radius_near_limit = (p_settings.radius * 1.2f); + if (p_settings.quality <= RS::ENV_SSAO_QUALITY_LOW) { + radius_near_limit *= 1.50f; + + if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { + ssao.gather_push_constant.radius *= 0.8f; + } + if (p_settings.half_size) { + ssao.gather_push_constant.radius *= 0.5f; + } + } + radius_near_limit /= tan_half_fov_y; + ssao.gather_push_constant.radius = p_settings.radius; + ssao.gather_push_constant.intensity = p_settings.intensity; + ssao.gather_push_constant.shadow_power = p_settings.power; + ssao.gather_push_constant.shadow_clamp = 0.98; + ssao.gather_push_constant.fade_out_mul = -1.0 / (p_settings.fadeout_to - p_settings.fadeout_from); + ssao.gather_push_constant.fade_out_add = p_settings.fadeout_from / (p_settings.fadeout_to - p_settings.fadeout_from) + 1.0; + ssao.gather_push_constant.horizon_angle_threshold = p_settings.horizon; + ssao.gather_push_constant.inv_radius_near_limit = 1.0f / radius_near_limit; + ssao.gather_push_constant.neg_inv_radius = -1.0 / ssao.gather_push_constant.radius; + + ssao.gather_push_constant.load_counter_avg_div = 9.0 / float((p_settings.quarter_screen_size.x) * (p_settings.quarter_screen_size.y) * 255); + ssao.gather_push_constant.adaptive_sample_limit = p_settings.adaptive_target; + + ssao.gather_push_constant.detail_intensity = p_settings.detail; + ssao.gather_push_constant.quality = MAX(0, p_settings.quality - 1); + ssao.gather_push_constant.size_multiplier = p_settings.half_size ? 2 : 1; + + if (p_invalidate_uniform_sets) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 0; + u.ids.push_back(ssao.mirror_sampler); + u.ids.push_back(p_depth_mipmaps_texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 1; + u.ids.push_back(p_normal_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 2; + u.ids.push_back(ssao.gather_constants_buffer); + uniforms.push_back(u); + } + ssao.gather_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 0), 0); + } - int x_groups = (ssao.gather_push_constant.screen_size[0] - 1) / 8 + 1; - int y_groups = (ssao.gather_push_constant.screen_size[1] - 1) / 8 + 1; + if (p_invalidate_uniform_sets) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 0; + u.ids.push_back(p_ao_pong); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 1; + u.ids.push_back(default_sampler); + u.ids.push_back(p_importance_map); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 2; + u.ids.push_back(ssao.importance_map_load_counter); + uniforms.push_back(u); + } + ssao.importance_map_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 2), 1); + } - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); - RD::get_singleton()->compute_list_add_barrier(compute_list); + if (p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) { + RD::get_singleton()->draw_command_begin_label("Generate Importance Map"); + ssao.importance_map_push_constant.half_screen_pixel_size[0] = 1.0 / p_settings.half_screen_size.x; + ssao.importance_map_push_constant.half_screen_pixel_size[1] = 1.0 / p_settings.half_screen_size.y; + ssao.importance_map_push_constant.intensity = p_settings.intensity; + ssao.importance_map_push_constant.power = p_settings.power; + //base pass + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_BASE]); + gather_ssao(compute_list, p_ao_pong_slices, p_settings, true); + //generate importance map + int x_groups = (p_settings.quarter_screen_size.x - 1) / 8 + 1; + int y_groups = (p_settings.quarter_screen_size.y - 1) / 8 + 1; + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GENERATE_IMPORTANCE_MAP]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao_pong), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_importance_map), 1); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.importance_map_push_constant, sizeof(SSAOImportanceMapPushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + //process importance map A + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_PROCESS_IMPORTANCE_MAPA]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_importance_map), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_importance_map_pong), 1); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.importance_map_push_constant, sizeof(SSAOImportanceMapPushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + //process Importance Map B + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_PROCESS_IMPORTANCE_MAPB]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_importance_map_pong), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_importance_map), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ssao.counter_uniform_set, 2); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.importance_map_push_constant, sizeof(SSAOImportanceMapPushConstant)); + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); - /* THIRD PASS */ - // Blur horizontal - - ssao.blur_push_constant.edge_sharpness = p_edge_sharpness; - ssao.blur_push_constant.filter_scale = p_blur; - ssao.blur_push_constant.screen_size[0] = ssao.gather_push_constant.screen_size[0]; - ssao.blur_push_constant.screen_size[1] = ssao.gather_push_constant.screen_size[1]; - ssao.blur_push_constant.z_far = p_projection.get_z_far(); - ssao.blur_push_constant.z_near = p_projection.get_z_near(); - ssao.blur_push_constant.orthogonal = p_projection.is_orthogonal(); - ssao.blur_push_constant.axis[0] = 1; - ssao.blur_push_constant.axis[1] = 0; - - if (p_blur != RS::ENV_SSAO_BLUR_DISABLED) { - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[p_half_size ? SSAO_BLUR_PASS_HALF : SSAO_BLUR_PASS]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao1), 0); - if (p_half_size) { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_mipmaps_texture), 1); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_ADAPTIVE]); + RD::get_singleton()->draw_command_end_label(); // Importance Map } else { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 1); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER]); } - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao2), 3); - - RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant)); - - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); - RD::get_singleton()->compute_list_add_barrier(compute_list); - /* THIRD PASS */ - // Blur vertical - - ssao.blur_push_constant.axis[0] = 0; - ssao.blur_push_constant.axis[1] = 1; + gather_ssao(compute_list, p_ao_slices, p_settings, false); + RD::get_singleton()->draw_command_end_label(); // Gather SSAO + } - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao2), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao1), 3); + // /* THIRD PASS */ + // // Blur + // + { + RD::get_singleton()->draw_command_begin_label("Edge Aware Blur"); + ssao.blur_push_constant.edge_sharpness = 1.0 - p_settings.sharpness; + ssao.blur_push_constant.half_screen_pixel_size[0] = 1.0 / p_settings.half_screen_size.x; + ssao.blur_push_constant.half_screen_pixel_size[1] = 1.0 / p_settings.half_screen_size.y; + + int blur_passes = p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW ? p_settings.blur_passes : 1; + + for (int pass = 0; pass < blur_passes; pass++) { + int blur_pipeline = SSAO_BLUR_PASS; + if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW) { + if (pass < blur_passes - 2) { + blur_pipeline = SSAO_BLUR_PASS_WIDE; + } + blur_pipeline = SSAO_BLUR_PASS_SMART; + } - RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant)); + for (int i = 0; i < 4; i++) { + if ((p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { + continue; + } + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[blur_pipeline]); + if (pass % 2 == 0) { + if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao_slices[i]), 0); + } else { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_and_sampler(p_ao_slices[i], ssao.mirror_sampler), 0); + } + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao_pong_slices[i]), 1); + } else { + if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao_pong_slices[i]), 0); + } else { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_and_sampler(p_ao_pong_slices[i], ssao.mirror_sampler), 0); + } + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao_slices[i]), 1); + } + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant)); + + int x_groups = ((p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1)) - 1) / 8 + 1; + int y_groups = ((p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1)) - 1) / 8 + 1; + + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + } - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW) { + RD::get_singleton()->compute_list_add_barrier(compute_list); + } + } + RD::get_singleton()->draw_command_end_label(); // Blur } - if (p_half_size) { //must upscale - /* FOURTH PASS */ - // upscale if half size - //back to full size - ssao.blur_push_constant.screen_size[0] = p_depth_buffer_size.x; - ssao.blur_push_constant.screen_size[1] = p_depth_buffer_size.y; + /* FOURTH PASS */ + // Interleave buffers + // back to full size + { + RD::get_singleton()->draw_command_begin_label("Interleave Buffers"); + ssao.interleave_push_constant.inv_sharpness = 1.0 - p_settings.sharpness; + ssao.interleave_push_constant.pixel_size[0] = 1.0 / p_settings.full_screen_size.x; + ssao.interleave_push_constant.pixel_size[1] = 1.0 / p_settings.full_screen_size.y; + ssao.interleave_push_constant.size_modifier = uint32_t(p_settings.half_size ? 4 : 2); + + int interleave_pipeline = SSAO_INTERLEAVE_HALF; + if (p_settings.quality == RS::ENV_SSAO_QUALITY_LOW) { + interleave_pipeline = SSAO_INTERLEAVE; + } else if (p_settings.quality >= RS::ENV_SSAO_QUALITY_MEDIUM) { + interleave_pipeline = SSAO_INTERLEAVE_SMART; + } - RD::get_singleton()->compute_list_add_barrier(compute_list); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_BLUR_UPSCALE]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[interleave_pipeline]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao1), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_upscale_buffer), 3); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 1); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_mipmaps_texture), 2); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_upscale_buffer), 0); + if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW && p_settings.blur_passes % 2 == 0) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao), 1); + } else { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao_pong), 1); + } - RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant)); //not used but set anyway + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.interleave_push_constant, sizeof(SSAOInterleavePushConstant)); - x_groups = (p_depth_buffer_size.x - 1) / 8 + 1; - y_groups = (p_depth_buffer_size.y - 1) / 8 + 1; + int x_groups = (p_settings.full_screen_size.x - 1) / 8 + 1; + int y_groups = (p_settings.full_screen_size.y - 1) / 8 + 1; RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + RD::get_singleton()->draw_command_end_label(); // Interleave } - + RD::get_singleton()->draw_command_end_label(); //SSAO RD::get_singleton()->compute_list_end(); + + int zero[1] = { 0 }; + RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero); } -void RasterizerEffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve) { +void EffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve) { roughness_limiter.push_constant.screen_size[0] = p_size.x; roughness_limiter.push_constant.screen_size[1] = p_size.y; roughness_limiter.push_constant.curve = p_curve; @@ -1121,7 +1347,7 @@ void RasterizerEffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) { +void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) { zeromem(&roughness.push_constant, sizeof(CubemapRoughnessPushConstant)); roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id; @@ -1146,7 +1372,7 @@ void RasterizerEffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_ RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) { +void EffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) { cubemap_downsampler.push_constant.face_size = p_size.x; RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); @@ -1164,11 +1390,11 @@ void RasterizerEffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cu RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array) { +void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array) { Vector<RD::Uniform> uniforms; for (int i = 0; i < p_dest_cubemap.size(); i++) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = i; u.ids.push_back(p_dest_cubemap[i]); uniforms.push_back(u); @@ -1193,7 +1419,7 @@ void RasterizerEffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_des RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) { +void EffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) { SkyPushConstant sky_push_constant; zeromem(&sky_push_constant, sizeof(SkyPushConstant)); @@ -1229,7 +1455,7 @@ void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_ RD::get_singleton()->draw_list_draw(draw_list, true); } -void RasterizerEffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_giprobe, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_giprobe, Vector2i p_screen_size, int p_samples) { +void EffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_giprobe, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_giprobe, Vector2i p_screen_size, int p_samples) { ResolvePushConstant push_constant; push_constant.screen_size[0] = p_screen_size.x; push_constant.screen_size[1] = p_screen_size.y; @@ -1251,7 +1477,7 @@ void RasterizerEffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_rou RD::get_singleton()->compute_list_end(); } -void RasterizerEffectsRD::reduce_shadow(RID p_source_shadow, RID p_dest_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, int p_shrink_limit, RD::ComputeListID compute_list) { +void EffectsRD::reduce_shadow(RID p_source_shadow, RID p_dest_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, int p_shrink_limit, RD::ComputeListID compute_list) { uint32_t push_constant[8] = { (uint32_t)p_source_size.x, (uint32_t)p_source_size.y, (uint32_t)p_source_rect.position.x, (uint32_t)p_source_rect.position.y, (uint32_t)p_shrink_limit, 0, 0, 0 }; RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shadow_reduce.pipelines[SHADOW_REDUCE_REDUCE]); @@ -1260,7 +1486,7 @@ void RasterizerEffectsRD::reduce_shadow(RID p_source_shadow, RID p_dest_shadow, RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_source_rect.size.width, p_source_rect.size.height, 1, 8, 8, 1); } -void RasterizerEffectsRD::filter_shadow(RID p_shadow, RID p_backing_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, RenderingServer::EnvVolumetricFogShadowFilter p_filter, RD::ComputeListID compute_list, bool p_vertical, bool p_horizontal) { +void EffectsRD::filter_shadow(RID p_shadow, RID p_backing_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, RenderingServer::EnvVolumetricFogShadowFilter p_filter, RD::ComputeListID compute_list, bool p_vertical, bool p_horizontal) { uint32_t push_constant[8] = { (uint32_t)p_source_size.x, (uint32_t)p_source_size.y, (uint32_t)p_source_rect.position.x, (uint32_t)p_source_rect.position.y, 0, 0, 0, 0 }; switch (p_filter) { @@ -1296,7 +1522,7 @@ void RasterizerEffectsRD::filter_shadow(RID p_shadow, RID p_backing_shadow, cons } } -void RasterizerEffectsRD::sort_buffer(RID p_uniform_set, int p_size) { +void EffectsRD::sort_buffer(RID p_uniform_set, int p_size) { Sort::PushConstant push_constant; push_constant.total_elements = p_size; @@ -1365,7 +1591,7 @@ void RasterizerEffectsRD::sort_buffer(RID p_uniform_set, int p_size) { RD::get_singleton()->compute_list_end(); } -RasterizerEffectsRD::RasterizerEffectsRD() { +EffectsRD::EffectsRD() { { // Initialize copy Vector<String> copy_modes; copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); @@ -1423,6 +1649,8 @@ RasterizerEffectsRD::RasterizerEffectsRD() { Vector<String> tonemap_modes; tonemap_modes.push_back("\n"); tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n"); + tonemap_modes.push_back("\n#define USE_1D_LUT\n"); + tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n"); tonemap.shader.initialize(tonemap_modes); @@ -1457,8 +1685,12 @@ RasterizerEffectsRD::RasterizerEffectsRD() { cube_to_dp.shader.initialize(copy_modes); cube_to_dp.shader_version = cube_to_dp.shader.version_create(); - - cube_to_dp.pipeline = RD::get_singleton()->compute_pipeline_create(cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0)); + RID shader = cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0); + RD::PipelineDepthStencilState dss; + dss.enable_depth_test = true; + dss.depth_compare_operator = RD::COMPARE_OP_ALWAYS; + dss.enable_depth_write = true; + cube_to_dp.pipeline.setup(shader, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), dss, RD::PipelineColorBlendState(), 0); } { @@ -1481,57 +1713,144 @@ RasterizerEffectsRD::RasterizerEffectsRD() { { // Initialize ssao + + RD::SamplerState sampler; + sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST; + sampler.min_filter = RD::SAMPLER_FILTER_NEAREST; + sampler.mip_filter = RD::SAMPLER_FILTER_NEAREST; + sampler.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler.repeat_w = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler.max_lod = 4; + + ssao.mirror_sampler = RD::get_singleton()->sampler_create(sampler); + uint32_t pipeline = 0; { Vector<String> ssao_modes; - ssao_modes.push_back("\n#define MINIFY_START\n"); ssao_modes.push_back("\n"); + ssao_modes.push_back("\n#define USE_HALF_SIZE\n"); + ssao_modes.push_back("\n#define GENERATE_MIPS\n"); + ssao_modes.push_back("\n#define GENERATE_MIPS\n#define USE_HALF_SIZE"); + ssao_modes.push_back("\n#define USE_HALF_BUFFERS\n"); + ssao_modes.push_back("\n#define USE_HALF_BUFFERS\n#define USE_HALF_SIZE"); - ssao.minify_shader.initialize(ssao_modes); + ssao.downsample_shader.initialize(ssao_modes); - ssao.minify_shader_version = ssao.minify_shader.version_create(); + ssao.downsample_shader_version = ssao.downsample_shader.version_create(); - for (int i = 0; i <= SSAO_MINIFY_MIPMAP; i++) { - ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.minify_shader.version_get_shader(ssao.minify_shader_version, i)); + for (int i = 0; i <= SSAO_DOWNSAMPLE_HALF_RES_HALF; i++) { + ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.downsample_shader.version_get_shader(ssao.downsample_shader_version, i)); pipeline++; } } { Vector<String> ssao_modes; - ssao_modes.push_back("\n#define SSAO_QUALITY_LOW\n"); + ssao_modes.push_back("\n"); - ssao_modes.push_back("\n#define SSAO_QUALITY_HIGH\n"); - ssao_modes.push_back("\n#define SSAO_QUALITY_ULTRA\n"); - ssao_modes.push_back("\n#define SSAO_QUALITY_LOW\n#define USE_HALF_SIZE\n"); - ssao_modes.push_back("\n#define USE_HALF_SIZE\n"); - ssao_modes.push_back("\n#define SSAO_QUALITY_HIGH\n#define USE_HALF_SIZE\n"); - ssao_modes.push_back("\n#define SSAO_QUALITY_ULTRA\n#define USE_HALF_SIZE\n"); + ssao_modes.push_back("\n#define SSAO_BASE\n"); + ssao_modes.push_back("\n#define ADAPTIVE\n"); ssao.gather_shader.initialize(ssao_modes); ssao.gather_shader_version = ssao.gather_shader.version_create(); - for (int i = SSAO_GATHER_LOW; i <= SSAO_GATHER_ULTRA_HALF; i++) { - ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.gather_shader.version_get_shader(ssao.gather_shader_version, i - SSAO_GATHER_LOW)); + for (int i = SSAO_GATHER; i <= SSAO_GATHER_ADAPTIVE; i++) { + ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.gather_shader.version_get_shader(ssao.gather_shader_version, i - SSAO_GATHER)); pipeline++; } + + ssao.gather_constants_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SSAOGatherConstants)); + SSAOGatherConstants gather_constants; + + const int sub_pass_count = 5; + for (int pass = 0; pass < 4; pass++) { + for (int subPass = 0; subPass < sub_pass_count; subPass++) { + int a = pass; + int b = subPass; + + int spmap[5]{ 0, 1, 4, 3, 2 }; + b = spmap[subPass]; + + float ca, sa; + float angle0 = (float(a) + float(b) / float(sub_pass_count)) * Math_PI * 0.5f; + + ca = Math::cos(angle0); + sa = Math::sin(angle0); + + float scale = 1.0f + (a - 1.5f + (b - (sub_pass_count - 1.0f) * 0.5f) / float(sub_pass_count)) * 0.07f; + + gather_constants.rotation_matrices[pass * 20 + subPass * 4 + 0] = scale * ca; + gather_constants.rotation_matrices[pass * 20 + subPass * 4 + 1] = scale * -sa; + gather_constants.rotation_matrices[pass * 20 + subPass * 4 + 2] = -scale * sa; + gather_constants.rotation_matrices[pass * 20 + subPass * 4 + 3] = -scale * ca; + } + } + + RD::get_singleton()->buffer_update(ssao.gather_constants_buffer, 0, sizeof(SSAOGatherConstants), &gather_constants); } { Vector<String> ssao_modes; - ssao_modes.push_back("\n#define MODE_FULL_SIZE\n"); - ssao_modes.push_back("\n"); - ssao_modes.push_back("\n#define MODE_UPSCALE\n"); + ssao_modes.push_back("\n#define GENERATE_MAP\n"); + ssao_modes.push_back("\n#define PROCESS_MAPA\n"); + ssao_modes.push_back("\n#define PROCESS_MAPB\n"); + + ssao.importance_map_shader.initialize(ssao_modes); + + ssao.importance_map_shader_version = ssao.importance_map_shader.version_create(); + + for (int i = SSAO_GENERATE_IMPORTANCE_MAP; i <= SSAO_PROCESS_IMPORTANCE_MAPB; i++) { + ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, i - SSAO_GENERATE_IMPORTANCE_MAP)); + + pipeline++; + } + ssao.importance_map_load_counter = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t)); + int zero[1] = { 0 }; + RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero); + RD::get_singleton()->set_resource_name(ssao.importance_map_load_counter, "Importance Map Load Counter"); + + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 0; + u.ids.push_back(ssao.importance_map_load_counter); + uniforms.push_back(u); + } + ssao.counter_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, 2), 2); + RD::get_singleton()->set_resource_name(ssao.counter_uniform_set, "Load Counter Uniform Set"); + } + { + Vector<String> ssao_modes; + ssao_modes.push_back("\n#define MODE_NON_SMART\n"); + ssao_modes.push_back("\n#define MODE_SMART\n"); + ssao_modes.push_back("\n#define MODE_WIDE\n"); ssao.blur_shader.initialize(ssao_modes); ssao.blur_shader_version = ssao.blur_shader.version_create(); - for (int i = SSAO_BLUR_PASS; i <= SSAO_BLUR_UPSCALE; i++) { + for (int i = SSAO_BLUR_PASS; i <= SSAO_BLUR_PASS_WIDE; i++) { ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.blur_shader.version_get_shader(ssao.blur_shader_version, i - SSAO_BLUR_PASS)); pipeline++; } } + { + Vector<String> ssao_modes; + ssao_modes.push_back("\n#define MODE_NON_SMART\n"); + ssao_modes.push_back("\n#define MODE_SMART\n"); + ssao_modes.push_back("\n#define MODE_HALF\n"); + + ssao.interleave_shader.initialize(ssao_modes); + + ssao.interleave_shader_version = ssao.interleave_shader.version_create(); + for (int i = SSAO_INTERLEAVE; i <= SSAO_INTERLEAVE_HALF; i++) { + ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, i - SSAO_INTERLEAVE)); + RD::get_singleton()->set_resource_name(ssao.pipelines[pipeline], "Interleave Pipeline " + itos(i)); + pipeline++; + } + } ERR_FAIL_COND(pipeline != SSAO_MAX); } @@ -1577,16 +1896,16 @@ RasterizerEffectsRD::RasterizerEffectsRD() { if (filter.use_high_quality) { filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(high_quality_coeffs)); - RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(high_quality_coeffs), &high_quality_coeffs[0], false); + RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(high_quality_coeffs), &high_quality_coeffs[0]); } else { filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(low_quality_coeffs)); - RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0], false); + RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0]); } Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(filter.coefficient_buffer); uniforms.push_back(u); @@ -1733,12 +2052,14 @@ RasterizerEffectsRD::RasterizerEffectsRD() { sampler.max_lod = 0; default_sampler = RD::get_singleton()->sampler_create(sampler); + RD::get_singleton()->set_resource_name(default_sampler, "Default Linear Sampler"); sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; sampler.mip_filter = RD::SAMPLER_FILTER_LINEAR; sampler.max_lod = 1e20; default_mipmap_sampler = RD::get_singleton()->sampler_create(sampler); + RD::get_singleton()->set_resource_name(default_mipmap_sampler, "Default MipMap Sampler"); { //create index array for copy shaders Vector<uint8_t> pv; @@ -1758,7 +2079,7 @@ RasterizerEffectsRD::RasterizerEffectsRD() { } } -RasterizerEffectsRD::~RasterizerEffectsRD() { +EffectsRD::~EffectsRD() { if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) { RD::get_singleton()->free(filter.image_uniform_set); } @@ -1772,6 +2093,10 @@ RasterizerEffectsRD::~RasterizerEffectsRD() { RD::get_singleton()->free(index_buffer); //array gets freed as dependency RD::get_singleton()->free(filter.coefficient_buffer); + RD::get_singleton()->free(ssao.mirror_sampler); + RD::get_singleton()->free(ssao.gather_constants_buffer); + RD::get_singleton()->free(ssao.importance_map_load_counter); + bokeh.shader.version_free(bokeh.shader_version); copy.shader.version_free(copy.shader_version); copy_to_fb.shader.version_free(copy_to_fb.shader_version); @@ -1786,7 +2111,9 @@ RasterizerEffectsRD::~RasterizerEffectsRD() { specular_merge.shader.version_free(specular_merge.shader_version); ssao.blur_shader.version_free(ssao.blur_shader_version); ssao.gather_shader.version_free(ssao.gather_shader_version); - ssao.minify_shader.version_free(ssao.minify_shader_version); + ssao.downsample_shader.version_free(ssao.downsample_shader_version); + ssao.interleave_shader.version_free(ssao.interleave_shader_version); + ssao.importance_map_shader.version_free(ssao.importance_map_shader_version); ssr.shader.version_free(ssr.shader_version); ssr_filter.shader.version_free(ssr_filter.shader_version); ssr_scale.shader.version_free(ssr_scale.shader_version); diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index a0bdd59fd2..00309b4d0f 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_effects_rd.h */ +/* effects_rd.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,36 +28,38 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RASTERIZER_EFFECTS_RD_H -#define RASTERIZER_EFFECTS_RD_H +#ifndef EFFECTS_RD_H +#define EFFECTS_RD_H #include "core/math/camera_matrix.h" -#include "servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h" -#include "servers/rendering/rasterizer_rd/shaders/bokeh_dof.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/copy.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/cubemap_downsampler.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/cubemap_filter.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/cubemap_roughness.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/luminance_reduce.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/resolve.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/roughness_limiter.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/sort.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/specular_merge.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/ssao.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/ssao_minify.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/tonemap.glsl.gen.h" +#include "servers/rendering/renderer_rd/pipeline_cache_rd.h" +#include "servers/rendering/renderer_rd/shaders/bokeh_dof.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/copy.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/copy_to_fb.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/cube_to_dp.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/cubemap_filter.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/luminance_reduce.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/resolve.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/roughness_limiter.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/shadow_reduce.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sort.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/specular_merge.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssao.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssao_blur.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssao_downsample.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssao_interleave.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/tonemap.glsl.gen.h" #include "servers/rendering_server.h" -class RasterizerEffectsRD { +class EffectsRD { enum CopyMode { COPY_MODE_GAUSSIAN_COPY, COPY_MODE_GAUSSIAN_COPY_8BIT, @@ -144,7 +146,7 @@ class RasterizerEffectsRD { CopyToFbPushConstant push_constant; CopyToFbShaderRD shader; RID shader_version; - RenderPipelineVertexFormatCacheRD pipelines[COPY_TO_FB_MAX]; + PipelineCacheRD pipelines[COPY_TO_FB_MAX]; } copy_to_fb; @@ -167,6 +169,8 @@ class RasterizerEffectsRD { enum TonemapMode { TONEMAP_MODE_NORMAL, TONEMAP_MODE_BICUBIC_GLOW_FILTER, + TONEMAP_MODE_1D_LUT, + TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT, TONEMAP_MODE_MAX }; @@ -198,13 +202,13 @@ class RasterizerEffectsRD { /* tonemap actually writes to a framebuffer, which is * better to do using the raster pipeline rather than - * comptute, as that framebuffer might be in different formats + * compute, as that framebuffer might be in different formats */ struct Tonemap { TonemapPushConstant push_constant; TonemapShaderRD shader; RID shader_version; - RenderPipelineVertexFormatCacheRD pipelines[TONEMAP_MODE_MAX]; + PipelineCacheRD pipelines[TONEMAP_MODE_MAX]; } tonemap; enum LuminanceReduceMode { @@ -230,18 +234,17 @@ class RasterizerEffectsRD { } luminance_reduce; struct CopyToDPPushConstant { - int32_t screen_size[2]; - int32_t dest_offset[2]; - float bias; float z_far; float z_near; uint32_t z_flip; + uint32_t pad; + float screen_rect[4]; }; struct CoptToDP { CubeToDpShaderRD shader; RID shader_version; - RID pipeline; + PipelineCacheRD pipeline; } cube_to_dp; struct BokehPushConstant { @@ -286,71 +289,121 @@ class RasterizerEffectsRD { } bokeh; enum SSAOMode { - SSAO_MINIFY_FIRST, - SSAO_MINIFY_MIPMAP, - SSAO_GATHER_LOW, - SSAO_GATHER_MEDIUM, - SSAO_GATHER_HIGH, - SSAO_GATHER_ULTRA, - SSAO_GATHER_LOW_HALF, - SSAO_GATHER_MEDIUM_HALF, - SSAO_GATHER_HIGH_HALF, - SSAO_GATHER_ULTRA_HALF, + SSAO_DOWNSAMPLE, + SSAO_DOWNSAMPLE_HALF_RES, + SSAO_DOWNSAMPLE_MIPMAP, + SSAO_DOWNSAMPLE_MIPMAP_HALF_RES, + SSAO_DOWNSAMPLE_HALF, + SSAO_DOWNSAMPLE_HALF_RES_HALF, + SSAO_GATHER, + SSAO_GATHER_BASE, + SSAO_GATHER_ADAPTIVE, + SSAO_GENERATE_IMPORTANCE_MAP, + SSAO_PROCESS_IMPORTANCE_MAPA, + SSAO_PROCESS_IMPORTANCE_MAPB, SSAO_BLUR_PASS, - SSAO_BLUR_PASS_HALF, - SSAO_BLUR_UPSCALE, + SSAO_BLUR_PASS_SMART, + SSAO_BLUR_PASS_WIDE, + SSAO_INTERLEAVE, + SSAO_INTERLEAVE_SMART, + SSAO_INTERLEAVE_HALF, SSAO_MAX }; - struct SSAOMinifyPushConstant { + struct SSAODownsamplePushConstant { float pixel_size[2]; float z_far; float z_near; - int32_t source_size[2]; uint32_t orthogonal; - uint32_t pad; + float radius_sq; + uint32_t pad[2]; }; struct SSAOGatherPushConstant { int32_t screen_size[2]; - float z_far; - float z_near; + int pass; + int quality; + + float half_screen_pixel_size[2]; + int size_multiplier; + float detail_intensity; + + float NDC_to_view_mul[2]; + float NDC_to_view_add[2]; + + float pad[2]; + float half_screen_pixel_size_x025[2]; - uint32_t orthogonal; - float intensity_div_r6; float radius; - float bias; + float intensity; + float shadow_power; + float shadow_clamp; - float proj_info[4]; - float pixel_size[2]; - float proj_scale; - uint32_t pad; + float fade_out_mul; + float fade_out_add; + float horizon_angle_threshold; + float inv_radius_near_limit; + + bool is_orthogonal; + float neg_inv_radius; + float load_counter_avg_div; + float adaptive_sample_limit; + + int32_t pass_coord_offset[2]; + float pass_uv_offset[2]; + }; + + struct SSAOGatherConstants { + float rotation_matrices[80]; //5 vec4s * 4 + }; + + struct SSAOImportanceMapPushConstant { + float half_screen_pixel_size[2]; + float intensity; + float power; }; struct SSAOBlurPushConstant { float edge_sharpness; - int32_t filter_scale; - float z_far; - float z_near; - uint32_t orthogonal; - uint32_t pad[3]; - int32_t axis[2]; - int32_t screen_size[2]; + float pad; + float half_screen_pixel_size[2]; + }; + + struct SSAOInterleavePushConstant { + float inv_sharpness; + uint32_t size_modifier; + float pixel_size[2]; }; struct SSAO { - SSAOMinifyPushConstant minify_push_constant; - SsaoMinifyShaderRD minify_shader; - RID minify_shader_version; + SSAODownsamplePushConstant downsample_push_constant; + SsaoDownsampleShaderRD downsample_shader; + RID downsample_shader_version; + RID downsample_uniform_set; SSAOGatherPushConstant gather_push_constant; SsaoShaderRD gather_shader; RID gather_shader_version; + RID gather_uniform_set; + RID gather_constants_buffer; + bool gather_initialized = false; + + SSAOImportanceMapPushConstant importance_map_push_constant; + SsaoImportanceMapShaderRD importance_map_shader; + RID importance_map_shader_version; + RID importance_map_load_counter; + RID importance_map_uniform_set; + RID counter_uniform_set; SSAOBlurPushConstant blur_push_constant; SsaoBlurShaderRD blur_shader; RID blur_shader_version; + SSAOInterleavePushConstant interleave_push_constant; + SsaoInterleaveShaderRD interleave_shader; + RID interleave_shader_version; + + RID mirror_sampler; RID pipelines[SSAO_MAX]; } ssao; @@ -424,7 +477,7 @@ class RasterizerEffectsRD { struct SpecularMerge { SpecularMergeShaderRD shader; RID shader_version; - RenderPipelineVertexFormatCacheRD pipelines[SPECULAR_MERGE_MAX]; + PipelineCacheRD pipelines[SPECULAR_MERGE_MAX]; } specular_merge; @@ -596,13 +649,27 @@ class RasterizerEffectsRD { } }; + struct TextureSamplerPair { + RID texture; + RID sampler; + _FORCE_INLINE_ bool operator<(const TextureSamplerPair &p_pair) const { + if (texture == p_pair.texture) { + return sampler < p_pair.sampler; + } else { + return texture < p_pair.texture; + } + } + }; + Map<RID, RID> texture_to_compute_uniform_set_cache; Map<TexturePair, RID> texture_pair_to_compute_uniform_set_cache; Map<TexturePair, RID> image_pair_to_compute_uniform_set_cache; + Map<TextureSamplerPair, RID> texture_sampler_to_compute_uniform_set_cache; RID _get_uniform_set_from_image(RID p_texture); RID _get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false); RID _get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false); + RID _get_compute_uniform_set_from_texture_and_sampler(RID p_texture, RID p_sampler); RID _get_compute_uniform_set_from_texture_pair(RID p_texture, RID p_texture2, bool p_use_mipmaps = false); RID _get_compute_uniform_set_from_image_pair(RID p_texture, RID p_texture2); @@ -619,7 +686,7 @@ public: void cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size); - void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip); + void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2 &p_rect, float p_z_near, float p_z_far, bool p_dp_flip); void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false); void bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_bokeh_texture1, RID p_bokeh_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RS::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal); @@ -654,6 +721,7 @@ public: float saturation = 1.0; bool use_color_correction = false; + bool use_1d_color_correction = false; RID color_correction_texture; bool use_fxaa = false; @@ -661,14 +729,35 @@ public: Vector2i texture_size; }; + struct SSAOSettings { + float radius = 1.0; + float intensity = 2.0; + float power = 1.5; + float detail = 0.5; + float horizon = 0.06; + float sharpness = 0.98; + + RS::EnvironmentSSAOQuality quality = RS::ENV_SSAO_QUALITY_MEDIUM; + bool half_size = false; + float adaptive_target = 0.5; + int blur_passes = 2; + float fadeout_from = 50.0; + float fadeout_to = 300.0; + + Size2i full_screen_size = Size2i(); + Size2i half_screen_size = Size2i(); + Size2i quarter_screen_size = Size2i(); + }; + void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings); - void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, const Size2i &p_depth_buffer_size, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao1, bool p_half_size, RID p_ao2, RID p_upscale_buffer, float p_intensity, float p_radius, float p_bias, const CameraMatrix &p_projection, RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOBlur p_blur, float p_edge_sharpness); + void gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass); + void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets); void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve); void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size); void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array); - void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position); + void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position); void screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera); void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection); @@ -681,8 +770,8 @@ public: void sort_buffer(RID p_uniform_set, int p_size); - RasterizerEffectsRD(); - ~RasterizerEffectsRD(); + EffectsRD(); + ~EffectsRD(); }; #endif // !RASTERIZER_EFFECTS_RD_H diff --git a/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp index 5cc3da8d4e..b2b919c40e 100644 --- a/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp +++ b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* render_pipeline_vertex_format_cache_rd.cpp */ +/* pipeline_cache_rd.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,10 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "render_pipeline_vertex_format_cache_rd.h" +#include "pipeline_cache_rd.h" #include "core/os/memory.h" -RID RenderPipelineVertexFormatCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe) { +RID PipelineCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe) { RD::PipelineMultisampleState multisample_state_version = multisample_state; multisample_state_version.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_framebuffer_format_id); @@ -49,7 +49,7 @@ RID RenderPipelineVertexFormatCacheRD::_generate_version(RD::VertexFormatID p_ve return pipeline; } -void RenderPipelineVertexFormatCacheRD::_clear() { +void PipelineCacheRD::_clear() { if (versions) { for (uint32_t i = 0; i < version_count; i++) { //shader may be gone, so this may not be valid @@ -63,7 +63,7 @@ void RenderPipelineVertexFormatCacheRD::_clear() { } } -void RenderPipelineVertexFormatCacheRD::setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags) { +void PipelineCacheRD::setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags) { ERR_FAIL_COND(p_shader.is_null()); _clear(); shader = p_shader; @@ -76,24 +76,24 @@ void RenderPipelineVertexFormatCacheRD::setup(RID p_shader, RD::RenderPrimitive dynamic_state_flags = p_dynamic_state_flags; } -void RenderPipelineVertexFormatCacheRD::update_shader(RID p_shader) { +void PipelineCacheRD::update_shader(RID p_shader) { ERR_FAIL_COND(p_shader.is_null()); _clear(); setup(p_shader, render_primitive, rasterization_state, multisample_state, depth_stencil_state, blend_state, dynamic_state_flags); } -void RenderPipelineVertexFormatCacheRD::clear() { +void PipelineCacheRD::clear() { _clear(); shader = RID(); //clear shader input_mask = 0; } -RenderPipelineVertexFormatCacheRD::RenderPipelineVertexFormatCacheRD() { +PipelineCacheRD::PipelineCacheRD() { version_count = 0; versions = nullptr; input_mask = 0; } -RenderPipelineVertexFormatCacheRD::~RenderPipelineVertexFormatCacheRD() { +PipelineCacheRD::~PipelineCacheRD() { _clear(); } diff --git a/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h b/servers/rendering/renderer_rd/pipeline_cache_rd.h index cf15e79586..b1c8f21ecc 100644 --- a/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h +++ b/servers/rendering/renderer_rd/pipeline_cache_rd.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* render_pipeline_vertex_format_cache_rd.h */ +/* pipeline_cache_rd.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RENDER_PIPELINE_CACHE_RD_H -#define RENDER_PIPELINE_CACHE_RD_H +#ifndef PIPELINE_CACHE_RD_H +#define PIPELINE_CACHE_RD_H -#include "core/spin_lock.h" +#include "core/os/spin_lock.h" #include "servers/rendering/rendering_device.h" -class RenderPipelineVertexFormatCacheRD { +class PipelineCacheRD { SpinLock spin_lock; RID shader; @@ -89,8 +89,8 @@ public: return input_mask; } void clear(); - RenderPipelineVertexFormatCacheRD(); - ~RenderPipelineVertexFormatCacheRD(); + PipelineCacheRD(); + ~PipelineCacheRD(); }; #endif // RENDER_PIPELINE_CACHE_RD_H diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index da30291353..c354ad8c1c 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_canvas_rd.cpp */ +/* renderer_canvas_render_rd.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,12 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rasterizer_canvas_rd.h" +#include "renderer_canvas_render_rd.h" +#include "core/config/project_settings.h" +#include "core/math/geometry_2d.h" #include "core/math/math_funcs.h" -#include "core/project_settings.h" -#include "rasterizer_rd.h" +#include "renderer_compositor_rd.h" -void RasterizerCanvasRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) { +void RendererCanvasRenderRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) { p_mat4[0] = p_transform.elements[0][0]; p_mat4[1] = p_transform.elements[0][1]; p_mat4[2] = 0; @@ -52,7 +53,7 @@ void RasterizerCanvasRD::_update_transform_2d_to_mat4(const Transform2D &p_trans p_mat4[15] = 1; } -void RasterizerCanvasRD::_update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4) { +void RendererCanvasRenderRD::_update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4) { p_mat2x4[0] = p_transform.elements[0][0]; p_mat2x4[1] = p_transform.elements[1][0]; p_mat2x4[2] = 0; @@ -64,7 +65,7 @@ void RasterizerCanvasRD::_update_transform_2d_to_mat2x4(const Transform2D &p_tra p_mat2x4[7] = p_transform.elements[2][1]; } -void RasterizerCanvasRD::_update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3) { +void RendererCanvasRenderRD::_update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3) { p_mat2x3[0] = p_transform.elements[0][0]; p_mat2x3[1] = p_transform.elements[0][1]; p_mat2x3[2] = p_transform.elements[1][0]; @@ -73,7 +74,7 @@ void RasterizerCanvasRD::_update_transform_2d_to_mat2x3(const Transform2D &p_tra p_mat2x3[5] = p_transform.elements[2][1]; } -void RasterizerCanvasRD::_update_transform_to_mat4(const Transform &p_transform, float *p_mat4) { +void RendererCanvasRenderRD::_update_transform_to_mat4(const Transform &p_transform, float *p_mat4) { p_mat4[0] = p_transform.basis.elements[0][0]; p_mat4[1] = p_transform.basis.elements[1][0]; p_mat4[2] = p_transform.basis.elements[2][0]; @@ -92,7 +93,7 @@ void RasterizerCanvasRD::_update_transform_to_mat4(const Transform &p_transform, p_mat4[15] = 1; } -RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights) { +RendererCanvasRender::PolygonID RendererCanvasRenderRD::request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights) { // Care must be taken to generate array formats // in ways where they could be reused, so we will // put single-occuring elements first, and repeated @@ -118,9 +119,9 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int Vector<uint8_t> polygon_buffer; polygon_buffer.resize(buffer_size * sizeof(float)); Vector<RD::VertexAttribute> descriptions; - descriptions.resize(4); + descriptions.resize(5); Vector<RID> buffers; - buffers.resize(4); + buffers.resize(5); { const uint8_t *r = polygon_buffer.ptr(); @@ -183,7 +184,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int vd.stride = 0; descriptions.write[1] = vd; - buffers.write[1] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_COLOR); + buffers.write[1] = storage->mesh_get_default_rd_buffer(RendererStorageRD::DEFAULT_RD_BUFFER_COLOR); } //uvs @@ -211,13 +212,13 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int vd.stride = 0; descriptions.write[2] = vd; - buffers.write[2] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_TEX_UV); + buffers.write[2] = storage->mesh_get_default_rd_buffer(RendererStorageRD::DEFAULT_RD_BUFFER_TEX_UV); } //bones if ((uint32_t)p_indices.size() == vertex_count * 4 && (uint32_t)p_weights.size() == vertex_count * 4) { RD::VertexAttribute vd; - vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; + vd.format = RD::DATA_FORMAT_R16G16B16A16_UINT; vd.offset = base_offset * sizeof(float); vd.location = RS::ARRAY_BONES; vd.stride = stride * sizeof(float); @@ -225,16 +226,42 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int descriptions.write[3] = vd; const int *bone_ptr = p_bones.ptr(); - const float *weight_ptr = p_weights.ptr(); for (uint32_t i = 0; i < vertex_count; i++) { uint16_t *bone16w = (uint16_t *)&uptr[base_offset + i * stride]; - uint16_t *weight16w = (uint16_t *)&uptr[base_offset + i * stride + 2]; bone16w[0] = bone_ptr[i * 4 + 0]; bone16w[1] = bone_ptr[i * 4 + 1]; bone16w[2] = bone_ptr[i * 4 + 2]; bone16w[3] = bone_ptr[i * 4 + 3]; + } + + base_offset += 2; + } else { + RD::VertexAttribute vd; + vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; + vd.offset = 0; + vd.location = RS::ARRAY_BONES; + vd.stride = 0; + + descriptions.write[3] = vd; + buffers.write[3] = storage->mesh_get_default_rd_buffer(RendererStorageRD::DEFAULT_RD_BUFFER_BONES); + } + + //weights + if ((uint32_t)p_weights.size() == vertex_count * 4) { + RD::VertexAttribute vd; + vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM; + vd.offset = base_offset * sizeof(float); + vd.location = RS::ARRAY_WEIGHTS; + vd.stride = stride * sizeof(float); + + descriptions.write[4] = vd; + + const float *weight_ptr = p_weights.ptr(); + + for (uint32_t i = 0; i < vertex_count; i++) { + uint16_t *weight16w = (uint16_t *)&uptr[base_offset + i * stride]; weight16w[0] = CLAMP(weight_ptr[i * 4 + 0] * 65535, 0, 65535); weight16w[1] = CLAMP(weight_ptr[i * 4 + 1] * 65535, 0, 65535); @@ -242,16 +269,16 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int weight16w[3] = CLAMP(weight_ptr[i * 4 + 3] * 65535, 0, 65535); } - base_offset += 4; + base_offset += 2; } else { RD::VertexAttribute vd; - vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; vd.offset = 0; - vd.location = RS::ARRAY_BONES; + vd.location = RS::ARRAY_WEIGHTS; vd.stride = 0; - descriptions.write[3] = vd; - buffers.write[3] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_BONES); + descriptions.write[4] = vd; + buffers.write[4] = storage->mesh_get_default_rd_buffer(RendererStorageRD::DEFAULT_RD_BUFFER_BONES); } //check that everything is as it should be @@ -292,7 +319,7 @@ RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int return id; } -void RasterizerCanvasRD::free_polygon(PolygonID p_polygon) { +void RendererCanvasRenderRD::free_polygon(PolygonID p_polygon) { PolygonBuffers *pb_ptr = polygon_buffers.polygons.getptr(p_polygon); ERR_FAIL_COND(!pb_ptr); @@ -313,7 +340,7 @@ void RasterizerCanvasRD::free_polygon(PolygonID p_polygon) { //////////////////// -void RasterizerCanvasRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size) { +void RendererCanvasRenderRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size) { if (p_texture == RID()) { p_texture = default_canvas_texture; } @@ -328,7 +355,7 @@ void RasterizerCanvasRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RID p_ bool use_normal; bool use_specular; - bool success = storage->canvas_texture_get_unifom_set(p_texture, p_base_filter, p_base_repeat, shader.default_version_rd_shader, CANVAS_TEXTURE_UNIFORM_SET, uniform_set, size, specular_shininess, use_normal, use_specular); + bool success = storage->canvas_texture_get_uniform_set(p_texture, p_base_filter, p_base_repeat, shader.default_version_rd_shader, CANVAS_TEXTURE_UNIFORM_SET, uniform_set, size, specular_shininess, use_normal, use_specular); //something odd happened if (!success) { _bind_canvas_texture(p_draw_list, default_canvas_texture, p_base_filter, p_base_repeat, r_last_texture, push_constant, r_texpixel_size); @@ -363,7 +390,7 @@ void RasterizerCanvasRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RID p_ r_last_texture = p_texture; } -void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) { +void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) { //create an empty push constant RS::CanvasItemTextureFilter current_filter = default_filter; @@ -416,10 +443,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ light_count++; - if (light->mode == RS::CANVAS_LIGHT_MODE_MASK) { - base_flags |= FLAGS_USING_LIGHT_MASK; - } - if (light_count == MAX_LIGHTS_PER_ITEM) { break; } @@ -430,7 +453,7 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT; } - light_mode = light_count > 0 ? PIPELINE_LIGHT_MODE_ENABLED : PIPELINE_LIGHT_MODE_DISABLED; + light_mode = (light_count > 0 || using_directional_lights) ? PIPELINE_LIGHT_MODE_ENABLED : PIPELINE_LIGHT_MODE_DISABLED; PipelineVariants *pipeline_variants = p_pipeline_variants; @@ -578,10 +601,10 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ push_constant.flags |= FLAGS_NINEPACH_DRAW_CENTER; } - push_constant.ninepatch_margins[0] = np->margin[MARGIN_LEFT]; - push_constant.ninepatch_margins[1] = np->margin[MARGIN_TOP]; - push_constant.ninepatch_margins[2] = np->margin[MARGIN_RIGHT]; - push_constant.ninepatch_margins[3] = np->margin[MARGIN_BOTTOM]; + push_constant.ninepatch_margins[0] = np->margin[SIDE_LEFT]; + push_constant.ninepatch_margins[1] = np->margin[SIDE_TOP]; + push_constant.ninepatch_margins[2] = np->margin[SIDE_RIGHT]; + push_constant.ninepatch_margins[3] = np->margin[SIDE_BOTTOM]; RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array); @@ -691,7 +714,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ #if 0 case Item::Command::TYPE_MESH: { - Item::CommandMesh *mesh = static_cast<Item::CommandMesh *>(c); _set_texture_rect_mode(false); @@ -706,7 +728,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(mesh->mesh); if (mesh_data) { - for (int j = 0; j < mesh_data->surfaces.size(); j++) { RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j]; // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing @@ -727,7 +748,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } break; case Item::Command::TYPE_MULTIMESH: { - Item::CommandMultiMesh *mmesh = static_cast<Item::CommandMultiMesh *>(c); RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(mmesh->multimesh); @@ -790,7 +810,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ int custom_data_ofs = color_ofs; switch (multi_mesh->color_format) { - case RS::MULTIMESH_COLOR_NONE: { glDisableVertexAttribArray(11); glVertexAttrib4f(11, 1, 1, 1, 1); @@ -811,7 +830,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } switch (multi_mesh->custom_data_format) { - case RS::MULTIMESH_CUSTOM_DATA_NONE: { glDisableVertexAttribArray(12); glVertexAttrib4f(12, 1, 1, 1, 1); @@ -845,7 +863,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } break; case Item::Command::TYPE_PARTICLES: { - Item::CommandParticles *particles_cmd = static_cast<Item::CommandParticles *>(c); RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(particles_cmd->particles); @@ -857,7 +874,7 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); //not used, so keep white - RenderingServerRaster::redraw_request(); + RenderingServerDefault::redraw_request(); storage->particles_request_process(particles_cmd->particles); //enable instancing @@ -879,7 +896,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } if (!particles->use_local_coords) { - Transform2D inv_xf; inv_xf.set_axis(0, Vector2(particles->emission_transform.basis.get_axis(0).x, particles->emission_transform.basis.get_axis(0).y)); inv_xf.set_axis(1, Vector2(particles->emission_transform.basis.get_axis(1).x, particles->emission_transform.basis.get_axis(1).y)); @@ -897,7 +913,6 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ int amount = particles->amount; if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_LIFETIME) { - glEnableVertexAttribArray(8); //xform x glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3)); glVertexAttribDivisor(8, 1); @@ -1001,13 +1016,13 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } } -RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_backbuffer) { +RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, bool p_backbuffer) { //re create canvas state Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 1; u.ids.push_back(state.canvas_state_buffer); uniforms.push_back(u); @@ -1015,7 +1030,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 2; u.ids.push_back(state.lights_uniform_buffer); uniforms.push_back(u); @@ -1023,7 +1038,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 3; u.ids.push_back(storage->decal_atlas_get_texture()); uniforms.push_back(u); @@ -1031,7 +1046,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 4; u.ids.push_back(state.shadow_texture); uniforms.push_back(u); @@ -1039,7 +1054,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 5; u.ids.push_back(state.shadow_sampler); uniforms.push_back(u); @@ -1047,7 +1062,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 6; RID screen; if (p_backbuffer) { @@ -1055,7 +1070,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ } else { screen = storage->render_target_get_rd_backbuffer(p_to_render_target); if (screen.is_null()) { //unallocated backbuffer - screen = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE); + screen = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); } } u.ids.push_back(screen); @@ -1063,10 +1078,19 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ } { - //needs samplers for the material (uses custom textures) create them RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 7; + RID sdf = storage->render_target_get_sdf_texture(p_to_render_target); + u.ids.push_back(sdf); + uniforms.push_back(u); + } + + { + //needs samplers for the material (uses custom textures) create them + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 8; u.ids.resize(12); RID *ids_ptr = u.ids.ptrw(); ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); @@ -1086,8 +1110,8 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 8; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 9; u.ids.push_back(storage->global_variables_get_storage_buffer()); uniforms.push_back(u); } @@ -1102,7 +1126,7 @@ RID RasterizerCanvasRD::_create_base_uniform_set(RID p_to_render_target, bool p_ return uniform_set; } -void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer) { +void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer) { Item *current_clip = nullptr; Transform2D canvas_transform_inverse = p_canvas_transform_inverse; @@ -1169,7 +1193,7 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, if (material != prev_material) { MaterialData *material_data = nullptr; if (material.is_valid()) { - material_data = (MaterialData *)storage->material_get_data(material, RasterizerStorageRD::SHADER_TYPE_2D); + material_data = (MaterialData *)storage->material_get_data(material, RendererStorageRD::SHADER_TYPE_2D); } if (material_data) { @@ -1194,51 +1218,84 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, RD::get_singleton()->draw_list_end(); } -void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) { +void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) { + r_sdf_used = false; int item_count = 0; //setup canvas state uniforms if needed Transform2D canvas_transform_inverse = p_canvas_transform.affine_inverse(); + //setup directional lights if exist + + uint32_t light_count = 0; + uint32_t directional_light_count = 0; { - //update canvas state uniform buffer - State::Buffer state_buffer; + Light *l = p_directional_light_list; + uint32_t index = 0; - Size2i ssize = storage->render_target_get_size(p_to_render_target); + while (l) { + if (index == state.max_lights_per_render) { + l->render_index_cache = -1; + l = l->next_ptr; + continue; + } - Transform screen_transform; - screen_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f); - screen_transform.scale(Vector3(2.0f / ssize.width, 2.0f / ssize.height, 1.0f)); - _update_transform_to_mat4(screen_transform, state_buffer.screen_transform); - _update_transform_2d_to_mat4(p_canvas_transform, state_buffer.canvas_transform); + CanvasLight *clight = canvas_light_owner.getornull(l->light_internal); + if (!clight) { //unused or invalid texture + l->render_index_cache = -1; + l = l->next_ptr; + ERR_CONTINUE(!clight); + } - Transform2D normal_transform = p_canvas_transform; - normal_transform.elements[0].normalize(); - normal_transform.elements[1].normalize(); - normal_transform.elements[2] = Vector2(); - _update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform); + Vector2 canvas_light_dir = l->xform_cache.elements[1].normalized(); - state_buffer.canvas_modulate[0] = p_modulate.r; - state_buffer.canvas_modulate[1] = p_modulate.g; - state_buffer.canvas_modulate[2] = p_modulate.b; - state_buffer.canvas_modulate[3] = p_modulate.a; + state.light_uniforms[index].position[0] = -canvas_light_dir.x; + state.light_uniforms[index].position[1] = -canvas_light_dir.y; - Size2 render_target_size = storage->render_target_get_size(p_to_render_target); - state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x; - state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y; + _update_transform_2d_to_mat2x4(clight->shadow.directional_xform, state.light_uniforms[index].shadow_matrix); - state_buffer.time = state.time; - state_buffer.use_pixel_snap = p_snap_2d_vertices_to_pixel; + state.light_uniforms[index].height = l->height; //0..1 here + + for (int i = 0; i < 4; i++) { + state.light_uniforms[index].shadow_color[i] = uint8_t(CLAMP(int32_t(l->shadow_color[i] * 255.0), 0, 255)); + state.light_uniforms[index].color[i] = l->color[i]; + } + + state.light_uniforms[index].color[3] = l->energy; //use alpha for energy, so base color can go separate + + if (state.shadow_fb.is_valid()) { + state.light_uniforms[index].shadow_pixel_size = (1.0 / state.shadow_texture_size) * (1.0 + l->shadow_smooth); + state.light_uniforms[index].shadow_z_far_inv = 1.0 / clight->shadow.z_far; + state.light_uniforms[index].shadow_y_ofs = clight->shadow.y_offset; + } else { + state.light_uniforms[index].shadow_pixel_size = 1.0; + state.light_uniforms[index].shadow_z_far_inv = 1.0; + state.light_uniforms[index].shadow_y_ofs = 0; + } + + state.light_uniforms[index].flags = l->blend_mode << LIGHT_FLAGS_BLEND_SHIFT; + state.light_uniforms[index].flags |= l->shadow_filter << LIGHT_FLAGS_FILTER_SHIFT; + if (clight->shadow.enabled) { + state.light_uniforms[index].flags |= LIGHT_FLAGS_HAS_SHADOW; + } + + l->render_index_cache = index; - RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true); + index++; + l = l->next_ptr; + } + + light_count = index; + directional_light_count = light_count; + using_directional_lights = directional_light_count > 0; } //setup lights if exist { Light *l = p_light_list; - uint32_t index = 0; + uint32_t index = light_count; while (l) { if (index == state.max_lights_per_render) { @@ -1280,7 +1337,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite state.light_uniforms[index].shadow_y_ofs = 0; } - state.light_uniforms[index].flags |= l->mode << LIGHT_FLAGS_BLEND_SHIFT; + state.light_uniforms[index].flags = l->blend_mode << LIGHT_FLAGS_BLEND_SHIFT; state.light_uniforms[index].flags |= l->shadow_filter << LIGHT_FLAGS_FILTER_SHIFT; if (clight->shadow.enabled) { state.light_uniforms[index].flags |= LIGHT_FLAGS_HAS_SHADOW; @@ -1306,9 +1363,65 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite l = l->next_ptr; } - if (index > 0) { - RD::get_singleton()->buffer_update(state.lights_uniform_buffer, 0, sizeof(LightUniform) * index, &state.light_uniforms[0], true); - } + light_count = index; + } + + if (light_count > 0) { + RD::get_singleton()->buffer_update(state.lights_uniform_buffer, 0, sizeof(LightUniform) * light_count, &state.light_uniforms[0]); + } + + { + //update canvas state uniform buffer + State::Buffer state_buffer; + + Size2i ssize = storage->render_target_get_size(p_to_render_target); + + Transform screen_transform; + screen_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f); + screen_transform.scale(Vector3(2.0f / ssize.width, 2.0f / ssize.height, 1.0f)); + _update_transform_to_mat4(screen_transform, state_buffer.screen_transform); + _update_transform_2d_to_mat4(p_canvas_transform, state_buffer.canvas_transform); + + Transform2D normal_transform = p_canvas_transform; + normal_transform.elements[0].normalize(); + normal_transform.elements[1].normalize(); + normal_transform.elements[2] = Vector2(); + _update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform); + + state_buffer.canvas_modulate[0] = p_modulate.r; + state_buffer.canvas_modulate[1] = p_modulate.g; + state_buffer.canvas_modulate[2] = p_modulate.b; + state_buffer.canvas_modulate[3] = p_modulate.a; + + Size2 render_target_size = storage->render_target_get_size(p_to_render_target); + state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x; + state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y; + + state_buffer.time = state.time; + state_buffer.use_pixel_snap = p_snap_2d_vertices_to_pixel; + + state_buffer.directional_light_count = directional_light_count; + + Vector2 canvas_scale = p_canvas_transform.get_scale(); + + state_buffer.sdf_to_screen[0] = render_target_size.width / canvas_scale.x; + state_buffer.sdf_to_screen[1] = render_target_size.height / canvas_scale.y; + + state_buffer.screen_to_sdf[0] = 1.0 / state_buffer.sdf_to_screen[0]; + state_buffer.screen_to_sdf[1] = 1.0 / state_buffer.sdf_to_screen[1]; + + Rect2 sdf_rect = storage->render_target_get_sdf_rect(p_to_render_target); + Rect2 sdf_tex_rect(sdf_rect.position / canvas_scale, sdf_rect.size / canvas_scale); + + state_buffer.sdf_to_tex[0] = 1.0 / sdf_tex_rect.size.width; + state_buffer.sdf_to_tex[1] = 1.0 / sdf_tex_rect.size.height; + state_buffer.sdf_to_tex[2] = -sdf_tex_rect.position.x / sdf_tex_rect.size.width; + state_buffer.sdf_to_tex[3] = -sdf_tex_rect.position.y / sdf_tex_rect.size.height; + + //print_line("w: " + itos(ssize.width) + " s: " + rtos(canvas_scale)); + state_buffer.tex_to_sdf = 1.0 / ((canvas_scale.x + canvas_scale.y) * 0.5); + + RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer); } { //default filter/repeat @@ -1336,7 +1449,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite } if (ci->material.is_valid()) { - MaterialData *md = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D); + MaterialData *md = (MaterialData *)storage->material_get_data(ci->material, RendererStorageRD::SHADER_TYPE_2D); if (md && md->shader_data->valid) { if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) { if (!material_screen_texture_found) { @@ -1345,12 +1458,15 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite } } - if (md->last_frame != RasterizerRD::singleton->get_frame_number()) { - md->last_frame = RasterizerRD::singleton->get_frame_number(); + if (md->shader_data->uses_sdf) { + r_sdf_used = true; + } + if (md->last_frame != RendererCompositorRD::singleton->get_frame_number()) { + md->last_frame = RendererCompositorRD::singleton->get_frame_number(); if (!RD::get_singleton()->uniform_set_is_valid(md->uniform_set)) { // uniform set may be gone because a dependency was erased. In this case, it will happen // if a texture is deleted, so just re-create it. - storage->material_force_update_textures(ci->material, RasterizerStorageRD::SHADER_TYPE_2D); + storage->material_force_update_textures(ci->material, RendererStorageRD::SHADER_TYPE_2D); } } } @@ -1411,12 +1527,12 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite } } -RID RasterizerCanvasRD::light_create() { +RID RendererCanvasRenderRD::light_create() { CanvasLight canvas_light; return canvas_light_owner.make_rid(canvas_light); } -void RasterizerCanvasRD::light_set_texture(RID p_rid, RID p_texture) { +void RendererCanvasRenderRD::light_set_texture(RID p_rid, RID p_texture) { CanvasLight *cl = canvas_light_owner.getornull(p_rid); ERR_FAIL_COND(!cl); if (cl->texture == p_texture) { @@ -1432,17 +1548,14 @@ void RasterizerCanvasRD::light_set_texture(RID p_rid, RID p_texture) { } } -void RasterizerCanvasRD::light_set_use_shadow(RID p_rid, bool p_enable) { +void RendererCanvasRenderRD::light_set_use_shadow(RID p_rid, bool p_enable) { CanvasLight *cl = canvas_light_owner.getornull(p_rid); ERR_FAIL_COND(!cl); cl->shadow.enabled = p_enable; } -void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) { - CanvasLight *cl = canvas_light_owner.getornull(p_rid); - ERR_FAIL_COND(!cl->shadow.enabled); - +void RendererCanvasRenderRD::_update_shadow_atlas() { if (state.shadow_fb == RID()) { //ah, we lack the shadow texture.. RD::get_singleton()->free(state.shadow_texture); //erase placeholder @@ -1451,7 +1564,7 @@ void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, cons { //texture RD::TextureFormat tf; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.width = state.shadow_texture_size; tf.height = state.max_lights_per_render * 2; tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; @@ -1462,7 +1575,7 @@ void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, cons } { RD::TextureFormat tf; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.width = state.shadow_texture_size; tf.height = state.max_lights_per_render * 2; tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; @@ -1474,6 +1587,12 @@ void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, cons state.shadow_fb = RD::get_singleton()->framebuffer_create(fb_textures); } +} +void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) { + CanvasLight *cl = canvas_light_owner.getornull(p_rid); + ERR_FAIL_COND(!cl->shadow.enabled); + + _update_shadow_atlas(); cl->shadow.z_far = p_far; cl->shadow.y_offset = float(p_shadow_index * 2 + 1) / float(state.max_lights_per_render * 2); @@ -1547,18 +1666,185 @@ void RasterizerCanvasRD::light_update_shadow(RID p_rid, int p_shadow_index, cons } } -RID RasterizerCanvasRD::occluder_polygon_create() { +void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) { + CanvasLight *cl = canvas_light_owner.getornull(p_rid); + ERR_FAIL_COND(!cl->shadow.enabled); + + _update_shadow_atlas(); + + Vector2 light_dir = p_light_xform.elements[1].normalized(); + + Vector2 center = p_clip_rect.position + p_clip_rect.size * 0.5; + + float to_edge_distance = ABS(light_dir.dot(p_clip_rect.get_support(light_dir)) - light_dir.dot(center)); + + Vector2 from_pos = center - light_dir * (to_edge_distance + p_cull_distance); + float distance = to_edge_distance * 2.0 + p_cull_distance; + float half_size = p_clip_rect.size.length() * 0.5; //shadow length, must keep this no matter the angle + + cl->shadow.z_far = distance; + cl->shadow.y_offset = float(p_shadow_index * 2 + 1) / float(state.max_lights_per_render * 2); + + Transform2D to_light_xform; + + to_light_xform[2] = from_pos; + to_light_xform[1] = light_dir; + to_light_xform[0] = -light_dir.orthogonal(); + + to_light_xform.invert(); + + Vector<Color> cc; + cc.push_back(Color(1, 1, 1, 1)); + + Rect2i rect(0, p_shadow_index * 2, state.shadow_texture_size, 2); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(state.shadow_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, rect); + + CameraMatrix projection; + projection.set_orthogonal(-half_size, half_size, -0.5, 0.5, 0.0, distance); + projection = projection * CameraMatrix(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, -1)).affine_inverse()); + + ShadowRenderPushConstant push_constant; + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 4; x++) { + push_constant.projection[y * 4 + x] = projection.matrix[y][x]; + } + } + + push_constant.direction[0] = 0.0; + push_constant.direction[1] = 1.0; + push_constant.z_far = distance; + push_constant.pad = 0; + + LightOccluderInstance *instance = p_occluders; + + while (instance) { + OccluderPolygon *co = occluder_polygon_owner.getornull(instance->occluder); + + if (!co || co->index_array.is_null() || !(p_light_mask & instance->light_mask)) { + instance = instance->next; + continue; + } + + _update_transform_2d_to_mat2x4(to_light_xform * instance->xform_cache, push_constant.modelview); + + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shadow_render.render_pipelines[co->cull_mode]); + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, co->vertex_array); + RD::get_singleton()->draw_list_bind_index_array(draw_list, co->index_array); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowRenderPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + + instance = instance->next; + } + + RD::get_singleton()->draw_list_end(); + + Transform2D to_shadow; + to_shadow.elements[0].x = 1.0 / -(half_size * 2.0); + to_shadow.elements[2].x = 0.5; + + cl->shadow.directional_xform = to_shadow * to_light_xform; +} + +void RendererCanvasRenderRD::render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) { + RID fb = storage->render_target_get_sdf_framebuffer(p_render_target); + Rect2i rect = storage->render_target_get_sdf_rect(p_render_target); + + Transform2D to_sdf; + to_sdf.elements[0] *= rect.size.width; + to_sdf.elements[1] *= rect.size.height; + to_sdf.elements[2] = rect.position; + + Transform2D to_clip; + to_clip.elements[0] *= 2.0; + to_clip.elements[1] *= 2.0; + to_clip.elements[2] = -Vector2(1.0, 1.0); + + to_clip = to_clip * to_sdf.affine_inverse(); + + Vector<Color> cc; + cc.push_back(Color(0, 0, 0, 0)); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc); + + CameraMatrix projection; + + ShadowRenderPushConstant push_constant; + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 4; x++) { + push_constant.projection[y * 4 + x] = projection.matrix[y][x]; + } + } + + push_constant.direction[0] = 0.0; + push_constant.direction[1] = 0.0; + push_constant.z_far = 0; + push_constant.pad = 0; + + LightOccluderInstance *instance = p_occluders; + + while (instance) { + OccluderPolygon *co = occluder_polygon_owner.getornull(instance->occluder); + + if (!co || co->sdf_index_array.is_null()) { + instance = instance->next; + continue; + } + + _update_transform_2d_to_mat2x4(to_clip * instance->xform_cache, push_constant.modelview); + + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shadow_render.sdf_render_pipelines[co->sdf_is_lines ? SHADOW_RENDER_SDF_LINES : SHADOW_RENDER_SDF_TRIANGLES]); + RD::get_singleton()->draw_list_bind_vertex_array(draw_list, co->sdf_vertex_array); + RD::get_singleton()->draw_list_bind_index_array(draw_list, co->sdf_index_array); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowRenderPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + + instance = instance->next; + } + + RD::get_singleton()->draw_list_end(); + + storage->render_target_sdf_process(p_render_target); //done rendering, process it +} + +RID RendererCanvasRenderRD::occluder_polygon_create() { OccluderPolygon occluder; - occluder.point_count = 0; + occluder.line_point_count = 0; + occluder.sdf_point_count = 0; + occluder.sdf_index_count = 0; occluder.cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; return occluder_polygon_owner.make_rid(occluder); } -void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines) { +void RendererCanvasRenderRD::occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) { OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder); ERR_FAIL_COND(!oc); - if (oc->point_count != p_lines.size() && oc->vertex_array.is_valid()) { + Vector<Vector2> lines; + + if (p_points.size()) { + int lc = p_points.size() * 2; + + lines.resize(lc - (p_closed ? 0 : 2)); + { + Vector2 *w = lines.ptrw(); + const Vector2 *r = p_points.ptr(); + + int max = lc / 2; + if (!p_closed) { + max--; + } + for (int i = 0; i < max; i++) { + Vector2 a = r[i]; + Vector2 b = r[(i + 1) % (lc / 2)]; + w[i * 2 + 0] = a; + w[i * 2 + 1] = b; + } + } + } + + if (oc->line_point_count != lines.size() && oc->vertex_array.is_valid()) { RD::get_singleton()->free(oc->vertex_array); RD::get_singleton()->free(oc->vertex_buffer); RD::get_singleton()->free(oc->index_array); @@ -1568,12 +1854,14 @@ void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, con oc->vertex_buffer = RID(); oc->index_array = RID(); oc->index_buffer = RID(); + + oc->line_point_count = lines.size(); } - if (p_lines.size()) { + if (lines.size()) { Vector<uint8_t> geometry; Vector<uint8_t> indices; - int lc = p_lines.size(); + int lc = lines.size(); geometry.resize(lc * 6 * sizeof(float)); indices.resize(lc * 3 * sizeof(uint16_t)); @@ -1584,7 +1872,7 @@ void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, con uint8_t *iw = indices.ptrw(); uint16_t *iwptr = (uint16_t *)iw; - const Vector2 *lr = p_lines.ptr(); + const Vector2 *lr = lines.ptr(); const int POLY_HEIGHT = 16384; @@ -1638,15 +1926,73 @@ void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, con RD::get_singleton()->buffer_update(oc->index_buffer, 0, indices.size(), ir); } } + + // sdf + + Vector<int> sdf_indices; + + if (p_points.size()) { + if (p_closed) { + sdf_indices = Geometry2D::triangulate_polygon(p_points); + oc->sdf_is_lines = false; + } else { + int max = p_points.size(); + sdf_indices.resize(max * 2); + + int *iw = sdf_indices.ptrw(); + for (int i = 0; i < max; i++) { + iw[i * 2 + 0] = i; + iw[i * 2 + 1] = (i + 1) % max; + } + oc->sdf_is_lines = true; + } + } + + if (oc->sdf_index_count != sdf_indices.size() && oc->sdf_point_count != p_points.size() && oc->sdf_vertex_array.is_valid()) { + RD::get_singleton()->free(oc->sdf_vertex_array); + RD::get_singleton()->free(oc->sdf_vertex_buffer); + RD::get_singleton()->free(oc->sdf_index_array); + RD::get_singleton()->free(oc->sdf_index_buffer); + + oc->sdf_vertex_array = RID(); + oc->sdf_vertex_buffer = RID(); + oc->sdf_index_array = RID(); + oc->sdf_index_buffer = RID(); + + oc->sdf_index_count = sdf_indices.size(); + oc->sdf_point_count = p_points.size(); + + oc->sdf_is_lines = false; + } + + if (sdf_indices.size()) { + if (oc->sdf_vertex_array.is_null()) { + //create from scratch + //vertices + oc->sdf_vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_points.size() * 2 * sizeof(real_t), p_points.to_byte_array()); + oc->sdf_index_buffer = RD::get_singleton()->index_buffer_create(sdf_indices.size(), RD::INDEX_BUFFER_FORMAT_UINT32, sdf_indices.to_byte_array()); + oc->sdf_index_array = RD::get_singleton()->index_array_create(oc->sdf_index_buffer, 0, sdf_indices.size()); + + Vector<RID> buffer; + buffer.push_back(oc->sdf_vertex_buffer); + oc->sdf_vertex_array = RD::get_singleton()->vertex_array_create(p_points.size(), shadow_render.sdf_vertex_format, buffer); + //indices + + } else { + //update existing + RD::get_singleton()->buffer_update(oc->vertex_buffer, 0, sizeof(real_t) * 2 * p_points.size(), p_points.ptr()); + RD::get_singleton()->buffer_update(oc->index_buffer, 0, sdf_indices.size() * sizeof(int32_t), sdf_indices.ptr()); + } + } } -void RasterizerCanvasRD::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) { +void RendererCanvasRenderRD::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) { OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder); ERR_FAIL_COND(!oc); oc->cull_mode = p_mode; } -void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { +void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) { //compile code = p_code; @@ -1654,6 +2000,7 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { ubo_size = 0; uniforms.clear(); uses_screen_texture = false; + uses_sdf = false; if (code == String()) { return; //just invalid, but no error @@ -1661,7 +2008,6 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { ShaderCompilerRD::GeneratedCode gen_code; - int light_mode = LIGHT_MODE_NORMAL; int blend_mode = BLEND_MODE_MIX; uses_screen_texture = false; @@ -1674,14 +2020,12 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PMALPHA); actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_mode, BLEND_MODE_DISABLED); - actions.render_mode_values["unshaded"] = Pair<int *, int>(&light_mode, LIGHT_MODE_UNSHADED); - actions.render_mode_values["light_only"] = Pair<int *, int>(&light_mode, LIGHT_MODE_LIGHT_ONLY); - actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture; + actions.usage_flag_pointers["texture_sdf"] = &uses_sdf; actions.uniforms = &uniforms; - RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::singleton; + RendererCanvasRenderRD *canvas_singleton = (RendererCanvasRenderRD *)RendererCanvasRender::singleton; Error err = canvas_singleton->shader.compiler.compile(RS::SHADER_CANVAS_ITEM, code, &actions, path, gen_code); @@ -1826,7 +2170,7 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { valid = true; } -void RasterizerCanvasRD::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { +void RendererCanvasRenderRD::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { if (!p_texture.is_valid()) { default_texture_params.erase(p_name); } else { @@ -1834,7 +2178,7 @@ void RasterizerCanvasRD::ShaderData::set_default_texture_param(const StringName } } -void RasterizerCanvasRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { +void RendererCanvasRenderRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { Map<int, StringName> order; for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { @@ -1855,13 +2199,13 @@ void RasterizerCanvasRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_ } } -void RasterizerCanvasRD::ShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const { +void RendererCanvasRenderRD::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; } - RasterizerStorage::InstanceShaderParam p; + RendererStorage::InstanceShaderParam p; p.info = ShaderLanguage::uniform_to_property_info(E->get()); p.info.name = E->key(); //supply name p.index = E->get().instance_index; @@ -1870,7 +2214,7 @@ void RasterizerCanvasRD::ShaderData::get_instance_param_list(List<RasterizerStor } } -bool RasterizerCanvasRD::ShaderData::is_param_texture(const StringName &p_param) const { +bool RendererCanvasRenderRD::ShaderData::is_param_texture(const StringName &p_param) const { if (!uniforms.has(p_param)) { return false; } @@ -1878,15 +2222,15 @@ bool RasterizerCanvasRD::ShaderData::is_param_texture(const StringName &p_param) return uniforms[p_param].texture_order >= 0; } -bool RasterizerCanvasRD::ShaderData::is_animated() const { +bool RendererCanvasRenderRD::ShaderData::is_animated() const { return false; } -bool RasterizerCanvasRD::ShaderData::casts_shadows() const { +bool RendererCanvasRenderRD::ShaderData::casts_shadows() const { return false; } -Variant RasterizerCanvasRD::ShaderData::get_default_parameter(const StringName &p_parameter) const { +Variant RendererCanvasRenderRD::ShaderData::get_default_parameter(const StringName &p_parameter) const { if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; @@ -1895,13 +2239,19 @@ Variant RasterizerCanvasRD::ShaderData::get_default_parameter(const StringName & return Variant(); } -RasterizerCanvasRD::ShaderData::ShaderData() { +RS::ShaderNativeSourceCode RendererCanvasRenderRD::ShaderData::get_native_source_code() const { + RendererCanvasRenderRD *canvas_singleton = (RendererCanvasRenderRD *)RendererCanvasRender::singleton; + return canvas_singleton->shader.canvas_shader.version_get_native_source_code(version); +} + +RendererCanvasRenderRD::ShaderData::ShaderData() { valid = false; uses_screen_texture = false; + uses_sdf = false; } -RasterizerCanvasRD::ShaderData::~ShaderData() { - RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::singleton; +RendererCanvasRenderRD::ShaderData::~ShaderData() { + RendererCanvasRenderRD *canvas_singleton = (RendererCanvasRenderRD *)RendererCanvasRender::singleton; ERR_FAIL_COND(!canvas_singleton); //pipeline variants will clear themselves if shader is gone if (version.is_valid()) { @@ -1909,13 +2259,13 @@ RasterizerCanvasRD::ShaderData::~ShaderData() { } } -RasterizerStorageRD::ShaderData *RasterizerCanvasRD::_create_shader_func() { +RendererStorageRD::ShaderData *RendererCanvasRenderRD::_create_shader_func() { ShaderData *shader_data = memnew(ShaderData); return shader_data; } -void RasterizerCanvasRD::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { - RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::singleton; +void RendererCanvasRenderRD::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { + RendererCanvasRenderRD *canvas_singleton = (RendererCanvasRenderRD *)RendererCanvasRender::singleton; if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { p_uniform_dirty = true; @@ -1975,7 +2325,7 @@ void RasterizerCanvasRD::MaterialData::update_parameters(const Map<StringName, V { if (shader_data->ubo_size) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 0; u.ids.push_back(uniform_buffer); uniforms.push_back(u); @@ -1984,7 +2334,7 @@ void RasterizerCanvasRD::MaterialData::update_parameters(const Map<StringName, V const RID *textures = texture_cache.ptrw(); for (uint32_t i = 0; i < tex_uniform_count; i++) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1 + i; u.ids.push_back(textures[i]); uniforms.push_back(u); @@ -1994,7 +2344,7 @@ void RasterizerCanvasRD::MaterialData::update_parameters(const Map<StringName, V uniform_set = RD::get_singleton()->uniform_set_create(uniforms, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET); } -RasterizerCanvasRD::MaterialData::~MaterialData() { +RendererCanvasRenderRD::MaterialData::~MaterialData() { if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { RD::get_singleton()->free(uniform_set); } @@ -2004,7 +2354,7 @@ RasterizerCanvasRD::MaterialData::~MaterialData() { } } -RasterizerStorageRD::MaterialData *RasterizerCanvasRD::_create_material_func(ShaderData *p_shader) { +RendererStorageRD::MaterialData *RendererCanvasRenderRD::_create_material_func(ShaderData *p_shader) { MaterialData *material_data = memnew(MaterialData); material_data->shader_data = p_shader; material_data->last_frame = false; @@ -2012,14 +2362,14 @@ RasterizerStorageRD::MaterialData *RasterizerCanvasRD::_create_material_func(Sha return material_data; } -void RasterizerCanvasRD::set_time(double p_time) { +void RendererCanvasRenderRD::set_time(double p_time) { state.time = p_time; } -void RasterizerCanvasRD::update() { +void RendererCanvasRenderRD::update() { } -RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { +RendererCanvasRenderRD::RendererCanvasRenderRD(RendererStorageRD *p_storage) { storage = p_storage; { //create default samplers @@ -2143,8 +2493,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { actions.renames["COLOR"] = "color"; actions.renames["NORMAL"] = "normal"; - actions.renames["NORMALMAP"] = "normal_map"; - actions.renames["NORMALMAP_DEPTH"] = "normal_depth"; + actions.renames["NORMAL_MAP"] = "normal_map"; + actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; actions.renames["TEXTURE"] = "color_texture"; actions.renames["TEXTURE_PIXEL_SIZE"] = "draw_data.color_texture_pixel_size"; actions.renames["NORMAL_TEXTURE"] = "normal_texture"; @@ -2156,21 +2506,28 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { actions.renames["FRAGCOORD"] = "gl_FragCoord"; actions.renames["POINT_COORD"] = "gl_PointCoord"; - actions.renames["LIGHT_POSITION"] = "light_pos"; + actions.renames["LIGHT_POSITION"] = "light_position"; actions.renames["LIGHT_COLOR"] = "light_color"; actions.renames["LIGHT_ENERGY"] = "light_energy"; actions.renames["LIGHT"] = "light"; actions.renames["SHADOW_MODULATE"] = "shadow_modulate"; + actions.renames["texture_sdf"] = "texture_sdf"; + actions.renames["texture_sdf_normal"] = "texture_sdf_normal"; + actions.renames["sdf_to_screen_uv"] = "sdf_to_screen_uv"; + actions.renames["screen_uv_to_sdf"] = "screen_uv_to_sdf"; + actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; actions.usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV"; actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n"; - actions.usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n"; + actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n"; actions.usage_defines["LIGHT"] = "#define LIGHT_SHADER_CODE_USED\n"; actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; + actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n"; + actions.render_mode_defines["light_only"] = "#define MODE_LIGHT_ONLY\n"; actions.custom_samplers["TEXTURE"] = "texture_sampler"; actions.custom_samplers["NORMAL_TEXTURE"] = "texture_sampler"; @@ -2191,7 +2548,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { { //shadow rendering Vector<String> versions; - versions.push_back(String()); //no versions + versions.push_back("\n#define MODE_SHADOW\n"); //shadow + versions.push_back("\n#define MODE_SDF\n"); //sdf shadow_render.shader.initialize(versions); { @@ -2212,16 +2570,34 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { shadow_render.framebuffer_format = RD::get_singleton()->framebuffer_format_create(attachments); } + { + Vector<RD::AttachmentFormat> attachments; + + RD::AttachmentFormat af_color; + af_color.format = RD::DATA_FORMAT_R8_UNORM; + af_color.usage_flags = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + + attachments.push_back(af_color); + + shadow_render.sdf_framebuffer_format = RD::get_singleton()->framebuffer_format_create(attachments); + } + //pipelines Vector<RD::VertexAttribute> vf; RD::VertexAttribute vd; - vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; + vd.format = sizeof(real_t) == sizeof(float) ? RD::DATA_FORMAT_R32G32B32_SFLOAT : RD::DATA_FORMAT_R64G64B64_SFLOAT; vd.location = 0; vd.offset = 0; - vd.stride = sizeof(float) * 3; + vd.stride = sizeof(real_t) * 3; vf.push_back(vd); shadow_render.vertex_format = RD::get_singleton()->vertex_format_create(vf); + vd.format = sizeof(real_t) == sizeof(float) ? RD::DATA_FORMAT_R32G32_SFLOAT : RD::DATA_FORMAT_R64G64_SFLOAT; + vd.stride = sizeof(real_t) * 2; + + vf.write[0] = vd; + shadow_render.sdf_vertex_format = RD::get_singleton()->vertex_format_create(vf); + shadow_render.shader_version = shadow_render.shader.version_create(); for (int i = 0; i < 3; i++) { @@ -2231,7 +2607,11 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { ds.enable_depth_write = true; ds.enable_depth_test = true; ds.depth_compare_operator = RD::COMPARE_OP_LESS; - shadow_render.render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, 0), shadow_render.framebuffer_format, shadow_render.vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); + shadow_render.render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, SHADOW_RENDER_MODE_SHADOW), shadow_render.framebuffer_format, shadow_render.vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); + } + + for (int i = 0; i < 2; i++) { + shadow_render.sdf_render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, SHADOW_RENDER_MODE_SDF), shadow_render.sdf_framebuffer_format, shadow_render.sdf_vertex_format, i == 0 ? RD::RENDER_PRIMITIVE_TRIANGLES : RD::RENDER_PRIMITIVE_LINES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); } } @@ -2292,7 +2672,7 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { { //default shadow texture to keep uniform set happy RD::TextureFormat tf; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.width = 4; tf.height = 4; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; @@ -2306,7 +2686,7 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(storage->get_default_rd_storage_buffer()); uniforms.push_back(u); @@ -2320,8 +2700,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { state.shadow_texture_size = GLOBAL_GET("rendering/quality/2d_shadow_atlas/size"); //create functions for shader and material - storage->shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_2D, _create_shader_funcs); - storage->material_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_2D, _create_material_funcs); + storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_2D, _create_shader_funcs); + storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_2D, _create_material_funcs); state.time = 0; @@ -2335,14 +2715,14 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { static_assert(sizeof(PushConstant) == 128); } -bool RasterizerCanvasRD::free(RID p_rid) { +bool RendererCanvasRenderRD::free(RID p_rid) { if (canvas_light_owner.owns(p_rid)) { CanvasLight *cl = canvas_light_owner.getornull(p_rid); ERR_FAIL_COND_V(!cl, false); light_set_use_shadow(p_rid, false); canvas_light_owner.free(p_rid); } else if (occluder_polygon_owner.owns(p_rid)) { - occluder_polygon_set_shape_as_lines(p_rid, Vector<Vector2>()); + occluder_polygon_set_shape(p_rid, Vector<Vector2>(), false); occluder_polygon_owner.free(p_rid); } else { return false; @@ -2351,7 +2731,7 @@ bool RasterizerCanvasRD::free(RID p_rid) { return true; } -void RasterizerCanvasRD::set_shadow_texture_size(int p_size) { +void RendererCanvasRenderRD::set_shadow_texture_size(int p_size) { p_size = nearest_power_of_2_templated(p_size); if (p_size == state.shadow_texture_size) { return; @@ -2365,7 +2745,7 @@ void RasterizerCanvasRD::set_shadow_texture_size(int p_size) { { //create a default shadow texture to keep uniform set happy (and that it gets erased when a new one is created) RD::TextureFormat tf; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.width = 4; tf.height = 4; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; @@ -2376,7 +2756,7 @@ void RasterizerCanvasRD::set_shadow_texture_size(int p_size) { } } -RasterizerCanvasRD::~RasterizerCanvasRD() { +RendererCanvasRenderRD::~RendererCanvasRenderRD() { //canvas state storage->free(default_canvas_group_material); @@ -2419,6 +2799,4 @@ RasterizerCanvasRD::~RasterizerCanvasRD() { storage->free(default_canvas_texture); //pipelines don't need freeing, they are all gone after shaders are gone - - RD::get_singleton()->free(state.default_transforms_uniform_set); } diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index 3412435367..cb947d7180 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_canvas_rd.h */ +/* renderer_canvas_render_rd.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,19 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RASTERIZER_CANVAS_RD_H -#define RASTERIZER_CANVAS_RD_H +#ifndef RENDERING_SERVER_CANVAS_RENDER_RD_H +#define RENDERING_SERVER_CANVAS_RENDER_RD_H -#include "servers/rendering/rasterizer.h" -#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h" -#include "servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h" -#include "servers/rendering/rasterizer_rd/shader_compiler_rd.h" -#include "servers/rendering/rasterizer_rd/shaders/canvas.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl.gen.h" +#include "servers/rendering/renderer_canvas_render.h" +#include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_rd/pipeline_cache_rd.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" +#include "servers/rendering/renderer_rd/shader_compiler_rd.h" +#include "servers/rendering/renderer_rd/shaders/canvas.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl.gen.h" #include "servers/rendering/rendering_device.h" -class RasterizerCanvasRD : public RasterizerCanvas { - RasterizerStorageRD *storage; +class RendererCanvasRenderRD : public RendererCanvasRender { + RendererStorageRD *storage; enum { BASE_UNIFORM_SET = 0, @@ -75,7 +76,6 @@ class RasterizerCanvasRD : public RasterizerCanvas { FLAGS_CLIP_RECT_UV = (1 << 9), FLAGS_TRANSPOSE_RECT = (1 << 10), - FLAGS_USING_LIGHT_MASK = (1 << 11), FLAGS_NINEPACH_DRAW_CENTER = (1 << 12), FLAGS_USING_PARTICLES = (1 << 13), @@ -134,7 +134,7 @@ class RasterizerCanvasRD : public RasterizerCanvas { }; struct PipelineVariants { - RenderPipelineVertexFormatCacheRD variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX]; + PipelineCacheRD variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX]; }; struct { @@ -152,7 +152,7 @@ class RasterizerCanvasRD : public RasterizerCanvas { ShaderCompilerRD compiler; } shader; - struct ShaderData : public RasterizerStorageRD::ShaderData { + struct ShaderData : public RendererStorageRD::ShaderData { enum BlendMode { //used internally BLEND_MODE_MIX, BLEND_MODE_ADD, @@ -162,12 +162,6 @@ class RasterizerCanvasRD : public RasterizerCanvas { BLEND_MODE_DISABLED, }; - enum LightMode { - LIGHT_MODE_NORMAL, - LIGHT_MODE_UNSHADED, - LIGHT_MODE_LIGHT_ONLY - }; - bool valid; RID version; PipelineVariants pipeline_variants; @@ -182,27 +176,30 @@ class RasterizerCanvasRD : public RasterizerCanvas { String code; Map<StringName, RID> default_texture_params; - bool uses_screen_texture; + bool uses_screen_texture = false; + bool uses_sdf = false; virtual void set_code(const String &p_Code); virtual void set_default_texture_param(const StringName &p_name, RID p_texture); virtual void get_param_list(List<PropertyInfo> *p_param_list) const; - virtual void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const; + virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; virtual bool is_param_texture(const StringName &p_param) const; virtual bool is_animated() const; virtual bool casts_shadows() const; virtual Variant get_default_parameter(const StringName &p_parameter) const; + virtual RS::ShaderNativeSourceCode get_native_source_code() const; + ShaderData(); virtual ~ShaderData(); }; - RasterizerStorageRD::ShaderData *_create_shader_func(); - static RasterizerStorageRD::ShaderData *_create_shader_funcs() { - return static_cast<RasterizerCanvasRD *>(singleton)->_create_shader_func(); + RendererStorageRD::ShaderData *_create_shader_func(); + static RendererStorageRD::ShaderData *_create_shader_funcs() { + return static_cast<RendererCanvasRenderRD *>(singleton)->_create_shader_func(); } - struct MaterialData : public RasterizerStorageRD::MaterialData { + struct MaterialData : public RendererStorageRD::MaterialData { uint64_t last_frame; ShaderData *shader_data; RID uniform_buffer; @@ -216,9 +213,9 @@ class RasterizerCanvasRD : public RasterizerCanvas { virtual ~MaterialData(); }; - RasterizerStorageRD::MaterialData *_create_material_func(ShaderData *p_shader); - static RasterizerStorageRD::MaterialData *_create_material_funcs(RasterizerStorageRD::ShaderData *p_shader) { - return static_cast<RasterizerCanvasRD *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader)); + RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader); + static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) { + return static_cast<RendererCanvasRenderRD *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader)); } /**************************/ @@ -269,6 +266,7 @@ class RasterizerCanvasRD : public RasterizerCanvas { bool enabled = false; float z_far; float y_offset; + Transform2D directional_xform; } shadow; }; @@ -284,11 +282,19 @@ class RasterizerCanvasRD : public RasterizerCanvas { struct OccluderPolygon { RS::CanvasOccluderPolygonCullMode cull_mode; - int point_count; + int line_point_count; RID vertex_buffer; RID vertex_array; RID index_buffer; RID index_array; + + int sdf_point_count; + int sdf_index_count; + RID sdf_vertex_buffer; + RID sdf_vertex_array; + RID sdf_index_buffer; + RID sdf_index_array; + bool sdf_is_lines; }; struct LightUniform { @@ -310,12 +316,25 @@ class RasterizerCanvasRD : public RasterizerCanvas { RID_Owner<OccluderPolygon> occluder_polygon_owner; + enum ShadowRenderMode { + SHADOW_RENDER_MODE_SHADOW, + SHADOW_RENDER_MODE_SDF, + }; + + enum { + SHADOW_RENDER_SDF_TRIANGLES, + SHADOW_RENDER_SDF_LINES, + }; + struct { CanvasOcclusionShaderRD shader; RID shader_version; RID render_pipelines[3]; + RID sdf_render_pipelines[2]; RD::VertexFormatID vertex_format; + RD::VertexFormatID sdf_vertex_format; RD::FramebufferFormatID framebuffer_format; + RD::FramebufferFormatID sdf_framebuffer_format; } shadow_render; /***************/ @@ -331,12 +350,19 @@ class RasterizerCanvasRD : public RasterizerCanvas { float screen_transform[16]; float canvas_normal_transform[16]; float canvas_modulate[4]; + float screen_pixel_size[2]; float time; uint32_t use_pixel_snap; - //uint32_t light_count; - //uint32_t pad[3]; + float sdf_to_tex[4]; + float sdf_to_screen[2]; + float screen_to_sdf[2]; + + uint32_t directional_light_count; + float tex_to_sdf; + uint32_t pad1; + uint32_t pad2; }; LightUniform *light_uniforms; @@ -355,6 +381,7 @@ class RasterizerCanvasRD : public RasterizerCanvas { uint32_t max_lights_per_item; double time; + } state; struct PushConstant { @@ -388,6 +415,7 @@ class RasterizerCanvasRD : public RasterizerCanvas { Item *items[MAX_RENDER_ITEMS]; + bool using_directional_lights = false; RID default_canvas_texture; RID default_canvas_group_shader; @@ -408,6 +436,8 @@ class RasterizerCanvasRD : public RasterizerCanvas { _FORCE_INLINE_ void _update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4); _FORCE_INLINE_ void _update_transform_to_mat4(const Transform &p_transform, float *p_mat4); + void _update_shadow_atlas(); + public: PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()); void free_polygon(PolygonID p_polygon); @@ -416,12 +446,15 @@ public: void light_set_texture(RID p_rid, RID p_texture); void light_set_use_shadow(RID p_rid, bool p_enable); void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders); + void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders); + + virtual void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders); RID occluder_polygon_create(); - void occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines); + void occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed); void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode); - void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel); + void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used); void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) {} @@ -432,8 +465,8 @@ public: void set_time(double p_time); void update(); bool free(RID p_rid); - RasterizerCanvasRD(RasterizerStorageRD *p_storage); - ~RasterizerCanvasRD(); + RendererCanvasRenderRD(RendererStorageRD *p_storage); + ~RendererCanvasRenderRD(); }; #endif // RASTERIZER_CANVAS_RD_H diff --git a/servers/rendering/rasterizer_rd/rasterizer_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 509bd3ee73..be2552bd32 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_rd.cpp */ +/* renderer_compositor_rd.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rasterizer_rd.h" +#include "renderer_compositor_rd.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h" -void RasterizerRD::prepare_for_blitting_render_targets() { +void RendererCompositorRD::prepare_for_blitting_render_targets() { RD::get_singleton()->prepare_screen_for_drawing(); } -void RasterizerRD::blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) { +void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) { RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin_for_screen(p_screen); for (int i = 0; i < p_amount; i++) { @@ -47,7 +47,7 @@ void RasterizerRD::blit_render_targets_to_screen(DisplayServer::WindowID p_scree if (!render_target_descriptors.has(rd_texture) || !RD::get_singleton()->uniform_set_is_valid(render_target_descriptors[rd_texture])) { Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 0; u.ids.push_back(copy_viewports_sampler); u.ids.push_back(rd_texture); @@ -76,7 +76,7 @@ void RasterizerRD::blit_render_targets_to_screen(DisplayServer::WindowID p_scree RD::get_singleton()->draw_list_end(); } -void RasterizerRD::begin_frame(double frame_step) { +void RendererCompositorRD::begin_frame(double frame_step) { frame++; delta = frame_step; time += frame_step; @@ -88,14 +88,14 @@ void RasterizerRD::begin_frame(double frame_step) { scene->set_time(time, frame_step); } -void RasterizerRD::end_frame(bool p_swap_buffers) { +void RendererCompositorRD::end_frame(bool p_swap_buffers) { #ifndef _MSC_VER #warning TODO: likely pass a bool to swap buffers to avoid display? #endif RD::get_singleton()->swap_buffers(); //probably should pass some bool to avoid display? } -void RasterizerRD::initialize() { +void RendererCompositorRD::initialize() { { //create framebuffer copy shader RenderingDevice::ShaderStageData vert; vert.shader_stage = RenderingDevice::SHADER_STAGE_VERTEX; @@ -154,12 +154,9 @@ void RasterizerRD::initialize() { } } -ThreadWorkPool RasterizerRD::thread_work_pool; -uint64_t RasterizerRD::frame = 1; - -void RasterizerRD::finalize() { - thread_work_pool.finish(); +uint64_t RendererCompositorRD::frame = 1; +void RendererCompositorRD::finalize() { memdelete(scene); memdelete(canvas); memdelete(storage); @@ -170,14 +167,13 @@ void RasterizerRD::finalize() { RD::get_singleton()->free(copy_viewports_sampler); } -RasterizerRD *RasterizerRD::singleton = nullptr; +RendererCompositorRD *RendererCompositorRD::singleton = nullptr; -RasterizerRD::RasterizerRD() { +RendererCompositorRD::RendererCompositorRD() { singleton = this; - thread_work_pool.init(); time = 0; - storage = memnew(RasterizerStorageRD); - canvas = memnew(RasterizerCanvasRD(storage)); - scene = memnew(RasterizerSceneHighEndRD(storage)); + storage = memnew(RendererStorageRD); + canvas = memnew(RendererCanvasRenderRD(storage)); + scene = memnew(RendererSceneRenderForward(storage)); } diff --git a/servers/rendering/rasterizer_rd/rasterizer_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index cdcc6bfd73..cb85fc79e0 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_rd.h */ +/* renderer_compositor_rd.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,21 +28,21 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RASTERIZER_RD_H -#define RASTERIZER_RD_H +#ifndef RENDERING_SERVER_COMPOSITOR_RD_H +#define RENDERING_SERVER_COMPOSITOR_RD_H #include "core/os/os.h" -#include "core/thread_work_pool.h" -#include "servers/rendering/rasterizer.h" -#include "servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h" -#include "servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h" -#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h" +#include "core/templates/thread_work_pool.h" +#include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_rd/renderer_canvas_render_rd.h" +#include "servers/rendering/renderer_rd/renderer_scene_render_forward.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" -class RasterizerRD : public Rasterizer { +class RendererCompositorRD : public RendererCompositor { protected: - RasterizerCanvasRD *canvas; - RasterizerStorageRD *storage; - RasterizerSceneHighEndRD *scene; + RendererCanvasRenderRD *canvas; + RendererStorageRD *storage; + RendererSceneRenderForward *scene; RID copy_viewports_rd_shader; RID copy_viewports_rd_pipeline; @@ -58,9 +58,9 @@ protected: static uint64_t frame; public: - RasterizerStorage *get_storage() { return storage; } - RasterizerCanvas *get_canvas() { return canvas; } - RasterizerScene *get_scene() { return scene; } + RendererStorage *get_storage() { return storage; } + RendererCanvasRender *get_canvas() { return canvas; } + RendererSceneRender *get_scene() { return scene; } void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) {} @@ -80,8 +80,8 @@ public: return OK; } - static Rasterizer *_create_current() { - return memnew(RasterizerRD); + static RendererCompositor *_create_current() { + return memnew(RendererCompositorRD); } static void make_current() { @@ -90,10 +90,8 @@ public: virtual bool is_low_end() const { return false; } - static ThreadWorkPool thread_work_pool; - - static RasterizerRD *singleton; - RasterizerRD(); - ~RasterizerRD() {} + static RendererCompositorRD *singleton; + RendererCompositorRD(); + ~RendererCompositorRD() {} }; #endif // RASTERIZER_RD_H diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp index 35b0591289..a20a5073c3 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_scene_high_end_rd.cpp */ +/* renderer_scene_render_forward.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rasterizer_scene_high_end_rd.h" -#include "core/project_settings.h" +#include "renderer_scene_render_forward.h" +#include "core/config/project_settings.h" #include "servers/rendering/rendering_device.h" -#include "servers/rendering/rendering_server_raster.h" +#include "servers/rendering/rendering_server_default.h" /* SCENE SHADER */ -void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { +void RendererSceneRenderForward::ShaderData::set_code(const String &p_code) { //compile code = p_code; @@ -51,6 +51,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { int blend_mode = BLEND_MODE_MIX; int depth_testi = DEPTH_TEST_ENABLED; + int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF; int cull = CULL_BACK; uses_point_size = false; @@ -82,6 +83,9 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB); actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL); + actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE); + actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE); + actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED); actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE); actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS); @@ -108,7 +112,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["TIME"] = &uses_time; actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness; actions.usage_flag_pointers["NORMAL"] = &uses_normal; - actions.usage_flag_pointers["NORMALMAP"] = &uses_normal; + actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal; actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size; actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size; @@ -119,7 +123,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { actions.uniforms = &uniforms; - RasterizerSceneHighEndRD *scene_singleton = (RasterizerSceneHighEndRD *)RasterizerSceneHighEndRD::singleton; + RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton; Error err = scene_singleton->shader.compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code); @@ -154,6 +158,11 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { //blend modes + // if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage + if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) { + blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE; + } + RD::PipelineColorBlendState::Attachment blend_attachment; switch (blend_mode) { @@ -199,6 +208,15 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO; uses_blend_alpha = true; //force alpha used because of blend } break; + case BLEND_MODE_ALPHA_TO_COVERAGE: { + blend_attachment.enable_blend = true; + blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD; + blend_attachment.color_blend_op = RD::BLEND_OP_ADD; + blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE; + blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO; + } } RD::PipelineColorBlendState blend_state_blend; @@ -239,14 +257,26 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j]; for (int k = 0; k < SHADER_VERSION_MAX; k++) { + if (!static_cast<RendererSceneRenderForward *>(singleton)->shader.scene_shader.is_variant_enabled(k)) { + continue; + } RD::PipelineRasterizationState raster_state; raster_state.cull_mode = cull_mode_rd; raster_state.wireframe = wireframe; RD::PipelineColorBlendState blend_state; RD::PipelineDepthStencilState depth_stencil = depth_stencil_state; + RD::PipelineMultisampleState multisample_state; if (uses_alpha || uses_blend_alpha) { + // only allow these flags to go through if we have some form of msaa + if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) { + multisample_state.enable_alpha_to_coverage = true; + } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) { + multisample_state.enable_alpha_to_coverage = true; + multisample_state.enable_alpha_to_one = true; + } + if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { blend_state = blend_state_blend; if (depth_draw == DEPTH_DRAW_OPAQUE) { @@ -286,7 +316,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { } RID shader_variant = scene_singleton->shader.scene_shader.version_get_shader(version, k); - pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, RD::PipelineMultisampleState(), depth_stencil, blend_state, 0); + pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0); } } } @@ -294,7 +324,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_code(const String &p_code) { valid = true; } -void RasterizerSceneHighEndRD::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { +void RendererSceneRenderForward::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { if (!p_texture.is_valid()) { default_texture_params.erase(p_name); } else { @@ -302,7 +332,7 @@ void RasterizerSceneHighEndRD::ShaderData::set_default_texture_param(const Strin } } -void RasterizerSceneHighEndRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { +void RendererSceneRenderForward::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { Map<int, StringName> order; for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { @@ -324,13 +354,13 @@ void RasterizerSceneHighEndRD::ShaderData::get_param_list(List<PropertyInfo> *p_ } } -void RasterizerSceneHighEndRD::ShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const { +void RendererSceneRenderForward::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; } - RasterizerStorage::InstanceShaderParam p; + RendererStorage::InstanceShaderParam p; p.info = ShaderLanguage::uniform_to_property_info(E->get()); p.info.name = E->key(); //supply name p.index = E->get().instance_index; @@ -339,7 +369,7 @@ void RasterizerSceneHighEndRD::ShaderData::get_instance_param_list(List<Rasteriz } } -bool RasterizerSceneHighEndRD::ShaderData::is_param_texture(const StringName &p_param) const { +bool RendererSceneRenderForward::ShaderData::is_param_texture(const StringName &p_param) const { if (!uniforms.has(p_param)) { return false; } @@ -347,15 +377,15 @@ bool RasterizerSceneHighEndRD::ShaderData::is_param_texture(const StringName &p_ return uniforms[p_param].texture_order >= 0; } -bool RasterizerSceneHighEndRD::ShaderData::is_animated() const { +bool RendererSceneRenderForward::ShaderData::is_animated() const { return false; } -bool RasterizerSceneHighEndRD::ShaderData::casts_shadows() const { +bool RendererSceneRenderForward::ShaderData::casts_shadows() const { return false; } -Variant RasterizerSceneHighEndRD::ShaderData::get_default_parameter(const StringName &p_parameter) const { +Variant RendererSceneRenderForward::ShaderData::get_default_parameter(const StringName &p_parameter) const { if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; @@ -364,13 +394,19 @@ Variant RasterizerSceneHighEndRD::ShaderData::get_default_parameter(const String return Variant(); } -RasterizerSceneHighEndRD::ShaderData::ShaderData() { +RS::ShaderNativeSourceCode RendererSceneRenderForward::ShaderData::get_native_source_code() const { + RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton; + + return scene_singleton->shader.scene_shader.version_get_native_source_code(version); +} + +RendererSceneRenderForward::ShaderData::ShaderData() { valid = false; uses_screen_texture = false; } -RasterizerSceneHighEndRD::ShaderData::~ShaderData() { - RasterizerSceneHighEndRD *scene_singleton = (RasterizerSceneHighEndRD *)RasterizerSceneHighEndRD::singleton; +RendererSceneRenderForward::ShaderData::~ShaderData() { + RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton; ERR_FAIL_COND(!scene_singleton); //pipeline variants will clear themselves if shader is gone if (version.is_valid()) { @@ -378,21 +414,21 @@ RasterizerSceneHighEndRD::ShaderData::~ShaderData() { } } -RasterizerStorageRD::ShaderData *RasterizerSceneHighEndRD::_create_shader_func() { +RendererStorageRD::ShaderData *RendererSceneRenderForward::_create_shader_func() { ShaderData *shader_data = memnew(ShaderData); return shader_data; } -void RasterizerSceneHighEndRD::MaterialData::set_render_priority(int p_priority) { +void RendererSceneRenderForward::MaterialData::set_render_priority(int p_priority) { priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits } -void RasterizerSceneHighEndRD::MaterialData::set_next_pass(RID p_pass) { +void RendererSceneRenderForward::MaterialData::set_next_pass(RID p_pass) { next_pass = p_pass; } -void RasterizerSceneHighEndRD::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { - RasterizerSceneHighEndRD *scene_singleton = (RasterizerSceneHighEndRD *)RasterizerSceneHighEndRD::singleton; +void RendererSceneRenderForward::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { + RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton; if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { p_uniform_dirty = true; @@ -452,7 +488,7 @@ void RasterizerSceneHighEndRD::MaterialData::update_parameters(const Map<StringN { if (shader_data->ubo_size) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 0; u.ids.push_back(uniform_buffer); uniforms.push_back(u); @@ -461,7 +497,7 @@ void RasterizerSceneHighEndRD::MaterialData::update_parameters(const Map<StringN const RID *textures = texture_cache.ptrw(); for (uint32_t i = 0; i < tex_uniform_count; i++) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1 + i; u.ids.push_back(textures[i]); uniforms.push_back(u); @@ -471,7 +507,7 @@ void RasterizerSceneHighEndRD::MaterialData::update_parameters(const Map<StringN uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->shader.scene_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET); } -RasterizerSceneHighEndRD::MaterialData::~MaterialData() { +RendererSceneRenderForward::MaterialData::~MaterialData() { if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { RD::get_singleton()->free(uniform_set); } @@ -481,7 +517,7 @@ RasterizerSceneHighEndRD::MaterialData::~MaterialData() { } } -RasterizerStorageRD::MaterialData *RasterizerSceneHighEndRD::_create_material_func(ShaderData *p_shader) { +RendererStorageRD::MaterialData *RendererSceneRenderForward::_create_material_func(ShaderData *p_shader) { MaterialData *material_data = memnew(MaterialData); material_data->shader_data = p_shader; material_data->last_frame = false; @@ -489,11 +525,11 @@ RasterizerStorageRD::MaterialData *RasterizerSceneHighEndRD::_create_material_fu return material_data; } -RasterizerSceneHighEndRD::RenderBufferDataHighEnd::~RenderBufferDataHighEnd() { +RendererSceneRenderForward::RenderBufferDataForward::~RenderBufferDataForward() { clear(); } -void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::ensure_specular() { +void RendererSceneRenderForward::RenderBufferDataForward::ensure_specular() { if (!specular.is_valid()) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; @@ -547,20 +583,7 @@ void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::ensure_specular() { } } -void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::ensure_gi() { - if (!reflection_buffer.is_valid()) { - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.width = width; - tf.height = height; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - - reflection_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); - ambient_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); - } -} - -void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::ensure_giprobe() { +void RendererSceneRenderForward::RenderBufferDataForward::ensure_giprobe() { if (!giprobe_buffer.is_valid()) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8G8_UINT; @@ -596,17 +619,7 @@ void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::ensure_giprobe() { } } -void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::clear() { - if (ambient_buffer != RID() && ambient_buffer != color) { - RD::get_singleton()->free(ambient_buffer); - ambient_buffer = RID(); - } - - if (reflection_buffer != RID() && reflection_buffer != specular) { - RD::get_singleton()->free(reflection_buffer); - reflection_buffer = RID(); - } - +void RendererSceneRenderForward::RenderBufferDataForward::clear() { if (giprobe_buffer != RID()) { RD::get_singleton()->free(giprobe_buffer); giprobe_buffer = RID(); @@ -660,7 +673,7 @@ void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::clear() { } } -void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) { +void RendererSceneRenderForward::RenderBufferDataForward::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) { clear(); msaa = p_msaa; @@ -690,7 +703,7 @@ void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::configure(RID p_color_bu tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; tf.width = p_width; tf.height = p_height; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = { @@ -727,7 +740,7 @@ void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::configure(RID p_color_bu } } -void RasterizerSceneHighEndRD::_allocate_normal_roughness_texture(RenderBufferDataHighEnd *rb) { +void RendererSceneRenderForward::_allocate_normal_roughness_texture(RenderBufferDataForward *rb) { if (rb->normal_roughness_buffer.is_valid()) { return; } @@ -736,7 +749,7 @@ void RasterizerSceneHighEndRD::_allocate_normal_roughness_texture(RenderBufferDa tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; tf.width = rb->width; tf.height = rb->height; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; @@ -752,7 +765,7 @@ void RasterizerSceneHighEndRD::_allocate_normal_roughness_texture(RenderBufferDa fb.push_back(rb->normal_roughness_buffer); rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb); } else { - tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; tf.samples = rb->texture_samples; rb->normal_roughness_buffer_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -765,264 +778,100 @@ void RasterizerSceneHighEndRD::_allocate_normal_roughness_texture(RenderBufferDa _render_buffers_clear_uniform_set(rb); } -RasterizerSceneRD::RenderBufferData *RasterizerSceneHighEndRD::_create_render_buffer_data() { - return memnew(RenderBufferDataHighEnd); +RendererSceneRenderRD::RenderBufferData *RendererSceneRenderForward::_create_render_buffer_data() { + return memnew(RenderBufferDataForward); } -bool RasterizerSceneHighEndRD::free(RID p_rid) { - if (RasterizerSceneRD::free(p_rid)) { +bool RendererSceneRenderForward::free(RID p_rid) { + if (RendererSceneRenderRD::free(p_rid)) { return true; } return false; } -void RasterizerSceneHighEndRD::_fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth, bool p_has_sdfgi, bool p_has_opaque_gi) { - uint32_t lightmap_captures_used = 0; - - for (int i = 0; i < p_element_count; i++) { - const RenderList::Element *e = p_elements[i]; - InstanceData &id = scene_state.instances[i]; - bool store_transform = true; - id.flags = 0; - id.mask = e->instance->layer_mask; - id.instance_uniforms_ofs = e->instance->instance_allocated_shader_parameters_offset >= 0 ? e->instance->instance_allocated_shader_parameters_offset : 0; - - if (e->instance->base_type == RS::INSTANCE_MULTIMESH) { - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH; - uint32_t stride; - if (storage->multimesh_get_transform_format(e->instance->base) == RS::MULTIMESH_TRANSFORM_2D) { - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; - stride = 2; - } else { - stride = 3; - } - if (storage->multimesh_uses_colors(e->instance->base)) { - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; - stride += 1; - } - if (storage->multimesh_uses_custom_data(e->instance->base)) { - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; - stride += 1; - } - - id.flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); - } else if (e->instance->base_type == RS::INSTANCE_PARTICLES) { - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH; - uint32_t stride; - if (false) { // 2D particles - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; - stride = 2; - } else { - stride = 3; - } - - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; - stride += 1; - - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; - stride += 1; - - id.flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); - - if (!storage->particles_is_using_local_coords(e->instance->base)) { - store_transform = false; - } - - } else if (e->instance->base_type == RS::INSTANCE_MESH) { - if (e->instance->skeleton.is_valid()) { - id.flags |= INSTANCE_DATA_FLAG_SKELETON; - } - } - - if (store_transform) { - RasterizerStorageRD::store_transform(e->instance->transform, id.transform); - RasterizerStorageRD::store_transform(Transform(e->instance->transform.basis.inverse().transposed()), id.normal_transform); - } else { - RasterizerStorageRD::store_transform(Transform(), id.transform); - RasterizerStorageRD::store_transform(Transform(), id.normal_transform); - } - - if (p_for_depth) { - id.gi_offset = 0xFFFFFFFF; - continue; - } - - if (e->instance->lightmap) { - int32_t lightmap_index = storage->lightmap_get_array_index(e->instance->lightmap->base); - if (lightmap_index >= 0) { - id.gi_offset = lightmap_index; - id.gi_offset |= e->instance->lightmap_slice_index << 12; - id.gi_offset |= e->instance->lightmap_cull_index << 20; - id.lightmap_uv_scale[0] = e->instance->lightmap_uv_scale.position.x; - id.lightmap_uv_scale[1] = e->instance->lightmap_uv_scale.position.y; - id.lightmap_uv_scale[2] = e->instance->lightmap_uv_scale.size.width; - id.lightmap_uv_scale[3] = e->instance->lightmap_uv_scale.size.height; - id.flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP; - if (storage->lightmap_uses_spherical_harmonics(e->instance->lightmap->base)) { - id.flags |= INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP; - } - } else { - id.gi_offset = 0xFFFFFFFF; - } - } else if (!e->instance->lightmap_sh.empty()) { - if (lightmap_captures_used < scene_state.max_lightmap_captures) { - const Color *src_capture = e->instance->lightmap_sh.ptr(); - LightmapCaptureData &lcd = scene_state.lightmap_captures[lightmap_captures_used]; - for (int j = 0; j < 9; j++) { - lcd.sh[j * 4 + 0] = src_capture[j].r; - lcd.sh[j * 4 + 1] = src_capture[j].g; - lcd.sh[j * 4 + 2] = src_capture[j].b; - lcd.sh[j * 4 + 3] = src_capture[j].a; - } - id.flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE; - id.gi_offset = lightmap_captures_used; - lightmap_captures_used++; - } - - } else { - if (p_has_opaque_gi) { - id.flags |= INSTANCE_DATA_FLAG_USE_GI_BUFFERS; - } - - if (!e->instance->gi_probe_instances.empty()) { - uint32_t written = 0; - for (int j = 0; j < e->instance->gi_probe_instances.size(); j++) { - RID probe = e->instance->gi_probe_instances[j]; - - uint32_t index = gi_probe_instance_get_render_index(probe); - - if (written == 0) { - id.gi_offset = index; - id.flags |= INSTANCE_DATA_FLAG_USE_GIPROBE; - written = 1; - } else { - id.gi_offset = index << 16; - written = 2; - break; - } - } - if (written == 0) { - id.gi_offset = 0xFFFFFFFF; - } else if (written == 1) { - id.gi_offset |= 0xFFFF0000; - } - } else { - if (p_has_sdfgi && (e->instance->baked_light || e->instance->dynamic_gi)) { - id.flags |= INSTANCE_DATA_FLAG_USE_SDFGI; - } - id.gi_offset = 0xFFFFFFFF; - } - } - } - - RD::get_singleton()->buffer_update(scene_state.instance_buffer, 0, sizeof(InstanceData) * p_element_count, scene_state.instances, true); - if (lightmap_captures_used) { - RD::get_singleton()->buffer_update(scene_state.lightmap_capture_buffer, 0, sizeof(LightmapCaptureData) * lightmap_captures_used, scene_state.lightmap_captures, true); - } -} - /// RENDERING /// -void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_radiance_uniform_set, RID p_render_buffers_uniform_set, bool p_force_wireframe, const Vector2 &p_uv_offset) { +template <RendererSceneRenderForward::PassMode p_pass_mode> +void RendererSceneRenderForward::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { RD::DrawListID draw_list = p_draw_list; RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format; //global scope bindings RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_base_uniform_set, SCENE_UNIFORM_SET); - if (p_radiance_uniform_set.is_valid()) { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_radiance_uniform_set, RADIANCE_UNIFORM_SET); - } else { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_radiance_uniform_set, RADIANCE_UNIFORM_SET); - } - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, view_dependant_uniform_set, VIEW_DEPENDANT_UNIFORM_SET); - if (p_render_buffers_uniform_set.is_valid()) { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_render_buffers_uniform_set, RENDER_BUFFERS_UNIFORM_SET); - } else { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_render_buffers_uniform_set, RENDER_BUFFERS_UNIFORM_SET); - } + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_params->render_pass_uniform_set, RENDER_PASS_UNIFORM_SET); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET); - MaterialData *prev_material = nullptr; + RID prev_material_uniform_set; RID prev_vertex_array_rd; RID prev_index_array_rd; RID prev_pipeline_rd; RID prev_xforms_uniform_set; - PushConstant push_constant; - zeromem(&push_constant, sizeof(PushConstant)); - push_constant.bake_uv2_offset[0] = p_uv_offset.x; - push_constant.bake_uv2_offset[1] = p_uv_offset.y; + bool shadow_pass = (p_params->pass_mode == PASS_MODE_SHADOW) || (p_params->pass_mode == PASS_MODE_SHADOW_DP); + + float old_offset[2] = { 0, 0 }; + + for (uint32_t i = p_from_element; i < p_to_element; i++) { + const GeometryInstanceSurfaceDataCache *surf = p_params->elements[i]; - for (int i = 0; i < p_element_count; i++) { - const RenderList::Element *e = p_elements[i]; + RID material_uniform_set; + ShaderData *shader; + void *mesh_surface; - MaterialData *material = e->material; - ShaderData *shader = material->shader_data; - RID xforms_uniform_set; + if (shadow_pass || p_params->pass_mode == PASS_MODE_DEPTH) { //regular depth pass can use these too + material_uniform_set = surf->material_uniform_set_shadow; + shader = surf->shader_shadow; + mesh_surface = surf->surface_shadow; + + } else { + material_uniform_set = surf->material_uniform_set; + shader = surf->shader; + mesh_surface = surf->surface; + } + + if (!mesh_surface) { + continue; + } + + if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) { + old_offset[0] = surf->owner->push_constant.lightmap_uv_scale[0]; + old_offset[1] = surf->owner->push_constant.lightmap_uv_scale[1]; + surf->owner->push_constant.lightmap_uv_scale[0] = p_params->uv_offset.x; + surf->owner->push_constant.lightmap_uv_scale[1] = p_params->uv_offset.y; + } //find cull variant ShaderData::CullVariant cull_variant; - if (p_pass_mode == PASS_MODE_DEPTH_MATERIAL || p_pass_mode == PASS_MODE_SDF || ((p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) && e->instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED)) { + if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL || p_params->pass_mode == PASS_MODE_SDF || ((p_params->pass_mode == PASS_MODE_SHADOW || p_params->pass_mode == PASS_MODE_SHADOW_DP) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) { cull_variant = ShaderData::CULL_VARIANT_DOUBLE_SIDED; } else { - bool mirror = e->instance->mirror; - if (p_reverse_cull) { + bool mirror = surf->owner->mirror; + if (p_params->reverse_cull) { mirror = !mirror; } cull_variant = mirror ? ShaderData::CULL_VARIANT_REVERSED : ShaderData::CULL_VARIANT_NORMAL; } - //find primitive and vertex format - RS::PrimitiveType primitive; - - switch (e->instance->base_type) { - case RS::INSTANCE_MESH: { - primitive = storage->mesh_surface_get_primitive(e->instance->base, e->surface_index); - if (e->instance->skeleton.is_valid()) { - xforms_uniform_set = storage->skeleton_get_3d_uniform_set(e->instance->skeleton, default_shader_rd, TRANSFORMS_UNIFORM_SET); - } - } break; - case RS::INSTANCE_MULTIMESH: { - RID mesh = storage->multimesh_get_mesh(e->instance->base); - ERR_CONTINUE(!mesh.is_valid()); //should be a bug - primitive = storage->mesh_surface_get_primitive(mesh, e->surface_index); - - xforms_uniform_set = storage->multimesh_get_3d_uniform_set(e->instance->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); - - } break; - case RS::INSTANCE_IMMEDIATE: { - ERR_CONTINUE(true); //should be a bug - } break; - case RS::INSTANCE_PARTICLES: { - RID mesh = storage->particles_get_draw_pass_mesh(e->instance->base, e->surface_index >> 16); - ERR_CONTINUE(!mesh.is_valid()); //should be a bug - primitive = storage->mesh_surface_get_primitive(mesh, e->surface_index & 0xFFFF); - - xforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(e->instance->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); - - } break; - default: { - ERR_CONTINUE(true); //should be a bug - } - } + RS::PrimitiveType primitive = surf->primitive; + RID xforms_uniform_set = surf->owner->transforms_uniform_set; ShaderVersion shader_version = SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized. - switch (p_pass_mode) { + switch (p_params->pass_mode) { case PASS_MODE_COLOR: case PASS_MODE_COLOR_TRANSPARENT: { - if (e->uses_lightmap) { + if (surf->sort.uses_lightmap) { shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS; - } else if (e->uses_forward_gi) { + } else if (surf->sort.uses_forward_gi) { shader_version = SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI; } else { shader_version = SHADER_VERSION_COLOR_PASS; } } break; case PASS_MODE_COLOR_SPECULAR: { - if (e->uses_lightmap) { + if (surf->sort.uses_lightmap) { shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR; } else { shader_version = SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR; @@ -1049,7 +898,7 @@ void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_l } break; } - RenderPipelineVertexFormatCacheRD *pipeline = nullptr; + PipelineCacheRD *pipeline = nullptr; pipeline = &shader->pipelines[cull_variant][primitive][shader_version]; @@ -1057,26 +906,37 @@ void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_l RID vertex_array_rd; RID index_array_rd; - switch (e->instance->base_type) { - case RS::INSTANCE_MESH: { - storage->mesh_surface_get_arrays_and_format(e->instance->base, e->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format); - } break; - case RS::INSTANCE_MULTIMESH: { - RID mesh = storage->multimesh_get_mesh(e->instance->base); - ERR_CONTINUE(!mesh.is_valid()); //should be a bug - storage->mesh_surface_get_arrays_and_format(mesh, e->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format); - } break; - case RS::INSTANCE_IMMEDIATE: { - ERR_CONTINUE(true); //should be a bug - } break; - case RS::INSTANCE_PARTICLES: { - RID mesh = storage->particles_get_draw_pass_mesh(e->instance->base, e->surface_index >> 16); - ERR_CONTINUE(!mesh.is_valid()); //should be a bug - storage->mesh_surface_get_arrays_and_format(mesh, e->surface_index & 0xFFFF, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format); - } break; - default: { - ERR_CONTINUE(true); //should be a bug + //skeleton and blend shape + if (surf->owner->mesh_instance.is_valid()) { + storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format); + } else { + storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format); + } + + if (p_params->screen_lod_threshold > 0.0 && storage->mesh_surface_has_lod(mesh_surface)) { + //lod + Vector3 support_min = surf->owner->transformed_aabb.get_support(-p_params->lod_plane.normal); + Vector3 support_max = surf->owner->transformed_aabb.get_support(p_params->lod_plane.normal); + + float distance_min = p_params->lod_plane.distance_to(support_min); + float distance_max = p_params->lod_plane.distance_to(support_max); + + float distance = 0.0; + + if (distance_min * distance_max < 0.0) { + //crossing plane + distance = 0.0; + } else if (distance_min >= 0.0) { + distance = distance_min; + } else if (distance_max <= 0.0) { + distance = -distance_max; } + + index_array_rd = storage->mesh_surface_get_index_array_with_lod(mesh_surface, surf->owner->lod_model_scale * surf->owner->lod_bias, distance * p_params->lod_distance_multiplier, p_params->screen_lod_threshold); + + } else { + //no lod + index_array_rd = storage->mesh_surface_get_index_array(mesh_surface); } if (prev_vertex_array_rd != vertex_array_rd) { @@ -1091,7 +951,7 @@ void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_l prev_index_array_rd = index_array_rd; } - RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_force_wireframe); + RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe); if (pipeline_rd != prev_pipeline_rd) { // checking with prev shader does not make so much sense, as @@ -1105,40 +965,90 @@ void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_l prev_xforms_uniform_set = xforms_uniform_set; } - if (material != prev_material) { + if (material_uniform_set != prev_material_uniform_set) { //update uniform set - if (material->uniform_set.is_valid()) { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material->uniform_set, MATERIAL_UNIFORM_SET); + if (material_uniform_set.is_valid()) { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET); } - prev_material = material; + prev_material_uniform_set = material_uniform_set; } - push_constant.index = i; - RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(PushConstant)); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &surf->owner->push_constant, sizeof(GeometryInstanceForward::PushConstant)); - switch (e->instance->base_type) { - case RS::INSTANCE_MESH: { - RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid()); - } break; - case RS::INSTANCE_MULTIMESH: { - uint32_t instances = storage->multimesh_get_instances_to_draw(e->instance->base); - RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instances); - } break; - case RS::INSTANCE_IMMEDIATE: { - } break; - case RS::INSTANCE_PARTICLES: { - uint32_t instances = storage->particles_get_amount(e->instance->base); - RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instances); - } break; - default: { - ERR_CONTINUE(true); //should be a bug - } + RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), surf->owner->instance_count); + + if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) { + surf->owner->push_constant.lightmap_uv_scale[0] = old_offset[0]; + surf->owner->push_constant.lightmap_uv_scale[1] = old_offset[1]; } } } -void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers, bool p_pancake_shadows) { +void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { + //use template for faster performance (pass mode comparisons are inlined) + + switch (p_params->pass_mode) { + case PASS_MODE_COLOR: { + _render_list_template<PASS_MODE_COLOR>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_COLOR_SPECULAR: { + _render_list_template<PASS_MODE_COLOR_SPECULAR>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_COLOR_TRANSPARENT: { + _render_list_template<PASS_MODE_COLOR_TRANSPARENT>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_SHADOW: { + _render_list_template<PASS_MODE_SHADOW>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_SHADOW_DP: { + _render_list_template<PASS_MODE_SHADOW_DP>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH: { + _render_list_template<PASS_MODE_DEPTH>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { + _render_list_template<PASS_MODE_DEPTH_NORMAL_ROUGHNESS>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: { + _render_list_template<PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH_MATERIAL: { + _render_list_template<PASS_MODE_DEPTH_MATERIAL>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_SDF: { + _render_list_template<PASS_MODE_SDF>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + } +} + +void RendererSceneRenderForward::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) { + uint32_t render_total = p_params->element_count; + uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count(); + uint32_t render_from = p_thread * render_total / total_threads; + uint32_t render_to = (p_thread + 1 == total_threads) ? render_total : ((p_thread + 1) * render_total / total_threads); + _render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to); +} + +void RendererSceneRenderForward::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) { + RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer); + p_params->framebuffer_format = fb_format; + + if ((uint32_t)p_params->element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time + //multi threaded + thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count()); + RD::get_singleton()->draw_list_begin_split(p_framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); + RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RendererSceneRenderForward::_render_list_thread_function, p_params); + RD::get_singleton()->draw_list_end(); + } else { + //single threaded + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); + _render_list(draw_list, fb_format, p_params, 0, p_params->element_count); + RD::get_singleton()->draw_list_end(); + } +} + +void RendererSceneRenderForward::_setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers, bool p_pancake_shadows) { //CameraMatrix projection = p_cam_projection; //projection.flip_y(); // Vulkan and modern APIs use Y-Down CameraMatrix correction; @@ -1146,28 +1056,38 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende CameraMatrix projection = correction * p_cam_projection; //store camera into ubo - RasterizerStorageRD::store_camera(projection, scene_state.ubo.projection_matrix); - RasterizerStorageRD::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix); - RasterizerStorageRD::store_transform(p_cam_transform, scene_state.ubo.camera_matrix); - RasterizerStorageRD::store_transform(p_cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix); + RendererStorageRD::store_camera(projection, scene_state.ubo.projection_matrix); + RendererStorageRD::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix); + RendererStorageRD::store_transform(p_cam_transform, scene_state.ubo.camera_matrix); + RendererStorageRD::store_transform(p_cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix); scene_state.ubo.z_far = p_zfar; scene_state.ubo.z_near = p_znear; scene_state.ubo.pancake_shadows = p_pancake_shadows; - RasterizerStorageRD::store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel); - RasterizerStorageRD::store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel); - RasterizerStorageRD::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel); - RasterizerStorageRD::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel); + RendererStorageRD::store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel); + RendererStorageRD::store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel); + RendererStorageRD::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel); + RendererStorageRD::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel); scene_state.ubo.directional_penumbra_shadow_samples = directional_penumbra_shadow_samples_get(); scene_state.ubo.directional_soft_shadow_samples = directional_soft_shadow_samples_get(); scene_state.ubo.penumbra_shadow_samples = penumbra_shadow_samples_get(); scene_state.ubo.soft_shadow_samples = soft_shadow_samples_get(); - scene_state.ubo.screen_pixel_size[0] = p_screen_pixel_size.x; - scene_state.ubo.screen_pixel_size[1] = p_screen_pixel_size.y; + Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size); + scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x; + scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y; + + scene_state.ubo.cluster_shift = get_shift_from_power_of_2(p_cluster_size); + scene_state.ubo.max_cluster_element_count_div_32 = p_max_cluster_elements / 32; + { + uint32_t cluster_screen_width = (p_screen_size.width - 1) / p_cluster_size + 1; + uint32_t cluster_screen_height = (p_screen_size.height - 1) / p_cluster_size + 1; + scene_state.ubo.cluster_type_size = cluster_screen_width * cluster_screen_height * (scene_state.ubo.max_cluster_element_count_div_32 + 32); + scene_state.ubo.cluster_width = cluster_screen_width; + } if (p_shadow_atlas.is_valid()) { Vector2 sas = shadow_atlas_get_size(p_shadow_atlas); @@ -1187,7 +1107,7 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende scene_state.ubo.fog_enabled = false; if (p_render_buffers.is_valid()) { - RenderBufferDataHighEnd *render_buffers = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); + RenderBufferDataForward *render_buffers = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) { scene_state.ubo.gi_upscale_for_msaa = true; } @@ -1211,7 +1131,6 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende } #if 0 if (p_render_buffers.is_valid() && render_buffers_is_sdfgi_enabled(p_render_buffers)) { - scene_state.ubo.sdfgi_cascade_count = render_buffers_get_sdfgi_cascade_count(p_render_buffers); scene_state.ubo.sdfgi_probe_axis_size = render_buffers_get_sdfgi_cascade_probe_count(p_render_buffers); scene_state.ubo.sdfgi_cascade_probe_size[0] = scene_state.ubo.sdfgi_probe_axis_size - 1; //float version for performance @@ -1304,7 +1223,7 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende Basis sky_transform = environment_get_sky_orientation(p_environment); sky_transform = sky_transform.inverse() * p_cam_transform.basis; - RasterizerStorageRD::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform); + RendererStorageRD::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform); scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY; scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR; @@ -1368,255 +1287,200 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende scene_state.ubo.roughness_limiter_amount = screen_space_roughness_limiter_get_amount(); scene_state.ubo.roughness_limiter_limit = screen_space_roughness_limiter_get_limit(); - RD::get_singleton()->buffer_update(scene_state.uniform_buffer, 0, sizeof(SceneState::UBO), &scene_state.ubo, true); + RD::get_singleton()->buffer_update(scene_state.uniform_buffer, 0, sizeof(SceneState::UBO), &scene_state.ubo); } -void RasterizerSceneHighEndRD::_add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode, uint32_t p_geometry_index, bool p_using_sdfgi) { - RID m_src; - - m_src = p_instance->material_override.is_valid() ? p_instance->material_override : p_material; - - if (unlikely(get_debug_draw_mode() != RS::VIEWPORT_DEBUG_DRAW_DISABLED)) { - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { - m_src = overdraw_material; - } else if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING) { - m_src = default_material; - } - } - - MaterialData *material = nullptr; - - if (m_src.is_valid()) { - material = (MaterialData *)storage->material_get_data(m_src, RasterizerStorageRD::SHADER_TYPE_3D); - if (!material || !material->shader_data->valid) { - material = nullptr; - } - } - - if (!material) { - material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D); - m_src = default_material; - } - - ERR_FAIL_COND(!material); - - _add_geometry_with_material(p_instance, p_surface, material, m_src, p_pass_mode, p_geometry_index, p_using_sdfgi); - - while (material->next_pass.is_valid()) { - material = (MaterialData *)storage->material_get_data(material->next_pass, RasterizerStorageRD::SHADER_TYPE_3D); - if (!material || !material->shader_data->valid) { - break; - } - _add_geometry_with_material(p_instance, p_surface, material, material->next_pass, p_pass_mode, p_geometry_index, p_using_sdfgi); - } -} - -void RasterizerSceneHighEndRD::_add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, RID p_material_rid, PassMode p_pass_mode, uint32_t p_geometry_index, bool p_using_sdfgi) { - bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture; - bool has_base_alpha = (p_material->shader_data->uses_alpha || has_read_screen_alpha); - bool has_blend_alpha = p_material->shader_data->uses_blend_alpha; - bool has_alpha = has_base_alpha || has_blend_alpha; - - if (p_material->shader_data->uses_sss) { - scene_state.used_sss = true; - } - - if (p_material->shader_data->uses_screen_texture) { - scene_state.used_screen_texture = true; - } - - if (p_material->shader_data->uses_depth_texture) { - scene_state.used_depth_texture = true; - } - - if (p_material->shader_data->uses_normal_texture) { - scene_state.used_normal_texture = true; - } - - if (p_pass_mode != PASS_MODE_COLOR && p_pass_mode != PASS_MODE_COLOR_SPECULAR) { - if (has_blend_alpha || has_read_screen_alpha || (has_base_alpha && !p_material->shader_data->uses_depth_pre_pass) || p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED || p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_OFF) { - //conditions in which no depth pass should be processed - return; - } - - if ((p_pass_mode != PASS_MODE_DEPTH_MATERIAL && p_pass_mode != PASS_MODE_SDF) && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) { - //shader does not use discard and does not write a vertex position, use generic material - if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_DEPTH) { - p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D); - } else if ((p_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || p_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE) && !p_material->shader_data->uses_normal && !p_material->shader_data->uses_roughness) { - p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D); - } - } - - has_alpha = false; - } - - has_alpha = has_alpha || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED; - - RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); - - if (!e) { - return; - } - - e->instance = p_instance; - e->material = p_material; - e->surface_index = p_surface; - e->sort_key = 0; - - if (e->material->last_pass != render_pass) { - if (!RD::get_singleton()->uniform_set_is_valid(e->material->uniform_set)) { - //uniform set no longer valid, probably a texture changed - storage->material_force_update_textures(p_material_rid, RasterizerStorageRD::SHADER_TYPE_3D); - } - e->material->last_pass = render_pass; - e->material->index = scene_state.current_material_index++; - if (e->material->shader_data->last_pass != render_pass) { - e->material->shader_data->last_pass = scene_state.current_material_index++; - e->material->shader_data->index = scene_state.current_shader_index++; - } - } - e->geometry_index = p_geometry_index; - e->material_index = e->material->index; - e->uses_instancing = e->instance->base_type == RS::INSTANCE_MULTIMESH; - e->uses_lightmap = e->instance->lightmap != nullptr || !e->instance->lightmap_sh.empty(); - e->uses_forward_gi = has_alpha && (e->instance->gi_probe_instances.size() || p_using_sdfgi); - e->shader_index = e->shader_index; - e->depth_layer = e->instance->depth_layer; - e->priority = p_material->priority; - - if (p_material->shader_data->uses_time) { - RenderingServerRaster::redraw_request(); - } -} - -void RasterizerSceneHighEndRD::_fill_render_list(InstanceBase **p_cull_result, int p_cull_count, PassMode p_pass_mode, bool p_using_sdfgi) { - scene_state.current_shader_index = 0; - scene_state.current_material_index = 0; +void RendererSceneRenderForward::_fill_render_list(const PagedArray<GeometryInstance *> &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi, bool p_using_opaque_gi) { scene_state.used_sss = false; scene_state.used_screen_texture = false; scene_state.used_normal_texture = false; scene_state.used_depth_texture = false; - uint32_t geometry_index = 0; - - //fill list - - for (int i = 0; i < p_cull_count; i++) { - InstanceBase *inst = p_cull_result[i]; + Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(Vector3::AXIS_Z)); + near_plane.d += p_cam_projection.get_z_near(); + float z_max = p_cam_projection.get_z_far() - p_cam_projection.get_z_near(); + uint32_t lightmap_captures_used = 0; - //add geometry for drawing - switch (inst->base_type) { - case RS::INSTANCE_MESH: { - const RID *materials = nullptr; - uint32_t surface_count; + _update_dirty_geometry_instances(); + render_list.clear(); - materials = storage->mesh_get_surface_count_and_materials(inst->base, surface_count); - if (!materials) { - continue; //nothing to do - } + //fill list - const RID *inst_materials = inst->materials.ptr(); + for (int i = 0; i < (int)p_instances.size(); i++) { + GeometryInstanceForward *inst = static_cast<GeometryInstanceForward *>(p_instances[i]); - for (uint32_t j = 0; j < surface_count; j++) { - RID material = inst_materials[j].is_valid() ? inst_materials[j] : materials[j]; + Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal); + inst->depth = near_plane.distance_to(support_min); + uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15); - uint32_t surface_index = storage->mesh_surface_get_render_pass_index(inst->base, j, render_pass, &geometry_index); - _add_geometry(inst, j, material, p_pass_mode, surface_index, p_using_sdfgi); - } + uint32_t flags = inst->base_flags; //fill flags if appropriate - //mesh->last_pass=frame; + bool uses_lightmap = false; + bool uses_gi = false; - } break; + if (p_pass_mode == PASS_MODE_COLOR) { + //setup GI - case RS::INSTANCE_MULTIMESH: { - if (storage->multimesh_get_instances_to_draw(inst->base) == 0) { - //not visible, 0 instances - continue; + if (inst->lightmap_instance.is_valid()) { + int32_t lightmap_cull_index = -1; + for (uint32_t j = 0; j < scene_state.lightmaps_used; j++) { + if (scene_state.lightmap_ids[j] == inst->lightmap_instance) { + lightmap_cull_index = j; + break; + } } - - RID mesh = storage->multimesh_get_mesh(inst->base); - if (!mesh.is_valid()) { - continue; + if (lightmap_cull_index >= 0) { + inst->push_constant.gi_offset &= 0xFFFF; + inst->push_constant.gi_offset |= lightmap_cull_index; + flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP; + if (scene_state.lightmap_has_sh[lightmap_cull_index]) { + flags |= INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP; + } + uses_lightmap = true; + } else { + inst->push_constant.gi_offset = 0xFFFFFFFF; } - const RID *materials = nullptr; - uint32_t surface_count; - - materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); - if (!materials) { - continue; //nothing to do + } else if (inst->lightmap_sh) { + if (lightmap_captures_used < scene_state.max_lightmap_captures) { + const Color *src_capture = inst->lightmap_sh->sh; + LightmapCaptureData &lcd = scene_state.lightmap_captures[lightmap_captures_used]; + for (int j = 0; j < 9; j++) { + lcd.sh[j * 4 + 0] = src_capture[j].r; + lcd.sh[j * 4 + 1] = src_capture[j].g; + lcd.sh[j * 4 + 2] = src_capture[j].b; + lcd.sh[j * 4 + 3] = src_capture[j].a; + } + flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE; + inst->push_constant.gi_offset = lightmap_captures_used; + lightmap_captures_used++; + uses_lightmap = true; } - for (uint32_t j = 0; j < surface_count; j++) { - uint32_t surface_index = storage->mesh_surface_get_multimesh_render_pass_index(mesh, j, render_pass, &geometry_index); - _add_geometry(inst, j, materials[j], p_pass_mode, surface_index, p_using_sdfgi); + } else if (!low_end) { + if (p_using_opaque_gi) { + flags |= INSTANCE_DATA_FLAG_USE_GI_BUFFERS; } - } break; -#if 0 - case RS::INSTANCE_IMMEDIATE: { + if (inst->gi_probes[0].is_valid()) { + uint32_t probe0_index = 0xFFFF; + uint32_t probe1_index = 0xFFFF; - RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base); - ERR_CONTINUE(!immediate); + for (uint32_t j = 0; j < scene_state.giprobes_used; j++) { + if (scene_state.giprobe_ids[j] == inst->gi_probes[0]) { + probe0_index = j; + } else if (scene_state.giprobe_ids[j] == inst->gi_probes[1]) { + probe1_index = j; + } + } - _add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass); + if (probe0_index == 0xFFFF && probe1_index != 0xFFFF) { + //0 must always exist if a probe exists + SWAP(probe0_index, probe1_index); + } - } break; -#endif - case RS::INSTANCE_PARTICLES: { - int draw_passes = storage->particles_get_draw_passes(inst->base); + inst->push_constant.gi_offset = probe0_index | (probe1_index << 16); + flags |= INSTANCE_DATA_FLAG_USE_GIPROBE; + uses_gi = true; + } else { + if (p_using_sdfgi && inst->can_sdfgi) { + flags |= INSTANCE_DATA_FLAG_USE_SDFGI; + uses_gi = true; + } + inst->push_constant.gi_offset = 0xFFFFFFFF; + } + } + } + inst->push_constant.flags = flags; - for (int j = 0; j < draw_passes; j++) { - RID mesh = storage->particles_get_draw_pass_mesh(inst->base, j); - if (!mesh.is_valid()) - continue; + GeometryInstanceSurfaceDataCache *surf = inst->surface_caches; - const RID *materials = nullptr; - uint32_t surface_count; + while (surf) { + surf->sort.uses_forward_gi = 0; + surf->sort.uses_lightmap = 0; - materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); - if (!materials) { - continue; //nothing to do + if (p_pass_mode == PASS_MODE_COLOR) { + if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { + render_list.add_element(surf); + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA) { + render_list.add_alpha_element(surf); + if (uses_gi) { + surf->sort.uses_forward_gi = 1; } + } - for (uint32_t k = 0; k < surface_count; k++) { - uint32_t surface_index = storage->mesh_surface_get_particles_render_pass_index(mesh, j, render_pass, &geometry_index); - _add_geometry(inst, (j << 16) | k, materials[j], p_pass_mode, surface_index, p_using_sdfgi); - } + if (uses_lightmap) { + surf->sort.uses_lightmap = 1; } - } break; + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING) { + scene_state.used_sss = true; + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE) { + scene_state.used_screen_texture = true; + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE) { + scene_state.used_normal_texture = true; + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE) { + scene_state.used_depth_texture = true; + } - default: { + } else if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) { + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) { + render_list.add_element(surf); + } + } else { + if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { + render_list.add_element(surf); + } } + + surf->sort.depth_layer = depth_layer; + + surf = surf->next; } } + + if (lightmap_captures_used) { + RD::get_singleton()->buffer_update(scene_state.lightmap_capture_buffer, 0, sizeof(LightmapCaptureData) * lightmap_captures_used, scene_state.lightmap_captures); + } +} + +void RendererSceneRenderForward::_setup_giprobes(const PagedArray<RID> &p_giprobes) { + scene_state.giprobes_used = MIN(p_giprobes.size(), uint32_t(MAX_GI_PROBES)); + for (uint32_t i = 0; i < scene_state.giprobes_used; i++) { + scene_state.giprobe_ids[i] = p_giprobes[i]; + } } -void RasterizerSceneHighEndRD::_setup_lightmaps(InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, const Transform &p_cam_transform) { - uint32_t lightmaps_used = 0; - for (int i = 0; i < p_lightmap_cull_count; i++) { +void RendererSceneRenderForward::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform) { + scene_state.lightmaps_used = 0; + for (int i = 0; i < (int)p_lightmaps.size(); i++) { if (i >= (int)scene_state.max_lightmaps) { break; } - InstanceBase *lm = p_lightmap_cull_result[i]; - Basis to_lm = lm->transform.basis.inverse() * p_cam_transform.basis; + RID lightmap = lightmap_instance_get_lightmap(p_lightmaps[i]); + + Basis to_lm = lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis; to_lm = to_lm.inverse().transposed(); //will transform normals - RasterizerStorageRD::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform); - lm->lightmap_cull_index = i; - lightmaps_used++; + RendererStorageRD::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform); + scene_state.lightmap_ids[i] = p_lightmaps[i]; + scene_state.lightmap_has_sh[i] = storage->lightmap_uses_spherical_harmonics(lightmap); + + scene_state.lightmaps_used++; } - if (lightmaps_used > 0) { - RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * lightmaps_used, scene_state.lightmaps, true); + if (scene_state.lightmaps_used > 0) { + RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps); } } -void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color) { - RenderBufferDataHighEnd *render_buffer = nullptr; +void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, int p_directional_light_count, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_screen_lod_threshold) { + RenderBufferDataForward *render_buffer = nullptr; if (p_render_buffer.is_valid()) { - render_buffer = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffer); + render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffer); } //first of all, make a new render pass @@ -1632,6 +1496,13 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor scene_state.ubo.reflection_multiplier = 1.0; } + float lod_distance_multiplier = p_cam_projection.get_lod_multiplier(); + Plane lod_camera_plane(p_cam_transform.get_origin(), -p_cam_transform.basis.get_axis(Vector3::AXIS_Z)); + + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { + p_screen_lod_threshold = 0.0; + } + //scene_state.ubo.subsurface_scatter_width = subsurface_scatter_size; Vector2 vp_he = p_cam_projection.get_viewport_half_extents(); @@ -1639,7 +1510,6 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor scene_state.ubo.viewport_size[1] = vp_he.y; scene_state.ubo.directional_light_count = p_directional_light_count; - Size2 screen_pixel_size; Size2i screen_size; RID opaque_framebuffer; RID opaque_specular_framebuffer; @@ -1654,16 +1524,13 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor bool using_giprobe = false; if (render_buffer) { - screen_pixel_size.width = 1.0 / render_buffer->width; - screen_pixel_size.height = 1.0 / render_buffer->height; screen_size.x = render_buffer->width; screen_size.y = render_buffer->height; opaque_framebuffer = render_buffer->color_fb; - if (p_gi_probe_cull_count > 0) { + if (!low_end && p_gi_probes.size() > 0) { using_giprobe = true; - render_buffer->ensure_gi(); } if (!p_environment.is_valid() && using_giprobe) { @@ -1673,7 +1540,6 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor if (environment_is_sdfgi_enabled(p_environment)) { depth_pass_mode = using_giprobe ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; // also giprobe using_sdfgi = true; - render_buffer->ensure_gi(); } else { depth_pass_mode = using_giprobe ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; } @@ -1712,8 +1578,6 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor alpha_framebuffer = opaque_framebuffer; } else if (p_reflection_probe.is_valid()) { uint32_t resolution = reflection_probe_instance_get_resolution(p_reflection_probe); - screen_pixel_size.width = 1.0 / resolution; - screen_pixel_size.height = 1.0 / resolution; screen_size.x = resolution; screen_size.y = resolution; @@ -1728,15 +1592,15 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor ERR_FAIL(); //bug? } - _setup_lightmaps(p_lightmap_cull_result, p_lightmap_cull_count, p_cam_transform); - _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); + _setup_lightmaps(p_lightmaps, p_cam_transform); + _setup_giprobes(p_gi_probes); + _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); _update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example) - render_list.clear(); - _fill_render_list(p_cull_result, p_cull_count, PASS_MODE_COLOR, using_sdfgi); + _fill_render_list(p_instances, PASS_MODE_COLOR, p_cam_projection, p_cam_transform, using_sdfgi, using_sdfgi || using_giprobe); - bool using_sss = render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED; + bool using_sss = !low_end && render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED; if (using_sss) { using_separate_specular = true; @@ -1744,7 +1608,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor using_separate_specular = true; opaque_specular_framebuffer = render_buffer->color_specular_fb; } - RID radiance_uniform_set; + RID radiance_texture; bool draw_sky = false; bool draw_sky_fog_only = false; @@ -1794,6 +1658,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor // setup sky if used for ambient, reflections, or background if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) { RENDER_TIMESTAMP("Setup Sky"); + RD::get_singleton()->draw_command_begin_label("Setup Sky"); CameraMatrix projection = p_cam_projection; if (p_reflection_probe.is_valid()) { CameraMatrix correction; @@ -1806,45 +1671,43 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor RID sky = environment_get_sky(p_environment); if (sky.is_valid()) { _update_sky(p_environment, projection, p_cam_transform); - radiance_uniform_set = sky_get_radiance_uniform_set_rd(sky, default_shader_rd, RADIANCE_UNIFORM_SET); + radiance_texture = sky_get_radiance_texture_rd(sky); } else { // do not try to draw sky if invalid draw_sky = false; } + RD::get_singleton()->draw_command_end_label(); } } else { clear_color = p_default_bg_color; } - _setup_view_dependant_uniform_set(p_shadow_atlas, p_reflection_atlas, p_gi_probe_cull_result, p_gi_probe_cull_count); - render_list.sort_by_key(false); - _fill_instances(render_list.elements, render_list.element_count, false, false, using_sdfgi || using_giprobe); - bool debug_giprobes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION; bool debug_sdfgi_probes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES; - - bool depth_pre_pass = depth_framebuffer.is_valid(); - RID render_buffers_uniform_set; + bool depth_pre_pass = !low_end && depth_framebuffer.is_valid(); bool using_ssao = depth_pre_pass && p_render_buffer.is_valid() && p_environment.is_valid() && environment_is_ssao_enabled(p_environment); bool continue_depth = false; if (depth_pre_pass) { //depth pre pass RENDER_TIMESTAMP("Render Depth Pre-Pass"); - bool finish_depth = using_ssao || using_sdfgi || using_giprobe; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, depth_pass_clear); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(depth_framebuffer), render_list.elements, render_list.element_count, false, depth_pass_mode, render_buffer == nullptr, radiance_uniform_set, RID(), get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME); - RD::get_singleton()->draw_list_end(); + RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>()); + bool finish_depth = using_ssao || using_sdfgi || using_giprobe; + RenderListParameters render_list_params(render_list.elements, render_list.element_count, false, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + RD::get_singleton()->draw_command_begin_label("Render Depth Pre-Pass"); + _render_list_with_threads(&render_list_params, depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, depth_pass_clear); + RD::get_singleton()->draw_command_end_label(); if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { RENDER_TIMESTAMP("Resolve Depth Pre-Pass"); + RD::get_singleton()->draw_command_insert_label("Resolve Depth Pre-Pass"); if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE) { static int texture_samples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8, 16 }; storage->get_effects()->resolve_gi(render_buffer->depth_msaa, render_buffer->normal_roughness_buffer_msaa, using_giprobe ? render_buffer->giprobe_buffer_msaa : RID(), render_buffer->depth, render_buffer->normal_roughness_buffer, using_giprobe ? render_buffer->giprobe_buffer : RID(), Vector2i(render_buffer->width, render_buffer->height), texture_samples[render_buffer->msaa]); } else if (finish_depth) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth, true); + RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth); } } @@ -1856,19 +1719,15 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor } if (using_sdfgi || using_giprobe) { - _process_gi(p_render_buffer, render_buffer->normal_roughness_buffer, render_buffer->ambient_buffer, render_buffer->reflection_buffer, render_buffer->giprobe_buffer, p_environment, p_cam_projection, p_cam_transform, p_gi_probe_cull_result, p_gi_probe_cull_count); + _process_gi(p_render_buffer, render_buffer->normal_roughness_buffer, render_buffer->giprobe_buffer, p_environment, p_cam_projection, p_cam_transform, p_gi_probes); } - if (p_render_buffer.is_valid()) { - //update the render buffers uniform set in case it changed - _update_render_buffers_uniform_set(p_render_buffer); - render_buffers_uniform_set = render_buffer->uniform_set; - } - - _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), p_render_buffer.is_valid()); + _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), p_render_buffer.is_valid()); RENDER_TIMESTAMP("Render Opaque Pass"); + RID rp_uniform_set = _setup_render_pass_uniform_set(p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_cluster_buffer, p_gi_probes, p_lightmaps, true); + bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss; bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss; @@ -1888,13 +1747,13 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor } RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CONTINUE) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(framebuffer), render_list.elements, render_list.element_count, false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, radiance_uniform_set, render_buffers_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME); - RD::get_singleton()->draw_list_end(); - + RenderListParameters render_list_params(render_list.elements, render_list.element_count, false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + RD::get_singleton()->draw_command_begin_label("Render Opaque Pass"); + _render_list_with_threads(&render_list_params, framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CONTINUE) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); + RD::get_singleton()->draw_command_end_label(); if (will_continue_color && using_separate_specular) { // close the specular framebuffer, as it's no longer used - draw_list = RD::get_singleton()->draw_list_begin(render_buffer->specular_only_fb, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE); + RD::get_singleton()->draw_list_begin(render_buffer->specular_only_fb, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE); RD::get_singleton()->draw_list_end(); } } @@ -1908,9 +1767,11 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor dc.set_depth_correction(true); CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse()); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); - for (int i = 0; i < p_gi_probe_cull_count; i++) { - _debug_giprobe(p_gi_probe_cull_result[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0); + RD::get_singleton()->draw_command_begin_label("Debug GIProbes"); + for (int i = 0; i < (int)p_gi_probes.size(); i++) { + _debug_giprobe(p_gi_probes[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0); } + RD::get_singleton()->draw_command_end_label(); RD::get_singleton()->draw_list_end(); } @@ -1923,7 +1784,9 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor dc.set_depth_correction(true); CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse()); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); + RD::get_singleton()->draw_command_begin_label("Debug SDFGI"); _debug_sdfgi_probes(p_render_buffer, draw_list, opaque_framebuffer, cm); + RD::get_singleton()->draw_command_end_label(); RD::get_singleton()->draw_list_end(); } @@ -1936,30 +1799,35 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor correction.set_depth_correction(true); projection = correction * p_cam_projection; } - + RD::get_singleton()->draw_command_begin_label("Draw Sky"); _draw_sky(can_continue_color, can_continue_depth, opaque_framebuffer, p_environment, projection, p_cam_transform); + RD::get_singleton()->draw_command_end_label(); } if (render_buffer && !can_continue_color && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color, true); + RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color); if (using_separate_specular) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular, true); + RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular); } } if (render_buffer && !can_continue_depth && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth, true); + RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth); } if (using_separate_specular) { if (using_sss) { RENDER_TIMESTAMP("Sub Surface Scattering"); + RD::get_singleton()->draw_command_begin_label("Process Sub Surface Scattering"); _process_sss(p_render_buffer, p_cam_projection); + RD::get_singleton()->draw_command_end_label(); } if (using_ssr) { RENDER_TIMESTAMP("Screen Space Reflection"); + RD::get_singleton()->draw_command_begin_label("Process Screen Space Reflections"); _process_ssr(p_render_buffer, render_buffer->color_fb, render_buffer->normal_roughness_buffer, render_buffer->specular, render_buffer->specular, Color(0, 0, 0, 1), p_environment, p_cam_projection, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED); + RD::get_singleton()->draw_command_end_label(); } else { //just mix specular back RENDER_TIMESTAMP("Merge Specular"); @@ -1969,24 +1837,23 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor RENDER_TIMESTAMP("Render Transparent Pass"); - _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); + _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false); render_list.sort_by_reverse_depth_and_priority(true); - _fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, using_sdfgi); - { - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(alpha_framebuffer), &render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr, radiance_uniform_set, render_buffers_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME); - RD::get_singleton()->draw_list_end(); + RD::get_singleton()->draw_command_begin_label("Render Transparent Pass"); + RenderListParameters render_list_params(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + _render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); + RD::get_singleton()->draw_command_end_label(); } if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color, true); + RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color); } } -void RasterizerSceneHighEndRD::_render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake) { +void RendererSceneRenderForward::_render_shadow(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) { RENDER_TIMESTAMP("Setup Rendering Shadow"); _update_render_base_uniform_set(); @@ -1995,31 +1862,36 @@ void RasterizerSceneHighEndRD::_render_shadow(RID p_framebuffer, InstanceBase ** scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1; - _setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID(), true, Color(), 0, p_zfar, false, p_use_pancake); + _setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), !p_flip_y, Color(), 0, p_zfar, false, p_use_pancake); - render_list.clear(); + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { + p_screen_lod_threshold = 0.0; + } PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW; - _fill_render_list(p_cull_result, p_cull_count, pass_mode); + _fill_render_list(p_instances, pass_mode, p_projection, p_transform); - _setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>()); RENDER_TIMESTAMP("Render Shadow"); render_list.sort_by_key(false); - _fill_instances(render_list.elements, render_list.element_count, true); - { //regular forward for now - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, p_use_dp_flip, pass_mode, true, RID(), RID()); - RD::get_singleton()->draw_list_end(); + bool flip_cull = p_use_dp_flip; + if (p_flip_y) { + flip_cull = !flip_cull; + } + RD::get_singleton()->draw_command_begin_label("Render Shadow"); + RenderListParameters render_list_params(render_list.elements, render_list.element_count, flip_cull, pass_mode, true, rp_uniform_set, false, Vector2(), p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold); + _render_list_with_threads(&render_list_params, p_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : RD::INITIAL_ACTION_CONTINUE, p_end ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, Vector<Color>(), 1.0, 0, p_rect); + RD::get_singleton()->draw_command_end_label(); } } -void RasterizerSceneHighEndRD::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, InstanceBase **p_cull_result, int p_cull_count) { +void RendererSceneRenderForward::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) { RENDER_TIMESTAMP("Setup Render Collider Heightfield"); _update_render_base_uniform_set(); @@ -2028,31 +1900,28 @@ void RasterizerSceneHighEndRD::_render_particle_collider_heightfield(RID p_fb, c scene_state.ubo.dual_paraboloid_side = 0; - _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), true, Color(), 0, p_cam_projection.get_z_far(), false, false); - - render_list.clear(); + _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), true, Color(), 0, p_cam_projection.get_z_far(), false, false); PassMode pass_mode = PASS_MODE_SHADOW; - _fill_render_list(p_cull_result, p_cull_count, pass_mode); + _fill_render_list(p_instances, pass_mode, p_cam_projection, p_cam_transform); - _setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>()); - RENDER_TIMESTAMP("Render Collider Heightield"); + RENDER_TIMESTAMP("Render Collider Heightfield"); render_list.sort_by_key(false); - _fill_instances(render_list.elements, render_list.element_count, true); - { //regular forward for now - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_fb), render_list.elements, render_list.element_count, false, pass_mode, true, RID(), RID()); - RD::get_singleton()->draw_list_end(); + RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield"); + RenderListParameters render_list_params(render_list.elements, render_list.element_count, false, pass_mode, true, rp_uniform_set); + _render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); + RD::get_singleton()->draw_command_end_label(); } } -void RasterizerSceneHighEndRD::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) { +void RendererSceneRenderForward::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { RENDER_TIMESTAMP("Setup Rendering Material"); _update_render_base_uniform_set(); @@ -2060,24 +1929,21 @@ void RasterizerSceneHighEndRD::_render_material(const Transform &p_cam_transform render_pass++; scene_state.ubo.dual_paraboloid_side = 0; - scene_state.ubo.material_uv2_mode = true; + scene_state.ubo.material_uv2_mode = false; - _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), false, Color(), 0, 0); - - render_list.clear(); + _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0); PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; - _fill_render_list(p_cull_result, p_cull_count, pass_mode); + _fill_render_list(p_instances, pass_mode, p_cam_projection, p_cam_transform); - _setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>()); RENDER_TIMESTAMP("Render Material"); render_list.sort_by_key(false); - _fill_instances(render_list.elements, render_list.element_count, true); - { + RenderListParameters render_list_params(render_list.elements, render_list.element_count, true, pass_mode, true, rp_uniform_set); //regular forward for now Vector<Color> clear; clear.push_back(Color(0, 0, 0, 0)); @@ -2086,12 +1952,12 @@ void RasterizerSceneHighEndRD::_render_material(const Transform &p_cam_transform clear.push_back(Color(0, 0, 0, 0)); clear.push_back(Color(0, 0, 0, 0)); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, RID(), RID()); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); RD::get_singleton()->draw_list_end(); } } -void RasterizerSceneHighEndRD::_render_uv2(InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) { +void RendererSceneRenderForward::_render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { RENDER_TIMESTAMP("Setup Rendering UV2"); _update_render_base_uniform_set(); @@ -2101,22 +1967,19 @@ void RasterizerSceneHighEndRD::_render_uv2(InstanceBase **p_cull_result, int p_c scene_state.ubo.dual_paraboloid_side = 0; scene_state.ubo.material_uv2_mode = true; - _setup_environment(RID(), RID(), CameraMatrix(), Transform(), RID(), true, Vector2(1, 1), RID(), false, Color(), 0, 0); - - render_list.clear(); + _setup_environment(RID(), RID(), CameraMatrix(), Transform(), RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0); PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; - _fill_render_list(p_cull_result, p_cull_count, pass_mode); + _fill_render_list(p_instances, pass_mode, CameraMatrix(), Transform()); - _setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>()); RENDER_TIMESTAMP("Render Material"); render_list.sort_by_key(false); - _fill_instances(render_list.elements, render_list.element_count, true); - { + RenderListParameters render_list_params(render_list.elements, render_list.element_count, true, pass_mode, true, rp_uniform_set, true); //regular forward for now Vector<Color> clear; clear.push_back(Color(0, 0, 0, 0)); @@ -2144,69 +2007,35 @@ void RasterizerSceneHighEndRD::_render_uv2(InstanceBase **p_cull_result, int p_c Vector2 ofs = uv_offsets[i]; ofs.x /= p_region.size.width; ofs.y /= p_region.size.height; - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, RID(), RID(), true, ofs); //first wireframe, for pseudo conservative + render_list_params.uv_offset = ofs; + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //first wireframe, for pseudo conservative } - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, RID(), RID(), false); //second regular triangles + render_list_params.uv_offset = Vector2(); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //second regular triangles RD::get_singleton()->draw_list_end(); } } -void RasterizerSceneHighEndRD::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, InstanceBase **p_cull_result, int p_cull_count, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) { +void RendererSceneRenderForward::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) { RENDER_TIMESTAMP("Render SDFGI"); _update_render_base_uniform_set(); - RenderBufferDataHighEnd *render_buffer = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); + RenderBufferDataForward *render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); ERR_FAIL_COND(!render_buffer); render_pass++; - render_list.clear(); PassMode pass_mode = PASS_MODE_SDF; - _fill_render_list(p_cull_result, p_cull_count, pass_mode); + _fill_render_list(p_instances, pass_mode, CameraMatrix(), Transform()); render_list.sort_by_key(false); - _fill_instances(render_list.elements, render_list.element_count, true); - _setup_view_dependant_uniform_set(RID(), RID(), nullptr, 0); + RID rp_uniform_set = _setup_sdfgi_render_pass_uniform_set(p_albedo_texture, p_emission_texture, p_emission_aniso_texture, p_geom_facing_texture); Vector3 half_extents = p_bounds.size * 0.5; Vector3 center = p_bounds.position + half_extents; - if (render_buffer->render_sdfgi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_buffer->render_sdfgi_uniform_set)) { - Vector<RD::Uniform> uniforms; - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 0; - u.ids.push_back(p_albedo_texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 1; - u.ids.push_back(p_emission_texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 2; - u.ids.push_back(p_emission_aniso_texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 3; - u.ids.push_back(p_geom_facing_texture); - uniforms.push_back(u); - } - - render_buffer->render_sdfgi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_sdfgi_rd, RENDER_BUFFERS_UNIFORM_SET); - } - Vector<RID> sbs; sbs.push_back(p_albedo_texture); sbs.push_back(p_emission_texture); @@ -2251,9 +2080,9 @@ void RasterizerSceneHighEndRD::_render_sdfgi(RID p_render_buffers, const Vector3 to_bounds.origin = p_bounds.position; to_bounds.basis.scale(p_bounds.size); - RasterizerStorageRD::store_transform(to_bounds.affine_inverse() * cam_xform, scene_state.ubo.sdf_to_bounds); + RendererStorageRD::store_transform(to_bounds.affine_inverse() * cam_xform, scene_state.ubo.sdf_to_bounds); - _setup_environment(RID(), RID(), camera_proj, cam_xform, RID(), true, Vector2(1, 1), RID(), false, Color(), 0, 0); + _setup_environment(RID(), RID(), camera_proj, cam_xform, RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0); Map<Size2i, RID>::Element *E = sdfgi_framebuffer_size_cache.find(fb_size); if (!E) { @@ -2261,20 +2090,19 @@ void RasterizerSceneHighEndRD::_render_sdfgi(RID p_render_buffers, const Vector3 E = sdfgi_framebuffer_size_cache.insert(fb_size, fb); } - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(E->get(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, Rect2(), sbs); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(E->get()), render_list.elements, render_list.element_count, true, pass_mode, true, RID(), render_buffer->render_sdfgi_uniform_set, false); //second regular triangles - RD::get_singleton()->draw_list_end(); + RenderListParameters render_list_params(render_list.elements, render_list.element_count, true, pass_mode, true, rp_uniform_set, false); + _render_list_with_threads(&render_list_params, E->get(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, Rect2(), sbs); } } -void RasterizerSceneHighEndRD::_base_uniforms_changed() { +void RendererSceneRenderForward::_base_uniforms_changed() { if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { RD::get_singleton()->free(render_base_uniform_set); } render_base_uniform_set = RID(); } -void RasterizerSceneHighEndRD::_update_render_base_uniform_set() { +void RendererSceneRenderForward::_update_render_base_uniform_set() { if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version())) { if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { RD::get_singleton()->free(render_base_uniform_set); @@ -2286,7 +2114,7 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 1; u.ids.resize(12); RID *ids_ptr = u.ids.ptrw(); @@ -2308,7 +2136,7 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() { { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.ids.push_back(shadow_sampler); uniforms.push_back(u); } @@ -2316,124 +2144,90 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() { { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(scene_state.uniform_buffer); uniforms.push_back(u); } + { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.ids.push_back(scene_state.instance_buffer); + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(get_omni_light_buffer()); uniforms.push_back(u); } - { RD::Uniform u; u.binding = 5; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.ids.push_back(get_positional_light_buffer()); + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(get_spot_light_buffer()); uniforms.push_back(u); } { RD::Uniform u; u.binding = 6; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(get_reflection_probe_buffer()); uniforms.push_back(u); } { RD::Uniform u; u.binding = 7; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(get_directional_light_buffer()); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 10; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 8; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(scene_state.lightmap_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 11; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.ids = storage->lightmap_array_get_textures(); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 12; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 9; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(scene_state.lightmap_capture_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 13; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 10; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID decal_atlas = storage->decal_atlas_get_texture(); u.ids.push_back(decal_atlas); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 14; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 11; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID decal_atlas = storage->decal_atlas_get_texture_srgb(); u.ids.push_back(decal_atlas); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 15; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 12; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(get_decal_buffer()); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 16; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.push_back(get_cluster_builder_texture()); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 17; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.ids.push_back(get_cluster_builder_indices_buffer()); - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.binding = 18; - u.type = RD::UNIFORM_TYPE_TEXTURE; - if (directional_shadow_get_texture().is_valid()) { - u.ids.push_back(directional_shadow_get_texture()); - } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); - } - uniforms.push_back(u); - } - - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 19; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 13; u.ids.push_back(storage->global_variables_get_storage_buffer()); uniforms.push_back(u); } - { + if (!low_end) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 20; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 14; u.ids.push_back(sdfgi_get_ubo()); uniforms.push_back(u); } @@ -2442,9 +2236,14 @@ void RasterizerSceneHighEndRD::_update_render_base_uniform_set() { } } -void RasterizerSceneHighEndRD::_setup_view_dependant_uniform_set(RID p_shadow_atlas, RID p_reflection_atlas, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count) { - if (view_dependant_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(view_dependant_uniform_set)) { - RD::get_singleton()->free(view_dependant_uniform_set); +RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID p_cluster_buffer, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, bool p_use_directional_shadow_atlas) { + if (render_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_set)) { + RD::get_singleton()->free(render_pass_uniform_set); + } + + RenderBufferDataForward *rb = nullptr; + if (p_render_buffers.is_valid()) { + rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); } //default render buffer and scene state uniform set @@ -2452,211 +2251,907 @@ void RasterizerSceneHighEndRD::_setup_view_dependant_uniform_set(RID p_shadow_at Vector<RD::Uniform> uniforms; { - RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID(); + RID radiance_texture; + if (p_radiance_texture.is_valid()) { + radiance_texture = p_radiance_texture; + } else { + radiance_texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); + } RD::Uniform u; u.binding = 0; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(radiance_texture); + uniforms.push_back(u); + } + + { + RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID(); + RD::Uniform u; + u.binding = 1; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; if (ref_texture.is_valid()) { u.ids.push_back(ref_texture); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK)); } uniforms.push_back(u); } { RD::Uniform u; - u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 2; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID texture; if (p_shadow_atlas.is_valid()) { texture = shadow_atlas_get_texture(p_shadow_atlas); } if (!texture.is_valid()) { - texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE); + texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); } u.ids.push_back(texture); uniforms.push_back(u); } + { + RD::Uniform u; + u.binding = 3; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) { + u.ids.push_back(directional_shadow_get_texture()); + } else { + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + } + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 4; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(scene_state.max_lightmaps); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); + for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) { + if (i < p_lightmaps.size()) { + RID base = lightmap_instance_get_lightmap(p_lightmaps[i]); + RID texture = storage->lightmap_get_texture(base); + RID rd_texture = storage->texture_get_rd_texture(texture); + u.ids.write[i] = rd_texture; + } else { + u.ids.write[i] = default_tex; + } + } + uniforms.push_back(u); + } { RD::Uniform u; - u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID default_tex = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + u.binding = 5; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(MAX_GI_PROBES); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); for (int i = 0; i < MAX_GI_PROBES; i++) { - if (i < p_gi_probe_cull_count) { - RID tex = gi_probe_instance_get_texture(p_gi_probe_cull_result[i]); + if (i < (int)p_gi_probes.size()) { + RID tex = gi_probe_instance_get_texture(p_gi_probes[i]); if (!tex.is_valid()) { tex = default_tex; } - u.ids.push_back(tex); + u.ids.write[i] = tex; } else { - u.ids.push_back(default_tex); + u.ids.write[i] = default_tex; } } uniforms.push_back(u); } - view_dependant_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, VIEW_DEPENDANT_UNIFORM_SET); -} -void RasterizerSceneHighEndRD::_render_buffers_clear_uniform_set(RenderBufferDataHighEnd *rb) { - if (!rb->uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(rb->uniform_set)) { - RD::get_singleton()->free(rb->uniform_set); + { + RD::Uniform u; + u.binding = 6; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : default_vec4_xform_buffer; + u.ids.push_back(cb); + uniforms.push_back(u); } - rb->uniform_set = RID(); -} - -void RasterizerSceneHighEndRD::_render_buffers_uniform_set_changed(RID p_render_buffers) { - RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); - - _render_buffers_clear_uniform_set(rb); -} - -RID RasterizerSceneHighEndRD::_render_buffers_get_normal_texture(RID p_render_buffers) { - RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); - return rb->normal_roughness_buffer; -} - -RID RasterizerSceneHighEndRD::_render_buffers_get_ambient_texture(RID p_render_buffers) { - RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); - - return rb->ambient_buffer; -} - -RID RasterizerSceneHighEndRD::_render_buffers_get_reflection_texture(RID p_render_buffers) { - RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); - - return rb->reflection_buffer; -} - -void RasterizerSceneHighEndRD::_update_render_buffers_uniform_set(RID p_render_buffers) { - RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers); + { + RD::Uniform u; + u.binding = 7; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = (false && rb && rb->depth.is_valid()) ? rb->depth : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + u.ids.push_back(texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 8; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID bbt = rb ? render_buffers_get_back_buffer_texture(p_render_buffers) : RID(); + RID texture = bbt.is_valid() ? bbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.ids.push_back(texture); + uniforms.push_back(u); + } - if (rb->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->uniform_set)) { - Vector<RD::Uniform> uniforms; - { - RD::Uniform u; - u.binding = 0; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = false && rb->depth.is_valid() ? rb->depth : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE); - u.ids.push_back(texture); - uniforms.push_back(u); - } + if (!low_end) { { RD::Uniform u; - u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID bbt = render_buffers_get_back_buffer_texture(p_render_buffers); - RID texture = bbt.is_valid() ? bbt : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK); - u.ids.push_back(texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = rb->normal_roughness_buffer.is_valid() ? rb->normal_roughness_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_NORMAL); + u.binding = 9; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = rb && rb->normal_roughness_buffer.is_valid() ? rb->normal_roughness_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_NORMAL); u.ids.push_back(texture); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 4; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID aot = render_buffers_get_ao_texture(p_render_buffers); - RID texture = aot.is_valid() ? aot : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.binding = 10; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID aot = rb ? render_buffers_get_ao_texture(p_render_buffers) : RID(); + RID texture = aot.is_valid() ? aot : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(texture); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 5; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = rb->ambient_buffer.is_valid() ? rb->ambient_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.binding = 11; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID ambient_buffer = p_render_buffers.is_valid() ? render_buffers_get_gi_ambient_texture(p_render_buffers) : RID(); + RID texture = ambient_buffer.is_valid() ? ambient_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(texture); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 6; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = rb->reflection_buffer.is_valid() ? rb->reflection_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.binding = 12; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID reflection_buffer = p_render_buffers.is_valid() ? render_buffers_get_gi_reflection_texture(p_render_buffers) : RID(); + RID texture = reflection_buffer.is_valid() ? reflection_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(texture); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 7; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 13; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID t; - if (render_buffers_is_sdfgi_enabled(p_render_buffers)) { + if (rb && render_buffers_is_sdfgi_enabled(p_render_buffers)) { t = render_buffers_get_sdfgi_irradiance_probes(p_render_buffers); } else { - t = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); + t = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); } u.ids.push_back(t); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 8; - u.type = RD::UNIFORM_TYPE_TEXTURE; - if (render_buffers_is_sdfgi_enabled(p_render_buffers)) { + u.binding = 14; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + if (rb && render_buffers_is_sdfgi_enabled(p_render_buffers)) { u.ids.push_back(render_buffers_get_sdfgi_occlusion_texture(p_render_buffers)); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } uniforms.push_back(u); } { RD::Uniform u; - u.binding = 9; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.ids.push_back(render_buffers_get_gi_probe_buffer(p_render_buffers)); + u.binding = 15; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.ids.push_back(rb ? render_buffers_get_gi_probe_buffer(p_render_buffers) : render_buffers_get_default_gi_probe_buffer()); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 10; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 16; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID vfog = RID(); - if (p_render_buffers.is_valid() && render_buffers_has_volumetric_fog(p_render_buffers)) { + if (rb && render_buffers_has_volumetric_fog(p_render_buffers)) { vfog = render_buffers_get_volumetric_fog_texture(p_render_buffers); if (vfog.is_null()) { - vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); } } else { - vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); } u.ids.push_back(vfog); uniforms.push_back(u); } - rb->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_BUFFERS_UNIFORM_SET); } + + render_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_PASS_UNIFORM_SET); + return render_pass_uniform_set; } -RasterizerSceneHighEndRD *RasterizerSceneHighEndRD::singleton = nullptr; +RID RendererSceneRenderForward::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture) { + if (sdfgi_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sdfgi_pass_uniform_set)) { + RD::get_singleton()->free(sdfgi_pass_uniform_set); + } + + Vector<RD::Uniform> uniforms; + + { + // No radiance texture. + RID radiance_texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); + RD::Uniform u; + u.binding = 0; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(radiance_texture); + uniforms.push_back(u); + } + + { + // No reflection atlas. + RID ref_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK); + RD::Uniform u; + u.binding = 1; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.push_back(ref_texture); + uniforms.push_back(u); + } + + { + // No shadow atlas. + RD::Uniform u; + u.binding = 2; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + u.ids.push_back(texture); + uniforms.push_back(u); + } + + { + // No directional shadow atlas. + RD::Uniform u; + u.binding = 3; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + u.ids.push_back(texture); + uniforms.push_back(u); + } + + { + // No Lightmaps + RD::Uniform u; + u.binding = 4; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(scene_state.max_lightmaps); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); + for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) { + u.ids.write[i] = default_tex; + } + + uniforms.push_back(u); + } + + { + // No GIProbes + RD::Uniform u; + u.binding = 5; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(MAX_GI_PROBES); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + for (int i = 0; i < MAX_GI_PROBES; i++) { + u.ids.write[i] = default_tex; + } -void RasterizerSceneHighEndRD::set_time(double p_time, double p_step) { + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.binding = 6; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + RID cb = default_vec4_xform_buffer; + u.ids.push_back(cb); + uniforms.push_back(u); + } + + // actual sdfgi stuff + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 7; + u.ids.push_back(p_albedo_texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 8; + u.ids.push_back(p_emission_texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 9; + u.ids.push_back(p_emission_aniso_texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 10; + u.ids.push_back(p_geom_facing_texture); + uniforms.push_back(u); + } + + sdfgi_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_sdfgi_rd, RENDER_PASS_UNIFORM_SET); + return sdfgi_pass_uniform_set; +} + +void RendererSceneRenderForward::_render_buffers_clear_uniform_set(RenderBufferDataForward *rb) { +} + +void RendererSceneRenderForward::_render_buffers_uniform_set_changed(RID p_render_buffers) { + RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); + + _render_buffers_clear_uniform_set(rb); +} + +RID RendererSceneRenderForward::_render_buffers_get_normal_texture(RID p_render_buffers) { + RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers); + + return rb->normal_roughness_buffer; +} + +RendererSceneRenderForward *RendererSceneRenderForward::singleton = nullptr; + +void RendererSceneRenderForward::set_time(double p_time, double p_step) { time = p_time; - RasterizerSceneRD::set_time(p_time, p_step); + RendererSceneRenderRD::set_time(p_time, p_step); +} + +void RendererSceneRenderForward::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + if (ginstance->dirty_list_element.in_list()) { + return; + } + + //clear surface caches + GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches; + + while (surf) { + GeometryInstanceSurfaceDataCache *next = surf->next; + geometry_instance_surface_alloc.free(surf); + surf = next; + } + + ginstance->surface_caches = nullptr; + + geometry_instance_dirty_list.add(&ginstance->dirty_list_element); +} + +void RendererSceneRenderForward::_geometry_instance_add_surface_with_material(GeometryInstanceForward *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) { + bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture; + bool has_base_alpha = (p_material->shader_data->uses_alpha || has_read_screen_alpha); + bool has_blend_alpha = p_material->shader_data->uses_blend_alpha; + bool has_alpha = has_base_alpha || has_blend_alpha; + + uint32_t flags = 0; + + if (p_material->shader_data->uses_sss) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING; + } + + if (p_material->shader_data->uses_screen_texture) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE; + } + + if (p_material->shader_data->uses_depth_texture) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE; + } + + if (p_material->shader_data->uses_normal_texture) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE; + } + + if (ginstance->data->cast_double_sided_shaodows) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS; + } + + if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED) { + //material is only meant for alpha pass + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA; + if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED)) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; + } + } else { + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE; + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; + } + + MaterialData *material_shadow = nullptr; + void *surface_shadow = nullptr; + if (!p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL; + material_shadow = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); + + RID shadow_mesh = storage->mesh_get_shadow_mesh(p_mesh); + + if (shadow_mesh.is_valid()) { + surface_shadow = storage->mesh_get_surface(shadow_mesh, p_surface); + } + + } else { + material_shadow = p_material; + } + + GeometryInstanceSurfaceDataCache *sdcache = geometry_instance_surface_alloc.alloc(); + + sdcache->flags = flags; + + sdcache->shader = p_material->shader_data; + sdcache->material_uniform_set = p_material->uniform_set; + sdcache->surface = storage->mesh_get_surface(p_mesh, p_surface); + sdcache->primitive = storage->mesh_surface_get_primitive(sdcache->surface); + sdcache->surface_index = p_surface; + + if (ginstance->data->dirty_dependencies) { + storage->base_update_dependency(p_mesh, &ginstance->data->dependency_tracker); + } + + //shadow + sdcache->shader_shadow = material_shadow->shader_data; + sdcache->material_uniform_set_shadow = material_shadow->uniform_set; + + sdcache->surface_shadow = surface_shadow ? surface_shadow : sdcache->surface; + + sdcache->owner = ginstance; + + sdcache->next = ginstance->surface_caches; + ginstance->surface_caches = sdcache; + + //sortkey + + sdcache->sort.sort_key1 = 0; + sdcache->sort.sort_key2 = 0; + + sdcache->sort.surface_type = ginstance->data->base_type; + sdcache->sort.material_id = p_material_id; + sdcache->sort.shader_id = p_shader_id; + sdcache->sort.geometry_id = p_mesh.get_local_index(); + sdcache->sort.uses_forward_gi = ginstance->can_sdfgi; + sdcache->sort.priority = p_material->priority; +} + +void RendererSceneRenderForward::_geometry_instance_add_surface(GeometryInstanceForward *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) { + RID m_src; + + m_src = ginstance->data->material_override.is_valid() ? ginstance->data->material_override : p_material; + + MaterialData *material = nullptr; + + if (m_src.is_valid()) { + material = (MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D); + if (!material || !material->shader_data->valid) { + material = nullptr; + } + } + + if (material) { + if (ginstance->data->dirty_dependencies) { + storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker); + } + } else { + material = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); + m_src = default_material; + } + + ERR_FAIL_COND(!material); + + _geometry_instance_add_surface_with_material(ginstance, p_surface, material, m_src.get_local_index(), storage->material_get_shader_id(m_src), p_mesh); + + while (material->next_pass.is_valid()) { + RID next_pass = material->next_pass; + material = (MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D); + if (!material || !material->shader_data->valid) { + break; + } + if (ginstance->data->dirty_dependencies) { + storage->material_update_dependency(next_pass, &ginstance->data->dependency_tracker); + } + _geometry_instance_add_surface_with_material(ginstance, p_surface, material, next_pass.get_local_index(), storage->material_get_shader_id(next_pass), p_mesh); + } +} + +void RendererSceneRenderForward::_geometry_instance_update(GeometryInstance *p_geometry_instance) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + + if (ginstance->data->dirty_dependencies) { + ginstance->data->dependency_tracker.update_begin(); + } + + //add geometry for drawing + switch (ginstance->data->base_type) { + case RS::INSTANCE_MESH: { + const RID *materials = nullptr; + uint32_t surface_count; + RID mesh = ginstance->data->base; + + materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); + if (materials) { + //if no materials, no surfaces. + const RID *inst_materials = ginstance->data->surface_materials.ptr(); + uint32_t surf_mat_count = ginstance->data->surface_materials.size(); + + for (uint32_t j = 0; j < surface_count; j++) { + RID material = (j < surf_mat_count && inst_materials[j].is_valid()) ? inst_materials[j] : materials[j]; + _geometry_instance_add_surface(ginstance, j, material, mesh); + } + } + + ginstance->instance_count = 1; + + } break; + + case RS::INSTANCE_MULTIMESH: { + RID mesh = storage->multimesh_get_mesh(ginstance->data->base); + if (mesh.is_valid()) { + const RID *materials = nullptr; + uint32_t surface_count; + + materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); + if (materials) { + for (uint32_t j = 0; j < surface_count; j++) { + _geometry_instance_add_surface(ginstance, j, materials[j], mesh); + } + } + + ginstance->instance_count = storage->multimesh_get_instances_to_draw(ginstance->data->base); + } + + } break; +#if 0 + case RS::INSTANCE_IMMEDIATE: { + RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base); + ERR_CONTINUE(!immediate); + + _add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass); + + } break; +#endif + case RS::INSTANCE_PARTICLES: { + int draw_passes = storage->particles_get_draw_passes(ginstance->data->base); + + for (int j = 0; j < draw_passes; j++) { + RID mesh = storage->particles_get_draw_pass_mesh(ginstance->data->base, j); + if (!mesh.is_valid()) + continue; + + const RID *materials = nullptr; + uint32_t surface_count; + + materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); + if (materials) { + for (uint32_t k = 0; k < surface_count; k++) { + _geometry_instance_add_surface(ginstance, k, materials[k], mesh); + } + } + } + + ginstance->instance_count = storage->particles_get_amount(ginstance->data->base); + + } break; + + default: { + } + } + + //Fill push constant + + ginstance->push_constant.instance_uniforms_ofs = ginstance->data->shader_parameters_offset >= 0 ? ginstance->data->shader_parameters_offset : 0; + ginstance->push_constant.layer_mask = ginstance->data->layer_mask; + ginstance->push_constant.flags = 0; + ginstance->push_constant.gi_offset = 0xFFFFFFFF; //disabled + + bool store_transform = true; + + if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; + uint32_t stride; + if (storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; + stride = 2; + } else { + stride = 3; + } + if (storage->multimesh_uses_colors(ginstance->data->base)) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; + stride += 1; + } + if (storage->multimesh_uses_custom_data(ginstance->data->base)) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; + stride += 1; + } + + ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); + ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); + + } else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; + uint32_t stride; + if (false) { // 2D particles + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; + stride = 2; + } else { + stride = 3; + } + + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; + stride += 1; + + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; + stride += 1; + + ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); + + if (!storage->particles_is_using_local_coords(ginstance->data->base)) { + store_transform = false; + } + ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); + + } else if (ginstance->data->base_type == RS::INSTANCE_MESH) { + if (storage->skeleton_is_valid(ginstance->data->skeleton)) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_SKELETON; + ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, default_shader_rd, TRANSFORMS_UNIFORM_SET); + if (ginstance->data->dirty_dependencies) { + storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker); + } + } + } + + if (store_transform) { + RendererStorageRD::store_transform(ginstance->data->transform, ginstance->push_constant.transform); + } else { + RendererStorageRD::store_transform(Transform(), ginstance->push_constant.transform); + } + + ginstance->can_sdfgi = false; + + if (lightmap_instance_is_valid(ginstance->lightmap_instance)) { + ginstance->push_constant.gi_offset = ginstance->data->lightmap_slice_index << 16; + ginstance->push_constant.lightmap_uv_scale[0] = ginstance->data->lightmap_uv_scale.position.x; + ginstance->push_constant.lightmap_uv_scale[1] = ginstance->data->lightmap_uv_scale.position.y; + ginstance->push_constant.lightmap_uv_scale[2] = ginstance->data->lightmap_uv_scale.size.width; + ginstance->push_constant.lightmap_uv_scale[3] = ginstance->data->lightmap_uv_scale.size.height; + } else if (!low_end) { + if (ginstance->gi_probes[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) { + ginstance->can_sdfgi = true; + } + } + + if (ginstance->data->dirty_dependencies) { + ginstance->data->dependency_tracker.update_end(); + ginstance->data->dirty_dependencies = false; + } + + ginstance->dirty_list_element.remove_from_list(); +} + +void RendererSceneRenderForward::_update_dirty_geometry_instances() { + while (geometry_instance_dirty_list.first()) { + _geometry_instance_update(geometry_instance_dirty_list.first()->self()); + } } -RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storage) : - RasterizerSceneRD(p_storage) { +void RendererSceneRenderForward::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) { + switch (p_notification) { + case RendererStorage::DEPENDENCY_CHANGED_MATERIAL: + case RendererStorage::DEPENDENCY_CHANGED_MESH: + case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH: + case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: { + static_cast<RendererSceneRenderForward *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata)); + } break; + case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_tracker->userdata); + if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { + ginstance->instance_count = static_cast<RendererSceneRenderForward *>(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base); + } + } break; + default: { + //rest of notifications of no interest + } break; + } +} +void RendererSceneRenderForward::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) { + static_cast<RendererSceneRenderForward *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata)); +} + +RendererSceneRender::GeometryInstance *RendererSceneRenderForward::geometry_instance_create(RID p_base) { + RS::InstanceType type = storage->get_base_type(p_base); + ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr); + + GeometryInstanceForward *ginstance = geometry_instance_alloc.alloc(); + ginstance->data = memnew(GeometryInstanceForward::Data); + + ginstance->data->base = p_base; + ginstance->data->base_type = type; + ginstance->data->dependency_tracker.userdata = ginstance; + ginstance->data->dependency_tracker.changed_callback = _geometry_instance_dependency_changed; + ginstance->data->dependency_tracker.deleted_callback = _geometry_instance_dependency_deleted; + + _geometry_instance_mark_dirty(ginstance); + + return ginstance; +} +void RendererSceneRenderForward::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->skeleton = p_skeleton; + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} +void RendererSceneRenderForward::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->material_override = p_override; + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} +void RendererSceneRenderForward::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->surface_materials = p_materials; + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} +void RendererSceneRenderForward::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->mesh_instance = p_mesh_instance; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + RendererStorageRD::store_transform(p_transform, ginstance->push_constant.transform); + ginstance->data->transform = p_transform; + ginstance->mirror = p_transform.basis.determinant() < 0; + ginstance->data->aabb = p_aabb; + ginstance->transformed_aabb = p_transformed_aabb; + + Vector3 model_scale_vec = p_transform.basis.get_scale_abs(); + // handle non uniform scale here + + float max_scale = MAX(model_scale_vec.x, MAX(model_scale_vec.y, model_scale_vec.z)); + float min_scale = MIN(model_scale_vec.x, MIN(model_scale_vec.y, model_scale_vec.z)); + ginstance->non_uniform_scale = max_scale >= 0.0 && (min_scale / max_scale) < 0.9; + + ginstance->lod_model_scale = max_scale; +} +void RendererSceneRenderForward::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->lod_bias = p_lod_bias; +} +void RendererSceneRenderForward::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->use_baked_light = p_enable; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->use_dynamic_gi = p_enable; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->lightmap_instance = p_lightmap_instance; + ginstance->data->lightmap_uv_scale = p_lightmap_uv_scale; + ginstance->data->lightmap_slice_index = p_lightmap_slice_index; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + if (p_sh9) { + if (ginstance->lightmap_sh == nullptr) { + ginstance->lightmap_sh = geometry_instance_lightmap_sh.alloc(); + } + + copymem(ginstance->lightmap_sh->sh, p_sh9, sizeof(Color) * 9); + } else { + if (ginstance->lightmap_sh != nullptr) { + geometry_instance_lightmap_sh.free(ginstance->lightmap_sh); + ginstance->lightmap_sh = nullptr; + } + } + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->shader_parameters_offset = p_offset; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + + ginstance->data->cast_double_sided_shaodows = p_enable; + _geometry_instance_mark_dirty(ginstance); +} + +void RendererSceneRenderForward::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->layer_mask = p_layer_mask; + ginstance->push_constant.layer_mask = p_layer_mask; +} + +void RendererSceneRenderForward::geometry_instance_free(GeometryInstance *p_geometry_instance) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + if (ginstance->lightmap_sh != nullptr) { + geometry_instance_lightmap_sh.free(ginstance->lightmap_sh); + } + GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches; + while (surf) { + GeometryInstanceSurfaceDataCache *next = surf->next; + geometry_instance_surface_alloc.free(surf); + surf = next; + } + memdelete(ginstance->data); + geometry_instance_alloc.free(ginstance); +} + +uint32_t RendererSceneRenderForward::geometry_instance_get_pair_mask() { + return (1 << RS::INSTANCE_GI_PROBE); +} +void RendererSceneRenderForward::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) { +} +void RendererSceneRenderForward::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) { +} +void RendererSceneRenderForward::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) { +} + +Transform RendererSceneRenderForward::geometry_instance_get_transform(GeometryInstance *p_instance) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_instance); + ERR_FAIL_COND_V(!ginstance, Transform()); + return ginstance->data->transform; +} +AABB RendererSceneRenderForward::geometry_instance_get_aabb(GeometryInstance *p_instance) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_instance); + ERR_FAIL_COND_V(!ginstance, AABB()); + return ginstance->data->aabb; +} + +void RendererSceneRenderForward::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) { + GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + if (p_gi_probe_instance_count > 0) { + ginstance->gi_probes[0] = p_gi_probe_instances[0]; + } else { + ginstance->gi_probes[0] = RID(); + } + + if (p_gi_probe_instance_count > 1) { + ginstance->gi_probes[1] = p_gi_probe_instances[1]; + } else { + ginstance->gi_probes[1] = RID(); + } +} + +RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_storage) : + RendererSceneRenderRD(p_storage) { singleton = this; + low_end = is_low_end(); storage = p_storage; /* SCENE SHADER */ { String defines; + if (low_end) { + defines += "\n#define LOW_END_MODE \n"; + } + defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n"; if (is_using_radiance_cubemap_array()) { defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; @@ -2666,11 +3161,10 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag { //lightmaps - scene_state.max_lightmaps = storage->lightmap_array_get_size(); + scene_state.max_lightmaps = low_end ? 2 : MAX_LIGHTMAPS; defines += "\n#define MAX_LIGHTMAP_TEXTURES " + itos(scene_state.max_lightmaps) + "\n"; defines += "\n#define MAX_LIGHTMAPS " + itos(scene_state.max_lightmaps) + "\n"; - scene_state.lightmaps = memnew_arr(LightmapData, scene_state.max_lightmaps); scene_state.lightmap_buffer = RD::get_singleton()->storage_buffer_create(sizeof(LightmapData) * scene_state.max_lightmaps); } { @@ -2696,10 +3190,20 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag shader_versions.push_back("\n#define USE_LIGHTMAP\n"); shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n"); shader.scene_shader.initialize(shader_versions, defines); + + if (is_low_end()) { + //disable the high end versions + shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_SDF, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, false); + shader.scene_shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, false); + } } - storage->shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_3D, _create_shader_funcs); - storage->material_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_3D, _create_material_funcs); + storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs); + storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_material_funcs); { //shader compiler @@ -2725,6 +3229,11 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.renames["POINT_SIZE"] = "gl_PointSize"; actions.renames["INSTANCE_ID"] = "gl_InstanceIndex"; + actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold"; + actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale"; + actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge"; + actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate"; + //builtins actions.renames["TIME"] = "scene_data.time"; @@ -2732,8 +3241,8 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.renames["FRAGCOORD"] = "gl_FragCoord"; actions.renames["FRONT_FACING"] = "gl_FrontFacing"; - actions.renames["NORMALMAP"] = "normalmap"; - actions.renames["NORMALMAP_DEPTH"] = "normaldepth"; + actions.renames["NORMAL_MAP"] = "normal_map"; + actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; actions.renames["ALBEDO"] = "albedo"; actions.renames["ALPHA"] = "alpha"; actions.renames["METALLIC"] = "metallic"; @@ -2765,6 +3274,12 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.renames["FOG"] = "custom_fog"; actions.renames["RADIANCE"] = "custom_radiance"; actions.renames["IRRADIANCE"] = "custom_irradiance"; + actions.renames["BONE_INDICES"] = "bone_attrib"; + actions.renames["BONE_WEIGHTS"] = "weight_attrib"; + actions.renames["CUSTOM0"] = "custom0_attrib"; + actions.renames["CUSTOM1"] = "custom1_attrib"; + actions.renames["CUSTOM2"] = "custom2_attrib"; + actions.renames["CUSTOM3"] = "custom3_attrib"; //for light actions.renames["VIEW"] = "view"; @@ -2775,6 +3290,7 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.renames["DIFFUSE_LIGHT"] = "diffuse_light"; actions.renames["SPECULAR_LIGHT"] = "specular_light"; + actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n"; actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n"; actions.usage_defines["BINORMAL"] = "@TANGENT"; actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n"; @@ -2787,12 +3303,23 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n"; actions.usage_defines["UV"] = "#define UV_USED\n"; actions.usage_defines["UV2"] = "#define UV2_USED\n"; - actions.usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n"; - actions.usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP"; + actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n"; + actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n"; + actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n"; + actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n"; + actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n"; + actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n"; + actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n"; + actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP"; actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; + actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n"; + actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n"; + actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n"; + actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE"; + actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n"; actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n"; @@ -2850,7 +3377,7 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; actions.global_buffer_array_variable = "global_variables.data"; - actions.instance_uniform_index_variable = "instances.data[instance_index].instance_uniforms_ofs"; + actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs"; shader.compiler.initialize(actions); } @@ -2860,12 +3387,6 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag render_list.init(); render_pass = 0; - { - scene_state.max_instances = render_list.max_elements; - scene_state.instances = memnew_arr(InstanceData, scene_state.max_instances); - scene_state.instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(InstanceData) * scene_state.max_instances); - } - scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO)); { @@ -2875,9 +3396,11 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag default_material = storage->material_create(); storage->material_set_shader(default_material, default_shader); - MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D); + MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); default_shader_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS); - default_shader_sdfgi_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF); + if (!low_end) { + default_shader_sdfgi_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF); + } } { @@ -2896,7 +3419,7 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256); Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(default_vec4_xform_buffer); u.binding = 0; uniforms.push_back(u); @@ -2912,73 +3435,21 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag shadow_sampler = RD::get_singleton()->sampler_create(sampler); } - { - Vector<RD::Uniform> uniforms; - - RD::Uniform u; - u.binding = 0; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); - u.ids.push_back(texture); - uniforms.push_back(u); - - default_radiance_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RADIANCE_UNIFORM_SET); - } - - { //render buffers - Vector<RD::Uniform> uniforms; - for (int i = 0; i < 7; i++) { - RD::Uniform u; - u.binding = i; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = storage->texture_rd_get_default(i == 0 ? RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE : (i == 2 ? RasterizerStorageRD::DEFAULT_RD_TEXTURE_NORMAL : RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK)); - u.ids.push_back(texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 7; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); - u.ids.push_back(texture); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 8; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 9; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.ids.push_back(render_buffers_get_default_gi_probe_buffer()); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 10; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); - uniforms.push_back(u); - } - - default_render_buffers_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_BUFFERS_UNIFORM_SET); - } + render_list_thread_threshold = GLOBAL_GET("rendering/forward_renderer/threaded_render_minimum_instances"); } -RasterizerSceneHighEndRD::~RasterizerSceneHighEndRD() { +RendererSceneRenderForward::~RendererSceneRenderForward() { directional_shadow_atlas_set_size(0); //clear base uniform set if still valid - if (view_dependant_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(view_dependant_uniform_set)) { - RD::get_singleton()->free(view_dependant_uniform_set); + if (render_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_set)) { + RD::get_singleton()->free(render_pass_uniform_set); + } + + if (sdfgi_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sdfgi_pass_uniform_set)) { + RD::get_singleton()->free(sdfgi_pass_uniform_set); } - RD::get_singleton()->free(default_render_buffers_uniform_set); - RD::get_singleton()->free(default_radiance_uniform_set); RD::get_singleton()->free(default_vec4_xform_buffer); RD::get_singleton()->free(shadow_sampler); @@ -2992,11 +3463,8 @@ RasterizerSceneHighEndRD::~RasterizerSceneHighEndRD() { { RD::get_singleton()->free(scene_state.uniform_buffer); - RD::get_singleton()->free(scene_state.instance_buffer); RD::get_singleton()->free(scene_state.lightmap_buffer); RD::get_singleton()->free(scene_state.lightmap_capture_buffer); - memdelete_arr(scene_state.instances); - memdelete_arr(scene_state.lightmaps); memdelete_arr(scene_state.lightmap_captures); } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.h b/servers/rendering/renderer_rd/renderer_scene_render_forward.h new file mode 100644 index 0000000000..0b57c7f76c --- /dev/null +++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.h @@ -0,0 +1,744 @@ +/*************************************************************************/ +/* renderer_scene_render_forward.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERING_SERVER_SCENE_RENDER_FORWARD_H +#define RENDERING_SERVER_SCENE_RENDER_FORWARD_H + +#include "core/templates/paged_allocator.h" +#include "servers/rendering/renderer_rd/pipeline_cache_rd.h" +#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" +#include "servers/rendering/renderer_rd/shaders/scene_forward.glsl.gen.h" + +class RendererSceneRenderForward : public RendererSceneRenderRD { + enum { + SCENE_UNIFORM_SET = 0, + RENDER_PASS_UNIFORM_SET = 1, + TRANSFORMS_UNIFORM_SET = 2, + MATERIAL_UNIFORM_SET = 3 + }; + + enum { + SDFGI_MAX_CASCADES = 8, + MAX_GI_PROBES = 8, + MAX_LIGHTMAPS = 8, + MAX_GI_PROBES_PER_INSTANCE = 2, + }; + + /* Scene Shader */ + + enum ShaderVersion { + SHADER_VERSION_DEPTH_PASS, + SHADER_VERSION_DEPTH_PASS_DP, + SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, + SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, + SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL, + SHADER_VERSION_DEPTH_PASS_WITH_SDF, + SHADER_VERSION_COLOR_PASS, + SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, + SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, + SHADER_VERSION_LIGHTMAP_COLOR_PASS, + SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, + SHADER_VERSION_MAX + }; + + struct { + SceneForwardShaderRD scene_shader; + ShaderCompilerRD compiler; + } shader; + + RendererStorageRD *storage; + + /* Material */ + + struct ShaderData : public RendererStorageRD::ShaderData { + enum BlendMode { //used internally + BLEND_MODE_MIX, + BLEND_MODE_ADD, + BLEND_MODE_SUB, + BLEND_MODE_MUL, + BLEND_MODE_ALPHA_TO_COVERAGE + }; + + enum DepthDraw { + DEPTH_DRAW_DISABLED, + DEPTH_DRAW_OPAQUE, + DEPTH_DRAW_ALWAYS + }; + + enum DepthTest { + DEPTH_TEST_DISABLED, + DEPTH_TEST_ENABLED + }; + + enum Cull { + CULL_DISABLED, + CULL_FRONT, + CULL_BACK + }; + + enum CullVariant { + CULL_VARIANT_NORMAL, + CULL_VARIANT_REVERSED, + CULL_VARIANT_DOUBLE_SIDED, + CULL_VARIANT_MAX + + }; + + enum AlphaAntiAliasing { + ALPHA_ANTIALIASING_OFF, + ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE, + ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE + }; + + bool valid; + RID version; + uint32_t vertex_input_mask; + PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX]; + + String path; + + Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; + Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; + + Vector<uint32_t> ubo_offsets; + uint32_t ubo_size; + + String code; + Map<StringName, RID> default_texture_params; + + DepthDraw depth_draw; + DepthTest depth_test; + + bool uses_point_size; + bool uses_alpha; + bool uses_blend_alpha; + bool uses_alpha_clip; + bool uses_depth_pre_pass; + bool uses_discard; + bool uses_roughness; + bool uses_normal; + + bool unshaded; + bool uses_vertex; + bool uses_sss; + bool uses_transmittance; + bool uses_screen_texture; + bool uses_depth_texture; + bool uses_normal_texture; + bool uses_time; + bool writes_modelview_or_projection; + bool uses_world_coordinates; + + uint64_t last_pass = 0; + uint32_t index = 0; + + virtual void set_code(const String &p_Code); + virtual void set_default_texture_param(const StringName &p_name, RID p_texture); + virtual void get_param_list(List<PropertyInfo> *p_param_list) const; + void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; + + virtual bool is_param_texture(const StringName &p_param) const; + virtual bool is_animated() const; + virtual bool casts_shadows() const; + virtual Variant get_default_parameter(const StringName &p_parameter) const; + virtual RS::ShaderNativeSourceCode get_native_source_code() const; + + ShaderData(); + virtual ~ShaderData(); + }; + + RendererStorageRD::ShaderData *_create_shader_func(); + static RendererStorageRD::ShaderData *_create_shader_funcs() { + return static_cast<RendererSceneRenderForward *>(singleton)->_create_shader_func(); + } + + struct MaterialData : public RendererStorageRD::MaterialData { + uint64_t last_frame; + ShaderData *shader_data; + RID uniform_buffer; + RID uniform_set; + Vector<RID> texture_cache; + Vector<uint8_t> ubo_data; + uint64_t last_pass = 0; + uint32_t index = 0; + RID next_pass; + uint8_t priority; + virtual void set_render_priority(int p_priority); + virtual void set_next_pass(RID p_pass); + virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); + virtual ~MaterialData(); + }; + + RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader); + static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) { + return static_cast<RendererSceneRenderForward *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader)); + } + + /* Framebuffer */ + + struct RenderBufferDataForward : public RenderBufferData { + //for rendering, may be MSAAd + + RID color; + RID depth; + RID specular; + RID normal_roughness_buffer; + RID giprobe_buffer; + + RS::ViewportMSAA msaa; + RD::TextureSamples texture_samples; + + RID color_msaa; + RID depth_msaa; + RID specular_msaa; + RID normal_roughness_buffer_msaa; + RID roughness_buffer_msaa; + RID giprobe_buffer_msaa; + + RID depth_fb; + RID depth_normal_roughness_fb; + RID depth_normal_roughness_giprobe_fb; + RID color_fb; + RID color_specular_fb; + RID specular_only_fb; + int width, height; + + RID render_sdfgi_uniform_set; + void ensure_specular(); + void ensure_giprobe(); + void clear(); + virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa); + + ~RenderBufferDataForward(); + }; + + virtual RenderBufferData *_create_render_buffer_data(); + void _allocate_normal_roughness_texture(RenderBufferDataForward *rb); + + RID shadow_sampler; + RID render_base_uniform_set; + RID render_pass_uniform_set; + RID sdfgi_pass_uniform_set; + + uint64_t lightmap_texture_array_version = 0xFFFFFFFF; + + virtual void _base_uniforms_changed(); + void _render_buffers_clear_uniform_set(RenderBufferDataForward *rb); + virtual void _render_buffers_uniform_set_changed(RID p_render_buffers); + virtual RID _render_buffers_get_normal_texture(RID p_render_buffers); + + void _update_render_base_uniform_set(); + RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture); + RID _setup_render_pass_uniform_set(RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID p_cluster_buffer, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, bool p_use_directional_shadow_atlas = false); + + struct LightmapData { + float normal_xform[12]; + }; + + struct LightmapCaptureData { + float sh[9 * 4]; + }; + + enum { + INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6, + INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7, + INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8, + INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9, + INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10, + INSTANCE_DATA_FLAG_USE_GIPROBE = 1 << 11, + INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12, + INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13, + INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14, + INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15, + INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT = 16, + INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_MASK = 0x7, + INSTANCE_DATA_FLAG_SKELETON = 1 << 19, + }; + + struct SceneState { + struct UBO { + float projection_matrix[16]; + float inv_projection_matrix[16]; + + float camera_matrix[16]; + float inv_camera_matrix[16]; + + float viewport_size[2]; + float screen_pixel_size[2]; + + uint32_t cluster_shift; + uint32_t cluster_width; + uint32_t cluster_type_size; + uint32_t max_cluster_element_count_div_32; + + float directional_penumbra_shadow_kernel[128]; //32 vec4s + float directional_soft_shadow_kernel[128]; + float penumbra_shadow_kernel[128]; + float soft_shadow_kernel[128]; + + uint32_t directional_penumbra_shadow_samples; + uint32_t directional_soft_shadow_samples; + uint32_t penumbra_shadow_samples; + uint32_t soft_shadow_samples; + + float ambient_light_color_energy[4]; + + float ambient_color_sky_mix; + uint32_t use_ambient_light; + uint32_t use_ambient_cubemap; + uint32_t use_reflection_cubemap; + + float radiance_inverse_xform[12]; + + float shadow_atlas_pixel_size[2]; + float directional_shadow_pixel_size[2]; + + uint32_t directional_light_count; + float dual_paraboloid_side; + float z_far; + float z_near; + + uint32_t ssao_enabled; + float ssao_light_affect; + float ssao_ao_affect; + uint32_t roughness_limiter_enabled; + + float roughness_limiter_amount; + float roughness_limiter_limit; + uint32_t roughness_limiter_pad[2]; + + float ao_color[4]; + + float sdf_to_bounds[16]; + + int32_t sdf_offset[3]; + uint32_t material_uv2_mode; + + int32_t sdf_size[3]; + uint32_t gi_upscale_for_msaa; + + uint32_t volumetric_fog_enabled; + float volumetric_fog_inv_length; + float volumetric_fog_detail_spread; + uint32_t volumetric_fog_pad; + + // Fog + uint32_t fog_enabled; + float fog_density; + float fog_height; + float fog_height_density; + + float fog_light_color[3]; + float fog_sun_scatter; + + float fog_aerial_perspective; + + float time; + float reflection_multiplier; + + uint32_t pancake_shadows; + }; + + UBO ubo; + + RID uniform_buffer; + + LightmapData lightmaps[MAX_LIGHTMAPS]; + RID lightmap_ids[MAX_LIGHTMAPS]; + bool lightmap_has_sh[MAX_LIGHTMAPS]; + uint32_t lightmaps_used = 0; + uint32_t max_lightmaps; + RID lightmap_buffer; + + LightmapCaptureData *lightmap_captures; + uint32_t max_lightmap_captures; + RID lightmap_capture_buffer; + + RID giprobe_ids[MAX_GI_PROBES]; + uint32_t giprobes_used = 0; + + bool used_screen_texture = false; + bool used_normal_texture = false; + bool used_depth_texture = false; + bool used_sss = false; + + } scene_state; + + static RendererSceneRenderForward *singleton; + uint64_t render_pass; + double time; + RID default_shader; + RID default_material; + RID overdraw_material_shader; + RID overdraw_material; + RID wireframe_material_shader; + RID wireframe_material; + RID default_shader_rd; + RID default_shader_sdfgi_rd; + + RID default_vec4_xform_buffer; + RID default_vec4_xform_uniform_set; + + enum PassMode { + PASS_MODE_COLOR, + PASS_MODE_COLOR_SPECULAR, + PASS_MODE_COLOR_TRANSPARENT, + PASS_MODE_SHADOW, + PASS_MODE_SHADOW_DP, + PASS_MODE_DEPTH, + PASS_MODE_DEPTH_NORMAL_ROUGHNESS, + PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE, + PASS_MODE_DEPTH_MATERIAL, + PASS_MODE_SDF, + }; + + void _setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false); + void _setup_giprobes(const PagedArray<RID> &p_giprobes); + void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform); + + struct GeometryInstanceSurfaceDataCache; + + struct RenderListParameters { + GeometryInstanceSurfaceDataCache **elements = nullptr; + int element_count = 0; + bool reverse_cull = false; + PassMode pass_mode = PASS_MODE_COLOR; + bool no_gi = false; + RID render_pass_uniform_set; + bool force_wireframe = false; + Vector2 uv_offset; + Plane lod_plane; + float lod_distance_multiplier = 0.0; + float screen_lod_threshold = 0.0; + RD::FramebufferFormatID framebuffer_format = 0; + RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0) { + elements = p_elements; + element_count = p_element_count; + reverse_cull = p_reverse_cull; + pass_mode = p_pass_mode; + no_gi = p_no_gi; + render_pass_uniform_set = p_render_pass_uniform_set; + force_wireframe = p_force_wireframe; + uv_offset = p_uv_offset; + lod_plane = p_lod_plane; + lod_distance_multiplier = p_lod_distance_multiplier; + screen_lod_threshold = p_screen_lod_threshold; + } + }; + + template <PassMode p_pass_mode> + _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); + + void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); + + LocalVector<RD::DrawListID> thread_draw_lists; + void _render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params); + void _render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>()); + + uint32_t render_list_thread_threshold = 500; + + void _fill_render_list(const PagedArray<GeometryInstance *> &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi = false, bool p_using_opaque_gi = false); + + Map<Size2i, RID> sdfgi_framebuffer_size_cache; + + struct GeometryInstanceData; + struct GeometryInstanceForward; + + struct GeometryInstanceLightmapSH { + Color sh[9]; + }; + + // Cached data for drawing surfaces + struct GeometryInstanceSurfaceDataCache { + enum { + FLAG_PASS_DEPTH = 1, + FLAG_PASS_OPAQUE = 2, + FLAG_PASS_ALPHA = 4, + FLAG_PASS_SHADOW = 8, + FLAG_USES_SHARED_SHADOW_MATERIAL = 128, + FLAG_USES_SUBSURFACE_SCATTERING = 2048, + FLAG_USES_SCREEN_TEXTURE = 4096, + FLAG_USES_DEPTH_TEXTURE = 8192, + FLAG_USES_NORMAL_TEXTURE = 16384, + FLAG_USES_DOUBLE_SIDED_SHADOWS = 32768, + }; + + union { + struct { + uint32_t geometry_id; + uint32_t material_id; + uint32_t shader_id; + uint32_t surface_type : 4; + uint32_t uses_forward_gi : 1; //set during addition + uint32_t uses_lightmap : 1; //set during addition + uint32_t depth_layer : 4; //set during addition + uint32_t priority : 8; + }; + struct { + uint64_t sort_key1; + uint64_t sort_key2; + }; + } sort; + + RS::PrimitiveType primitive = RS::PRIMITIVE_MAX; + uint32_t flags = 0; + uint32_t surface_index = 0; + + void *surface = nullptr; + RID material_uniform_set; + ShaderData *shader = nullptr; + + void *surface_shadow = nullptr; + RID material_uniform_set_shadow; + ShaderData *shader_shadow = nullptr; + + GeometryInstanceSurfaceDataCache *next = nullptr; + GeometryInstanceForward *owner = nullptr; + }; + + struct GeometryInstanceForward : public GeometryInstance { + //used during rendering + bool mirror = false; + bool non_uniform_scale = false; + float lod_bias = 0.0; + float lod_model_scale = 1.0; + AABB transformed_aabb; //needed for LOD + float depth = 0; + struct PushConstant { + float transform[16]; + uint32_t flags; + uint32_t instance_uniforms_ofs; //base offset in global buffer for instance variables + uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap index) + uint32_t layer_mask; + float lightmap_uv_scale[4]; + } push_constant; + RID transforms_uniform_set; + uint32_t instance_count = 0; + RID mesh_instance; + bool can_sdfgi = false; + //used during setup + uint32_t base_flags = 0; + RID gi_probes[MAX_GI_PROBES_PER_INSTANCE]; + RID lightmap_instance; + GeometryInstanceLightmapSH *lightmap_sh = nullptr; + GeometryInstanceSurfaceDataCache *surface_caches = nullptr; + SelfList<GeometryInstanceForward> dirty_list_element; + + struct Data { + //data used less often goes into regular heap + RID base; + RS::InstanceType base_type; + + RID skeleton; + + uint32_t layer_mask = 1; + + Vector<RID> surface_materials; + RID material_override; + Transform transform; + AABB aabb; + int32_t shader_parameters_offset = -1; + + bool use_dynamic_gi = false; + bool use_baked_light = false; + bool cast_double_sided_shaodows = false; + bool mirror = false; + Rect2 lightmap_uv_scale; + uint32_t lightmap_slice_index = 0; + bool dirty_dependencies = false; + + RendererStorage::DependencyTracker dependency_tracker; + }; + + Data *data = nullptr; + + GeometryInstanceForward() : + dirty_list_element(this) {} + }; + + static void _geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker); + static void _geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker); + + SelfList<GeometryInstanceForward>::List geometry_instance_dirty_list; + + PagedAllocator<GeometryInstanceForward> geometry_instance_alloc; + PagedAllocator<GeometryInstanceSurfaceDataCache> geometry_instance_surface_alloc; + PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh; + + void _geometry_instance_add_surface_with_material(GeometryInstanceForward *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh); + void _geometry_instance_add_surface(GeometryInstanceForward *ginstance, uint32_t p_surface, RID p_material, RID p_mesh); + void _geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance); + void _geometry_instance_update(GeometryInstance *p_geometry_instance); + void _update_dirty_geometry_instances(); + + bool low_end = false; + + /* Render List */ + + struct RenderList { + int max_elements; + + GeometryInstanceSurfaceDataCache **elements = nullptr; + + int element_count; + int alpha_element_count; + + void clear() { + element_count = 0; + alpha_element_count = 0; + } + + //should eventually be replaced by radix + + struct SortByKey { + _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { + return (A->sort.sort_key2 == B->sort.sort_key2) ? (A->sort.sort_key1 < B->sort.sort_key1) : (A->sort.sort_key2 < B->sort.sort_key2); + } + }; + + void sort_by_key(bool p_alpha) { + SortArray<GeometryInstanceSurfaceDataCache *, SortByKey> sorter; + if (p_alpha) { + sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); + } else { + sorter.sort(elements, element_count); + } + } + + struct SortByDepth { + _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { + return (A->owner->depth < B->owner->depth); + } + }; + + void sort_by_depth(bool p_alpha) { //used for shadows + + SortArray<GeometryInstanceSurfaceDataCache *, SortByDepth> sorter; + if (p_alpha) { + sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); + } else { + sorter.sort(elements, element_count); + } + } + + struct SortByReverseDepthAndPriority { + _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { + return (A->sort.priority == B->sort.priority) ? (A->owner->depth > B->owner->depth) : (A->sort.priority < B->sort.priority); + } + }; + + void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha + + SortArray<GeometryInstanceSurfaceDataCache *, SortByReverseDepthAndPriority> sorter; + if (p_alpha) { + sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); + } else { + sorter.sort(elements, element_count); + } + } + + _FORCE_INLINE_ void add_element(GeometryInstanceSurfaceDataCache *p_element) { + if (element_count + alpha_element_count >= max_elements) { + return; + } + elements[element_count] = p_element; + element_count++; + } + + _FORCE_INLINE_ void add_alpha_element(GeometryInstanceSurfaceDataCache *p_element) { + if (element_count + alpha_element_count >= max_elements) { + return; + } + int idx = max_elements - alpha_element_count - 1; + elements[idx] = p_element; + alpha_element_count++; + } + + void init() { + element_count = 0; + alpha_element_count = 0; + elements = memnew_arr(GeometryInstanceSurfaceDataCache *, max_elements); + } + + RenderList() { + max_elements = 0; + } + + ~RenderList() { + memdelete_arr(elements); + } + }; + + RenderList render_list; + +protected: + virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, int p_directional_light_count, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_lod_threshold); + virtual void _render_shadow(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true); + virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region); + virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region); + virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture); + virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances); + +public: + virtual GeometryInstance *geometry_instance_create(RID p_base); + virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton); + virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override); + virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials); + virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance); + virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb); + virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask); + virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias); + virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable); + virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable); + virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index); + virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9); + virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset); + virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable); + + virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance); + virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance); + + virtual void geometry_instance_free(GeometryInstance *p_geometry_instance); + + virtual uint32_t geometry_instance_get_pair_mask(); + virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count); + virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count); + virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count); + virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count); + + virtual void set_time(double p_time, double p_step); + + virtual bool free(RID p_rid); + + RendererSceneRenderForward(RendererStorageRD *p_storage); + ~RendererSceneRenderForward(); +}; +#endif // RASTERIZER_SCENE_HIGHEND_RD_H diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 0cae141138..1461be8088 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_scene_rd.cpp */ +/* renderer_scene_render_rd.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,14 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rasterizer_scene_rd.h" +#include "renderer_scene_render_rd.h" +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" -#include "rasterizer_rd.h" -#include "servers/rendering/rendering_server_raster.h" +#include "renderer_compositor_rd.h" +#include "servers/rendering/rendering_server_default.h" -uint64_t RasterizerSceneRD::auto_exposure_counter = 2; +uint64_t RendererSceneRenderRD::auto_exposure_counter = 2; void get_vogel_disk(float *r_kernel, int p_sample_count) { const float golden_angle = 2.4; @@ -49,7 +49,7 @@ void get_vogel_disk(float *r_kernel, int p_sample_count) { } } -void RasterizerSceneRD::_clear_reflection_data(ReflectionData &rd) { +void RendererSceneRenderRD::_clear_reflection_data(ReflectionData &rd) { rd.layers.clear(); rd.radiance_base_cubemap = RID(); if (rd.downsampled_radiance_cubemap.is_valid()) { @@ -60,7 +60,7 @@ void RasterizerSceneRD::_clear_reflection_data(ReflectionData &rd) { rd.coefficient_buffer = RID(); } -void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality) { +void RendererSceneRenderRD::_update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality) { //recreate radiance and all data int mipmaps = p_mipmaps; @@ -129,7 +129,7 @@ void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size, tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; tf.width = 64; // Always 64x64 tf.height = 64; - tf.type = RD::TEXTURE_TYPE_CUBE; + tf.texture_type = RD::TEXTURE_TYPE_CUBE; tf.array_layers = 6; tf.mipmaps = 7; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; @@ -151,7 +151,7 @@ void RasterizerSceneRD::_update_reflection_data(ReflectionData &rd, int p_size, } } -void RasterizerSceneRD::_create_reflection_fast_filter(ReflectionData &rd, bool p_use_arrays) { +void RendererSceneRenderRD::_create_reflection_fast_filter(ReflectionData &rd, bool p_use_arrays) { storage->get_effects()->cubemap_downsample(rd.radiance_base_cubemap, rd.downsampled_layer.mipmaps[0].view, rd.downsampled_layer.mipmaps[0].size); for (int i = 1; i < rd.downsampled_layer.mipmaps.size(); i++) { @@ -172,7 +172,7 @@ void RasterizerSceneRD::_create_reflection_fast_filter(ReflectionData &rd, bool storage->get_effects()->cubemap_filter(rd.downsampled_radiance_cubemap, views, p_use_arrays); } -void RasterizerSceneRD::_create_reflection_importance_sample(ReflectionData &rd, bool p_use_arrays, int p_cube_side, int p_base_layer) { +void RendererSceneRenderRD::_create_reflection_importance_sample(ReflectionData &rd, bool p_use_arrays, int p_cube_side, int p_base_layer) { if (p_use_arrays) { //render directly to the layers storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, rd.layers[p_base_layer].views[0], p_cube_side, sky_ggx_samples_quality, float(p_base_layer) / (rd.layers.size() - 1.0), rd.layers[p_base_layer].mipmaps[0].size.x); @@ -181,20 +181,18 @@ void RasterizerSceneRD::_create_reflection_importance_sample(ReflectionData &rd, } } -void RasterizerSceneRD::_update_reflection_mipmaps(ReflectionData &rd, int p_start, int p_end) { +void RendererSceneRenderRD::_update_reflection_mipmaps(ReflectionData &rd, int p_start, int p_end) { for (int i = p_start; i < p_end; i++) { - for (int j = 0; j < rd.layers[i].mipmaps.size() - 1; j++) { - for (int k = 0; k < 6; k++) { - RID view = rd.layers[i].mipmaps[j].views[k]; - RID texture = rd.layers[i].mipmaps[j + 1].views[k]; - Size2i size = rd.layers[i].mipmaps[j + 1].size; - storage->get_effects()->make_mipmap(view, texture, size); - } + for (int j = 0; j < rd.layers[i].views.size() - 1; j++) { + RID view = rd.layers[i].views[j]; + RID texture = rd.layers[i].views[j + 1]; + Size2i size = rd.layers[i].mipmaps[j + 1].size; + storage->get_effects()->cubemap_downsample(view, texture, size); } } } -void RasterizerSceneRD::_sdfgi_erase(RenderBuffers *rb) { +void RendererSceneRenderRD::_sdfgi_erase(RenderBuffers *rb) { for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { const SDFGI::Cascade &c = rb->sdfgi->cascades[i]; RD::get_singleton()->free(c.light_data); @@ -236,9 +234,9 @@ void RasterizerSceneRD::_sdfgi_erase(RenderBuffers *rb) { rb->sdfgi = nullptr; } -const Vector3i RasterizerSceneRD::SDFGI::Cascade::DIRTY_ALL = Vector3i(0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF); +const Vector3i RendererSceneRenderRD::SDFGI::Cascade::DIRTY_ALL = Vector3i(0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF); -void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) { +void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) { Environment *env = environment_owner.getornull(p_environment); RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); bool needs_sdfgi = env && env->sdfgi_enabled; @@ -284,7 +282,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co tf_sdf.width = sdfgi->cascade_size; // Always 64x64 tf_sdf.height = sdfgi->cascade_size; tf_sdf.depth = sdfgi->cascade_size; - tf_sdf.type = RD::TEXTURE_TYPE_3D; + tf_sdf.texture_type = RD::TEXTURE_TYPE_3D; tf_sdf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; { @@ -341,7 +339,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co tf_probes.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count; tf_probes.height = sdfgi->probe_axis_count * SDFGI::SH_SIZE; tf_probes.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; - tf_probes.type = RD::TEXTURE_TYPE_2D_ARRAY; + tf_probes.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; sdfgi->history_size = requested_history_size; @@ -351,8 +349,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co RD::TextureFormat tf_probe_average = tf_probes; tf_probe_average.format = RD::DATA_FORMAT_R32G32B32A32_SINT; //signed integer because SH are signed - tf_probe_average.type = RD::TEXTURE_TYPE_2D_ARRAY; - tf_probe_average.array_layers = 1; + tf_probe_average.texture_type = RD::TEXTURE_TYPE_2D; sdfgi->lightprobe_history_scroll = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView()); sdfgi->lightprobe_average_scroll = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView()); @@ -379,7 +376,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co tf_ambient.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; //pack well with RGBE tf_ambient.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count; tf_ambient.height = sdfgi->probe_axis_count; - tf_ambient.type = RD::TEXTURE_TYPE_2D_ARRAY; + tf_ambient.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; //lightprobe texture is an octahedral texture sdfgi->ambient_texture = RD::get_singleton()->texture_create(tf_ambient, RD::TextureView()); } @@ -444,21 +441,21 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_sdf[(passes & 1) ? 1 : 0]); //if passes are even, we read from buffer 0, else we read from buffer 1 uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; for (int j = 0; j < 8; j++) { u.ids.push_back(sdfgi->render_occlusion[j]); @@ -467,21 +464,21 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 4; u.ids.push_back(sdfgi->render_emission); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; u.ids.push_back(sdfgi->render_emission_aniso); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 6; u.ids.push_back(sdfgi->render_geom_facing); uniforms.push_back(u); @@ -489,28 +486,28 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 7; u.ids.push_back(cascade.sdf_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 8; u.ids.push_back(sdfgi->occlusion_data); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 10; u.ids.push_back(cascade.solid_cell_dispatch_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 11; u.ids.push_back(cascade.solid_cell_buffer); uniforms.push_back(u); @@ -523,42 +520,42 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_geom_facing); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; u.ids.push_back(sdfgi->render_emission); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 4; u.ids.push_back(sdfgi->render_emission_aniso); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 5; u.ids.push_back(cascade.solid_cell_dispatch_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 6; u.ids.push_back(cascade.solid_cell_buffer); uniforms.push_back(u); @@ -570,7 +567,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; for (int j = 0; j < 8; j++) { u.ids.push_back(sdfgi->render_occlusion[j]); @@ -579,7 +576,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->occlusion_data); uniforms.push_back(u); @@ -597,12 +594,12 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (j < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[j].sdf_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -610,63 +607,63 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(cascade.solid_cell_dispatch_buffer); uniforms.push_back(u); } { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(cascade.solid_cell_buffer); uniforms.push_back(u); } { RD::Uniform u; u.binding = 5; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.ids.push_back(cascade.light_data); uniforms.push_back(u); } { RD::Uniform u; u.binding = 6; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.ids.push_back(cascade.light_aniso_0_tex); uniforms.push_back(u); } { RD::Uniform u; u.binding = 7; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.ids.push_back(cascade.light_aniso_1_tex); uniforms.push_back(u); } { RD::Uniform u; u.binding = 8; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(rb->sdfgi->cascades_ubo); uniforms.push_back(u); } { RD::Uniform u; u.binding = 9; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(cascade.lights_buffer); uniforms.push_back(u); } { RD::Uniform u; u.binding = 10; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->sdfgi->lightprobe_texture); uniforms.push_back(u); } @@ -679,14 +676,14 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_sdf[0]); uniforms.push_back(u); @@ -699,14 +696,14 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_sdf_half[0]); uniforms.push_back(u); @@ -720,14 +717,14 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_sdf[0]); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_sdf[1]); uniforms.push_back(u); @@ -742,14 +739,14 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_sdf_half[0]); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_sdf_half[1]); uniforms.push_back(u); @@ -765,21 +762,21 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; u.ids.push_back(sdfgi->render_sdf_half[(passes & 1) ? 0 : 1]); //reverse pass order because half size uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; u.ids.push_back(sdfgi->render_sdf[(passes & 1) ? 0 : 1]); //reverse pass order because it needs an extra JFA pass uniforms.push_back(u); @@ -794,14 +791,14 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 1; u.ids.push_back(sdfgi->render_albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 2; for (int i = 0; i < 8; i++) { u.ids.push_back(sdfgi->render_occlusion[i]); @@ -810,7 +807,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; u.ids.push_back(sdfgi->render_geom_facing); uniforms.push_back(u); @@ -827,12 +824,12 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (j < sdfgi->cascades.size()) { u.ids.push_back(sdfgi->cascades[j].sdf_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -840,12 +837,12 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (j < sdfgi->cascades.size()) { u.ids.push_back(sdfgi->cascades[j].light_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -853,12 +850,12 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (j < sdfgi->cascades.size()) { u.ids.push_back(sdfgi->cascades[j].light_aniso_0_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -866,19 +863,19 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (j < sdfgi->cascades.size()) { u.ids.push_back(sdfgi->cascades[j].light_aniso_1_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 6; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -886,14 +883,14 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 7; u.ids.push_back(sdfgi->cascades_ubo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 8; u.ids.push_back(sdfgi->lightprobe_data); uniforms.push_back(u); @@ -901,14 +898,14 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 9; u.ids.push_back(sdfgi->cascades[i].lightprobe_history_tex); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 10; u.ids.push_back(sdfgi->cascades[i].lightprobe_average_tex); uniforms.push_back(u); @@ -916,21 +913,21 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 11; u.ids.push_back(sdfgi->lightprobe_history_scroll); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 12; u.ids.push_back(sdfgi->lightprobe_average_scroll); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 13; RID parent_average; if (i < sdfgi->cascades.size() - 1) { @@ -943,7 +940,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 14; u.ids.push_back(sdfgi->ambient_texture); uniforms.push_back(u); @@ -1022,7 +1019,7 @@ void RasterizerSceneRD::sdfgi_update(RID p_render_buffers, RID p_environment, co } } -int RasterizerSceneRD::sdfgi_get_pending_region_count(RID p_render_buffers) const { +int RendererSceneRenderRD::sdfgi_get_pending_region_count(RID p_render_buffers) const { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(rb == nullptr, 0); @@ -1049,7 +1046,7 @@ int RasterizerSceneRD::sdfgi_get_pending_region_count(RID p_render_buffers) cons return dirty_count; } -int RasterizerSceneRD::_sdfgi_get_pending_region_data(RID p_render_buffers, int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const { +int RendererSceneRenderRD::_sdfgi_get_pending_region_data(RID p_render_buffers, int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(rb == nullptr, -1); ERR_FAIL_COND_V(rb->sdfgi == nullptr, -1); @@ -1109,7 +1106,7 @@ int RasterizerSceneRD::_sdfgi_get_pending_region_data(RID p_render_buffers, int return -1; } -AABB RasterizerSceneRD::sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const { +AABB RendererSceneRenderRD::sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const { AABB bounds; Vector3i from; Vector3i size; @@ -1119,7 +1116,7 @@ AABB RasterizerSceneRD::sdfgi_get_pending_region_bounds(RID p_render_buffers, in return bounds; } -uint32_t RasterizerSceneRD::sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const { +uint32_t RendererSceneRenderRD::sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const { AABB bounds; Vector3i from; Vector3i size; @@ -1127,7 +1124,7 @@ uint32_t RasterizerSceneRD::sdfgi_get_pending_region_cascade(RID p_render_buffer return _sdfgi_get_pending_region_data(p_render_buffers, p_region, from, size, bounds); } -void RasterizerSceneRD::_sdfgi_update_cascades(RID p_render_buffers) { +void RendererSceneRenderRD::_sdfgi_update_cascades(RID p_render_buffers) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(rb == nullptr); if (rb->sdfgi == nullptr) { @@ -1151,10 +1148,10 @@ void RasterizerSceneRD::_sdfgi_update_cascades(RID p_render_buffers) { cascade_data[i].pad = 0; } - RD::get_singleton()->buffer_update(rb->sdfgi->cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data, true); + RD::get_singleton()->buffer_update(rb->sdfgi->cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data); } -void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environment, const RID *p_directional_light_instances, uint32_t p_directional_light_count, const RID *p_positional_light_instances, uint32_t p_positional_light_count) { +void RendererSceneRenderRD::sdfgi_update_probes(RID p_render_buffers, RID p_environment, const Vector<RID> &p_directional_lights, const RID *p_positional_light_instances, uint32_t p_positional_light_count) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(rb == nullptr); if (rb->sdfgi == nullptr) { @@ -1180,13 +1177,18 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm SDGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS]; uint32_t idx = 0; - for (uint32_t j = 0; j < p_directional_light_count; j++) { + for (uint32_t j = 0; j < (uint32_t)p_directional_lights.size(); j++) { if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) { break; } - LightInstance *li = light_instance_owner.getornull(p_directional_light_instances[j]); + LightInstance *li = light_instance_owner.getornull(p_directional_lights[j]); ERR_CONTINUE(!li); + + if (storage->light_directional_is_sky_only(li->light)) { + continue; + } + Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z); dir.y *= rb->sdfgi->y_mult; dir.normalize(); @@ -1255,7 +1257,7 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm } if (idx > 0) { - RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights, true); + RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights); } cascade_light_count[i] = idx; @@ -1274,14 +1276,26 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm push_constant.multibounce = rb->sdfgi->uses_multibounce; push_constant.y_mult = rb->sdfgi->y_mult; - push_constant.process_offset = 0; - push_constant.process_increment = 1; - for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) { SDFGI::Cascade &cascade = rb->sdfgi->cascades[i]; push_constant.light_count = cascade_light_count[i]; push_constant.cascade = i; + if (rb->sdfgi->cascades[i].all_dynamic_lights_dirty || sdfgi_frames_to_update_light == RS::ENV_SDFGI_UPDATE_LIGHT_IN_1_FRAME) { + push_constant.process_offset = 0; + push_constant.process_increment = 1; + } else { + static uint32_t frames_to_update_table[RS::ENV_SDFGI_UPDATE_LIGHT_MAX] = { + 1, 2, 4, 8, 16 + }; + + uint32_t frames_to_update = frames_to_update_table[sdfgi_frames_to_update_light]; + + push_constant.process_offset = RSG::rasterizer->get_frame_number() % frames_to_update; + push_constant.process_increment = frames_to_update; + } + rb->sdfgi->cascades[i].all_dynamic_lights_dirty = false; + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascade.sdf_direct_light_uniform_set, 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::DirectLightPushConstant)); RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascade.solid_cell_dispatch_buffer, 0); @@ -1299,7 +1313,7 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm push_constant.probe_axis_size = rb->sdfgi->probe_axis_count; push_constant.history_index = rb->sdfgi->render_pass % rb->sdfgi->history_size; push_constant.history_size = rb->sdfgi->history_size; - static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 8, 16, 32, 64, 96, 128 }; + static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 4, 8, 16, 32, 64, 96, 128 }; push_constant.ray_count = ray_count[sdfgi_ray_count]; push_constant.ray_bias = rb->sdfgi->probe_bias; push_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count; @@ -1334,7 +1348,7 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; u.ids.push_back(sky->radiance); uniforms.push_back(u); @@ -1342,7 +1356,7 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 1; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -1398,7 +1412,7 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm RENDER_TIMESTAMP("<SDFGI Update Probes"); } -void RasterizerSceneRD::_setup_giprobes(RID p_render_buffers, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, uint32_t &r_gi_probes_used) { +void RendererSceneRenderRD::_setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used) { r_gi_probes_used = 0; RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(rb == nullptr); @@ -1413,8 +1427,8 @@ void RasterizerSceneRD::_setup_giprobes(RID p_render_buffers, const Transform &p for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) { RID texture; - if (i < p_gi_probe_cull_count) { - GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_gi_probe_cull_result[i]); + if (i < (int)p_gi_probes.size()) { + GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_gi_probes[i]); if (gipi) { texture = gipi->texture; @@ -1461,7 +1475,7 @@ void RasterizerSceneRD::_setup_giprobes(RID p_render_buffers, const Transform &p } if (texture == RID()) { - texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); } if (texture != rb->giprobe_textures[i]) { @@ -1471,7 +1485,9 @@ void RasterizerSceneRD::_setup_giprobes(RID p_render_buffers, const Transform &p } if (giprobes_changed) { - RD::get_singleton()->free(rb->gi_uniform_set); + if (RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) { + RD::get_singleton()->free(rb->gi_uniform_set); + } rb->gi_uniform_set = RID(); if (rb->volumetric_fog) { if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { @@ -1483,18 +1499,40 @@ void RasterizerSceneRD::_setup_giprobes(RID p_render_buffers, const Transform &p } } - if (p_gi_probe_cull_count > 0) { - RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GI::GIProbeData) * MIN(RenderBuffers::MAX_GIPROBES, p_gi_probe_cull_count), gi_probe_data, true); + if (p_gi_probes.size() > 0) { + RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GI::GIProbeData) * MIN((uint64_t)RenderBuffers::MAX_GIPROBES, p_gi_probes.size()), gi_probe_data); } } -void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_ambient_buffer, RID p_reflection_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count) { +void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes) { RENDER_TIMESTAMP("Render GI"); RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(rb == nullptr); Environment *env = environment_owner.getornull(p_environment); + if (rb->ambient_buffer.is_null() || rb->using_half_size_gi != gi.half_resolution) { + if (rb->ambient_buffer.is_valid()) { + RD::get_singleton()->free(rb->ambient_buffer); + RD::get_singleton()->free(rb->reflection_buffer); + } + + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.width = rb->width; + tf.height = rb->height; + if (gi.half_resolution) { + tf.width >>= 1; + tf.height >>= 1; + } + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb->reflection_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); + rb->ambient_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); + rb->using_half_size_gi = gi.half_resolution; + + _render_buffers_uniform_set_changed(p_render_buffers); + } + GI::PushConstant push_constant; push_constant.screen_size[0] = rb->width; @@ -1506,9 +1544,11 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness push_constant.proj_info[1] = -2.0f / (rb->height * p_projection.matrix[1][1]); push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0]; push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1]; - push_constant.max_giprobes = MIN(RenderBuffers::MAX_GIPROBES, p_gi_probe_cull_count); + push_constant.max_giprobes = MIN((uint64_t)RenderBuffers::MAX_GIPROBES, p_gi_probes.size()); push_constant.high_quality_vct = gi_probe_quality == RS::GI_PROBE_QUALITY_HIGH; - push_constant.use_sdfgi = rb->sdfgi != nullptr; + + bool use_sdfgi = rb->sdfgi != nullptr; + bool use_giprobes = push_constant.max_giprobes > 0; if (env) { push_constant.ao_color[0] = env->ao_color.r; @@ -1600,7 +1640,7 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness c.to_cell = 1.0 / rb->sdfgi->cascades[i].cell_size; } - RD::get_singleton()->buffer_update(gi.sdfgi_ubo, 0, sizeof(GI::SDFGIData), &sdfgi_data, true); + RD::get_singleton()->buffer_update(gi.sdfgi_ubo, 0, sizeof(GI::SDFGIData), &sdfgi_data); } if (rb->gi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) { @@ -1608,12 +1648,12 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness { RD::Uniform u; u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[j].sdf_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -1621,12 +1661,12 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[j].light_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -1634,12 +1674,12 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_0_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -1647,37 +1687,37 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) { if (rb->sdfgi && j < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_1_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 5; if (rb->sdfgi) { u.ids.push_back(rb->sdfgi->occlusion_texture); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 6; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 7; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -1685,70 +1725,70 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 9; - u.ids.push_back(p_ambient_buffer); + u.ids.push_back(rb->ambient_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 10; - u.ids.push_back(p_reflection_buffer); + u.ids.push_back(rb->reflection_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 11; if (rb->sdfgi) { u.ids.push_back(rb->sdfgi->lightprobe_texture); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE)); } uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 12; u.ids.push_back(rb->depth_texture); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 13; u.ids.push_back(p_normal_roughness_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 14; - RID buffer = p_gi_probe_buffer.is_valid() ? p_gi_probe_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK); + RID buffer = p_gi_probe_buffer.is_valid() ? p_gi_probe_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 15; u.ids.push_back(gi.sdfgi_ubo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 16; u.ids.push_back(rb->giprobe_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 17; for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) { u.ids.push_back(rb->giprobe_textures[i]); @@ -1759,19 +1799,31 @@ void RasterizerSceneRD::_process_gi(RID p_render_buffers, RID p_normal_roughness rb->gi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi.shader.version_get_shader(gi.shader_version, 0), 0); } + GI::Mode mode; + + if (rb->using_half_size_gi) { + mode = (use_sdfgi && use_giprobes) ? GI::MODE_HALF_RES_COMBINED : (use_sdfgi ? GI::MODE_HALF_RES_SDFGI : GI::MODE_HALF_RES_GIPROBE); + } else { + mode = (use_sdfgi && use_giprobes) ? GI::MODE_COMBINED : (use_sdfgi ? GI::MODE_SDFGI : GI::MODE_GIPROBE); + } RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi.pipelines[0]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi.pipelines[mode]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->gi_uniform_set, 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GI::PushConstant)); - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1, 8, 8, 1); + + if (rb->using_half_size_gi) { + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width >> 1, rb->height >> 1, 1, 8, 8, 1); + } else { + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1, 8, 8, 1); + } RD::get_singleton()->compute_list_end(); } -RID RasterizerSceneRD::sky_create() { +RID RendererSceneRenderRD::sky_create() { return sky_owner.make_rid(Sky()); } -void RasterizerSceneRD::_sky_invalidate(Sky *p_sky) { +void RendererSceneRenderRD::_sky_invalidate(Sky *p_sky) { if (!p_sky->dirty) { p_sky->dirty = true; p_sky->dirty_list = dirty_sky_list; @@ -1779,7 +1831,7 @@ void RasterizerSceneRD::_sky_invalidate(Sky *p_sky) { } } -void RasterizerSceneRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) { +void RendererSceneRenderRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) { Sky *sky = sky_owner.getornull(p_sky); ERR_FAIL_COND(!sky); ERR_FAIL_COND(p_radiance_size < 32 || p_radiance_size > 2048); @@ -1801,7 +1853,7 @@ void RasterizerSceneRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) { _clear_reflection_data(sky->reflection); } -void RasterizerSceneRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) { +void RendererSceneRenderRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) { Sky *sky = sky_owner.getornull(p_sky); ERR_FAIL_COND(!sky); @@ -1824,14 +1876,14 @@ void RasterizerSceneRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) { _clear_reflection_data(sky->reflection); } -void RasterizerSceneRD::sky_set_material(RID p_sky, RID p_material) { +void RendererSceneRenderRD::sky_set_material(RID p_sky, RID p_material) { Sky *sky = sky_owner.getornull(p_sky); ERR_FAIL_COND(!sky); sky->material = p_material; _sky_invalidate(sky); } -Ref<Image> RasterizerSceneRD::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) { +Ref<Image> RendererSceneRenderRD::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) { Sky *sky = sky_owner.getornull(p_sky); ERR_FAIL_COND_V(!sky, Ref<Image>()); @@ -1867,7 +1919,7 @@ Ref<Image> RasterizerSceneRD::sky_bake_panorama(RID p_sky, float p_energy, bool return Ref<Image>(); } -void RasterizerSceneRD::_update_dirty_skys() { +void RendererSceneRenderRD::_update_dirty_skys() { Sky *sky = dirty_sky_list; while (sky) { @@ -1891,7 +1943,7 @@ void RasterizerSceneRD::_update_dirty_skys() { RD::TextureFormat tf; tf.array_layers = layers * 6; tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; tf.mipmaps = mipmaps; tf.width = w; tf.height = h; @@ -1906,7 +1958,7 @@ void RasterizerSceneRD::_update_dirty_skys() { RD::TextureFormat tf; tf.array_layers = 6; tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.type = RD::TEXTURE_TYPE_CUBE; + tf.texture_type = RD::TEXTURE_TYPE_CUBE; tf.mipmaps = MIN(mipmaps, layers); tf.width = w; tf.height = h; @@ -1926,7 +1978,7 @@ void RasterizerSceneRD::_update_dirty_skys() { tformat.width = sky->screen_size.x / 2; tformat.height = sky->screen_size.y / 2; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - tformat.type = RD::TEXTURE_TYPE_2D; + tformat.texture_type = RD::TEXTURE_TYPE_2D; sky->half_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView()); Vector<RID> texs; @@ -1941,7 +1993,7 @@ void RasterizerSceneRD::_update_dirty_skys() { tformat.width = sky->screen_size.x / 4; tformat.height = sky->screen_size.y / 4; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - tformat.type = RD::TEXTURE_TYPE_2D; + tformat.texture_type = RD::TEXTURE_TYPE_2D; sky->quarter_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView()); Vector<RID> texs; @@ -1971,14 +2023,14 @@ void RasterizerSceneRD::_update_dirty_skys() { dirty_sky_list = nullptr; } -RID RasterizerSceneRD::sky_get_radiance_texture_rd(RID p_sky) const { +RID RendererSceneRenderRD::sky_get_radiance_texture_rd(RID p_sky) const { Sky *sky = sky_owner.getornull(p_sky); ERR_FAIL_COND_V(!sky, RID()); return sky->radiance; } -RID RasterizerSceneRD::sky_get_radiance_uniform_set_rd(RID p_sky, RID p_shader, int p_set) const { +RID RendererSceneRenderRD::sky_get_radiance_uniform_set_rd(RID p_sky, RID p_shader, int p_set) const { Sky *sky = sky_owner.getornull(p_sky); ERR_FAIL_COND_V(!sky, RID()); @@ -1988,7 +2040,7 @@ RID RasterizerSceneRD::sky_get_radiance_uniform_set_rd(RID p_sky, RID p_shader, Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; u.ids.push_back(sky->radiance); uniforms.push_back(u); @@ -2001,25 +2053,25 @@ RID RasterizerSceneRD::sky_get_radiance_uniform_set_rd(RID p_sky, RID p_shader, return sky->uniform_set; } -RID RasterizerSceneRD::_get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_version) { +RID RendererSceneRenderRD::_get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_version) { if (p_sky->texture_uniform_sets[p_version].is_valid() && RD::get_singleton()->uniform_set_is_valid(p_sky->texture_uniform_sets[p_version])) { return p_sky->texture_uniform_sets[p_version]; } Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; if (p_sky->radiance.is_valid() && p_version <= SKY_TEXTURE_SET_QUARTER_RES) { u.ids.push_back(p_sky->radiance); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); } uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; // half res if (p_sky->half_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_HALF_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_HALF_RES) { if (p_version >= SKY_TEXTURE_SET_CUBEMAP) { @@ -2029,16 +2081,16 @@ RID RasterizerSceneRD::_get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_vers } } else { if (p_version < SKY_TEXTURE_SET_CUBEMAP) { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); } } uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; // quarter res if (p_sky->quarter_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_QUARTER_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES) { if (p_version >= SKY_TEXTURE_SET_CUBEMAP) { @@ -2048,9 +2100,9 @@ RID RasterizerSceneRD::_get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_vers } } else { if (p_version < SKY_TEXTURE_SET_CUBEMAP) { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); } } uniforms.push_back(u); @@ -2060,14 +2112,14 @@ RID RasterizerSceneRD::_get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_vers return p_sky->texture_uniform_sets[p_version]; } -RID RasterizerSceneRD::sky_get_material(RID p_sky) const { +RID RendererSceneRenderRD::sky_get_material(RID p_sky) const { Sky *sky = sky_owner.getornull(p_sky); ERR_FAIL_COND_V(!sky, RID()); return sky->material; } -void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) { +void RendererSceneRenderRD::_draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) { ERR_FAIL_COND(!is_environment(p_environment)); SkyMaterialData *material = nullptr; @@ -2083,7 +2135,7 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue sky_material = sky_get_material(environment_get_sky(p_environment)); if (sky_material.is_valid()) { - material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); if (!material || !material->shader_data->valid) { material = nullptr; } @@ -2091,13 +2143,13 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue if (!material) { sky_material = sky_shader.default_material; - material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); } } if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) { sky_material = sky_scene_state.fog_material; - material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); } ERR_FAIL_COND(!material); @@ -2128,7 +2180,7 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue sky_transform = p_transform.basis * sky_transform; if (shader_data->uses_quarter_res) { - RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_QUARTER_RES]; + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_QUARTER_RES]; RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_QUARTER_RES); @@ -2141,7 +2193,7 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue } if (shader_data->uses_half_res) { - RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_HALF_RES]; + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_HALF_RES]; RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_HALF_RES); @@ -2153,7 +2205,7 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue RD::get_singleton()->draw_list_end(); } - RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND]; + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND]; RID texture_uniform_set; if (sky) { @@ -2167,7 +2219,7 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue RD::get_singleton()->draw_list_end(); } -void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size) { +void RendererSceneRenderRD::_setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size) { ERR_FAIL_COND(!is_environment(p_environment)); SkyMaterialData *material = nullptr; @@ -2185,7 +2237,7 @@ void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, cons sky_material = sky_get_material(environment_get_sky(p_environment)); if (sky_material.is_valid()) { - material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); if (!material || !material->shader_data->valid) { material = nullptr; } @@ -2193,7 +2245,7 @@ void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, cons if (!material) { sky_material = sky_shader.default_material; - material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); } ERR_FAIL_COND(!material); @@ -2236,7 +2288,7 @@ void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, cons if (shader_data->uses_time && time - sky->prev_time > 0.00001) { sky->prev_time = time; sky->reflection.dirty = true; - RenderingServerRaster::redraw_request(); + RenderingServerDefault::redraw_request(); } if (material != sky->prev_material) { @@ -2282,9 +2334,9 @@ void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, cons } if (light_data_dirty) { - RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights, true); + RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights); - RasterizerSceneRD::SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights; + RendererSceneRenderRD::SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights; sky_scene_state.last_frame_directional_lights = sky_scene_state.directional_lights; sky_scene_state.directional_lights = temp; sky_scene_state.last_frame_directional_light_count = sky_scene_state.ubo.directional_light_count; @@ -2334,10 +2386,10 @@ void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, cons sky_scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy; sky_scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_environment); - RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo, true); + RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo); } -void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) { +void RendererSceneRenderRD::_update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) { ERR_FAIL_COND(!is_environment(p_environment)); Sky *sky = sky_owner.getornull(environment_get_sky(p_environment)); @@ -2348,7 +2400,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro SkyMaterialData *material = nullptr; if (sky_material.is_valid()) { - material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); if (!material || !material->shader_data->valid) { material = nullptr; } @@ -2356,7 +2408,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro if (!material) { sky_material = sky_shader.default_material; - material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY); + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); } ERR_FAIL_COND(!material); @@ -2417,7 +2469,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro cm = correction * cm; if (shader_data->uses_quarter_res) { - RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES]; + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES]; Vector<Color> clear_colors; clear_colors.push_back(Color(0.0, 0.0, 0.0)); @@ -2435,7 +2487,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro } if (shader_data->uses_half_res) { - RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES]; + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES]; Vector<Color> clear_colors; clear_colors.push_back(Color(0.0, 0.0, 0.0)); @@ -2453,7 +2505,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro } RD::DrawListID cubemap_draw_list; - RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP]; + PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP]; for (int i = 0; i < 6; i++) { Transform local_view; @@ -2504,7 +2556,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro /* SKY SHADER */ -void RasterizerSceneRD::SkyShaderData::set_code(const String &p_code) { +void RendererSceneRenderRD::SkyShaderData::set_code(const String &p_code) { //compile code = p_code; @@ -2553,7 +2605,7 @@ void RasterizerSceneRD::SkyShaderData::set_code(const String &p_code) { actions.uniforms = &uniforms; - RasterizerSceneRD *scene_singleton = (RasterizerSceneRD *)RasterizerSceneRD::singleton; + RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; Error err = scene_singleton->sky_shader.compiler.compile(RS::SHADER_SKY, code, &actions, path, gen_code); @@ -2598,7 +2650,7 @@ void RasterizerSceneRD::SkyShaderData::set_code(const String &p_code) { valid = true; } -void RasterizerSceneRD::SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { +void RendererSceneRenderRD::SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { if (!p_texture.is_valid()) { default_texture_params.erase(p_name); } else { @@ -2606,7 +2658,7 @@ void RasterizerSceneRD::SkyShaderData::set_default_texture_param(const StringNam } } -void RasterizerSceneRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { +void RendererSceneRenderRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { Map<int, StringName> order; for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { @@ -2628,13 +2680,13 @@ void RasterizerSceneRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_para } } -void RasterizerSceneRD::SkyShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const { +void RendererSceneRenderRD::SkyShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; } - RasterizerStorage::InstanceShaderParam p; + RendererStorage::InstanceShaderParam p; p.info = ShaderLanguage::uniform_to_property_info(E->get()); p.info.name = E->key(); //supply name p.index = E->get().instance_index; @@ -2643,7 +2695,7 @@ void RasterizerSceneRD::SkyShaderData::get_instance_param_list(List<RasterizerSt } } -bool RasterizerSceneRD::SkyShaderData::is_param_texture(const StringName &p_param) const { +bool RendererSceneRenderRD::SkyShaderData::is_param_texture(const StringName &p_param) const { if (!uniforms.has(p_param)) { return false; } @@ -2651,15 +2703,15 @@ bool RasterizerSceneRD::SkyShaderData::is_param_texture(const StringName &p_para return uniforms[p_param].texture_order >= 0; } -bool RasterizerSceneRD::SkyShaderData::is_animated() const { +bool RendererSceneRenderRD::SkyShaderData::is_animated() const { return false; } -bool RasterizerSceneRD::SkyShaderData::casts_shadows() const { +bool RendererSceneRenderRD::SkyShaderData::casts_shadows() const { return false; } -Variant RasterizerSceneRD::SkyShaderData::get_default_parameter(const StringName &p_parameter) const { +Variant RendererSceneRenderRD::SkyShaderData::get_default_parameter(const StringName &p_parameter) const { if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; @@ -2668,12 +2720,18 @@ Variant RasterizerSceneRD::SkyShaderData::get_default_parameter(const StringName return Variant(); } -RasterizerSceneRD::SkyShaderData::SkyShaderData() { +RS::ShaderNativeSourceCode RendererSceneRenderRD::SkyShaderData::get_native_source_code() const { + RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; + + return scene_singleton->sky_shader.shader.version_get_native_source_code(version); +} + +RendererSceneRenderRD::SkyShaderData::SkyShaderData() { valid = false; } -RasterizerSceneRD::SkyShaderData::~SkyShaderData() { - RasterizerSceneRD *scene_singleton = (RasterizerSceneRD *)RasterizerSceneRD::singleton; +RendererSceneRenderRD::SkyShaderData::~SkyShaderData() { + RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; ERR_FAIL_COND(!scene_singleton); //pipeline variants will clear themselves if shader is gone if (version.is_valid()) { @@ -2681,13 +2739,13 @@ RasterizerSceneRD::SkyShaderData::~SkyShaderData() { } } -RasterizerStorageRD::ShaderData *RasterizerSceneRD::_create_sky_shader_func() { +RendererStorageRD::ShaderData *RendererSceneRenderRD::_create_sky_shader_func() { SkyShaderData *shader_data = memnew(SkyShaderData); return shader_data; } -void RasterizerSceneRD::SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { - RasterizerSceneRD *scene_singleton = (RasterizerSceneRD *)RasterizerSceneRD::singleton; +void RendererSceneRenderRD::SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { + RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; uniform_set_updated = true; @@ -2749,7 +2807,7 @@ void RasterizerSceneRD::SkyMaterialData::update_parameters(const Map<StringName, { if (shader_data->ubo_size) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 0; u.ids.push_back(uniform_buffer); uniforms.push_back(u); @@ -2758,7 +2816,7 @@ void RasterizerSceneRD::SkyMaterialData::update_parameters(const Map<StringName, const RID *textures = texture_cache.ptrw(); for (uint32_t i = 0; i < tex_uniform_count; i++) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1 + i; u.ids.push_back(textures[i]); uniforms.push_back(u); @@ -2768,7 +2826,7 @@ void RasterizerSceneRD::SkyMaterialData::update_parameters(const Map<StringName, uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL); } -RasterizerSceneRD::SkyMaterialData::~SkyMaterialData() { +RendererSceneRenderRD::SkyMaterialData::~SkyMaterialData() { if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { RD::get_singleton()->free(uniform_set); } @@ -2778,7 +2836,7 @@ RasterizerSceneRD::SkyMaterialData::~SkyMaterialData() { } } -RasterizerStorageRD::MaterialData *RasterizerSceneRD::_create_sky_material_func(SkyShaderData *p_shader) { +RendererStorageRD::MaterialData *RendererSceneRenderRD::_create_sky_material_func(SkyShaderData *p_shader) { SkyMaterialData *material_data = memnew(SkyMaterialData); material_data->shader_data = p_shader; material_data->last_frame = false; @@ -2786,53 +2844,53 @@ RasterizerStorageRD::MaterialData *RasterizerSceneRD::_create_sky_material_func( return material_data; } -RID RasterizerSceneRD::environment_create() { +RID RendererSceneRenderRD::environment_create() { return environment_owner.make_rid(Environment()); } -void RasterizerSceneRD::environment_set_background(RID p_env, RS::EnvironmentBG p_bg) { +void RendererSceneRenderRD::environment_set_background(RID p_env, RS::EnvironmentBG p_bg) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->background = p_bg; } -void RasterizerSceneRD::environment_set_sky(RID p_env, RID p_sky) { +void RendererSceneRenderRD::environment_set_sky(RID p_env, RID p_sky) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->sky = p_sky; } -void RasterizerSceneRD::environment_set_sky_custom_fov(RID p_env, float p_scale) { +void RendererSceneRenderRD::environment_set_sky_custom_fov(RID p_env, float p_scale) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->sky_custom_fov = p_scale; } -void RasterizerSceneRD::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) { +void RendererSceneRenderRD::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->sky_orientation = p_orientation; } -void RasterizerSceneRD::environment_set_bg_color(RID p_env, const Color &p_color) { +void RendererSceneRenderRD::environment_set_bg_color(RID p_env, const Color &p_color) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->bg_color = p_color; } -void RasterizerSceneRD::environment_set_bg_energy(RID p_env, float p_energy) { +void RendererSceneRenderRD::environment_set_bg_energy(RID p_env, float p_energy) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->bg_energy = p_energy; } -void RasterizerSceneRD::environment_set_canvas_max_layer(RID p_env, int p_max_layer) { +void RendererSceneRenderRD::environment_set_canvas_max_layer(RID p_env, int p_max_layer) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->canvas_max_layer = p_max_layer; } -void RasterizerSceneRD::environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color) { +void RendererSceneRenderRD::environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->ambient_light = p_color; @@ -2843,85 +2901,85 @@ void RasterizerSceneRD::environment_set_ambient_light(RID p_env, const Color &p_ env->ao_color = p_ao_color; } -RS::EnvironmentBG RasterizerSceneRD::environment_get_background(RID p_env) const { +RS::EnvironmentBG RendererSceneRenderRD::environment_get_background(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, RS::ENV_BG_MAX); return env->background; } -RID RasterizerSceneRD::environment_get_sky(RID p_env) const { +RID RendererSceneRenderRD::environment_get_sky(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, RID()); return env->sky; } -float RasterizerSceneRD::environment_get_sky_custom_fov(RID p_env) const { +float RendererSceneRenderRD::environment_get_sky_custom_fov(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->sky_custom_fov; } -Basis RasterizerSceneRD::environment_get_sky_orientation(RID p_env) const { +Basis RendererSceneRenderRD::environment_get_sky_orientation(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, Basis()); return env->sky_orientation; } -Color RasterizerSceneRD::environment_get_bg_color(RID p_env) const { +Color RendererSceneRenderRD::environment_get_bg_color(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, Color()); return env->bg_color; } -float RasterizerSceneRD::environment_get_bg_energy(RID p_env) const { +float RendererSceneRenderRD::environment_get_bg_energy(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->bg_energy; } -int RasterizerSceneRD::environment_get_canvas_max_layer(RID p_env) const { +int RendererSceneRenderRD::environment_get_canvas_max_layer(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->canvas_max_layer; } -Color RasterizerSceneRD::environment_get_ambient_light_color(RID p_env) const { +Color RendererSceneRenderRD::environment_get_ambient_light_color(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, Color()); return env->ambient_light; } -RS::EnvironmentAmbientSource RasterizerSceneRD::environment_get_ambient_source(RID p_env) const { +RS::EnvironmentAmbientSource RendererSceneRenderRD::environment_get_ambient_source(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, RS::ENV_AMBIENT_SOURCE_BG); return env->ambient_source; } -float RasterizerSceneRD::environment_get_ambient_light_energy(RID p_env) const { +float RendererSceneRenderRD::environment_get_ambient_light_energy(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->ambient_light_energy; } -float RasterizerSceneRD::environment_get_ambient_sky_contribution(RID p_env) const { +float RendererSceneRenderRD::environment_get_ambient_sky_contribution(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->ambient_sky_contribution; } -RS::EnvironmentReflectionSource RasterizerSceneRD::environment_get_reflection_source(RID p_env) const { +RS::EnvironmentReflectionSource RendererSceneRenderRD::environment_get_reflection_source(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, RS::ENV_REFLECTION_SOURCE_DISABLED); return env->reflection_source; } -Color RasterizerSceneRD::environment_get_ao_color(RID p_env) const { +Color RendererSceneRenderRD::environment_get_ao_color(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, Color()); return env->ao_color; } -void RasterizerSceneRD::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) { +void RendererSceneRenderRD::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->exposure = p_exposure; @@ -2937,7 +2995,7 @@ void RasterizerSceneRD::environment_set_tonemap(RID p_env, RS::EnvironmentToneMa env->auto_exp_scale = p_auto_exp_scale; } -void RasterizerSceneRD::environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) { +void RendererSceneRenderRD::environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); ERR_FAIL_COND_MSG(p_levels.size() != 7, "Size of array of glow levels must be 7"); @@ -2953,18 +3011,22 @@ void RasterizerSceneRD::environment_set_glow(RID p_env, bool p_enable, Vector<fl env->glow_hdr_luminance_cap = p_hdr_luminance_cap; } -void RasterizerSceneRD::environment_glow_set_use_bicubic_upscale(bool p_enable) { +void RendererSceneRenderRD::environment_glow_set_use_bicubic_upscale(bool p_enable) { glow_bicubic_upscale = p_enable; } -void RasterizerSceneRD::environment_glow_set_use_high_quality(bool p_enable) { +void RendererSceneRenderRD::environment_glow_set_use_high_quality(bool p_enable) { glow_high_quality = p_enable; } -void RasterizerSceneRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) { +void RendererSceneRenderRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + if (low_end) { + return; + } + env->sdfgi_enabled = p_enable; env->sdfgi_cascades = p_cascades; env->sdfgi_min_cell_size = p_min_cell_size; @@ -2977,7 +3039,7 @@ void RasterizerSceneRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::Envi env->sdfgi_y_scale = p_y_scale; } -void RasterizerSceneRD::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective) { +void RendererSceneRenderRD::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); @@ -2991,54 +3053,58 @@ void RasterizerSceneRD::environment_set_fog(RID p_env, bool p_enable, const Colo env->fog_aerial_perspective = p_fog_aerial_perspective; } -bool RasterizerSceneRD::environment_is_fog_enabled(RID p_env) const { +bool RendererSceneRenderRD::environment_is_fog_enabled(RID p_env) const { const Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, false); return env->fog_enabled; } -Color RasterizerSceneRD::environment_get_fog_light_color(RID p_env) const { +Color RendererSceneRenderRD::environment_get_fog_light_color(RID p_env) const { const Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, Color()); return env->fog_light_color; } -float RasterizerSceneRD::environment_get_fog_light_energy(RID p_env) const { +float RendererSceneRenderRD::environment_get_fog_light_energy(RID p_env) const { const Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_light_energy; } -float RasterizerSceneRD::environment_get_fog_sun_scatter(RID p_env) const { +float RendererSceneRenderRD::environment_get_fog_sun_scatter(RID p_env) const { const Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_sun_scatter; } -float RasterizerSceneRD::environment_get_fog_density(RID p_env) const { +float RendererSceneRenderRD::environment_get_fog_density(RID p_env) const { const Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_density; } -float RasterizerSceneRD::environment_get_fog_height(RID p_env) const { +float RendererSceneRenderRD::environment_get_fog_height(RID p_env) const { const Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_height; } -float RasterizerSceneRD::environment_get_fog_height_density(RID p_env) const { +float RendererSceneRenderRD::environment_get_fog_height_density(RID p_env) const { const Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_height_density; } -float RasterizerSceneRD::environment_get_fog_aerial_perspective(RID p_env) const { +float RendererSceneRenderRD::environment_get_fog_aerial_perspective(RID p_env) const { const Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_aerial_perspective; } -void RasterizerSceneRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RenderingServer::EnvVolumetricFogShadowFilter p_shadow_filter) { +void RendererSceneRenderRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RenderingServer::EnvVolumetricFogShadowFilter p_shadow_filter) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + if (low_end) { + return; + } + env->volumetric_fog_enabled = p_enable; env->volumetric_fog_density = p_density; env->volumetric_fog_light = p_light; @@ -3049,15 +3115,15 @@ void RasterizerSceneRD::environment_set_volumetric_fog(RID p_env, bool p_enable, env->volumetric_fog_gi_inject = p_gi_inject; } -void RasterizerSceneRD::environment_set_volumetric_fog_volume_size(int p_size, int p_depth) { +void RendererSceneRenderRD::environment_set_volumetric_fog_volume_size(int p_size, int p_depth) { volumetric_fog_size = p_size; volumetric_fog_depth = p_depth; } -void RasterizerSceneRD::environment_set_volumetric_fog_filter_active(bool p_enable) { +void RendererSceneRenderRD::environment_set_volumetric_fog_filter_active(bool p_enable) { volumetric_fog_filter_active = p_enable; } -void RasterizerSceneRD::environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size) { +void RendererSceneRenderRD::environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size) { p_shrink_size = nearest_power_of_2_templated(p_shrink_size); if (volumetric_fog_directional_shadow_shrink == (uint32_t)p_shrink_size) { return; @@ -3065,7 +3131,7 @@ void RasterizerSceneRD::environment_set_volumetric_fog_directional_shadow_shrink _clear_shadow_shrink_stages(directional_shadow.shrink_stages); } -void RasterizerSceneRD::environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size) { +void RendererSceneRenderRD::environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size) { p_shrink_size = nearest_power_of_2_templated(p_shrink_size); if (volumetric_fog_positional_shadow_shrink == (uint32_t)p_shrink_size) { return; @@ -3077,18 +3143,25 @@ void RasterizerSceneRD::environment_set_volumetric_fog_positional_shadow_shrink_ } } -void RasterizerSceneRD::environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) { +void RendererSceneRenderRD::environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) { sdfgi_ray_count = p_ray_count; } -void RasterizerSceneRD::environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) { +void RendererSceneRenderRD::environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) { sdfgi_frames_to_converge = p_frames; } +void RendererSceneRenderRD::environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) { + sdfgi_frames_to_update_light = p_update; +} -void RasterizerSceneRD::environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) { +void RendererSceneRenderRD::environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + if (low_end) { + return; + } + env->ssr_enabled = p_enable; env->ssr_max_steps = p_max_steps; env->ssr_fade_in = p_fade_int; @@ -3096,66 +3169,76 @@ void RasterizerSceneRD::environment_set_ssr(RID p_env, bool p_enable, int p_max_ env->ssr_depth_tolerance = p_depth_tolerance; } -void RasterizerSceneRD::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) { +void RendererSceneRenderRD::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) { ssr_roughness_quality = p_quality; } -RS::EnvironmentSSRRoughnessQuality RasterizerSceneRD::environment_get_ssr_roughness_quality() const { +RS::EnvironmentSSRRoughnessQuality RendererSceneRenderRD::environment_get_ssr_roughness_quality() const { return ssr_roughness_quality; } -void RasterizerSceneRD::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) { +void RendererSceneRenderRD::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + if (low_end) { + return; + } + env->ssao_enabled = p_enable; env->ssao_radius = p_radius; env->ssao_intensity = p_intensity; - env->ssao_bias = p_bias; + env->ssao_power = p_power; + env->ssao_detail = p_detail; + env->ssao_horizon = p_horizon; + env->ssao_sharpness = p_sharpness; env->ssao_direct_light_affect = p_light_affect; env->ssao_ao_channel_affect = p_ao_channel_affect; - env->ssao_blur = p_blur; } -void RasterizerSceneRD::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size) { +void RendererSceneRenderRD::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { ssao_quality = p_quality; ssao_half_size = p_half_size; + ssao_adaptive_target = p_adaptive_target; + ssao_blur_passes = p_blur_passes; + ssao_fadeout_from = p_fadeout_from; + ssao_fadeout_to = p_fadeout_to; } -bool RasterizerSceneRD::environment_is_ssao_enabled(RID p_env) const { +bool RendererSceneRenderRD::environment_is_ssao_enabled(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, false); return env->ssao_enabled; } -float RasterizerSceneRD::environment_get_ssao_ao_affect(RID p_env) const { +float RendererSceneRenderRD::environment_get_ssao_ao_affect(RID p_env) const { Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND_V(!env, false); + ERR_FAIL_COND_V(!env, 0.0); return env->ssao_ao_channel_affect; } -float RasterizerSceneRD::environment_get_ssao_light_affect(RID p_env) const { +float RendererSceneRenderRD::environment_get_ssao_light_affect(RID p_env) const { Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND_V(!env, false); + ERR_FAIL_COND_V(!env, 0.0); return env->ssao_direct_light_affect; } -bool RasterizerSceneRD::environment_is_ssr_enabled(RID p_env) const { +bool RendererSceneRenderRD::environment_is_ssr_enabled(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, false); return env->ssr_enabled; } -bool RasterizerSceneRD::environment_is_sdfgi_enabled(RID p_env) const { +bool RendererSceneRenderRD::environment_is_sdfgi_enabled(RID p_env) const { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, false); return env->sdfgi_enabled; } -bool RasterizerSceneRD::is_environment(RID p_env) const { +bool RendererSceneRenderRD::is_environment(RID p_env) const { return environment_owner.owns(p_env); } -Ref<Image> RasterizerSceneRD::environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) { +Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND_V(!env, Ref<Image>()); @@ -3194,15 +3277,19 @@ Ref<Image> RasterizerSceneRD::environment_bake_panorama(RID p_env, bool p_bake_i //////////////////////////////////////////////////////////// -RID RasterizerSceneRD::reflection_atlas_create() { +RID RendererSceneRenderRD::reflection_atlas_create() { ReflectionAtlas ra; ra.count = GLOBAL_GET("rendering/quality/reflection_atlas/reflection_count"); ra.size = GLOBAL_GET("rendering/quality/reflection_atlas/reflection_size"); + ra.cluster_builder = memnew(ClusterBuilderRD); + ra.cluster_builder->set_shared(&cluster_builder_shared); + ra.cluster_builder->setup(Size2i(ra.size, ra.size), max_cluster_elements, RID(), RID(), RID()); + return reflection_atlas_owner.make_rid(ra); } -void RasterizerSceneRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) { +void RendererSceneRenderRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) { ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_ref_atlas); ERR_FAIL_COND(!ra); @@ -3210,6 +3297,8 @@ void RasterizerSceneRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflect return; //no changes } + ra->cluster_builder->setup(Size2i(ra->size, ra->size), max_cluster_elements, RID(), RID(), RID()); + ra->size = p_reflection_size; ra->count = p_reflection_count; @@ -3219,7 +3308,6 @@ void RasterizerSceneRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflect ra->reflection = RID(); RD::get_singleton()->free(ra->depth_buffer); ra->depth_buffer = RID(); - for (int i = 0; i < ra->reflections.size(); i++) { _clear_reflection_data(ra->reflections.write[i].data); if (ra->reflections[i].owner.is_null()) { @@ -3233,14 +3321,21 @@ void RasterizerSceneRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflect } } +int RendererSceneRenderRD::reflection_atlas_get_size(RID p_ref_atlas) const { + ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_ref_atlas); + ERR_FAIL_COND_V(!ra, 0); + + return ra->size; +} + //////////////////////// -RID RasterizerSceneRD::reflection_probe_instance_create(RID p_probe) { +RID RendererSceneRenderRD::reflection_probe_instance_create(RID p_probe) { ReflectionProbeInstance rpi; rpi.probe = p_probe; return reflection_probe_instance_owner.make_rid(rpi); } -void RasterizerSceneRD::reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) { +void RendererSceneRenderRD::reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND(!rpi); @@ -3248,7 +3343,7 @@ void RasterizerSceneRD::reflection_probe_instance_set_transform(RID p_instance, rpi->dirty = true; } -void RasterizerSceneRD::reflection_probe_release_atlas_index(RID p_instance) { +void RendererSceneRenderRD::reflection_probe_release_atlas_index(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND(!rpi); @@ -3263,7 +3358,7 @@ void RasterizerSceneRD::reflection_probe_release_atlas_index(RID p_instance) { rpi->atlas = RID(); } -bool RasterizerSceneRD::reflection_probe_instance_needs_redraw(RID p_instance) { +bool RendererSceneRenderRD::reflection_probe_instance_needs_redraw(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, false); @@ -3282,14 +3377,14 @@ bool RasterizerSceneRD::reflection_probe_instance_needs_redraw(RID p_instance) { return rpi->atlas_index == -1; } -bool RasterizerSceneRD::reflection_probe_instance_has_reflection(RID p_instance) { +bool RendererSceneRenderRD::reflection_probe_instance_has_reflection(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, false); return rpi->atlas.is_valid(); } -bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { +bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_reflection_atlas); ERR_FAIL_COND_V(!atlas, false); @@ -3325,7 +3420,7 @@ bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, R RD::TextureFormat tf; tf.array_layers = 6 * atlas->count; tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; tf.mipmaps = mipmaps; tf.width = atlas->size; tf.height = atlas->size; @@ -3388,7 +3483,7 @@ bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, R return true; } -bool RasterizerSceneRD::reflection_probe_instance_postprocess_step(RID p_instance) { +bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, false); ERR_FAIL_COND_V(!rpi->rendering, false); @@ -3434,7 +3529,7 @@ bool RasterizerSceneRD::reflection_probe_instance_postprocess_step(RID p_instanc return false; } -uint32_t RasterizerSceneRD::reflection_probe_instance_get_resolution(RID p_instance) { +uint32_t RendererSceneRenderRD::reflection_probe_instance_get_resolution(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, 0); @@ -3443,7 +3538,7 @@ uint32_t RasterizerSceneRD::reflection_probe_instance_get_resolution(RID p_insta return atlas->size; } -RID RasterizerSceneRD::reflection_probe_instance_get_framebuffer(RID p_instance, int p_index) { +RID RendererSceneRenderRD::reflection_probe_instance_get_framebuffer(RID p_instance, int p_index) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, RID()); ERR_FAIL_INDEX_V(p_index, 6, RID()); @@ -3453,7 +3548,7 @@ RID RasterizerSceneRD::reflection_probe_instance_get_framebuffer(RID p_instance, return atlas->reflections[rpi->atlas_index].fbs[p_index]; } -RID RasterizerSceneRD::reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index) { +RID RendererSceneRenderRD::reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, RID()); ERR_FAIL_INDEX_V(p_index, 6, RID()); @@ -3465,17 +3560,32 @@ RID RasterizerSceneRD::reflection_probe_instance_get_depth_framebuffer(RID p_ins /////////////////////////////////////////////////////////// -RID RasterizerSceneRD::shadow_atlas_create() { +RID RendererSceneRenderRD::shadow_atlas_create() { return shadow_atlas_owner.make_rid(ShadowAtlas()); } -void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) { +void RendererSceneRenderRD::_update_shadow_atlas(ShadowAtlas *shadow_atlas) { + if (shadow_atlas->size > 0 && shadow_atlas->depth.is_null()) { + RD::TextureFormat tf; + tf.format = shadow_atlas->use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT; + tf.width = shadow_atlas->size; + tf.height = shadow_atlas->size; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + shadow_atlas->depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + Vector<RID> fb_tex; + fb_tex.push_back(shadow_atlas->depth); + shadow_atlas->fb = RD::get_singleton()->framebuffer_create(fb_tex); + } +} + +void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) { ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); ERR_FAIL_COND(!shadow_atlas); ERR_FAIL_COND(p_size < 0); p_size = next_power_of_2(p_size); - if (p_size == shadow_atlas->size) { + if (p_size == shadow_atlas->size && p_16_bits == shadow_atlas->use_16_bits) { return; } @@ -3502,19 +3612,10 @@ void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) { shadow_atlas->shadow_owners.clear(); shadow_atlas->size = p_size; - - if (shadow_atlas->size) { - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R32_SFLOAT; - tf.width = shadow_atlas->size; - tf.height = shadow_atlas->size; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - - shadow_atlas->depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); - } + shadow_atlas->use_16_bits = p_size; } -void RasterizerSceneRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) { +void RendererSceneRenderRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) { ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); ERR_FAIL_COND(!shadow_atlas); ERR_FAIL_INDEX(p_quadrant, 4); @@ -3576,7 +3677,7 @@ void RasterizerSceneRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p } while (swaps > 0); } -bool RasterizerSceneRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) { +bool RendererSceneRenderRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) { for (int i = p_quadrant_count - 1; i >= 0; i--) { int qidx = p_in_quadrants[i]; @@ -3631,7 +3732,7 @@ bool RasterizerSceneRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int return false; } -bool RasterizerSceneRD::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) { +bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) { ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); ERR_FAIL_COND_V(!shadow_atlas, false); @@ -3766,10 +3867,24 @@ bool RasterizerSceneRD::shadow_atlas_update_light(RID p_atlas, RID p_light_intan return false; } -void RasterizerSceneRD::directional_shadow_atlas_set_size(int p_size) { +void RendererSceneRenderRD::_update_directional_shadow_atlas() { + if (directional_shadow.depth.is_null() && directional_shadow.size > 0) { + RD::TextureFormat tf; + tf.format = directional_shadow.use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT; + tf.width = directional_shadow.size; + tf.height = directional_shadow.size; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + directional_shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + Vector<RID> fb_tex; + fb_tex.push_back(directional_shadow.depth); + directional_shadow.fb = RD::get_singleton()->framebuffer_create(fb_tex); + } +} +void RendererSceneRenderRD::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) { p_size = nearest_power_of_2_templated(p_size); - if (directional_shadow.size == p_size) { + if (directional_shadow.size == p_size && directional_shadow.use_16_bits == p_16_bits) { return; } @@ -3779,22 +3894,11 @@ void RasterizerSceneRD::directional_shadow_atlas_set_size(int p_size) { RD::get_singleton()->free(directional_shadow.depth); _clear_shadow_shrink_stages(directional_shadow.shrink_stages); directional_shadow.depth = RID(); + _base_uniforms_changed(); } - - if (p_size > 0) { - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R32_SFLOAT; - tf.width = p_size; - tf.height = p_size; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - - directional_shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); - } - - _base_uniforms_changed(); } -void RasterizerSceneRD::set_directional_shadow_count(int p_count) { +void RendererSceneRenderRD::set_directional_shadow_count(int p_count) { directional_shadow.light_count = p_count; directional_shadow.current_light = 0; } @@ -3821,7 +3925,7 @@ static Rect2i _get_directional_shadow_rect(int p_size, int p_shadow_count, int p return rect; } -int RasterizerSceneRD::get_directional_light_shadow_size(RID p_light_intance) { +int RendererSceneRenderRD::get_directional_light_shadow_size(RID p_light_intance) { ERR_FAIL_COND_V(directional_shadow.light_count == 0, 0); Rect2i r = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, 0); @@ -3845,20 +3949,20 @@ int RasterizerSceneRD::get_directional_light_shadow_size(RID p_light_intance) { ////////////////////////////////////////////////// -RID RasterizerSceneRD::camera_effects_create() { +RID RendererSceneRenderRD::camera_effects_create() { return camera_effects_owner.make_rid(CameraEffects()); } -void RasterizerSceneRD::camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) { +void RendererSceneRenderRD::camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) { dof_blur_quality = p_quality; dof_blur_use_jitter = p_use_jitter; } -void RasterizerSceneRD::camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) { +void RendererSceneRenderRD::camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) { dof_blur_bokeh_shape = p_shape; } -void RasterizerSceneRD::camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) { +void RendererSceneRenderRD::camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) { CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects); ERR_FAIL_COND(!camfx); @@ -3873,7 +3977,7 @@ void RasterizerSceneRD::camera_effects_set_dof_blur(RID p_camera_effects, bool p camfx->dof_blur_amount = p_amount; } -void RasterizerSceneRD::camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) { +void RendererSceneRenderRD::camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) { CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects); ERR_FAIL_COND(!camfx); @@ -3881,7 +3985,7 @@ void RasterizerSceneRD::camera_effects_set_custom_exposure(RID p_camera_effects, camfx->override_exposure = p_exposure; } -RID RasterizerSceneRD::light_instance_create(RID p_light) { +RID RendererSceneRenderRD::light_instance_create(RID p_light) { RID li = light_instance_owner.make_rid(LightInstance()); LightInstance *light_instance = light_instance_owner.getornull(li); @@ -3893,21 +3997,21 @@ RID RasterizerSceneRD::light_instance_create(RID p_light) { return li; } -void RasterizerSceneRD::light_instance_set_transform(RID p_light_instance, const Transform &p_transform) { +void RendererSceneRenderRD::light_instance_set_transform(RID p_light_instance, const Transform &p_transform) { LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); ERR_FAIL_COND(!light_instance); light_instance->transform = p_transform; } -void RasterizerSceneRD::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) { +void RendererSceneRenderRD::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) { LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); ERR_FAIL_COND(!light_instance); light_instance->aabb = p_aabb; } -void RasterizerSceneRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) { +void RendererSceneRenderRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) { LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); ERR_FAIL_COND(!light_instance); @@ -3927,14 +4031,14 @@ void RasterizerSceneRD::light_instance_set_shadow_transform(RID p_light_instance light_instance->shadow_transform[p_pass].uv_scale = p_uv_scale; } -void RasterizerSceneRD::light_instance_mark_visible(RID p_light_instance) { +void RendererSceneRenderRD::light_instance_mark_visible(RID p_light_instance) { LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); ERR_FAIL_COND(!light_instance); light_instance->last_scene_pass = scene_pass; } -RasterizerSceneRD::ShadowCubemap *RasterizerSceneRD::_get_shadow_cubemap(int p_size) { +RendererSceneRenderRD::ShadowCubemap *RendererSceneRenderRD::_get_shadow_cubemap(int p_size) { if (!shadow_cubemaps.has(p_size)) { ShadowCubemap sc; { @@ -3942,7 +4046,7 @@ RasterizerSceneRD::ShadowCubemap *RasterizerSceneRD::_get_shadow_cubemap(int p_s tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; tf.width = p_size; tf.height = p_size; - tf.type = RD::TEXTURE_TYPE_CUBE; + tf.texture_type = RD::TEXTURE_TYPE_CUBE; tf.array_layers = 6; tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; sc.cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -3961,38 +4065,15 @@ RasterizerSceneRD::ShadowCubemap *RasterizerSceneRD::_get_shadow_cubemap(int p_s return &shadow_cubemaps[p_size]; } -RasterizerSceneRD::ShadowMap *RasterizerSceneRD::_get_shadow_map(const Size2i &p_size) { - if (!shadow_maps.has(p_size)) { - ShadowMap sm; - { - RD::TextureFormat tf; - tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32; - tf.width = p_size.width; - tf.height = p_size.height; - tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; - - sm.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); - } - - Vector<RID> fbtex; - fbtex.push_back(sm.depth); - sm.fb = RD::get_singleton()->framebuffer_create(fbtex); - - shadow_maps[p_size] = sm; - } - - return &shadow_maps[p_size]; -} - ////////////////////////// -RID RasterizerSceneRD::decal_instance_create(RID p_decal) { +RID RendererSceneRenderRD::decal_instance_create(RID p_decal) { DecalInstance di; di.decal = p_decal; return decal_instance_owner.make_rid(di); } -void RasterizerSceneRD::decal_instance_set_transform(RID p_decal, const Transform &p_transform) { +void RendererSceneRenderRD::decal_instance_set_transform(RID p_decal, const Transform &p_transform) { DecalInstance *di = decal_instance_owner.getornull(p_decal); ERR_FAIL_COND(!di); di->transform = p_transform; @@ -4000,32 +4081,53 @@ void RasterizerSceneRD::decal_instance_set_transform(RID p_decal, const Transfor ///////////////////////////////// -RID RasterizerSceneRD::gi_probe_instance_create(RID p_base) { +RID RendererSceneRenderRD::lightmap_instance_create(RID p_lightmap) { + LightmapInstance li; + li.lightmap = p_lightmap; + return lightmap_instance_owner.make_rid(li); +} +void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform) { + LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap); + ERR_FAIL_COND(!li); + li->transform = p_transform; +} + +///////////////////////////////// + +RID RendererSceneRenderRD::gi_probe_instance_create(RID p_base) { GIProbeInstance gi_probe; gi_probe.probe = p_base; RID rid = gi_probe_instance_owner.make_rid(gi_probe); return rid; } -void RasterizerSceneRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) { +void RendererSceneRenderRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) { GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); ERR_FAIL_COND(!gi_probe); gi_probe->transform = p_xform; } -bool RasterizerSceneRD::gi_probe_needs_update(RID p_probe) const { +bool RendererSceneRenderRD::gi_probe_needs_update(RID p_probe) const { GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); ERR_FAIL_COND_V(!gi_probe, false); + if (low_end) { + return false; + } + //return true; return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe); } -void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) { +void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) { GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe); ERR_FAIL_COND(!gi_probe); + if (low_end) { + return; + } + uint32_t data_version = storage->gi_probe_get_data_version(gi_probe->probe); // (RE)CREATE IF NEEDED @@ -4056,14 +4158,14 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc tf.width = octree_size.x; tf.height = octree_size.y; tf.depth = octree_size.z; - tf.type = RD::TEXTURE_TYPE_3D; + tf.texture_type = RD::TEXTURE_TYPE_3D; tf.mipmaps = levels.size(); tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; gi_probe->texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, levels.size(), 0, 1, false); + RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, levels.size(), 0, 1); { int total_elements = 0; @@ -4087,14 +4189,14 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(storage->gi_probe_get_octree_buffer(gi_probe->probe)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; u.ids.push_back(storage->gi_probe_get_data_buffer(gi_probe->probe)); uniforms.push_back(u); @@ -4102,21 +4204,21 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 4; u.ids.push_back(gi_probe->write_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 9; u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 10; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -4127,7 +4229,7 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc if (i == 0) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 3; u.ids.push_back(gi_probe_lights_uniform); copy_uniforms.push_back(u); @@ -4139,7 +4241,7 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 5; u.ids.push_back(gi_probe->texture); copy_uniforms.push_back(u); @@ -4152,7 +4254,7 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; u.ids.push_back(mipmap.texture); uniforms.push_back(u); @@ -4226,7 +4328,7 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 3; u.ids.push_back(gi_probe_lights_uniform); uniforms.push_back(u); @@ -4234,56 +4336,56 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; u.ids.push_back(dmap.albedo); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 6; u.ids.push_back(dmap.normal); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 7; u.ids.push_back(dmap.orm); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 8; u.ids.push_back(dmap.fb_depth); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 9; u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 10; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 11; u.ids.push_back(dmap.texture); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 12; u.ids.push_back(dmap.depth); uniforms.push_back(u); @@ -4299,14 +4401,14 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 5; u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].texture); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 6; u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].depth); uniforms.push_back(u); @@ -4315,14 +4417,14 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc if (write) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 7; u.ids.push_back(dmap.texture); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 8; u.ids.push_back(dmap.depth); uniforms.push_back(u); @@ -4331,14 +4433,14 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 9; u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 10; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -4347,14 +4449,17 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc if (plot) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 11; u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].texture); uniforms.push_back(u); } } - dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT], 0); + dmap.uniform_set = RD::get_singleton()->uniform_set_create( + uniforms, + giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : (write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT)], + 0); } gi_probe->dynamic_maps.push_back(dmap); @@ -4372,12 +4477,12 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc if (gi_probe->has_dynamic_object_data) { //if it has dynamic object data, it needs to be cleared - RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, gi_probe->mipmaps.size(), 0, 1, true); + RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, gi_probe->mipmaps.size(), 0, 1); } uint32_t light_count = 0; - if (p_update_light_instances || p_dynamic_object_count > 0) { + if (p_update_light_instances || p_dynamic_objects.size() > 0) { light_count = MIN(gi_probe_max_lights, (uint32_t)p_light_instances.size()); { @@ -4391,6 +4496,11 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc RID light = light_instance_get_base_light(light_instance); l.type = storage->light_get_type(light); + if (l.type == RS::LIGHT_DIRECTIONAL && storage->light_directional_is_sky_only(light)) { + light_count--; + continue; + } + l.attenuation = storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION); l.energy = storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY); l.radius = to_cell.basis.xform(Vector3(storage->light_get_param(light, RS::LIGHT_PARAM_RANGE), 0, 0)).length(); @@ -4418,11 +4528,11 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc l.has_shadow = storage->light_has_shadow(light); } - RD::get_singleton()->buffer_update(gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi_probe_lights, true); + RD::get_singleton()->buffer_update(gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi_probe_lights); } } - if (gi_probe->has_dynamic_object_data || p_update_light_instances || p_dynamic_object_count) { + if (gi_probe->has_dynamic_object_data || p_update_light_instances || p_dynamic_objects.size()) { // PROCESS MIPMAPS if (gi_probe->mipmaps.size()) { //can update mipmaps @@ -4515,7 +4625,7 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc gi_probe->has_dynamic_object_data = false; //clear until dynamic object data is used again - if (p_dynamic_object_count && gi_probe->dynamic_maps.size()) { + if (p_dynamic_objects.size() && gi_probe->dynamic_maps.size()) { Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe); int multiplier = gi_probe->dynamic_maps[0].size / MAX(MAX(octree_size.x, octree_size.y), octree_size.z); @@ -4529,14 +4639,11 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc AABB probe_aabb(Vector3(), octree_size); //this could probably be better parallelized in compute.. - for (int i = 0; i < p_dynamic_object_count; i++) { - InstanceBase *instance = p_dynamic_objects[i]; - //not used, so clear - instance->depth_layer = 0; - instance->depth = 0; + for (int i = 0; i < (int)p_dynamic_objects.size(); i++) { + GeometryInstance *instance = p_dynamic_objects[i]; //transform aabb to giprobe - AABB aabb = (to_probe_xform * instance->transform).xform(instance->aabb); + AABB aabb = (to_probe_xform * geometry_instance_get_transform(instance)).xform(geometry_instance_get_aabb(instance)); //this needs to wrap to grid resolution to avoid jitter //also extend margin a bit just in case @@ -4600,7 +4707,12 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc CameraMatrix cm; cm.set_orthogonal(-rect.size.width / 2, rect.size.width / 2, -rect.size.height / 2, rect.size.height / 2, 0.0001, aabb.size[z_axis]); - _render_material(to_world_xform * xform, cm, true, &instance, 1, gi_probe->dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size)); + if (cull_argument.size() == 0) { + cull_argument.push_back(nullptr); + } + cull_argument[0] = instance; + + _render_material(to_world_xform * xform, cm, true, cull_argument, gi_probe->dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size)); GIProbeDynamicPushConstant push_constant; zeromem(&push_constant, sizeof(GIProbeDynamicPushConstant)); @@ -4717,7 +4829,7 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc gi_probe->last_probe_version = storage->gi_probe_get_version(gi_probe->probe); } -void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) { +void RendererSceneRenderRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) { GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); @@ -4753,21 +4865,21 @@ void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_lis Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(storage->gi_probe_get_data_buffer(gi_probe->probe)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; u.ids.push_back(gi_probe->texture); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 3; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -4781,13 +4893,22 @@ void RasterizerSceneRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_lis } giprobe_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_debug_shader_version_shaders[0], 0); - RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, giprobe_debug_shader_version_pipelines[p_emission ? GI_PROBE_DEBUG_EMISSION : p_lighting ? (gi_probe->has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT) : GI_PROBE_DEBUG_COLOR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer))); + + int giprobe_debug_pipeline = GI_PROBE_DEBUG_COLOR; + if (p_emission) { + giprobe_debug_pipeline = GI_PROBE_DEBUG_EMISSION; + } else if (p_lighting) { + giprobe_debug_pipeline = gi_probe->has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT; + } + RD::get_singleton()->draw_list_bind_render_pipeline( + p_draw_list, + giprobe_debug_shader_version_pipelines[giprobe_debug_pipeline].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, giprobe_debug_uniform_set, 0); RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(GIProbeDebugPushConstant)); RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, 36); } -void RasterizerSceneRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform) { +void RendererSceneRenderRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -4826,28 +4947,28 @@ void RasterizerSceneRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID { RD::Uniform u; u.binding = 1; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(rb->sdfgi->cascades_ubo); uniforms.push_back(u); } { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->sdfgi->lightprobe_texture); uniforms.push_back(u); } { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->sdfgi->occlusion_texture); uniforms.push_back(u); } @@ -4924,13 +5045,13 @@ void RasterizerSceneRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID } //////////////////////////////// -RID RasterizerSceneRD::render_buffers_create() { +RID RendererSceneRenderRD::render_buffers_create() { RenderBuffers rb; rb.data = _create_render_buffer_data(); return render_buffers_owner.make_rid(rb); } -void RasterizerSceneRD::_allocate_blur_textures(RenderBuffers *rb) { +void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) { ERR_FAIL_COND(!rb->blur[0].texture.is_null()); uint32_t mipmaps_required = Image::get_image_required_mipmaps(rb->width, rb->height, Image::FORMAT_RGBAH); @@ -4939,7 +5060,7 @@ void RasterizerSceneRD::_allocate_blur_textures(RenderBuffers *rb) { tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; tf.width = rb->width; tf.height = rb->height; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; tf.mipmaps = mipmaps_required; @@ -4973,7 +5094,7 @@ void RasterizerSceneRD::_allocate_blur_textures(RenderBuffers *rb) { } } -void RasterizerSceneRD::_allocate_luminance_textures(RenderBuffers *rb) { +void RendererSceneRenderRD::_allocate_luminance_textures(RenderBuffers *rb) { ERR_FAIL_COND(!rb->luminance.current.is_null()); int w = rb->width; @@ -5006,7 +5127,7 @@ void RasterizerSceneRD::_allocate_luminance_textures(RenderBuffers *rb) { } } -void RasterizerSceneRD::_free_render_buffer_data(RenderBuffers *rb) { +void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) { if (rb->texture.is_valid()) { RD::get_singleton()->free(rb->texture); rb->texture = RID(); @@ -5039,21 +5160,24 @@ void RasterizerSceneRD::_free_render_buffer_data(RenderBuffers *rb) { rb->luminance.current = RID(); } - if (rb->ssao.ao[0].is_valid()) { + if (rb->ssao.depth.is_valid()) { RD::get_singleton()->free(rb->ssao.depth); - RD::get_singleton()->free(rb->ssao.ao[0]); - if (rb->ssao.ao[1].is_valid()) { - RD::get_singleton()->free(rb->ssao.ao[1]); - } - if (rb->ssao.ao_full.is_valid()) { - RD::get_singleton()->free(rb->ssao.ao_full); - } + RD::get_singleton()->free(rb->ssao.ao_deinterleaved); + RD::get_singleton()->free(rb->ssao.ao_pong); + RD::get_singleton()->free(rb->ssao.ao_final); + + RD::get_singleton()->free(rb->ssao.importance_map[0]); + RD::get_singleton()->free(rb->ssao.importance_map[1]); rb->ssao.depth = RID(); - rb->ssao.ao[0] = RID(); - rb->ssao.ao[1] = RID(); - rb->ssao.ao_full = RID(); + rb->ssao.ao_deinterleaved = RID(); + rb->ssao.ao_pong = RID(); + rb->ssao.ao_final = RID(); + rb->ssao.importance_map[0] = RID(); + rb->ssao.importance_map[1] = RID(); rb->ssao.depth_slices.clear(); + rb->ssao.ao_deinterleaved_slices.clear(); + rb->ssao.ao_pong_slices.clear(); } if (rb->ssr.blur_radius[0].is_valid()) { @@ -5069,9 +5193,16 @@ void RasterizerSceneRD::_free_render_buffer_data(RenderBuffers *rb) { RD::get_singleton()->free(rb->ssr.normal_scaled); rb->ssr.normal_scaled = RID(); } + + if (rb->ambient_buffer.is_valid()) { + RD::get_singleton()->free(rb->ambient_buffer); + RD::get_singleton()->free(rb->reflection_buffer); + rb->ambient_buffer = RID(); + rb->reflection_buffer = RID(); + } } -void RasterizerSceneRD::_process_sss(RID p_render_buffers, const CameraMatrix &p_camera) { +void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const CameraMatrix &p_camera) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -5090,7 +5221,7 @@ void RasterizerSceneRD::_process_sss(RID p_render_buffers, const CameraMatrix &p storage->get_effects()->sub_surface_scattering(rb->texture, rb->blur[0].mipmaps[0].texture, rb->depth_texture, p_camera, Size2i(rb->width, rb->height), sss_scale, sss_depth_scale, sss_quality); } -void RasterizerSceneRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive) { +void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -5112,7 +5243,7 @@ void RasterizerSceneRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffe tf.format = RD::DATA_FORMAT_R32_SFLOAT; tf.width = rb->width / 2; tf.height = rb->height / 2; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; rb->ssr.depth_scaled = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -5127,7 +5258,7 @@ void RasterizerSceneRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffe tf.format = RD::DATA_FORMAT_R8_UNORM; tf.width = rb->width / 2; tf.height = rb->height / 2; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; rb->ssr.blur_radius[0] = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -5143,7 +5274,7 @@ void RasterizerSceneRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffe storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->texture, rb->blur[0].mipmaps[1].texture); } -void RasterizerSceneRD::_process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection) { +void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -5152,67 +5283,144 @@ void RasterizerSceneRD::_process_ssao(RID p_render_buffers, RID p_environment, R RENDER_TIMESTAMP("Process SSAO"); - if (rb->ssao.ao[0].is_valid() && rb->ssao.ao_full.is_valid() != ssao_half_size) { + if (rb->ssao.ao_final.is_valid() && ssao_using_half_size != ssao_half_size) { RD::get_singleton()->free(rb->ssao.depth); - RD::get_singleton()->free(rb->ssao.ao[0]); - if (rb->ssao.ao[1].is_valid()) { - RD::get_singleton()->free(rb->ssao.ao[1]); - } - if (rb->ssao.ao_full.is_valid()) { - RD::get_singleton()->free(rb->ssao.ao_full); - } + RD::get_singleton()->free(rb->ssao.ao_deinterleaved); + RD::get_singleton()->free(rb->ssao.ao_pong); + RD::get_singleton()->free(rb->ssao.ao_final); + + RD::get_singleton()->free(rb->ssao.importance_map[0]); + RD::get_singleton()->free(rb->ssao.importance_map[1]); rb->ssao.depth = RID(); - rb->ssao.ao[0] = RID(); - rb->ssao.ao[1] = RID(); - rb->ssao.ao_full = RID(); + rb->ssao.ao_deinterleaved = RID(); + rb->ssao.ao_pong = RID(); + rb->ssao.ao_final = RID(); + rb->ssao.importance_map[0] = RID(); + rb->ssao.importance_map[1] = RID(); rb->ssao.depth_slices.clear(); + rb->ssao.ao_deinterleaved_slices.clear(); + rb->ssao.ao_pong_slices.clear(); + } + + int buffer_width; + int buffer_height; + int half_width; + int half_height; + if (ssao_half_size) { + buffer_width = (rb->width + 3) / 4; + buffer_height = (rb->height + 3) / 4; + half_width = (rb->width + 7) / 8; + half_height = (rb->height + 7) / 8; + } else { + buffer_width = (rb->width + 1) / 2; + buffer_height = (rb->height + 1) / 2; + half_width = (rb->width + 3) / 4; + half_height = (rb->height + 3) / 4; } - - if (!rb->ssao.ao[0].is_valid()) { + bool uniform_sets_are_invalid = false; + if (rb->ssao.depth.is_null()) { //allocate depth slices { RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R32_SFLOAT; - tf.width = rb->width / 2; - tf.height = rb->height / 2; - tf.mipmaps = Image::get_image_required_mipmaps(tf.width, tf.height, Image::FORMAT_RF) + 1; + tf.format = RD::DATA_FORMAT_R16_SFLOAT; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.width = buffer_width; + tf.height = buffer_height; + tf.mipmaps = 4; + tf.array_layers = 4; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; rb->ssao.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ssao.depth, "SSAO Depth"); for (uint32_t i = 0; i < tf.mipmaps; i++) { - RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ssao.depth, 0, i); + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ssao.depth, 0, i, RD::TEXTURE_SLICE_2D_ARRAY); rb->ssao.depth_slices.push_back(slice); + RD::get_singleton()->set_resource_name(rb->ssao.depth_slices[i], "SSAO Depth Mip " + itos(i) + " "); } } { RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R8_UNORM; - tf.width = ssao_half_size ? rb->width / 2 : rb->width; - tf.height = ssao_half_size ? rb->height / 2 : rb->height; + tf.format = RD::DATA_FORMAT_R8G8_UNORM; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.width = buffer_width; + tf.height = buffer_height; + tf.array_layers = 4; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb->ssao.ao_deinterleaved = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ssao.ao_deinterleaved, "SSAO De-interleaved Array"); + for (uint32_t i = 0; i < 4; i++) { + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ssao.ao_deinterleaved, i, 0); + rb->ssao.ao_deinterleaved_slices.push_back(slice); + RD::get_singleton()->set_resource_name(rb->ssao.ao_deinterleaved_slices[i], "SSAO De-interleaved Array Layer " + itos(i) + " "); + } + } + + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R8G8_UNORM; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.width = buffer_width; + tf.height = buffer_height; + tf.array_layers = 4; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - rb->ssao.ao[0] = RD::get_singleton()->texture_create(tf, RD::TextureView()); - rb->ssao.ao[1] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + rb->ssao.ao_pong = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ssao.ao_pong, "SSAO De-interleaved Array Pong"); + for (uint32_t i = 0; i < 4; i++) { + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ssao.ao_pong, i, 0); + rb->ssao.ao_pong_slices.push_back(slice); + RD::get_singleton()->set_resource_name(rb->ssao.ao_deinterleaved_slices[i], "SSAO De-interleaved Array Layer " + itos(i) + " Pong"); + } } - if (ssao_half_size) { - //upsample texture + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R8_UNORM; + tf.width = half_width; + tf.height = half_height; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb->ssao.importance_map[0] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ssao.importance_map[0], "SSAO Importance Map"); + rb->ssao.importance_map[1] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ssao.importance_map[1], "SSAO Importance Map Pong"); + } + { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8_UNORM; tf.width = rb->width; tf.height = rb->height; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - rb->ssao.ao_full = RD::get_singleton()->texture_create(tf, RD::TextureView()); + rb->ssao.ao_final = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ssao.ao_final, "SSAO Final"); + _render_buffers_uniform_set_changed(p_render_buffers); } - - _render_buffers_uniform_set_changed(p_render_buffers); + ssao_using_half_size = ssao_half_size; + uniform_sets_are_invalid = true; } - storage->get_effects()->generate_ssao(rb->depth_texture, p_normal_buffer, Size2i(rb->width, rb->height), rb->ssao.depth, rb->ssao.depth_slices, rb->ssao.ao[0], rb->ssao.ao_full.is_valid(), rb->ssao.ao[1], rb->ssao.ao_full, env->ssao_intensity, env->ssao_radius, env->ssao_bias, p_projection, ssao_quality, env->ssao_blur, env->ssao_blur_edge_sharpness); + EffectsRD::SSAOSettings settings; + settings.radius = env->ssao_radius; + settings.intensity = env->ssao_intensity; + settings.power = env->ssao_power; + settings.detail = env->ssao_detail; + settings.horizon = env->ssao_horizon; + settings.sharpness = env->ssao_sharpness; + + settings.quality = ssao_quality; + settings.half_size = ssao_half_size; + settings.adaptive_target = ssao_adaptive_target; + settings.blur_passes = ssao_blur_passes; + settings.fadeout_from = ssao_fadeout_from; + settings.fadeout_to = ssao_fadeout_to; + settings.full_screen_size = Size2i(rb->width, rb->height); + settings.half_screen_size = Size2i(buffer_width, buffer_height); + settings.quarter_screen_size = Size2i(half_width, half_height); + + storage->get_effects()->generate_ssao(rb->depth_texture, p_normal_buffer, rb->ssao.depth, rb->ssao.depth_slices, rb->ssao.ao_deinterleaved, rb->ssao.ao_deinterleaved_slices, rb->ssao.ao_pong, rb->ssao.ao_pong_slices, rb->ssao.ao_final, rb->ssao.importance_map[0], rb->ssao.importance_map[1], p_projection, settings, uniform_sets_are_invalid); } -void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_buffers, RID p_environment, RID p_camera_effects, const CameraMatrix &p_projection) { +void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(RID p_render_buffers, RID p_environment, RID p_camera_effects, const CameraMatrix &p_projection) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -5246,7 +5454,7 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu //swap final reduce with prev luminance SWAP(rb->luminance.current, rb->luminance.reduce.write[rb->luminance.reduce.size() - 1]); - RenderingServerRaster::redraw_request(); //redraw all the time if auto exposure rendering is on + RenderingServerDefault::redraw_request(); //redraw all the time if auto exposure rendering is on } int max_glow_level = -1; @@ -5287,21 +5495,19 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu { //tonemap - RasterizerEffectsRD::TonemapSettings tonemap; - - tonemap.color_correction_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + EffectsRD::TonemapSettings tonemap; if (can_use_effects && env && env->auto_exposure && rb->luminance.current.is_valid()) { tonemap.use_auto_exposure = true; tonemap.exposure_texture = rb->luminance.current; tonemap.auto_exposure_grey = env->auto_exp_scale; } else { - tonemap.exposure_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE); + tonemap.exposure_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); } if (can_use_effects && env && env->glow_enabled) { tonemap.use_glow = true; - tonemap.glow_mode = RasterizerEffectsRD::TonemapSettings::GlowMode(env->glow_blend_mode); + tonemap.glow_mode = EffectsRD::TonemapSettings::GlowMode(env->glow_blend_mode); tonemap.glow_intensity = env->glow_blend_mode == RS::ENV_GLOW_BLEND_MODE_MIX ? env->glow_mix : env->glow_intensity; for (int i = 0; i < RS::MAX_GLOW_LEVELS; i++) { tonemap.glow_levels[i] = env->glow_levels[i]; @@ -5311,7 +5517,7 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu tonemap.glow_use_bicubic_upscale = glow_bicubic_upscale; tonemap.glow_texture = rb->blur[1].texture; } else { - tonemap.glow_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK); + tonemap.glow_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); } if (rb->screen_space_aa == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) { @@ -5327,14 +5533,30 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu tonemap.exposure = env->exposure; } + tonemap.use_color_correction = false; + tonemap.use_1d_color_correction = false; + tonemap.color_correction_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + + if (can_use_effects && env) { + tonemap.use_bcs = env->adjustments_enabled; + tonemap.brightness = env->adjustments_brightness; + tonemap.contrast = env->adjustments_contrast; + tonemap.saturation = env->adjustments_saturation; + if (env->adjustments_enabled && env->color_correction.is_valid()) { + tonemap.use_color_correction = true; + tonemap.use_1d_color_correction = env->use_1d_color_correction; + tonemap.color_correction_texture = storage->texture_get_rd_texture(env->color_correction); + } + } + storage->get_effects()->tonemapper(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), tonemap); } storage->render_target_disable_clear_request(rb->render_target); } -void RasterizerSceneRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas) { - RasterizerEffectsRD *effects = storage->get_effects(); +void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas) { + EffectsRD *effects = storage->get_effects(); RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -5375,9 +5597,9 @@ void RasterizerSceneRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_s } } - if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb->ssao.ao[0].is_valid()) { + if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb->ssao.ao_final.is_valid()) { Size2 rtsize = storage->render_target_get_size(rb->render_target); - RID ao_buf = rb->ssao.ao_full.is_valid() ? rb->ssao.ao_full : rb->ssao.ao[0]; + RID ao_buf = rb->ssao.ao_final; effects->copy_to_fb_rect(ao_buf, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true); } @@ -5386,15 +5608,27 @@ void RasterizerSceneRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_s effects->copy_to_fb_rect(_render_buffers_get_normal_texture(p_render_buffers), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, false); } - if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER && _render_buffers_get_ambient_texture(p_render_buffers).is_valid()) { + if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER && rb->ambient_buffer.is_valid()) { Size2 rtsize = storage->render_target_get_size(rb->render_target); - RID ambient_texture = _render_buffers_get_ambient_texture(p_render_buffers); - RID reflection_texture = _render_buffers_get_reflection_texture(p_render_buffers); + RID ambient_texture = rb->ambient_buffer; + RID reflection_texture = rb->reflection_buffer; effects->copy_to_fb_rect(ambient_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, false, false, true, reflection_texture); } } -void RasterizerSceneRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform) { +void RendererSceneRenderRD::environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) { + Environment *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->adjustments_enabled = p_enable; + env->adjustments_brightness = p_brightness; + env->adjustments_contrast = p_contrast; + env->adjustments_saturation = p_saturation; + env->use_1d_color_correction = p_use_1d_color_correction; + env->color_correction = p_color_correction; +} + +void RendererSceneRenderRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -5407,12 +5641,12 @@ void RasterizerSceneRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatr { RD::Uniform u; u.binding = 1; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { if (i < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[i].sdf_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -5420,12 +5654,12 @@ void RasterizerSceneRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatr { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { if (i < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[i].light_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -5433,12 +5667,12 @@ void RasterizerSceneRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatr { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { if (i < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[i].light_aniso_0_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -5446,12 +5680,12 @@ void RasterizerSceneRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatr { RD::Uniform u; u.binding = 4; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) { if (i < rb->sdfgi->cascades.size()) { u.ids.push_back(rb->sdfgi->cascades[i].light_aniso_1_tex); } else { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); } } uniforms.push_back(u); @@ -5459,35 +5693,35 @@ void RasterizerSceneRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatr { RD::Uniform u; u.binding = 5; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->sdfgi->occlusion_texture); uniforms.push_back(u); } { RD::Uniform u; u.binding = 8; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } { RD::Uniform u; u.binding = 9; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(rb->sdfgi->cascades_ubo); uniforms.push_back(u); } { RD::Uniform u; u.binding = 10; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.ids.push_back(rb->texture); uniforms.push_back(u); } { RD::Uniform u; u.binding = 11; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->sdfgi->lightprobe_texture); uniforms.push_back(u); } @@ -5540,7 +5774,7 @@ void RasterizerSceneRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatr storage->get_effects()->copy_to_fb_rect(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), true); } -RID RasterizerSceneRD::render_buffers_get_back_buffer_texture(RID p_render_buffers) { +RID RendererSceneRenderRD::render_buffers_get_back_buffer_texture(RID p_render_buffers) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); if (!rb->blur[0].texture.is_valid()) { @@ -5549,14 +5783,14 @@ RID RasterizerSceneRD::render_buffers_get_back_buffer_texture(RID p_render_buffe return rb->blur[0].texture; } -RID RasterizerSceneRD::render_buffers_get_ao_texture(RID p_render_buffers) { +RID RendererSceneRenderRD::render_buffers_get_ao_texture(RID p_render_buffers) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); - return rb->ssao.ao_full.is_valid() ? rb->ssao.ao_full : rb->ssao.ao[0]; + return rb->ssao.ao_final; } -RID RasterizerSceneRD::render_buffers_get_gi_probe_buffer(RID p_render_buffers) { +RID RendererSceneRenderRD::render_buffers_get_gi_probe_buffer(RID p_render_buffers) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); if (rb->giprobe_buffer.is_null()) { @@ -5565,24 +5799,35 @@ RID RasterizerSceneRD::render_buffers_get_gi_probe_buffer(RID p_render_buffers) return rb->giprobe_buffer; } -RID RasterizerSceneRD::render_buffers_get_default_gi_probe_buffer() { +RID RendererSceneRenderRD::render_buffers_get_default_gi_probe_buffer() { return default_giprobe_buffer; } -uint32_t RasterizerSceneRD::render_buffers_get_sdfgi_cascade_count(RID p_render_buffers) const { +RID RendererSceneRenderRD::render_buffers_get_gi_ambient_texture(RID p_render_buffers) { + RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + ERR_FAIL_COND_V(!rb, RID()); + return rb->ambient_buffer; +} +RID RendererSceneRenderRD::render_buffers_get_gi_reflection_texture(RID p_render_buffers) { + RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + ERR_FAIL_COND_V(!rb, RID()); + return rb->reflection_buffer; +} + +uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_count(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, 0); ERR_FAIL_COND_V(!rb->sdfgi, 0); return rb->sdfgi->cascades.size(); } -bool RasterizerSceneRD::render_buffers_is_sdfgi_enabled(RID p_render_buffers) const { +bool RendererSceneRenderRD::render_buffers_is_sdfgi_enabled(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, false); return rb->sdfgi != nullptr; } -RID RasterizerSceneRD::render_buffers_get_sdfgi_irradiance_probes(RID p_render_buffers) const { +RID RendererSceneRenderRD::render_buffers_get_sdfgi_irradiance_probes(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); ERR_FAIL_COND_V(!rb->sdfgi, RID()); @@ -5590,7 +5835,7 @@ RID RasterizerSceneRD::render_buffers_get_sdfgi_irradiance_probes(RID p_render_b return rb->sdfgi->lightprobe_texture; } -Vector3 RasterizerSceneRD::render_buffers_get_sdfgi_cascade_offset(RID p_render_buffers, uint32_t p_cascade) const { +Vector3 RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_offset(RID p_render_buffers, uint32_t p_cascade) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, Vector3()); ERR_FAIL_COND_V(!rb->sdfgi, Vector3()); @@ -5599,7 +5844,7 @@ Vector3 RasterizerSceneRD::render_buffers_get_sdfgi_cascade_offset(RID p_render_ return Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + rb->sdfgi->cascades[p_cascade].position)) * rb->sdfgi->cascades[p_cascade].cell_size; } -Vector3i RasterizerSceneRD::render_buffers_get_sdfgi_cascade_probe_offset(RID p_render_buffers, uint32_t p_cascade) const { +Vector3i RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_offset(RID p_render_buffers, uint32_t p_cascade) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, Vector3i()); ERR_FAIL_COND_V(!rb->sdfgi, Vector3i()); @@ -5609,14 +5854,14 @@ Vector3i RasterizerSceneRD::render_buffers_get_sdfgi_cascade_probe_offset(RID p_ return rb->sdfgi->cascades[p_cascade].position / probe_divisor; } -float RasterizerSceneRD::render_buffers_get_sdfgi_normal_bias(RID p_render_buffers) const { +float RendererSceneRenderRD::render_buffers_get_sdfgi_normal_bias(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, 0); ERR_FAIL_COND_V(!rb->sdfgi, 0); return rb->sdfgi->normal_bias; } -float RasterizerSceneRD::render_buffers_get_sdfgi_cascade_probe_size(RID p_render_buffers, uint32_t p_cascade) const { +float RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_size(RID p_render_buffers, uint32_t p_cascade) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, 0); ERR_FAIL_COND_V(!rb->sdfgi, 0); @@ -5624,7 +5869,7 @@ float RasterizerSceneRD::render_buffers_get_sdfgi_cascade_probe_size(RID p_rende return float(rb->sdfgi->cascade_size) * rb->sdfgi->cascades[p_cascade].cell_size / float(rb->sdfgi->probe_axis_count - 1); } -uint32_t RasterizerSceneRD::render_buffers_get_sdfgi_cascade_probe_count(RID p_render_buffers) const { +uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_count(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, 0); ERR_FAIL_COND_V(!rb->sdfgi, 0); @@ -5632,7 +5877,7 @@ uint32_t RasterizerSceneRD::render_buffers_get_sdfgi_cascade_probe_count(RID p_r return rb->sdfgi->probe_axis_count; } -uint32_t RasterizerSceneRD::render_buffers_get_sdfgi_cascade_size(RID p_render_buffers) const { +uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_size(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, 0); ERR_FAIL_COND_V(!rb->sdfgi, 0); @@ -5640,7 +5885,7 @@ uint32_t RasterizerSceneRD::render_buffers_get_sdfgi_cascade_size(RID p_render_b return rb->sdfgi->cascade_size; } -bool RasterizerSceneRD::render_buffers_is_sdfgi_using_occlusion(RID p_render_buffers) const { +bool RendererSceneRenderRD::render_buffers_is_sdfgi_using_occlusion(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, false); ERR_FAIL_COND_V(!rb->sdfgi, false); @@ -5648,14 +5893,14 @@ bool RasterizerSceneRD::render_buffers_is_sdfgi_using_occlusion(RID p_render_buf return rb->sdfgi->uses_occlusion; } -float RasterizerSceneRD::render_buffers_get_sdfgi_energy(RID p_render_buffers) const { +float RendererSceneRenderRD::render_buffers_get_sdfgi_energy(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); - ERR_FAIL_COND_V(!rb, 0); - ERR_FAIL_COND_V(!rb->sdfgi, false); + ERR_FAIL_COND_V(!rb, 0.0); + ERR_FAIL_COND_V(!rb->sdfgi, 0.0); return rb->sdfgi->energy; } -RID RasterizerSceneRD::render_buffers_get_sdfgi_occlusion_texture(RID p_render_buffers) const { +RID RendererSceneRenderRD::render_buffers_get_sdfgi_occlusion_texture(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); ERR_FAIL_COND_V(!rb->sdfgi, RID()); @@ -5663,20 +5908,20 @@ RID RasterizerSceneRD::render_buffers_get_sdfgi_occlusion_texture(RID p_render_b return rb->sdfgi->occlusion_texture; } -bool RasterizerSceneRD::render_buffers_has_volumetric_fog(RID p_render_buffers) const { +bool RendererSceneRenderRD::render_buffers_has_volumetric_fog(RID p_render_buffers) const { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, false); return rb->volumetric_fog != nullptr; } -RID RasterizerSceneRD::render_buffers_get_volumetric_fog_texture(RID p_render_buffers) { +RID RendererSceneRenderRD::render_buffers_get_volumetric_fog_texture(RID p_render_buffers) { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, RID()); return rb->volumetric_fog->fog_map; } -RID RasterizerSceneRD::render_buffers_get_volumetric_fog_sky_uniform_set(RID p_render_buffers) { +RID RendererSceneRenderRD::render_buffers_get_volumetric_fog_sky_uniform_set(RID p_render_buffers) { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); @@ -5687,18 +5932,18 @@ RID RasterizerSceneRD::render_buffers_get_volumetric_fog_sky_uniform_set(RID p_r return rb->volumetric_fog->sky_uniform_set; } -float RasterizerSceneRD::render_buffers_get_volumetric_fog_end(RID p_render_buffers) { +float RendererSceneRenderRD::render_buffers_get_volumetric_fog_end(RID p_render_buffers) { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0); return rb->volumetric_fog->length; } -float RasterizerSceneRD::render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers) { +float RendererSceneRenderRD::render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers) { const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0); return rb->volumetric_fog->spread; } -void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) { +void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); rb->width = p_width; rb->height = p_height; @@ -5706,6 +5951,11 @@ void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_ren rb->msaa = p_msaa; rb->screen_space_aa = p_screen_space_aa; rb->use_debanding = p_use_debanding; + if (rb->cluster_builder == nullptr) { + rb->cluster_builder = memnew(ClusterBuilderRD); + } + rb->cluster_builder->set_shared(&cluster_builder_shared); + _free_render_buffer_data(rb); { @@ -5746,22 +5996,28 @@ void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_ren rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa); _render_buffers_uniform_set_changed(p_render_buffers); + + rb->cluster_builder->setup(Size2i(p_width, p_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture); +} + +void RendererSceneRenderRD::gi_set_use_half_resolution(bool p_enable) { + gi.half_resolution = p_enable; } -void RasterizerSceneRD::sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) { +void RendererSceneRenderRD::sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) { sss_quality = p_quality; } -RS::SubSurfaceScatteringQuality RasterizerSceneRD::sub_surface_scattering_get_quality() const { +RS::SubSurfaceScatteringQuality RendererSceneRenderRD::sub_surface_scattering_get_quality() const { return sss_quality; } -void RasterizerSceneRD::sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) { +void RendererSceneRenderRD::sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) { sss_scale = p_scale; sss_depth_scale = p_depth_scale; } -void RasterizerSceneRD::shadows_quality_set(RS::ShadowQuality p_quality) { +void RendererSceneRenderRD::shadows_quality_set(RS::ShadowQuality p_quality) { ERR_FAIL_INDEX_MSG(p_quality, RS::SHADOW_QUALITY_MAX, "Shadow quality too high, please see RenderingServer's ShadowQuality enum"); if (shadows_quality != p_quality) { @@ -5801,7 +6057,7 @@ void RasterizerSceneRD::shadows_quality_set(RS::ShadowQuality p_quality) { } } -void RasterizerSceneRD::directional_shadow_quality_set(RS::ShadowQuality p_quality) { +void RendererSceneRenderRD::directional_shadow_quality_set(RS::ShadowQuality p_quality) { ERR_FAIL_INDEX_MSG(p_quality, RS::SHADOW_QUALITY_MAX, "Shadow quality too high, please see RenderingServer's ShadowQuality enum"); if (directional_shadow_quality != p_quality) { @@ -5841,32 +6097,49 @@ void RasterizerSceneRD::directional_shadow_quality_set(RS::ShadowQuality p_quali } } -int RasterizerSceneRD::get_roughness_layers() const { +int RendererSceneRenderRD::get_roughness_layers() const { return roughness_layers; } -bool RasterizerSceneRD::is_using_radiance_cubemap_array() const { +bool RendererSceneRenderRD::is_using_radiance_cubemap_array() const { return sky_use_cubemap_array; } -RasterizerSceneRD::RenderBufferData *RasterizerSceneRD::render_buffers_get_data(RID p_render_buffers) { +RendererSceneRenderRD::RenderBufferData *RendererSceneRenderRD::render_buffers_get_data(RID p_render_buffers) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, nullptr); return rb->data; } -void RasterizerSceneRD::_setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment) { - for (int i = 0; i < p_reflection_probe_cull_count; i++) { - RID rpi = p_reflection_probe_cull_result[i]; +void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflections, const Transform &p_camera_inverse_transform, RID p_environment) { + cluster.reflection_count = 0; - if (i >= (int)cluster.max_reflections) { - reflection_probe_instance_set_render_index(rpi, 0); //invalid, but something needs to be set + for (uint32_t i = 0; i < (uint32_t)p_reflections.size(); i++) { + if (cluster.reflection_count == cluster.max_reflections) { + break; + } + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_reflections[i]); + if (!rpi) { continue; } - reflection_probe_instance_set_render_index(rpi, i); + cluster.reflection_sort[cluster.reflection_count].instance = rpi; + cluster.reflection_sort[cluster.reflection_count].depth = -p_camera_inverse_transform.xform(rpi->transform.origin).z; + cluster.reflection_count++; + } + + if (cluster.reflection_count > 0) { + SortArray<Cluster::InstanceSort<ReflectionProbeInstance>> sort_array; + sort_array.sort(cluster.reflection_sort, cluster.reflection_count); + } + + for (uint32_t i = 0; i < cluster.reflection_count; i++) { + ReflectionProbeInstance *rpi = cluster.reflection_sort[i].instance; + + rpi->render_index = i; - RID base_probe = reflection_probe_instance_get_probe(rpi); + RID base_probe = rpi->probe; Cluster::ReflectionData &reflection_ubo = cluster.reflections[i]; @@ -5875,7 +6148,7 @@ void RasterizerSceneRD::_setup_reflections(RID *p_reflection_probe_cull_result, reflection_ubo.box_extents[0] = extents.x; reflection_ubo.box_extents[1] = extents.y; reflection_ubo.box_extents[2] = extents.z; - reflection_ubo.index = reflection_probe_instance_get_atlas_index(rpi); + reflection_ubo.index = rpi->atlas_index; Vector3 origin_offset = storage->reflection_probe_get_origin_offset(base_probe); @@ -5884,61 +6157,98 @@ void RasterizerSceneRD::_setup_reflections(RID *p_reflection_probe_cull_result, reflection_ubo.box_offset[2] = origin_offset.z; reflection_ubo.mask = storage->reflection_probe_get_cull_mask(base_probe); - float intensity = storage->reflection_probe_get_intensity(base_probe); - bool interior = storage->reflection_probe_is_interior(base_probe); - bool box_projection = storage->reflection_probe_is_box_projection(base_probe); + reflection_ubo.intensity = storage->reflection_probe_get_intensity(base_probe); + reflection_ubo.ambient_mode = storage->reflection_probe_get_ambient_mode(base_probe); - reflection_ubo.params[0] = intensity; - reflection_ubo.params[1] = 0; - reflection_ubo.params[2] = interior ? 1.0 : 0.0; - reflection_ubo.params[3] = box_projection ? 1.0 : 0.0; + reflection_ubo.exterior = !storage->reflection_probe_is_interior(base_probe); + reflection_ubo.box_project = storage->reflection_probe_is_box_projection(base_probe); Color ambient_linear = storage->reflection_probe_get_ambient_color(base_probe).to_linear(); float interior_ambient_energy = storage->reflection_probe_get_ambient_color_energy(base_probe); - uint32_t ambient_mode = storage->reflection_probe_get_ambient_mode(base_probe); reflection_ubo.ambient[0] = ambient_linear.r * interior_ambient_energy; reflection_ubo.ambient[1] = ambient_linear.g * interior_ambient_energy; reflection_ubo.ambient[2] = ambient_linear.b * interior_ambient_energy; - reflection_ubo.ambient_mode = ambient_mode; - Transform transform = reflection_probe_instance_get_transform(rpi); + Transform transform = rpi->transform; Transform proj = (p_camera_inverse_transform * transform).inverse(); - RasterizerStorageRD::store_transform(proj, reflection_ubo.local_matrix); + RendererStorageRD::store_transform(proj, reflection_ubo.local_matrix); - cluster.builder.add_reflection_probe(transform, extents); + current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_REFLECTION_PROBE, transform, extents); - reflection_probe_instance_set_render_pass(rpi, RSG::rasterizer->get_frame_number()); + rpi->last_pass = RSG::rasterizer->get_frame_number(); } - if (p_reflection_probe_cull_count) { - RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, MIN(cluster.max_reflections, (unsigned int)p_reflection_probe_cull_count) * sizeof(ReflectionData), cluster.reflections, true); + if (cluster.reflection_count) { + RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, cluster.reflection_count * sizeof(ReflectionData), cluster.reflections); } } -void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count) { - uint32_t light_count = 0; +void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const Transform &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count) { + Transform inverse_transform = p_camera_transform.affine_inverse(); + r_directional_light_count = 0; r_positional_light_count = 0; sky_scene_state.ubo.directional_light_count = 0; - for (int i = 0; i < p_light_cull_count; i++) { - RID li = p_light_cull_result[i]; - RID base = light_instance_get_base_light(li); + Plane camera_plane(p_camera_transform.origin, -p_camera_transform.basis.get_axis(Vector3::AXIS_Z).normalized()); + + cluster.omni_light_count = 0; + cluster.spot_light_count = 0; + + for (int i = 0; i < (int)p_lights.size(); i++) { + LightInstance *li = light_instance_owner.getornull(p_lights[i]); + if (!li) { + continue; + } + RID base = li->light; ERR_CONTINUE(base.is_null()); RS::LightType type = storage->light_get_type(base); switch (type) { case RS::LIGHT_DIRECTIONAL: { - if (r_directional_light_count >= cluster.max_directional_lights) { + // Copy to SkyDirectionalLightData + if (r_directional_light_count < sky_scene_state.max_directional_lights) { + SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[r_directional_light_count]; + Transform light_transform = li->transform; + Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized(); + + sky_light_data.direction[0] = world_direction.x; + sky_light_data.direction[1] = world_direction.y; + sky_light_data.direction[2] = -world_direction.z; + + float sign = storage->light_is_negative(base) ? -1 : 1; + sky_light_data.energy = sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY); + + Color linear_col = storage->light_get_color(base).to_linear(); + sky_light_data.color[0] = linear_col.r; + sky_light_data.color[1] = linear_col.g; + sky_light_data.color[2] = linear_col.b; + + sky_light_data.enabled = true; + + float angular_diameter = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); + if (angular_diameter > 0.0) { + // I know tan(0) is 0, but let's not risk it with numerical precision. + // technically this will keep expanding until reaching the sun, but all we care + // is expand until we reach the radius of the near plane (there can't be more occluders than that) + angular_diameter = Math::tan(Math::deg2rad(angular_diameter)); + } else { + angular_diameter = 0.0; + } + sky_light_data.size = angular_diameter; + sky_scene_state.ubo.directional_light_count++; + } + + if (r_directional_light_count >= cluster.max_directional_lights || storage->light_directional_is_sky_only(base)) { continue; } Cluster::DirectionalLightData &light_data = cluster.directional_lights[r_directional_light_count]; - Transform light_transform = light_instance_get_base_transform(li); + Transform light_transform = li->transform; - Vector3 direction = p_camera_inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized(); + Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized(); light_data.direction[0] = direction.x; light_data.direction[1] = direction.y; @@ -6017,28 +6327,28 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull int limit = smode == RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ? 0 : (smode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS ? 1 : 3); light_data.blend_splits = storage->light_directional_get_blend_splits(base); for (int j = 0; j < 4; j++) { - Rect2 atlas_rect = light_instance_get_directional_shadow_atlas_rect(li, j); - CameraMatrix matrix = light_instance_get_shadow_camera(li, j); - float split = light_instance_get_directional_shadow_split(li, MIN(limit, j)); + Rect2 atlas_rect = li->shadow_transform[j].atlas_rect; + CameraMatrix matrix = li->shadow_transform[j].camera; + float split = li->shadow_transform[MIN(limit, j)].split; CameraMatrix bias; bias.set_light_bias(); CameraMatrix rectm; rectm.set_light_atlas_rect(atlas_rect); - Transform modelview = (p_camera_inverse_transform * light_instance_get_shadow_transform(li, j)).inverse(); + Transform modelview = (inverse_transform * li->shadow_transform[j].transform).inverse(); CameraMatrix shadow_mtx = rectm * bias * matrix * modelview; light_data.shadow_split_offsets[j] = split; - float bias_scale = light_instance_get_shadow_bias_scale(li, j); + float bias_scale = li->shadow_transform[j].bias_scale; light_data.shadow_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * bias_scale; - light_data.shadow_normal_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * light_instance_get_directional_shadow_texel_size(li, j); + light_data.shadow_normal_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * li->shadow_transform[j].shadow_texel_size; light_data.shadow_transmittance_bias[j] = storage->light_get_transmittance_bias(base) * bias_scale; - light_data.shadow_z_range[j] = light_instance_get_shadow_range(li, j); - light_data.shadow_range_begin[j] = light_instance_get_shadow_range_begin(li, j); - RasterizerStorageRD::store_camera(shadow_mtx, light_data.shadow_matrices[j]); + light_data.shadow_z_range[j] = li->shadow_transform[j].farplane; + light_data.shadow_range_begin[j] = li->shadow_transform[j].range_begin; + RendererStorageRD::store_camera(shadow_mtx, light_data.shadow_matrices[j]); - Vector2 uv_scale = light_instance_get_shadow_uv_scale(li, j); + Vector2 uv_scale = li->shadow_transform[j].uv_scale; uv_scale *= atlas_rect.size; //adapt to atlas size switch (j) { case 0: { @@ -6073,213 +6383,232 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull } } - // Copy to SkyDirectionalLightData - if (r_directional_light_count < sky_scene_state.max_directional_lights) { - SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[r_directional_light_count]; - - Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized(); - - sky_light_data.direction[0] = world_direction.x; - sky_light_data.direction[1] = world_direction.y; - sky_light_data.direction[2] = -world_direction.z; - - sky_light_data.energy = light_data.energy / Math_PI; - - sky_light_data.color[0] = light_data.color[0]; - sky_light_data.color[1] = light_data.color[1]; - sky_light_data.color[2] = light_data.color[2]; - - sky_light_data.enabled = true; - sky_light_data.size = angular_diameter; - sky_scene_state.ubo.directional_light_count++; - } - r_directional_light_count++; } break; - case RS::LIGHT_SPOT: case RS::LIGHT_OMNI: { - if (light_count >= cluster.max_lights) { + if (cluster.omni_light_count >= cluster.max_lights) { continue; } - Transform light_transform = light_instance_get_base_transform(li); + cluster.omni_light_sort[cluster.omni_light_count].instance = li; + cluster.omni_light_sort[cluster.omni_light_count].depth = camera_plane.distance_to(li->transform.origin); + cluster.omni_light_count++; + } break; + case RS::LIGHT_SPOT: { + if (cluster.spot_light_count >= cluster.max_lights) { + continue; + } - Cluster::LightData &light_data = cluster.lights[light_count]; - cluster.lights_instances[light_count] = li; + cluster.spot_light_sort[cluster.spot_light_count].instance = li; + cluster.spot_light_sort[cluster.spot_light_count].depth = camera_plane.distance_to(li->transform.origin); + cluster.spot_light_count++; + } break; + } - float sign = storage->light_is_negative(base) ? -1 : 1; - Color linear_col = storage->light_get_color(base).to_linear(); + li->last_pass = RSG::rasterizer->get_frame_number(); + } - light_data.attenuation_energy[0] = Math::make_half_float(storage->light_get_param(base, RS::LIGHT_PARAM_ATTENUATION)); - light_data.attenuation_energy[1] = Math::make_half_float(sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI); + if (cluster.omni_light_count) { + SortArray<Cluster::InstanceSort<LightInstance>> sorter; + sorter.sort(cluster.omni_light_sort, cluster.omni_light_count); + } - light_data.color_specular[0] = MIN(uint32_t(linear_col.r * 255), 255); - light_data.color_specular[1] = MIN(uint32_t(linear_col.g * 255), 255); - light_data.color_specular[2] = MIN(uint32_t(linear_col.b * 255), 255); - light_data.color_specular[3] = MIN(uint32_t(storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 255), 255); + if (cluster.spot_light_count) { + SortArray<Cluster::InstanceSort<LightInstance>> sorter; + sorter.sort(cluster.spot_light_sort, cluster.spot_light_count); + } - float radius = MAX(0.001, storage->light_get_param(base, RS::LIGHT_PARAM_RANGE)); - light_data.inv_radius = 1.0 / radius; + ShadowAtlas *shadow_atlas = nullptr; - Vector3 pos = p_camera_inverse_transform.xform(light_transform.origin); + if (p_shadow_atlas.is_valid() && p_using_shadows) { + shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + } - light_data.position[0] = pos.x; - light_data.position[1] = pos.y; - light_data.position[2] = pos.z; + for (uint32_t i = 0; i < (cluster.omni_light_count + cluster.spot_light_count); i++) { + uint32_t index = (i < cluster.omni_light_count) ? i : i - (cluster.omni_light_count); + Cluster::LightData &light_data = (i < cluster.omni_light_count) ? cluster.omni_lights[index] : cluster.spot_lights[index]; + RS::LightType type = (i < cluster.omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT; + LightInstance *li = (i < cluster.omni_light_count) ? cluster.omni_light_sort[index].instance : cluster.spot_light_sort[index].instance; + RID base = li->light; - Vector3 direction = p_camera_inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, -1))).normalized(); + cluster.lights_instances[i] = li->self; - light_data.direction[0] = direction.x; - light_data.direction[1] = direction.y; - light_data.direction[2] = direction.z; + Transform light_transform = li->transform; - float size = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); + float sign = storage->light_is_negative(base) ? -1 : 1; + Color linear_col = storage->light_get_color(base).to_linear(); - light_data.size = size; + light_data.attenuation = storage->light_get_param(base, RS::LIGHT_PARAM_ATTENUATION); - light_data.cone_attenuation_angle[0] = Math::make_half_float(storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION)); - float spot_angle = storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE); - light_data.cone_attenuation_angle[1] = Math::make_half_float(Math::cos(Math::deg2rad(spot_angle))); + float energy = sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI; - light_data.mask = storage->light_get_cull_mask(base); + light_data.color[0] = linear_col.r * energy; + light_data.color[1] = linear_col.g * energy; + light_data.color[2] = linear_col.b * energy; + light_data.specular_amount = storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 2.0; - light_data.atlas_rect[0] = 0; - light_data.atlas_rect[1] = 0; - light_data.atlas_rect[2] = 0; - light_data.atlas_rect[3] = 0; + float radius = MAX(0.001, storage->light_get_param(base, RS::LIGHT_PARAM_RANGE)); + light_data.inv_radius = 1.0 / radius; - RID projector = storage->light_get_projector(base); + Vector3 pos = inverse_transform.xform(light_transform.origin); - if (projector.is_valid()) { - Rect2 rect = storage->decal_atlas_get_texture_rect(projector); + light_data.position[0] = pos.x; + light_data.position[1] = pos.y; + light_data.position[2] = pos.z; - if (type == RS::LIGHT_SPOT) { - light_data.projector_rect[0] = rect.position.x; - light_data.projector_rect[1] = rect.position.y + rect.size.height; //flip because shadow is flipped - light_data.projector_rect[2] = rect.size.width; - light_data.projector_rect[3] = -rect.size.height; - } else { - light_data.projector_rect[0] = rect.position.x; - light_data.projector_rect[1] = rect.position.y; - light_data.projector_rect[2] = rect.size.width; - light_data.projector_rect[3] = rect.size.height * 0.5; //used by dp, so needs to be half - } - } else { - light_data.projector_rect[0] = 0; - light_data.projector_rect[1] = 0; - light_data.projector_rect[2] = 0; - light_data.projector_rect[3] = 0; - } + Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, -1))).normalized(); - if (p_using_shadows && p_shadow_atlas.is_valid() && shadow_atlas_owns_light_instance(p_shadow_atlas, li)) { - // fill in the shadow information + light_data.direction[0] = direction.x; + light_data.direction[1] = direction.y; + light_data.direction[2] = direction.z; - Color shadow_color = storage->light_get_shadow_color(base); + float size = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); - light_data.shadow_color_enabled[0] = MIN(uint32_t(shadow_color.r * 255), 255); - light_data.shadow_color_enabled[1] = MIN(uint32_t(shadow_color.g * 255), 255); - light_data.shadow_color_enabled[2] = MIN(uint32_t(shadow_color.b * 255), 255); - light_data.shadow_color_enabled[3] = 255; + light_data.size = size; - if (type == RS::LIGHT_SPOT) { - light_data.shadow_bias = (storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0); - float shadow_texel_size = Math::tan(Math::deg2rad(spot_angle)) * radius * 2.0; - shadow_texel_size *= light_instance_get_shadow_texel_size(li, p_shadow_atlas); + light_data.cone_attenuation = storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION); + float spot_angle = storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE); + light_data.cone_angle = Math::cos(Math::deg2rad(spot_angle)); - light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size; + light_data.mask = storage->light_get_cull_mask(base); - } else { //omni - light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0; - float shadow_texel_size = light_instance_get_shadow_texel_size(li, p_shadow_atlas); - light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 2.0; // applied in -1 .. 1 space - } + light_data.atlas_rect[0] = 0; + light_data.atlas_rect[1] = 0; + light_data.atlas_rect[2] = 0; + light_data.atlas_rect[3] = 0; - light_data.transmittance_bias = storage->light_get_transmittance_bias(base); + RID projector = storage->light_get_projector(base); - Rect2 rect = light_instance_get_shadow_atlas_rect(li, p_shadow_atlas); + if (projector.is_valid()) { + Rect2 rect = storage->decal_atlas_get_texture_rect(projector); - light_data.atlas_rect[0] = rect.position.x; - light_data.atlas_rect[1] = rect.position.y; - light_data.atlas_rect[2] = rect.size.width; - light_data.atlas_rect[3] = rect.size.height; + if (type == RS::LIGHT_SPOT) { + light_data.projector_rect[0] = rect.position.x; + light_data.projector_rect[1] = rect.position.y + rect.size.height; //flip because shadow is flipped + light_data.projector_rect[2] = rect.size.width; + light_data.projector_rect[3] = -rect.size.height; + } else { + light_data.projector_rect[0] = rect.position.x; + light_data.projector_rect[1] = rect.position.y; + light_data.projector_rect[2] = rect.size.width; + light_data.projector_rect[3] = rect.size.height * 0.5; //used by dp, so needs to be half + } + } else { + light_data.projector_rect[0] = 0; + light_data.projector_rect[1] = 0; + light_data.projector_rect[2] = 0; + light_data.projector_rect[3] = 0; + } - light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR); - light_data.shadow_volumetric_fog_fade = 1.0 / storage->light_get_shadow_volumetric_fog_fade(base); + if (shadow_atlas && shadow_atlas->shadow_owners.has(li->self)) { + // fill in the shadow information - if (type == RS::LIGHT_OMNI) { - light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another - Transform proj = (p_camera_inverse_transform * light_transform).inverse(); + light_data.shadow_enabled = true; - RasterizerStorageRD::store_transform(proj, light_data.shadow_matrix); + if (type == RS::LIGHT_SPOT) { + light_data.shadow_bias = (storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0); + float shadow_texel_size = Math::tan(Math::deg2rad(spot_angle)) * radius * 2.0; + shadow_texel_size *= light_instance_get_shadow_texel_size(li->self, p_shadow_atlas); - if (size > 0.0) { - light_data.soft_shadow_size = size; - } else { - light_data.soft_shadow_size = 0.0; - light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF - } + light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size; - } else if (type == RS::LIGHT_SPOT) { - Transform modelview = (p_camera_inverse_transform * light_transform).inverse(); - CameraMatrix bias; - bias.set_light_bias(); + } else { //omni + light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0; + float shadow_texel_size = light_instance_get_shadow_texel_size(li->self, p_shadow_atlas); + light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 2.0; // applied in -1 .. 1 space + } - CameraMatrix shadow_mtx = bias * light_instance_get_shadow_camera(li, 0) * modelview; - RasterizerStorageRD::store_camera(shadow_mtx, light_data.shadow_matrix); + light_data.transmittance_bias = storage->light_get_transmittance_bias(base); - if (size > 0.0) { - CameraMatrix cm = light_instance_get_shadow_camera(li, 0); - float half_np = cm.get_z_near() * Math::tan(Math::deg2rad(spot_angle)); - light_data.soft_shadow_size = (size * 0.5 / radius) / (half_np / cm.get_z_near()) * rect.size.width; - } else { - light_data.soft_shadow_size = 0.0; - light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF - } - } + Rect2 rect = light_instance_get_shadow_atlas_rect(li->self, p_shadow_atlas); + + light_data.atlas_rect[0] = rect.position.x; + light_data.atlas_rect[1] = rect.position.y; + light_data.atlas_rect[2] = rect.size.width; + light_data.atlas_rect[3] = rect.size.height; + + light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR); + light_data.shadow_volumetric_fog_fade = 1.0 / storage->light_get_shadow_volumetric_fog_fade(base); + + if (type == RS::LIGHT_OMNI) { + light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another + Transform proj = (inverse_transform * light_transform).inverse(); + + RendererStorageRD::store_transform(proj, light_data.shadow_matrix); + + if (size > 0.0) { + light_data.soft_shadow_size = size; } else { - light_data.shadow_color_enabled[3] = 0; + light_data.soft_shadow_size = 0.0; + light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF } - light_instance_set_index(li, light_count); + } else if (type == RS::LIGHT_SPOT) { + Transform modelview = (inverse_transform * light_transform).inverse(); + CameraMatrix bias; + bias.set_light_bias(); - cluster.builder.add_light(type == RS::LIGHT_SPOT ? LightClusterBuilder::LIGHT_TYPE_SPOT : LightClusterBuilder::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle); + CameraMatrix shadow_mtx = bias * li->shadow_transform[0].camera * modelview; + RendererStorageRD::store_camera(shadow_mtx, light_data.shadow_matrix); - light_count++; - r_positional_light_count++; - } break; + if (size > 0.0) { + CameraMatrix cm = li->shadow_transform[0].camera; + float half_np = cm.get_z_near() * Math::tan(Math::deg2rad(spot_angle)); + light_data.soft_shadow_size = (size * 0.5 / radius) / (half_np / cm.get_z_near()) * rect.size.width; + } else { + light_data.soft_shadow_size = 0.0; + light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF + } + } + } else { + light_data.shadow_enabled = false; } - light_instance_set_render_pass(li, RSG::rasterizer->get_frame_number()); + li->light_index = index; + + current_cluster_builder->add_light(type == RS::LIGHT_SPOT ? ClusterBuilderRD::LIGHT_TYPE_SPOT : ClusterBuilderRD::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle); + + r_positional_light_count++; + } - //update UBO for forward rendering, blit to texture for clustered + if (cluster.omni_light_count) { + RD::get_singleton()->buffer_update(cluster.omni_light_buffer, 0, sizeof(Cluster::LightData) * cluster.omni_light_count, cluster.omni_lights); } - if (light_count) { - RD::get_singleton()->buffer_update(cluster.light_buffer, 0, sizeof(Cluster::LightData) * light_count, cluster.lights, true); + if (cluster.spot_light_count) { + RD::get_singleton()->buffer_update(cluster.spot_light_buffer, 0, sizeof(Cluster::LightData) * cluster.spot_light_count, cluster.spot_lights); } if (r_directional_light_count) { - RD::get_singleton()->buffer_update(cluster.directional_light_buffer, 0, sizeof(Cluster::DirectionalLightData) * r_directional_light_count, cluster.directional_lights, true); + RD::get_singleton()->buffer_update(cluster.directional_light_buffer, 0, sizeof(Cluster::DirectionalLightData) * r_directional_light_count, cluster.directional_lights); } } -void RasterizerSceneRD::_setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform) { +void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const Transform &p_camera_inverse_xform) { Transform uv_xform; uv_xform.basis.scale(Vector3(2.0, 1.0, 2.0)); uv_xform.origin = Vector3(-1.0, 0.0, -1.0); - p_decal_count = MIN((uint32_t)p_decal_count, cluster.max_decals); - int idx = 0; - for (int i = 0; i < p_decal_count; i++) { - RID di = p_decal_instances[i]; - RID decal = decal_instance_get_base(di); + uint32_t decal_count = p_decals.size(); - Transform xform = decal_instance_get_transform(di); + cluster.decal_count = 0; - float fade = 1.0; + for (uint32_t i = 0; i < decal_count; i++) { + if (cluster.decal_count == cluster.max_decals) { + break; + } + + DecalInstance *di = decal_instance_owner.getornull(p_decals[i]); + if (!di) { + continue; + } + RID decal = di->decal; + + Transform xform = di->transform; + + real_t distance = -p_camera_inverse_xform.xform(xform.origin).z; if (storage->decal_is_distance_fade_enabled(decal)) { - real_t distance = -p_camera_inverse_xform.xform(xform.origin).z; float fade_begin = storage->decal_get_distance_fade_begin(decal); float fade_length = storage->decal_get_distance_fade_length(decal); @@ -6287,19 +6616,44 @@ void RasterizerSceneRD::_setup_decals(const RID *p_decal_instances, int p_decal_ if (distance > fade_begin + fade_length) { continue; // do not use this decal, its invisible } + } + } + cluster.decal_sort[cluster.decal_count].instance = di; + cluster.decal_sort[cluster.decal_count].depth = distance; + cluster.decal_count++; + } + + if (cluster.decal_count > 0) { + SortArray<Cluster::InstanceSort<DecalInstance>> sort_array; + sort_array.sort(cluster.decal_sort, cluster.decal_count); + } + + for (uint32_t i = 0; i < cluster.decal_count; i++) { + DecalInstance *di = cluster.decal_sort[i].instance; + RID decal = di->decal; + + Transform xform = di->transform; + float fade = 1.0; + + if (storage->decal_is_distance_fade_enabled(decal)) { + real_t distance = -p_camera_inverse_xform.xform(xform.origin).z; + float fade_begin = storage->decal_get_distance_fade_begin(decal); + float fade_length = storage->decal_get_distance_fade_length(decal); + + if (distance > fade_begin) { fade = 1.0 - (distance - fade_begin) / fade_length; } } - Cluster::DecalData &dd = cluster.decals[idx]; + Cluster::DecalData &dd = cluster.decals[i]; Vector3 decal_extents = storage->decal_get_extents(decal); Transform scale_xform; scale_xform.basis.scale(Vector3(decal_extents.x, decal_extents.y, decal_extents.z)); - Transform to_decal_xform = (p_camera_inverse_xform * decal_instance_get_transform(di) * scale_xform * uv_xform).affine_inverse(); - RasterizerStorageRD::store_transform(to_decal_xform, dd.xform); + Transform to_decal_xform = (p_camera_inverse_xform * di->transform * scale_xform * uv_xform).affine_inverse(); + RendererStorageRD::store_transform(to_decal_xform, dd.xform); Vector3 normal = xform.basis.get_axis(Vector3::AXIS_Y).normalized(); normal = p_camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine @@ -6337,7 +6691,7 @@ void RasterizerSceneRD::_setup_decals(const RID *p_decal_instances, int p_decal_ dd.normal_rect[3] = rect.size.y; Basis normal_xform = p_camera_inverse_xform.basis * xform.basis.orthonormalized(); - RasterizerStorageRD::store_basis_3x4(normal_xform, dd.normal_xform); + RendererStorageRD::store_basis_3x4(normal_xform, dd.normal_xform); } else { dd.normal_rect[0] = 0; dd.normal_rect[1] = 0; @@ -6383,17 +6737,15 @@ void RasterizerSceneRD::_setup_decals(const RID *p_decal_instances, int p_decal_ dd.upper_fade = storage->decal_get_upper_fade(decal); dd.lower_fade = storage->decal_get_lower_fade(decal); - cluster.builder.add_decal(xform, decal_extents); - - idx++; + current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_DECAL, xform, decal_extents); } - if (idx > 0) { - RD::get_singleton()->buffer_update(cluster.decal_buffer, 0, sizeof(Cluster::DecalData) * idx, cluster.decals, true); + if (cluster.decal_count > 0) { + RD::get_singleton()->buffer_update(cluster.decal_buffer, 0, sizeof(Cluster::DecalData) * cluster.decal_count, cluster.decals); } } -void RasterizerSceneRD::_volumetric_fog_erase(RenderBuffers *rb) { +void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) { ERR_FAIL_COND(!rb->volumetric_fog); RD::get_singleton()->free(rb->volumetric_fog->light_density_map); @@ -6417,7 +6769,7 @@ void RasterizerSceneRD::_volumetric_fog_erase(RenderBuffers *rb) { rb->volumetric_fog = nullptr; } -void RasterizerSceneRD::_allocate_shadow_shrink_stages(RID p_base, int p_base_size, Vector<ShadowShrinkStage> &shrink_stages, uint32_t p_target_size) { +void RendererSceneRenderRD::_allocate_shadow_shrink_stages(RID p_base, int p_base_size, Vector<ShadowShrinkStage> &shrink_stages, uint32_t p_target_size) { //create fog mipmaps uint32_t fog_texture_size = p_target_size; uint32_t base_texture_size = p_base_size; @@ -6450,7 +6802,7 @@ void RasterizerSceneRD::_allocate_shadow_shrink_stages(RID p_base, int p_base_si } } -void RasterizerSceneRD::_clear_shadow_shrink_stages(Vector<ShadowShrinkStage> &shrink_stages) { +void RendererSceneRenderRD::_clear_shadow_shrink_stages(Vector<ShadowShrinkStage> &shrink_stages) { for (int i = 1; i < shrink_stages.size(); i++) { RD::get_singleton()->free(shrink_stages[i].texture); if (shrink_stages[i].filter_texture.is_valid()) { @@ -6460,7 +6812,7 @@ void RasterizerSceneRD::_clear_shadow_shrink_stages(Vector<ShadowShrinkStage> &s shrink_stages.clear(); } -void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count) { +void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); Environment *env = environment_owner.getornull(p_environment); @@ -6494,7 +6846,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir tf.width = target_width; tf.height = target_height; tf.depth = volumetric_fog_depth; - tf.type = RD::TEXTURE_TYPE_3D; + tf.texture_type = RD::TEXTURE_TYPE_3D; tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; rb->volumetric_fog->light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -6508,7 +6860,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; u.binding = 0; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(rb->volumetric_fog->fog_map); uniforms.push_back(u); } @@ -6519,7 +6871,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir //update directional shadow if (p_use_directional_shadows) { - if (directional_shadow.shrink_stages.empty()) { + if (directional_shadow.shrink_stages.is_empty()) { if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { //invalidate uniform set, we will need a new one RD::get_singleton()->free(rb->volumetric_fog->uniform_set); @@ -6554,7 +6906,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir bool force_shrink_shadows = false; - if (shadow_atlas->shrink_stages.empty()) { + if (shadow_atlas->shrink_stages.is_empty()) { if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { //invalidate uniform set, we will need a new one RD::get_singleton()->free(rb->volumetric_fog->uniform_set); @@ -6572,8 +6924,10 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir cluster.lights_shadow_rect_cache_count = 0; - for (int i = 0; i < p_positional_light_count; i++) { - if (cluster.lights[i].shadow_color_enabled[3] > 127) { + for (uint32_t i = 0; i < cluster.omni_light_count + cluster.spot_light_count; i++) { + Cluster::LightData &ld = i < cluster.omni_light_count ? cluster.omni_lights[i] : cluster.spot_lights[i - cluster.omni_light_count]; + + if (ld.shadow_enabled != 0) { RID li = cluster.lights_instances[i]; ERR_CONTINUE(!shadow_atlas->shadow_owners.has(li)); @@ -6611,7 +6965,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir cluster.lights_shadow_rect_cache_count++; - if (cluster.lights_shadow_rect_cache_count == cluster.max_lights) { + if (cluster.lights_shadow_rect_cache_count == cluster.max_lights * 2) { break; //light limit reached } } @@ -6681,10 +7035,10 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; if (shadow_atlas == nullptr || shadow_atlas->shrink_stages.size() == 0) { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK)); } else { u.ids.push_back(shadow_atlas->shrink_stages[shadow_atlas->shrink_stages.size() - 1].texture); } @@ -6694,10 +7048,10 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; if (directional_shadow.shrink_stages.size() == 0) { - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK)); } else { u.ids.push_back(directional_shadow.shrink_stages[directional_shadow.shrink_stages.size() - 1].texture); } @@ -6706,39 +7060,38 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 3; - u.ids.push_back(get_positional_light_buffer()); + u.ids.push_back(get_omni_light_buffer()); uniforms.push_back(u); } - { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 4; - u.ids.push_back(get_directional_light_buffer()); + u.ids.push_back(get_spot_light_buffer()); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 5; - u.ids.push_back(get_cluster_builder_texture()); + u.ids.push_back(get_directional_light_buffer()); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 6; - u.ids.push_back(get_cluster_builder_indices_buffer()); + u.ids.push_back(rb->cluster_builder->get_cluster_buffer()); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 7; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); @@ -6746,7 +7099,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 8; u.ids.push_back(rb->volumetric_fog->light_density_map); uniforms.push_back(u); @@ -6754,7 +7107,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 9; u.ids.push_back(rb->volumetric_fog->fog_map); uniforms.push_back(u); @@ -6762,7 +7115,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 10; u.ids.push_back(shadow_sampler); uniforms.push_back(u); @@ -6770,7 +7123,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 11; u.ids.push_back(render_buffers_get_gi_probe_buffer(p_render_buffers)); uniforms.push_back(u); @@ -6778,7 +7131,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 12; for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) { u.ids.push_back(rb->giprobe_textures[i]); @@ -6787,11 +7140,18 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 13; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 14; + u.ids.push_back(volumetric_fog.params_ubo); + uniforms.push_back(u); + } rb->volumetric_fog->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, 0), 0); @@ -6808,7 +7168,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 0; u.ids.push_back(gi.sdfgi_ubo); uniforms.push_back(u); @@ -6816,7 +7176,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; u.ids.push_back(rb->sdfgi->ambient_texture); uniforms.push_back(u); @@ -6824,7 +7184,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; u.ids.push_back(rb->sdfgi->occlusion_texture); uniforms.push_back(u); @@ -6837,7 +7197,7 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir rb->volumetric_fog->length = env->volumetric_fog_length; rb->volumetric_fog->spread = env->volumetric_fog_detail_spread; - VolumetricFogShader::PushConstant push_constant; + VolumetricFogShader::ParamsUBO params; Vector2 frustum_near_size = p_cam_projection.get_viewport_half_extents(); Vector2 frustum_far_size = p_cam_projection.get_far_plane_half_extents(); @@ -6853,51 +7213,71 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir fog_near_size = Vector2(); } - push_constant.fog_frustum_size_begin[0] = fog_near_size.x; - push_constant.fog_frustum_size_begin[1] = fog_near_size.y; + params.fog_frustum_size_begin[0] = fog_near_size.x; + params.fog_frustum_size_begin[1] = fog_near_size.y; - push_constant.fog_frustum_size_end[0] = fog_far_size.x; - push_constant.fog_frustum_size_end[1] = fog_far_size.y; + params.fog_frustum_size_end[0] = fog_far_size.x; + params.fog_frustum_size_end[1] = fog_far_size.y; - push_constant.z_near = z_near; - push_constant.z_far = z_far; + params.z_near = z_near; + params.z_far = z_far; - push_constant.fog_frustum_end = fog_end; + params.fog_frustum_end = fog_end; - push_constant.fog_volume_size[0] = rb->volumetric_fog->width; - push_constant.fog_volume_size[1] = rb->volumetric_fog->height; - push_constant.fog_volume_size[2] = rb->volumetric_fog->depth; + params.fog_volume_size[0] = rb->volumetric_fog->width; + params.fog_volume_size[1] = rb->volumetric_fog->height; + params.fog_volume_size[2] = rb->volumetric_fog->depth; - push_constant.directional_light_count = p_directional_light_count; + params.directional_light_count = p_directional_light_count; Color light = env->volumetric_fog_light.to_linear(); - push_constant.light_energy[0] = light.r * env->volumetric_fog_light_energy; - push_constant.light_energy[1] = light.g * env->volumetric_fog_light_energy; - push_constant.light_energy[2] = light.b * env->volumetric_fog_light_energy; - push_constant.base_density = env->volumetric_fog_density; + params.light_energy[0] = light.r * env->volumetric_fog_light_energy; + params.light_energy[1] = light.g * env->volumetric_fog_light_energy; + params.light_energy[2] = light.b * env->volumetric_fog_light_energy; + params.base_density = env->volumetric_fog_density; + + params.detail_spread = env->volumetric_fog_detail_spread; + params.gi_inject = env->volumetric_fog_gi_inject; + + params.cam_rotation[0] = p_cam_transform.basis[0][0]; + params.cam_rotation[1] = p_cam_transform.basis[1][0]; + params.cam_rotation[2] = p_cam_transform.basis[2][0]; + params.cam_rotation[3] = 0; + params.cam_rotation[4] = p_cam_transform.basis[0][1]; + params.cam_rotation[5] = p_cam_transform.basis[1][1]; + params.cam_rotation[6] = p_cam_transform.basis[2][1]; + params.cam_rotation[7] = 0; + params.cam_rotation[8] = p_cam_transform.basis[0][2]; + params.cam_rotation[9] = p_cam_transform.basis[1][2]; + params.cam_rotation[10] = p_cam_transform.basis[2][2]; + params.cam_rotation[11] = 0; + params.filter_axis = 0; + params.max_gi_probes = env->volumetric_fog_gi_inject > 0.001 ? p_gi_probe_count : 0; - push_constant.detail_spread = env->volumetric_fog_detail_spread; - push_constant.gi_inject = env->volumetric_fog_gi_inject; + { + uint32_t cluster_size = rb->cluster_builder->get_cluster_size(); + params.cluster_shift = get_shift_from_power_of_2(cluster_size); - push_constant.cam_rotation[0] = p_cam_transform.basis[0][0]; - push_constant.cam_rotation[1] = p_cam_transform.basis[1][0]; - push_constant.cam_rotation[2] = p_cam_transform.basis[2][0]; - push_constant.cam_rotation[3] = 0; - push_constant.cam_rotation[4] = p_cam_transform.basis[0][1]; - push_constant.cam_rotation[5] = p_cam_transform.basis[1][1]; - push_constant.cam_rotation[6] = p_cam_transform.basis[2][1]; - push_constant.cam_rotation[7] = 0; - push_constant.cam_rotation[8] = p_cam_transform.basis[0][2]; - push_constant.cam_rotation[9] = p_cam_transform.basis[1][2]; - push_constant.cam_rotation[10] = p_cam_transform.basis[2][2]; - push_constant.cam_rotation[11] = 0; - push_constant.filter_axis = 0; - push_constant.max_gi_probes = env->volumetric_fog_gi_inject > 0.001 ? p_gi_probe_count : 0; + uint32_t cluster_screen_width = (rb->width - 1) / cluster_size + 1; + uint32_t cluster_screen_height = (rb->height - 1) / cluster_size + 1; + params.cluster_type_size = cluster_screen_width * cluster_screen_height * (32 + 32); + params.cluster_width = cluster_screen_width; + params.max_cluster_element_count_div_32 = max_cluster_elements / 32; + + params.screen_size[0] = rb->width; + params.screen_size[1] = rb->height; + } /* Vector2 dssize = directional_shadow_get_size(); push_constant.directional_shadow_pixel_size[0] = 1.0 / dssize.x; push_constant.directional_shadow_pixel_size[1] = 1.0 / dssize.y; */ + + RENDER_TIMESTAMP(">Volumetric Fog"); + + RENDER_TIMESTAMP("Render Fog"); + RD::get_singleton()->buffer_update(volumetric_fog.params_ubo, 0, sizeof(VolumetricFogShader::ParamsUBO), ¶ms); + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); bool use_filter = volumetric_fog_filter_active; @@ -6905,41 +7285,51 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[using_sdfgi ? VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI : VOLUMETRIC_FOG_SHADER_DENSITY]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0); + if (using_sdfgi) { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->sdfgi_uniform_set, 1); } - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant)); RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth, 4, 4, 4); RD::get_singleton()->compute_list_add_barrier(compute_list); if (use_filter) { + RENDER_TIMESTAMP("Filter Fog"); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FILTER]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant)); RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth, 8, 8, 1); - RD::get_singleton()->compute_list_add_barrier(compute_list); + RD::get_singleton()->compute_list_end(); + //need restart for buffer update - push_constant.filter_axis = 1; + params.filter_axis = 1; + RD::get_singleton()->buffer_update(volumetric_fog.params_ubo, 0, sizeof(VolumetricFogShader::ParamsUBO), ¶ms); + compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FILTER]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set2, 0); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant)); + if (using_sdfgi) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->sdfgi_uniform_set, 1); + } RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth, 8, 8, 1); RD::get_singleton()->compute_list_add_barrier(compute_list); } + RENDER_TIMESTAMP("Integrate Fog"); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FOG]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::PushConstant)); RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, 1, 8, 8, 1); RD::get_singleton()->compute_list_end(); + + RENDER_TIMESTAMP("<Volumetric Fog"); } -void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { +void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold) { Color clear_color; if (p_render_buffers.is_valid()) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); @@ -6950,20 +7340,43 @@ void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_ca } //assign render indices to giprobes - for (int i = 0; i < p_gi_probe_cull_count; i++) { - GIProbeInstance *giprobe_inst = gi_probe_instance_owner.getornull(p_gi_probe_cull_result[i]); + for (uint32_t i = 0; i < (uint32_t)p_gi_probes.size(); i++) { + GIProbeInstance *giprobe_inst = gi_probe_instance_owner.getornull(p_gi_probes[i]); if (giprobe_inst) { giprobe_inst->render_index = i; } } + const PagedArray<RID> *lights = &p_lights; + const PagedArray<RID> *reflections = &p_reflection_probes; + const PagedArray<RID> *gi_probes = &p_gi_probes; + + PagedArray<RID> empty; + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) { - p_light_cull_count = 0; - p_reflection_probe_cull_count = 0; - p_gi_probe_cull_count = 0; + lights = ∅ + reflections = ∅ + gi_probes = ∅ } - cluster.builder.begin(p_cam_transform.affine_inverse(), p_cam_projection); //prepare cluster + if (render_buffers_owner.owns(p_render_buffers)) { + RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + current_cluster_builder = rb->cluster_builder; + } else if (reflection_probe_instance_owner.owns(p_reflection_probe)) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_reflection_probe); + ReflectionAtlas *ra = reflection_atlas_owner.getornull(rpi->atlas); + if (!ra) { + ERR_PRINT("reflection probe has no reflection atlas! Bug?"); + current_cluster_builder = nullptr; + } else { + current_cluster_builder = ra->cluster_builder; + } + } else { + ERR_PRINT("No cluster builder, bug"); //should never happen, will crash + current_cluster_builder = nullptr; + } + + current_cluster_builder->begin(p_cam_transform, p_cam_projection, !p_reflection_probe.is_valid()); bool using_shadows = true; @@ -6973,17 +7386,20 @@ void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_ca } } else { //do not render reflections when rendering a reflection probe - _setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment); + _setup_reflections(*reflections, p_cam_transform.affine_inverse(), p_environment); } uint32_t directional_light_count = 0; uint32_t positional_light_count = 0; - _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows, directional_light_count, positional_light_count); - _setup_decals(p_decal_cull_result, p_decal_cull_count, p_cam_transform.affine_inverse()); - cluster.builder.bake_cluster(); //bake to cluster + _setup_lights(*lights, p_cam_transform, p_shadow_atlas, using_shadows, directional_light_count, positional_light_count); + _setup_decals(p_decals, p_cam_transform.affine_inverse()); + + current_cluster_builder->bake_cluster(); uint32_t gi_probe_count = 0; - _setup_giprobes(p_render_buffers, p_cam_transform, p_gi_probe_cull_result, p_gi_probe_cull_count, gi_probe_count); + if (p_render_buffers.is_valid()) { + _setup_giprobes(p_render_buffers, p_cam_transform, *gi_probes, gi_probe_count); + } if (p_render_buffers.is_valid()) { bool directional_shadows = false; @@ -6996,9 +7412,30 @@ void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_ca _update_volumetric_fog(p_render_buffers, p_environment, p_cam_projection, p_cam_transform, p_shadow_atlas, directional_light_count, directional_shadows, positional_light_count, gi_probe_count); } - _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, directional_light_count, p_gi_probe_cull_result, p_gi_probe_cull_count, p_lightmap_cull_result, p_lightmap_cull_count, p_environment, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color); + _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, directional_light_count, *gi_probes, p_lightmaps, p_environment, current_cluster_builder->get_cluster_buffer(), current_cluster_builder->get_cluster_size(), current_cluster_builder->get_max_cluster_elements(), p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color, p_screen_lod_threshold); if (p_render_buffers.is_valid()) { + if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) { + ClusterBuilderRD::ElementType elem_type = ClusterBuilderRD::ELEMENT_TYPE_MAX; + switch (debug_draw) { + case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS: + elem_type = ClusterBuilderRD::ELEMENT_TYPE_OMNI_LIGHT; + break; + case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS: + elem_type = ClusterBuilderRD::ELEMENT_TYPE_SPOT_LIGHT; + break; + case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS: + elem_type = ClusterBuilderRD::ELEMENT_TYPE_DECAL; + break; + case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES: + elem_type = ClusterBuilderRD::ELEMENT_TYPE_REFLECTION_PROBE; + break; + default: { + } + } + current_cluster_builder->debug(elem_type); + } + RENDER_TIMESTAMP("Tonemap"); _render_buffers_post_process_and_tonemap(p_render_buffers, p_environment, p_camera_effects, p_cam_projection); @@ -7009,31 +7446,36 @@ void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_ca } } -void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) { +void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold) { LightInstance *light_instance = light_instance_owner.getornull(p_light); ERR_FAIL_COND(!light_instance); Rect2i atlas_rect; - RID atlas_texture; + uint32_t atlas_size; + RID atlas_fb; bool using_dual_paraboloid = false; bool using_dual_paraboloid_flip = false; - float znear = 0; - float zfar = 0; RID render_fb; RID render_texture; - float bias = 0; - float normal_bias = 0; + float zfar; bool use_pancake = false; - bool use_linear_depth = false; bool render_cubemap = false; bool finalize_cubemap = false; + bool flip_y = false; + CameraMatrix light_projection; Transform light_transform; + bool clear_region = true; + bool begin_texture = true; + bool end_texture = true; + if (storage->light_get_type(light_instance->light) == RS::LIGHT_DIRECTIONAL) { + _update_directional_shadow_atlas(); + //set pssm stuff if (light_instance->last_scene_shadow_pass != scene_pass) { light_instance->directional_rect = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, directional_shadow.current_light); @@ -7050,6 +7492,7 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas atlas_rect.size.width = light_instance->directional_rect.size.x; atlas_rect.size.height = light_instance->directional_rect.size.y; + int pass_count = 1; if (storage->light_directional_get_shadow_mode(light_instance->light) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { atlas_rect.size.width /= 2; atlas_rect.size.height /= 2; @@ -7062,7 +7505,7 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas atlas_rect.position.x += atlas_rect.size.width; atlas_rect.position.y += atlas_rect.size.height; } - + pass_count = 4; } else if (storage->light_directional_get_shadow_mode(light_instance->light) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { atlas_rect.size.height /= 2; @@ -7070,6 +7513,7 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas } else { atlas_rect.position.y += atlas_rect.size.height; } + pass_count = 2; } light_instance->shadow_transform[p_pass].atlas_rect = atlas_rect; @@ -7077,15 +7521,15 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas light_instance->shadow_transform[p_pass].atlas_rect.position /= directional_shadow.size; light_instance->shadow_transform[p_pass].atlas_rect.size /= directional_shadow.size; - float bias_mult = light_instance->shadow_transform[p_pass].bias_scale; zfar = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE); - bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_BIAS) * bias_mult; - normal_bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * bias_mult; - ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size); - render_fb = shadow_map->fb; - render_texture = shadow_map->depth; - atlas_texture = directional_shadow.depth; + render_fb = directional_shadow.fb; + render_texture = RID(); + flip_y = true; + + clear_region = false; + begin_texture = (directional_shadow.current_light == 1) && (p_pass == 0); //light is 1-index because it was incremented above + end_texture = (directional_shadow.current_light == directional_shadow.light_count) && (p_pass == pass_count - 1); } else { //set from shadow atlas @@ -7094,6 +7538,8 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas ERR_FAIL_COND(!shadow_atlas); ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light)); + _update_shadow_atlas(shadow_atlas); + uint32_t key = shadow_atlas->shadow_owners[p_light]; uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; @@ -7112,11 +7558,8 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas atlas_rect.size.width = shadow_size; atlas_rect.size.height = shadow_size; - atlas_texture = shadow_atlas->depth; zfar = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE); - bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_BIAS); - normal_bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS); if (storage->light_get_type(light_instance->light) == RS::LIGHT_OMNI) { if (storage->light_omni_get_shadow_mode(light_instance->light) == RS::LIGHT_OMNI_SHADOW_CUBE) { @@ -7129,6 +7572,10 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas light_transform = light_instance->shadow_transform[0].transform; render_cubemap = true; finalize_cubemap = p_pass == 5; + atlas_fb = shadow_atlas->fb; + + atlas_size = shadow_atlas->size; + clear_region = false; } else { light_projection = light_instance->shadow_transform[0].camera; @@ -7139,57 +7586,46 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas using_dual_paraboloid = true; using_dual_paraboloid_flip = p_pass == 1; - - ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size); - render_fb = shadow_map->fb; - render_texture = shadow_map->depth; + render_fb = shadow_atlas->fb; + flip_y = true; } } else if (storage->light_get_type(light_instance->light) == RS::LIGHT_SPOT) { light_projection = light_instance->shadow_transform[0].camera; light_transform = light_instance->shadow_transform[0].transform; - ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size); - render_fb = shadow_map->fb; - render_texture = shadow_map->depth; + render_fb = shadow_atlas->fb; - znear = light_instance->shadow_transform[0].camera.get_z_near(); - use_linear_depth = true; + flip_y = true; } } if (render_cubemap) { //rendering to cubemap - _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake); + _render_shadow(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold); if (finalize_cubemap) { //reblit - atlas_rect.size.height /= 2; - storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_texture, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), 0.0, false); - atlas_rect.position.y += atlas_rect.size.height; - storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_texture, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), 0.0, true); + Rect2 atlas_rect_norm = atlas_rect; + atlas_rect_norm.position.x /= float(atlas_size); + atlas_rect_norm.position.y /= float(atlas_size); + atlas_rect_norm.size.x /= float(atlas_size); + atlas_rect_norm.size.y /= float(atlas_size); + atlas_rect_norm.size.height /= 2; + storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, light_projection.get_z_near(), light_projection.get_z_far(), false); + atlas_rect_norm.position.y += atlas_rect_norm.size.height; + storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, light_projection.get_z_near(), light_projection.get_z_far(), true); } } else { //render shadow - - _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, bias, normal_bias, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake); - - //copy to atlas - if (use_linear_depth) { - storage->get_effects()->copy_depth_to_rect_and_linearize(render_texture, atlas_texture, atlas_rect, true, znear, zfar); - } else { - storage->get_effects()->copy_depth_to_rect(render_texture, atlas_texture, atlas_rect, true); - } - - //does not work from depth to color - //RD::get_singleton()->texture_copy(render_texture, atlas_texture, Vector3(0, 0, 0), Vector3(atlas_rect.position.x, atlas_rect.position.y, 0), Vector3(atlas_rect.size.x, atlas_rect.size.y, 1), 0, 0, 0, 0, true); + _render_shadow(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, atlas_rect, flip_y, clear_region, begin_texture, end_texture); } } -void RasterizerSceneRD::render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) { - _render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_framebuffer, p_region); +void RendererSceneRenderRD::render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { + _render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, p_framebuffer, p_region); } -void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, InstanceBase **p_cull_result, int p_cull_count) { +void RendererSceneRenderRD::render_sdfgi(RID p_render_buffers, int p_region, const PagedArray<GeometryInstance *> &p_instances) { //print_line("rendering region " + itos(p_region)); RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -7205,14 +7641,14 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc if (cascade_prev != cascade) { //initialize render - RD::get_singleton()->texture_clear(rb->sdfgi->render_albedo, Color(0, 0, 0, 0), 0, 1, 0, 1, true); - RD::get_singleton()->texture_clear(rb->sdfgi->render_emission, Color(0, 0, 0, 0), 0, 1, 0, 1, true); - RD::get_singleton()->texture_clear(rb->sdfgi->render_emission_aniso, Color(0, 0, 0, 0), 0, 1, 0, 1, true); - RD::get_singleton()->texture_clear(rb->sdfgi->render_geom_facing, Color(0, 0, 0, 0), 0, 1, 0, 1, true); + RD::get_singleton()->texture_clear(rb->sdfgi->render_albedo, Color(0, 0, 0, 0), 0, 1, 0, 1); + RD::get_singleton()->texture_clear(rb->sdfgi->render_emission, Color(0, 0, 0, 0), 0, 1, 0, 1); + RD::get_singleton()->texture_clear(rb->sdfgi->render_emission_aniso, Color(0, 0, 0, 0), 0, 1, 0, 1); + RD::get_singleton()->texture_clear(rb->sdfgi->render_geom_facing, Color(0, 0, 0, 0), 0, 1, 0, 1); } //print_line("rendering cascade " + itos(p_region) + " objects: " + itos(p_cull_count) + " bounds: " + bounds + " from: " + from + " size: " + size + " cell size: " + rtos(rb->sdfgi->cascades[cascade].cell_size)); - _render_sdfgi(p_render_buffers, from, size, bounds, p_cull_result, p_cull_count, rb->sdfgi->render_albedo, rb->sdfgi->render_emission, rb->sdfgi->render_emission_aniso, rb->sdfgi->render_geom_facing); + _render_sdfgi(p_render_buffers, from, size, bounds, p_instances, rb->sdfgi->render_albedo, rb->sdfgi->render_emission, rb->sdfgi->render_emission_aniso, rb->sdfgi->render_geom_facing); if (cascade_next != cascade) { RENDER_TIMESTAMP(">SDFGI Update SDF"); @@ -7237,6 +7673,9 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc push_constant.scroll[1] = 0; push_constant.scroll[2] = 0; } + + rb->sdfgi->cascades[cascade].all_dynamic_lights_dirty = true; + push_constant.grid_size = rb->sdfgi->cascade_size; push_constant.cascade = cascade; @@ -7288,7 +7727,6 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc ipush_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count; ipush_constant.image_size[1] = rb->sdfgi->probe_axis_count; - ipush_constant.image_size[1] = rb->sdfgi->probe_axis_count; int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR; ipush_constant.cascade = cascade; @@ -7313,6 +7751,23 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1); RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant)); RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count, rb->sdfgi->probe_axis_count, 1, 8, 8, 1); + + RD::get_singleton()->compute_list_add_barrier(compute_list); + + if (rb->sdfgi->uses_multibounce) { + //multibounce requires this to be stored so direct light can read from it + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_STORE]); + + //convert to octahedral to store + ipush_constant.image_size[0] *= SDFGI::LIGHTPROBE_OCT_SIZE; + ipush_constant.image_size[1] *= SDFGI::LIGHTPROBE_OCT_SIZE; + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].integrate_uniform_set, 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1, 8, 8, 1); + } } //ok finally barrier @@ -7321,7 +7776,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc //clear dispatch indirect data uint32_t dispatch_indirct_data[4] = { 0, 0, 0, 0 }; - RD::get_singleton()->buffer_update(rb->sdfgi->cascades[cascade].solid_cell_dispatch_buffer, 0, sizeof(uint32_t) * 4, dispatch_indirct_data, true); + RD::get_singleton()->buffer_update(rb->sdfgi->cascades[cascade].solid_cell_dispatch_buffer, 0, sizeof(uint32_t) * 4, dispatch_indirct_data); RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); @@ -7492,9 +7947,9 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc RD::get_singleton()->compute_list_end(); //clear these textures, as they will have previous garbage on next draw - RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1, true); - RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1, true); - RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1, true); + RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); + RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); + RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); #if 0 Vector<uint8_t> data = RD::get_singleton()->texture_get_data(rb->sdfgi->cascades[cascade].sdf, 0); @@ -7527,7 +7982,7 @@ void RasterizerSceneRD::render_sdfgi(RID p_render_buffers, int p_region, Instanc } } -void RasterizerSceneRD::render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, InstanceBase **p_cull_result, int p_cull_count) { +void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) { ERR_FAIL_COND(!storage->particles_collision_is_heightfield(p_collider)); Vector3 extents = storage->particles_collision_get_extents(p_collider) * p_transform.basis.get_scale(); CameraMatrix cm; @@ -7541,37 +7996,18 @@ void RasterizerSceneRD::render_particle_collider_heightfield(RID p_collider, con RID fb = storage->particles_collision_get_heightfield_framebuffer(p_collider); - _render_particle_collider_heightfield(fb, cam_xform, cm, p_cull_result, p_cull_count); + _render_particle_collider_heightfield(fb, cam_xform, cm, p_instances); } -void RasterizerSceneRD::render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const RID **p_positional_light_cull_result, const uint32_t *p_positional_light_cull_count) { +void RendererSceneRenderRD::render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); ERR_FAIL_COND(!rb->sdfgi); - ERR_FAIL_COND(p_positional_light_cull_count == 0); - _sdfgi_update_cascades(p_render_buffers); //need cascades updated for this - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.direct_light_pipeline[SDGIShader::DIRECT_LIGHT_MODE_STATIC]); - - SDGIShader::DirectLightPushConstant dl_push_constant; - - dl_push_constant.grid_size[0] = rb->sdfgi->cascade_size; - dl_push_constant.grid_size[1] = rb->sdfgi->cascade_size; - dl_push_constant.grid_size[2] = rb->sdfgi->cascade_size; - dl_push_constant.max_cascades = rb->sdfgi->cascades.size(); - dl_push_constant.probe_axis_size = rb->sdfgi->probe_axis_count; - dl_push_constant.multibounce = false; // this is static light, do not multibounce yet - dl_push_constant.y_mult = rb->sdfgi->y_mult; - - //all must be processed - dl_push_constant.process_offset = 0; - dl_push_constant.process_increment = 1; - SDGIShader::Light lights[SDFGI::MAX_STATIC_LIGHTS]; + uint32_t light_count[SDFGI::MAX_STATIC_LIGHTS]; for (uint32_t i = 0; i < p_cascade_count; i++) { ERR_CONTINUE(p_cascade_indices[i] >= rb->sdfgi->cascades.size()); @@ -7586,7 +8022,7 @@ void RasterizerSceneRD::render_sdfgi_static_lights(RID p_render_buffers, uint32_ int idx = 0; - for (uint32_t j = 0; j < p_positional_light_cull_count[i]; j++) { + for (uint32_t j = 0; j < (uint32_t)p_positional_light_cull_result[i].size(); j++) { if (idx == SDFGI::MAX_STATIC_LIGHTS) { break; } @@ -7634,11 +8070,38 @@ void RasterizerSceneRD::render_sdfgi_static_lights(RID p_render_buffers, uint32_ } if (idx > 0) { - RD::get_singleton()->buffer_update(cc.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights, true); + RD::get_singleton()->buffer_update(cc.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights); } - dl_push_constant.light_count = idx; + + light_count[i] = idx; } + } + + /* Static Lights */ + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.direct_light_pipeline[SDGIShader::DIRECT_LIGHT_MODE_STATIC]); + + SDGIShader::DirectLightPushConstant dl_push_constant; + + dl_push_constant.grid_size[0] = rb->sdfgi->cascade_size; + dl_push_constant.grid_size[1] = rb->sdfgi->cascade_size; + dl_push_constant.grid_size[2] = rb->sdfgi->cascade_size; + dl_push_constant.max_cascades = rb->sdfgi->cascades.size(); + dl_push_constant.probe_axis_size = rb->sdfgi->probe_axis_count; + dl_push_constant.multibounce = false; // this is static light, do not multibounce yet + dl_push_constant.y_mult = rb->sdfgi->y_mult; + + //all must be processed + dl_push_constant.process_offset = 0; + dl_push_constant.process_increment = 1; + + for (uint32_t i = 0; i < p_cascade_count; i++) { + ERR_CONTINUE(p_cascade_indices[i] >= rb->sdfgi->cascades.size()); + SDFGI::Cascade &cc = rb->sdfgi->cascades[p_cascade_indices[i]]; + + dl_push_constant.light_count = light_count[i]; dl_push_constant.cascade = p_cascade_indices[i]; if (dl_push_constant.light_count > 0) { @@ -7651,7 +8114,7 @@ void RasterizerSceneRD::render_sdfgi_static_lights(RID p_render_buffers, uint32_ RD::get_singleton()->compute_list_end(); } -bool RasterizerSceneRD::free(RID p_rid) { +bool RendererSceneRenderRD::free(RID p_rid) { if (render_buffers_owner.owns(p_rid)) { RenderBuffers *rb = render_buffers_owner.getornull(p_rid); _free_render_buffer_data(rb); @@ -7662,6 +8125,9 @@ bool RasterizerSceneRD::free(RID p_rid) { if (rb->volumetric_fog) { _volumetric_fog_erase(rb); } + if (rb->cluster_builder) { + memdelete(rb->cluster_builder); + } render_buffers_owner.free(p_rid); } else if (environment_owner.owns(p_rid)) { //not much to delete, just free it @@ -7671,6 +8137,10 @@ bool RasterizerSceneRD::free(RID p_rid) { camera_effects_owner.free(p_rid); } else if (reflection_atlas_owner.owns(p_rid)) { reflection_atlas_set_size(p_rid, 0, 0); + ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_rid); + if (ra->cluster_builder) { + memdelete(ra->cluster_builder); + } reflection_atlas_owner.free(p_rid); } else if (reflection_probe_instance_owner.owns(p_rid)) { //not much to delete, just free it @@ -7679,6 +8149,8 @@ bool RasterizerSceneRD::free(RID p_rid) { reflection_probe_instance_owner.free(p_rid); } else if (decal_instance_owner.owns(p_rid)) { decal_instance_owner.free(p_rid); + } else if (lightmap_instance_owner.owns(p_rid)) { + lightmap_instance_owner.free(p_rid); } else if (gi_probe_instance_owner.owns(p_rid)) { GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_rid); if (gi_probe->texture.is_valid()) { @@ -7750,38 +8222,38 @@ bool RasterizerSceneRD::free(RID p_rid) { return true; } -void RasterizerSceneRD::set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) { +void RendererSceneRenderRD::set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) { debug_draw = p_debug_draw; } -void RasterizerSceneRD::update() { +void RendererSceneRenderRD::update() { _update_dirty_skys(); } -void RasterizerSceneRD::set_time(double p_time, double p_step) { +void RendererSceneRenderRD::set_time(double p_time, double p_step) { time = p_time; time_step = p_step; } -void RasterizerSceneRD::screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) { +void RendererSceneRenderRD::screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) { screen_space_roughness_limiter = p_enable; screen_space_roughness_limiter_amount = p_amount; screen_space_roughness_limiter_limit = p_limit; } -bool RasterizerSceneRD::screen_space_roughness_limiter_is_active() const { +bool RendererSceneRenderRD::screen_space_roughness_limiter_is_active() const { return screen_space_roughness_limiter; } -float RasterizerSceneRD::screen_space_roughness_limiter_get_amount() const { +float RendererSceneRenderRD::screen_space_roughness_limiter_get_amount() const { return screen_space_roughness_limiter_amount; } -float RasterizerSceneRD::screen_space_roughness_limiter_get_limit() const { +float RendererSceneRenderRD::screen_space_roughness_limiter_get_limit() const { return screen_space_roughness_limiter_limit; } -TypedArray<Image> RasterizerSceneRD::bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) { +TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; tf.width = p_image_size.width; // Always 64x64 @@ -7814,19 +8286,27 @@ TypedArray<Image> RasterizerSceneRD::bake_render_uv2(RID p_base, const Vector<RI //RID sampled_light; - InstanceBase ins; + GeometryInstance *gi = geometry_instance_create(p_base); - ins.base_type = RSG::storage->get_base_type(p_base); - ins.base = p_base; - ins.materials.resize(RSG::storage->mesh_get_surface_count(p_base)); - for (int i = 0; i < ins.materials.size(); i++) { - if (i < p_material_overrides.size()) { - ins.materials.write[i] = p_material_overrides[i]; + uint32_t sc = RSG::storage->mesh_get_surface_count(p_base); + Vector<RID> materials; + materials.resize(sc); + + for (uint32_t i = 0; i < sc; i++) { + if (i < (uint32_t)p_material_overrides.size()) { + materials.write[i] = p_material_overrides[i]; } } - InstanceBase *cull = &ins; - _render_uv2(&cull, 1, fb, Rect2i(0, 0, p_image_size.width, p_image_size.height)); + geometry_instance_set_surface_materials(gi, materials); + + if (cull_argument.size() == 0) { + cull_argument.push_back(nullptr); + } + cull_argument[0] = gi; + _render_uv2(cull_argument, fb, Rect2i(0, 0, p_image_size.width, p_image_size.height)); + + geometry_instance_free(gi); TypedArray<Image> ret; @@ -7872,49 +8352,64 @@ TypedArray<Image> RasterizerSceneRD::bake_render_uv2(RID p_base, const Vector<RI return ret; } -void RasterizerSceneRD::sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) { +void RendererSceneRenderRD::sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) { sdfgi_debug_probe_pos = p_position; sdfgi_debug_probe_dir = p_dir; } -RasterizerSceneRD *RasterizerSceneRD::singleton = nullptr; +RendererSceneRenderRD *RendererSceneRenderRD::singleton = nullptr; -RID RasterizerSceneRD::get_cluster_builder_texture() { - return cluster.builder.get_cluster_texture(); +RID RendererSceneRenderRD::get_reflection_probe_buffer() { + return cluster.reflection_buffer; } - -RID RasterizerSceneRD::get_cluster_builder_indices_buffer() { - return cluster.builder.get_cluster_indices_buffer(); +RID RendererSceneRenderRD::get_omni_light_buffer() { + return cluster.omni_light_buffer; } -RID RasterizerSceneRD::get_reflection_probe_buffer() { - return cluster.reflection_buffer; -} -RID RasterizerSceneRD::get_positional_light_buffer() { - return cluster.light_buffer; +RID RendererSceneRenderRD::get_spot_light_buffer() { + return cluster.spot_light_buffer; } -RID RasterizerSceneRD::get_directional_light_buffer() { + +RID RendererSceneRenderRD::get_directional_light_buffer() { return cluster.directional_light_buffer; } -RID RasterizerSceneRD::get_decal_buffer() { +RID RendererSceneRenderRD::get_decal_buffer() { return cluster.decal_buffer; } -int RasterizerSceneRD::get_max_directional_lights() const { +int RendererSceneRenderRD::get_max_directional_lights() const { return cluster.max_directional_lights; } -RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { +bool RendererSceneRenderRD::is_low_end() const { + return low_end; +} + +RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) { + max_cluster_elements = GLOBAL_GET("rendering/cluster_builder/max_clustered_elements"); + storage = p_storage; singleton = this; roughness_layers = GLOBAL_GET("rendering/quality/reflections/roughness_layers"); sky_ggx_samples_quality = GLOBAL_GET("rendering/quality/reflections/ggx_samples"); sky_use_cubemap_array = GLOBAL_GET("rendering/quality/reflections/texture_array_reflections"); - // sky_use_cubemap_array = false; - //uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE); + sdfgi_ray_count = RS::EnvironmentSDFGIRayCount(CLAMP(int32_t(GLOBAL_GET("rendering/sdfgi/probe_ray_count")), 0, int32_t(RS::ENV_SDFGI_RAY_COUNT_MAX - 1))); + sdfgi_frames_to_converge = RS::EnvironmentSDFGIFramesToConverge(CLAMP(int32_t(GLOBAL_GET("rendering/sdfgi/frames_to_converge")), 0, int32_t(RS::ENV_SDFGI_CONVERGE_MAX - 1))); + sdfgi_frames_to_update_light = RS::EnvironmentSDFGIFramesToUpdateLight(CLAMP(int32_t(GLOBAL_GET("rendering/sdfgi/frames_to_update_lights")), 0, int32_t(RS::ENV_SDFGI_UPDATE_LIGHT_MAX - 1))); - { + directional_shadow.size = GLOBAL_GET("rendering/quality/directional_shadow/size"); + directional_shadow.use_16_bits = GLOBAL_GET("rendering/quality/directional_shadow/16_bits"); + + uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE); + + low_end = GLOBAL_GET("rendering/quality/rd_renderer/use_low_end_renderer"); + + if (textures_per_stage < 48) { + low_end = true; + } + + if (!low_end) { //kinda complicated to compute the amount of slots, we try to use as many as we can gi_probe_max_lights = 32; @@ -7943,7 +8438,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { } } - { + if (!low_end) { String defines; Vector<String> versions; versions.push_back("\n#define MODE_DEBUG_COLOR\n"); @@ -7992,8 +8487,8 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { } // register our shader funds - storage->shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_SKY, _create_sky_shader_funcs); - storage->material_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_SKY, _create_sky_material_funcs); + storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_SKY, _create_sky_shader_funcs); + storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_SKY, _create_sky_material_funcs); { ShaderCompilerRD::DefaultIdentifierActions actions; @@ -8057,7 +8552,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { sky_shader.default_material = storage->material_create(); storage->material_set_shader(sky_shader.default_material, sky_shader.default_shader); - SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RasterizerStorageRD::SHADER_TYPE_SKY); + SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY); sky_shader.default_shader_rd = sky_shader.shader.version_get_shader(md->shader_data->version, SKY_VERSION_BACKGROUND); sky_scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SkySceneState::UBO)); @@ -8066,7 +8561,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 0; u.ids.resize(12); RID *ids_ptr = u.ids.ptrw(); @@ -8087,7 +8582,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(storage->global_variables_get_storage_buffer()); uniforms.push_back(u); @@ -8096,7 +8591,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { { RD::Uniform u; u.binding = 2; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(sky_scene_state.uniform_buffer); uniforms.push_back(u); } @@ -8104,7 +8599,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { { RD::Uniform u; u.binding = 3; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(sky_scene_state.directional_light_buffer); uniforms.push_back(u); } @@ -8117,8 +8612,8 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { { RD::Uniform u; u.binding = 0; - u.type = RD::UNIFORM_TYPE_TEXTURE; - RID vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); u.ids.push_back(vfog); uniforms.push_back(u); } @@ -8136,188 +8631,199 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE)); + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE)); uniforms.push_back(u); } sky_scene_state.fog_only_texture_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES); } - { - Vector<String> preprocess_modes; - preprocess_modes.push_back("\n#define MODE_SCROLL\n"); - preprocess_modes.push_back("\n#define MODE_SCROLL_OCCLUSION\n"); - preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD\n"); - preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD_HALF\n"); - preprocess_modes.push_back("\n#define MODE_JUMPFLOOD\n"); - preprocess_modes.push_back("\n#define MODE_JUMPFLOOD_OPTIMIZED\n"); - preprocess_modes.push_back("\n#define MODE_UPSCALE_JUMP_FLOOD\n"); - preprocess_modes.push_back("\n#define MODE_OCCLUSION\n"); - preprocess_modes.push_back("\n#define MODE_STORE\n"); - String defines = "\n#define OCCLUSION_SIZE " + itos(SDFGI::CASCADE_SIZE / SDFGI::PROBE_DIVISOR) + "\n"; - sdfgi_shader.preprocess.initialize(preprocess_modes, defines); - sdfgi_shader.preprocess_shader = sdfgi_shader.preprocess.version_create(); - for (int i = 0; i < SDGIShader::PRE_PROCESS_MAX; i++) { - sdfgi_shader.preprocess_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, i)); + if (!low_end) { + //SDFGI + { + Vector<String> preprocess_modes; + preprocess_modes.push_back("\n#define MODE_SCROLL\n"); + preprocess_modes.push_back("\n#define MODE_SCROLL_OCCLUSION\n"); + preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD\n"); + preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD_HALF\n"); + preprocess_modes.push_back("\n#define MODE_JUMPFLOOD\n"); + preprocess_modes.push_back("\n#define MODE_JUMPFLOOD_OPTIMIZED\n"); + preprocess_modes.push_back("\n#define MODE_UPSCALE_JUMP_FLOOD\n"); + preprocess_modes.push_back("\n#define MODE_OCCLUSION\n"); + preprocess_modes.push_back("\n#define MODE_STORE\n"); + String defines = "\n#define OCCLUSION_SIZE " + itos(SDFGI::CASCADE_SIZE / SDFGI::PROBE_DIVISOR) + "\n"; + sdfgi_shader.preprocess.initialize(preprocess_modes, defines); + sdfgi_shader.preprocess_shader = sdfgi_shader.preprocess.version_create(); + for (int i = 0; i < SDGIShader::PRE_PROCESS_MAX; i++) { + sdfgi_shader.preprocess_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, i)); + } } - } - { - //calculate tables - String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; + { + //calculate tables + String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - Vector<String> direct_light_modes; - direct_light_modes.push_back("\n#define MODE_PROCESS_STATIC\n"); - direct_light_modes.push_back("\n#define MODE_PROCESS_DYNAMIC\n"); - sdfgi_shader.direct_light.initialize(direct_light_modes, defines); - sdfgi_shader.direct_light_shader = sdfgi_shader.direct_light.version_create(); - for (int i = 0; i < SDGIShader::DIRECT_LIGHT_MODE_MAX; i++) { - sdfgi_shader.direct_light_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, i)); + Vector<String> direct_light_modes; + direct_light_modes.push_back("\n#define MODE_PROCESS_STATIC\n"); + direct_light_modes.push_back("\n#define MODE_PROCESS_DYNAMIC\n"); + sdfgi_shader.direct_light.initialize(direct_light_modes, defines); + sdfgi_shader.direct_light_shader = sdfgi_shader.direct_light.version_create(); + for (int i = 0; i < SDGIShader::DIRECT_LIGHT_MODE_MAX; i++) { + sdfgi_shader.direct_light_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, i)); + } } - } - { - //calculate tables - String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - defines += "\n#define SH_SIZE " + itos(SDFGI::SH_SIZE) + "\n"; - - Vector<String> integrate_modes; - integrate_modes.push_back("\n#define MODE_PROCESS\n"); - integrate_modes.push_back("\n#define MODE_STORE\n"); - integrate_modes.push_back("\n#define MODE_SCROLL\n"); - integrate_modes.push_back("\n#define MODE_SCROLL_STORE\n"); - sdfgi_shader.integrate.initialize(integrate_modes, defines); - sdfgi_shader.integrate_shader = sdfgi_shader.integrate.version_create(); + { + //calculate tables + String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; + defines += "\n#define SH_SIZE " + itos(SDFGI::SH_SIZE) + "\n"; + if (sky_use_cubemap_array) { + defines += "\n#define USE_CUBEMAP_ARRAY\n"; + } - for (int i = 0; i < SDGIShader::INTEGRATE_MODE_MAX; i++) { - sdfgi_shader.integrate_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, i)); - } + Vector<String> integrate_modes; + integrate_modes.push_back("\n#define MODE_PROCESS\n"); + integrate_modes.push_back("\n#define MODE_STORE\n"); + integrate_modes.push_back("\n#define MODE_SCROLL\n"); + integrate_modes.push_back("\n#define MODE_SCROLL_STORE\n"); + sdfgi_shader.integrate.initialize(integrate_modes, defines); + sdfgi_shader.integrate_shader = sdfgi_shader.integrate.version_create(); - { - Vector<RD::Uniform> uniforms; + for (int i = 0; i < SDGIShader::INTEGRATE_MODE_MAX; i++) { + sdfgi_shader.integrate_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, i)); + } { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 0; - u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE)); - uniforms.push_back(u); + Vector<RD::Uniform> uniforms; + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 0; + u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE)); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 1; + u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); + uniforms.push_back(u); + } + + sdfgi_shader.integrate_default_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 1); } - { - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; - u.binding = 1; - u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); - uniforms.push_back(u); + } + //GK + { + //calculate tables + String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; + Vector<String> gi_modes; + gi_modes.push_back("\n#define USE_GIPROBES\n"); + gi_modes.push_back("\n#define USE_SDFGI\n"); + gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_GIPROBES\n"); + gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_GIPROBES\n"); + gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n"); + gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_GIPROBES\n"); + + gi.shader.initialize(gi_modes, defines); + gi.shader_version = gi.shader.version_create(); + for (int i = 0; i < GI::MODE_MAX; i++) { + gi.pipelines[i] = RD::get_singleton()->compute_pipeline_create(gi.shader.version_get_shader(gi.shader_version, i)); } - sdfgi_shader.integrate_default_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 1); + gi.sdfgi_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(GI::SDFGIData)); } - } - { - //calculate tables - String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - Vector<String> gi_modes; - gi_modes.push_back(""); - gi.shader.initialize(gi_modes, defines); - gi.shader_version = gi.shader.version_create(); - for (int i = 0; i < GI::MODE_MAX; i++) { - gi.pipelines[i] = RD::get_singleton()->compute_pipeline_create(gi.shader.version_get_shader(gi.shader_version, i)); + { + String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; + Vector<String> debug_modes; + debug_modes.push_back(""); + sdfgi_shader.debug.initialize(debug_modes, defines); + sdfgi_shader.debug_shader = sdfgi_shader.debug.version_create(); + sdfgi_shader.debug_shader_version = sdfgi_shader.debug.version_get_shader(sdfgi_shader.debug_shader, 0); + sdfgi_shader.debug_pipeline = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.debug_shader_version); } + { + String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - gi.sdfgi_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(GI::SDFGIData)); - } - { - String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - Vector<String> debug_modes; - debug_modes.push_back(""); - sdfgi_shader.debug.initialize(debug_modes, defines); - sdfgi_shader.debug_shader = sdfgi_shader.debug.version_create(); - sdfgi_shader.debug_shader_version = sdfgi_shader.debug.version_get_shader(sdfgi_shader.debug_shader, 0); - sdfgi_shader.debug_pipeline = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.debug_shader_version); - } - { - String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; - - Vector<String> versions; - versions.push_back("\n#define MODE_PROBES\n"); - versions.push_back("\n#define MODE_VISIBILITY\n"); + Vector<String> versions; + versions.push_back("\n#define MODE_PROBES\n"); + versions.push_back("\n#define MODE_VISIBILITY\n"); - sdfgi_shader.debug_probes.initialize(versions, defines); - sdfgi_shader.debug_probes_shader = sdfgi_shader.debug_probes.version_create(); + sdfgi_shader.debug_probes.initialize(versions, defines); + sdfgi_shader.debug_probes_shader = sdfgi_shader.debug_probes.version_create(); - { - RD::PipelineRasterizationState rs; - rs.cull_mode = RD::POLYGON_CULL_DISABLED; - RD::PipelineDepthStencilState ds; - ds.enable_depth_test = true; - ds.enable_depth_write = true; - ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; - for (int i = 0; i < SDGIShader::PROBE_DEBUG_MAX; i++) { - RID debug_probes_shader_version = sdfgi_shader.debug_probes.version_get_shader(sdfgi_shader.debug_probes_shader, i); - sdfgi_shader.debug_probes_pipeline[i].setup(debug_probes_shader_version, RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); + { + RD::PipelineRasterizationState rs; + rs.cull_mode = RD::POLYGON_CULL_DISABLED; + RD::PipelineDepthStencilState ds; + ds.enable_depth_test = true; + ds.enable_depth_write = true; + ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + for (int i = 0; i < SDGIShader::PROBE_DEBUG_MAX; i++) { + RID debug_probes_shader_version = sdfgi_shader.debug_probes.version_get_shader(sdfgi_shader.debug_probes_shader, i); + sdfgi_shader.debug_probes_pipeline[i].setup(debug_probes_shader_version, RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); + } } } + default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GI::GIProbeData) * RenderBuffers::MAX_GIPROBES); } - //cluster setup - uint32_t uniform_max_size = RD::get_singleton()->limit_get(RD::LIMIT_MAX_UNIFORM_BUFFER_SIZE); - { //reflections - uint32_t reflection_buffer_size; - if (uniform_max_size < 65536) { - //Yes, you guessed right, ARM again - reflection_buffer_size = uniform_max_size; - } else { - reflection_buffer_size = 65536; - } - cluster.max_reflections = reflection_buffer_size / sizeof(Cluster::ReflectionData); + cluster.max_reflections = max_cluster_elements; cluster.reflections = memnew_arr(Cluster::ReflectionData, cluster.max_reflections); - cluster.reflection_buffer = RD::get_singleton()->storage_buffer_create(reflection_buffer_size); + cluster.reflection_sort = memnew_arr(Cluster::InstanceSort<ReflectionProbeInstance>, cluster.max_decals); + cluster.reflection_buffer = RD::get_singleton()->storage_buffer_create(sizeof(Cluster::ReflectionData) * cluster.max_reflections); } { //lights - cluster.max_lights = MIN(1024 * 1024, uniform_max_size) / sizeof(Cluster::LightData); //1mb of lights + cluster.max_lights = max_cluster_elements; + uint32_t light_buffer_size = cluster.max_lights * sizeof(Cluster::LightData); - cluster.lights = memnew_arr(Cluster::LightData, cluster.max_lights); - cluster.light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size); + cluster.omni_lights = memnew_arr(Cluster::LightData, cluster.max_lights); + cluster.omni_light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size); + cluster.omni_light_sort = memnew_arr(Cluster::InstanceSort<LightInstance>, cluster.max_lights); + cluster.spot_lights = memnew_arr(Cluster::LightData, cluster.max_lights); + cluster.spot_light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size); + cluster.spot_light_sort = memnew_arr(Cluster::InstanceSort<LightInstance>, cluster.max_lights); //defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(cluster.max_lights) + "\n"; - cluster.lights_instances = memnew_arr(RID, cluster.max_lights); - cluster.lights_shadow_rect_cache = memnew_arr(Rect2i, cluster.max_lights); - cluster.max_directional_lights = 8; + //used for volumetric fog shrinking + cluster.lights_instances = memnew_arr(RID, cluster.max_lights * 2); + cluster.lights_shadow_rect_cache = memnew_arr(Rect2i, cluster.max_lights * 2); + + cluster.max_directional_lights = MAX_DIRECTIONAL_LIGHTS; uint32_t directional_light_buffer_size = cluster.max_directional_lights * sizeof(Cluster::DirectionalLightData); cluster.directional_lights = memnew_arr(Cluster::DirectionalLightData, cluster.max_directional_lights); cluster.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size); } { //decals - cluster.max_decals = MIN(1024 * 1024, uniform_max_size) / sizeof(Cluster::DecalData); //1mb of decals + cluster.max_decals = max_cluster_elements; uint32_t decal_buffer_size = cluster.max_decals * sizeof(Cluster::DecalData); cluster.decals = memnew_arr(Cluster::DecalData, cluster.max_decals); + cluster.decal_sort = memnew_arr(Cluster::InstanceSort<DecalInstance>, cluster.max_decals); cluster.decal_buffer = RD::get_singleton()->storage_buffer_create(decal_buffer_size); } - cluster.builder.setup(16, 8, 24); - - { + if (!low_end) { String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n"; Vector<String> volumetric_fog_modes; volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n"); @@ -8329,8 +8835,8 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { for (int i = 0; i < VOLUMETRIC_FOG_SHADER_MAX; i++) { volumetric_fog.pipelines[i] = RD::get_singleton()->compute_pipeline_create(volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, i)); } + volumetric_fog.params_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::ParamsUBO)); } - default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GI::GIProbeData) * RenderBuffers::MAX_GIPROBES); { RD::SamplerState sampler; @@ -8343,7 +8849,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_shape")))); camera_effects_set_dof_blur_quality(RS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_use_jitter")); - environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size")); + environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size"), GLOBAL_GET("rendering/quality/ssao/adaptive_target"), GLOBAL_GET("rendering/quality/ssao/blur_passes"), GLOBAL_GET("rendering/quality/ssao/fadeout_from"), GLOBAL_GET("rendering/quality/ssao/fadeout_to")); screen_space_roughness_limiter = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_enabled"); screen_space_roughness_limiter_amount = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_amount"); screen_space_roughness_limiter_limit = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_limit"); @@ -8364,12 +8870,13 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/volumetric_fog/use_filter")); environment_set_volumetric_fog_directional_shadow_shrink_size(GLOBAL_GET("rendering/volumetric_fog/directional_shadow_shrink")); environment_set_volumetric_fog_positional_shadow_shrink_size(GLOBAL_GET("rendering/volumetric_fog/positional_shadow_shrink")); + + cull_argument.set_page_pool(&cull_argument_pool); + + gi.half_resolution = GLOBAL_GET("rendering/quality/gi/use_half_resolution"); } -RasterizerSceneRD::~RasterizerSceneRD() { - for (Map<Vector2i, ShadowMap>::Element *E = shadow_maps.front(); E; E = E->next()) { - RD::get_singleton()->free(E->get().depth); - } +RendererSceneRenderRD::~RendererSceneRenderRD() { for (Map<int, ShadowCubemap>::Element *E = shadow_cubemaps.front(); E; E = E->next()) { RD::get_singleton()->free(E->get().cubemap); } @@ -8378,23 +8885,27 @@ RasterizerSceneRD::~RasterizerSceneRD() { RD::get_singleton()->free(sky_scene_state.uniform_set); } - RD::get_singleton()->free(default_giprobe_buffer); - RD::get_singleton()->free(gi_probe_lights_uniform); - RD::get_singleton()->free(gi.sdfgi_ubo); + if (!low_end) { + RD::get_singleton()->free(default_giprobe_buffer); + RD::get_singleton()->free(gi_probe_lights_uniform); + RD::get_singleton()->free(gi.sdfgi_ubo); + + giprobe_debug_shader.version_free(giprobe_debug_shader_version); + giprobe_shader.version_free(giprobe_lighting_shader_version); + gi.shader.version_free(gi.shader_version); + sdfgi_shader.debug_probes.version_free(sdfgi_shader.debug_probes_shader); + sdfgi_shader.debug.version_free(sdfgi_shader.debug_shader); + sdfgi_shader.direct_light.version_free(sdfgi_shader.direct_light_shader); + sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader); + sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader); - giprobe_debug_shader.version_free(giprobe_debug_shader_version); - giprobe_shader.version_free(giprobe_lighting_shader_version); - gi.shader.version_free(gi.shader_version); - sdfgi_shader.debug_probes.version_free(sdfgi_shader.debug_probes_shader); - sdfgi_shader.debug.version_free(sdfgi_shader.debug_shader); - sdfgi_shader.direct_light.version_free(sdfgi_shader.direct_light_shader); - sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader); - sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader); + volumetric_fog.shader.version_free(volumetric_fog.shader_version); + RD::get_singleton()->free(volumetric_fog.params_ubo); - volumetric_fog.shader.version_free(volumetric_fog.shader_version); + memdelete_arr(gi_probe_lights); + } - memdelete_arr(gi_probe_lights); - SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RasterizerStorageRD::SHADER_TYPE_SKY); + SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY); sky_shader.shader.version_free(md->shader_data->version); RD::get_singleton()->free(sky_scene_state.directional_light_buffer); RD::get_singleton()->free(sky_scene_state.uniform_buffer); @@ -8411,18 +8922,25 @@ RasterizerSceneRD::~RasterizerSceneRD() { { RD::get_singleton()->free(cluster.directional_light_buffer); - RD::get_singleton()->free(cluster.light_buffer); + RD::get_singleton()->free(cluster.omni_light_buffer); + RD::get_singleton()->free(cluster.spot_light_buffer); RD::get_singleton()->free(cluster.reflection_buffer); RD::get_singleton()->free(cluster.decal_buffer); memdelete_arr(cluster.directional_lights); - memdelete_arr(cluster.lights); + memdelete_arr(cluster.omni_lights); + memdelete_arr(cluster.spot_lights); + memdelete_arr(cluster.omni_light_sort); + memdelete_arr(cluster.spot_light_sort); memdelete_arr(cluster.lights_shadow_rect_cache); memdelete_arr(cluster.lights_instances); memdelete_arr(cluster.reflections); + memdelete_arr(cluster.reflection_sort); memdelete_arr(cluster.decals); + memdelete_arr(cluster.decal_sort); } RD::get_singleton()->free(shadow_sampler); directional_shadow_atlas_set_size(0); + cull_argument.reset(); //avoid exit error } diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 2ad712a9d3..af8cdb9b71 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_scene_rd.h */ +/* renderer_scene_render_rd.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,27 +28,28 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RASTERIZER_SCENE_RD_H -#define RASTERIZER_SCENE_RD_H - -#include "core/local_vector.h" -#include "core/rid_owner.h" -#include "servers/rendering/rasterizer.h" -#include "servers/rendering/rasterizer_rd/light_cluster_builder.h" -#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h" -#include "servers/rendering/rasterizer_rd/shaders/gi.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/giprobe.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/giprobe_debug.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/sdfgi_debug.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/sdfgi_debug_probes.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/sky.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl.gen.h" +#ifndef RENDERING_SERVER_SCENE_RENDER_RD_H +#define RENDERING_SERVER_SCENE_RENDER_RD_H + +#include "core/templates/local_vector.h" +#include "core/templates/rid_owner.h" +#include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_rd/cluster_builder_rd.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" +#include "servers/rendering/renderer_rd/shaders/gi.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/giprobe.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/giprobe_debug.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/sky.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/volumetric_fog.glsl.gen.h" +#include "servers/rendering/renderer_scene_render.h" #include "servers/rendering/rendering_device.h" -class RasterizerSceneRD : public RasterizerScene { +class RendererSceneRenderRD : public RendererSceneRender { protected: double time; @@ -103,17 +104,17 @@ protected: }; virtual RenderBufferData *_create_render_buffer_data() = 0; - void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count); - void _setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform); - void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment); - void _setup_giprobes(RID p_render_buffers, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, uint32_t &r_gi_probes_used); + void _setup_lights(const PagedArray<RID> &p_lights, const Transform &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count); + void _setup_decals(const PagedArray<RID> &p_decals, const Transform &p_camera_inverse_xform); + void _setup_reflections(const PagedArray<RID> &p_reflections, const Transform &p_camera_inverse_transform, RID p_environment); + void _setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used); - virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color) = 0; - virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip, bool p_use_pancake) = 0; - virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0; - virtual void _render_uv2(InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0; - virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, InstanceBase **p_cull_result, int p_cull_count, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) = 0; - virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, InstanceBase **p_cull_result, int p_cull_count) = 0; + virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, int p_directional_light_count, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_cluster_max_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color, float p_screen_lod_threshold) = 0; + virtual void _render_shadow(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true) = 0; + virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; + virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; + virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) = 0; + virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) = 0; virtual void _debug_giprobe(RID p_gi_probe, RenderingDevice::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha); void _debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform); @@ -123,8 +124,6 @@ protected: virtual void _base_uniforms_changed() = 0; virtual void _render_buffers_uniform_set_changed(RID p_render_buffers) = 0; virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) = 0; - virtual RID _render_buffers_get_ambient_texture(RID p_render_buffers) = 0; - virtual RID _render_buffers_get_reflection_texture(RID p_render_buffers) = 0; void _process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection); void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive); @@ -133,16 +132,19 @@ protected: void _setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size); void _update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform); void _draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform); - void _process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_ambient_buffer, RID p_reflection_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count); + void _process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes); + // needed for a single argument calls (material and uv2) + PagedArrayPool<GeometryInstance *> cull_argument_pool; + PagedArray<GeometryInstance *> cull_argument; //need this to exist private: RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED; double time_step = 0; - static RasterizerSceneRD *singleton; + static RendererSceneRenderRD *singleton; int roughness_layers; - RasterizerStorageRD *storage; + RendererStorageRD *storage; struct ReflectionData { struct Layer { @@ -200,11 +202,11 @@ private: RID default_shader_rd; } sky_shader; - struct SkyShaderData : public RasterizerStorageRD::ShaderData { + struct SkyShaderData : public RendererStorageRD::ShaderData { bool valid; RID version; - RenderPipelineVertexFormatCacheRD pipelines[SKY_VERSION_MAX]; + PipelineCacheRD pipelines[SKY_VERSION_MAX]; Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; @@ -224,21 +226,22 @@ private: virtual void set_code(const String &p_Code); virtual void set_default_texture_param(const StringName &p_name, RID p_texture); virtual void get_param_list(List<PropertyInfo> *p_param_list) const; - virtual void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const; + virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; virtual bool is_param_texture(const StringName &p_param) const; virtual bool is_animated() const; virtual bool casts_shadows() const; virtual Variant get_default_parameter(const StringName &p_parameter) const; + virtual RS::ShaderNativeSourceCode get_native_source_code() const; SkyShaderData(); virtual ~SkyShaderData(); }; - RasterizerStorageRD::ShaderData *_create_sky_shader_func(); - static RasterizerStorageRD::ShaderData *_create_sky_shader_funcs() { - return static_cast<RasterizerSceneRD *>(singleton)->_create_sky_shader_func(); + RendererStorageRD::ShaderData *_create_sky_shader_func(); + static RendererStorageRD::ShaderData *_create_sky_shader_funcs() { + return static_cast<RendererSceneRenderRD *>(singleton)->_create_sky_shader_func(); }; - struct SkyMaterialData : public RasterizerStorageRD::MaterialData { + struct SkyMaterialData : public RendererStorageRD::MaterialData { uint64_t last_frame; SkyShaderData *shader_data; RID uniform_buffer; @@ -253,9 +256,9 @@ private: virtual ~SkyMaterialData(); }; - RasterizerStorageRD::MaterialData *_create_sky_material_func(SkyShaderData *p_shader); - static RasterizerStorageRD::MaterialData *_create_sky_material_funcs(RasterizerStorageRD::ShaderData *p_shader) { - return static_cast<RasterizerSceneRD *>(singleton)->_create_sky_material_func(static_cast<SkyShaderData *>(p_shader)); + RendererStorageRD::MaterialData *_create_sky_material_func(SkyShaderData *p_shader); + static RendererStorageRD::MaterialData *_create_sky_material_funcs(RendererStorageRD::ShaderData *p_shader) { + return static_cast<RendererSceneRenderRD *>(singleton)->_create_sky_material_func(static_cast<SkyShaderData *>(p_shader)); }; enum SkyTextureSetVersion { @@ -336,9 +339,11 @@ private: }; Vector<Reflection> reflections; + + ClusterBuilderRD *cluster_builder = nullptr; }; - RID_Owner<ReflectionAtlas> reflection_atlas_owner; + mutable RID_Owner<ReflectionAtlas> reflection_atlas_owner; /* REFLECTION PROBE INSTANCE */ @@ -370,6 +375,15 @@ private: mutable RID_Owner<DecalInstance> decal_instance_owner; + /* LIGHTMAP INSTANCE */ + + struct LightmapInstance { + RID lightmap; + Transform transform; + }; + + mutable RID_Owner<LightmapInstance> lightmap_instance_owner; + /* GIPROBE INSTANCE */ struct GIProbeLight { @@ -512,7 +526,7 @@ private: GiprobeDebugShaderRD giprobe_debug_shader; RID giprobe_debug_shader_version; RID giprobe_debug_shader_version_shaders[GI_PROBE_DEBUG_MAX]; - RenderPipelineVertexFormatCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX]; + PipelineCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX]; RID giprobe_debug_uniform_set; /* SHADOW ATLAS */ @@ -558,6 +572,7 @@ private: uint32_t smallest_subdiv = 0; int size = 0; + bool use_16_bits = false; RID depth; RID fb; //for copying @@ -569,6 +584,8 @@ private: RID_Owner<ShadowAtlas> shadow_atlas_owner; + void _update_shadow_atlas(ShadowAtlas *shadow_atlas); + bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow); RS::ShadowQuality shadows_quality = RS::SHADOW_QUALITY_MAX; //So it always updates when first set @@ -589,9 +606,11 @@ private: struct DirectionalShadow { RID depth; + RID fb; //when renderign direct int light_count = 0; int size = 0; + bool use_16_bits = false; int current_light = 0; Vector<ShadowShrinkStage> shrink_stages; @@ -601,6 +620,8 @@ private: void _allocate_shadow_shrink_stages(RID p_base, int p_base_size, Vector<ShadowShrinkStage> &shrink_stages, uint32_t p_target_size); void _clear_shadow_shrink_stages(Vector<ShadowShrinkStage> &shrink_stages); + void _update_directional_shadow_atlas(); + /* SHADOW CUBEMAPS */ struct ShadowCubemap { @@ -611,14 +632,6 @@ private: Map<int, ShadowCubemap> shadow_cubemaps; ShadowCubemap *_get_shadow_cubemap(int p_size); - struct ShadowMap { - RID depth; - RID fb; - }; - - Map<Vector2i, ShadowMap> shadow_maps; - ShadowMap *_get_shadow_map(const Size2i &p_size); - void _create_shadow_cubemaps(); /* LIGHT INSTANCE */ @@ -736,13 +749,14 @@ private: /// SSAO bool ssao_enabled = false; - float ssao_radius = 1; - float ssao_intensity = 1; - float ssao_bias = 0.01; + float ssao_radius = 1.0; + float ssao_intensity = 2.0; + float ssao_power = 1.5; + float ssao_detail = 0.5; + float ssao_horizon = 0.06; + float ssao_sharpness = 0.98; float ssao_direct_light_affect = 0.0; float ssao_ao_channel_affect = 0.0; - float ssao_blur_edge_sharpness = 4.0; - RS::EnvironmentSSAOBlur ssao_blur = RS::ENV_SSAO_BLUR_3x3; /// SSR /// @@ -763,10 +777,25 @@ private: float sdfgi_normal_bias = 1.1; float sdfgi_probe_bias = 1.1; RS::EnvironmentSDFGIYScale sdfgi_y_scale = RS::ENV_SDFGI_Y_SCALE_DISABLED; + + /// Adjustments + + bool adjustments_enabled = false; + float adjustments_brightness = 1.0f; + float adjustments_contrast = 1.0f; + float adjustments_saturation = 1.0f; + bool use_1d_color_correction = false; + RID color_correction = RID(); }; RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM; bool ssao_half_size = false; + bool ssao_using_half_size = false; + float ssao_adaptive_target = 0.5; + int ssao_blur_passes = 2; + float ssao_fadeout_from = 50.0; + float ssao_fadeout_to = 300.0; + bool glow_bicubic_upscale = false; bool glow_high_quality = false; RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGNESS_QUALITY_LOW; @@ -803,6 +832,9 @@ private: /* RENDER BUFFERS */ + ClusterBuilderSharedDataRD cluster_builder_shared; + ClusterBuilderRD *current_cluster_builder = nullptr; + struct SDFGI; struct VolumetricFog; @@ -828,6 +860,8 @@ private: SDFGI *sdfgi = nullptr; VolumetricFog *volumetric_fog = nullptr; + ClusterBuilderRD *cluster_builder = nullptr; + //built-in textures used for ping pong image processing and blurring struct Blur { RID texture; @@ -851,8 +885,12 @@ private: struct SSAO { RID depth; Vector<RID> depth_slices; - RID ao[2]; - RID ao_full; //when using half-size + RID ao_deinterleaved; + Vector<RID> ao_deinterleaved_slices; + RID ao_pong; + Vector<RID> ao_pong_slices; + RID ao_final; + RID importance_map[2]; } ssao; struct SSR { @@ -863,6 +901,16 @@ private: RID giprobe_textures[MAX_GIPROBES]; RID giprobe_buffer; + + RID ambient_buffer; + RID reflection_buffer; + bool using_half_size_gi = false; + + struct GI { + RID full_buffer; + RID full_dispatch; + RID full_mask; + } gi; }; RID default_giprobe_buffer; @@ -924,6 +972,8 @@ private: RID scroll_occlusion_uniform_set; RID integrate_uniform_set; RID lights_buffer; + + bool all_dynamic_lights_dirty = true; }; //used for rendering (voxelization) @@ -985,6 +1035,8 @@ private: RS::EnvironmentSDFGIRayCount sdfgi_ray_count = RS::ENV_SDFGI_RAY_COUNT_16; RS::EnvironmentSDFGIFramesToConverge sdfgi_frames_to_converge = RS::ENV_SDFGI_CONVERGE_IN_10_FRAMES; + RS::EnvironmentSDFGIFramesToUpdateLight sdfgi_frames_to_update_light = RS::ENV_SDFGI_UPDATE_LIGHT_IN_4_FRAMES; + float sdfgi_solid_cell_ratio = 0.25; Vector3 sdfgi_debug_probe_pos; Vector3 sdfgi_debug_probe_dir; @@ -1068,7 +1120,7 @@ private: RID debug_probes_shader; RID debug_probes_shader_version; - RenderPipelineVertexFormatCacheRD debug_probes_pipeline[PROBE_DEBUG_MAX]; + PipelineCacheRD debug_probes_pipeline[PROBE_DEBUG_MAX]; struct Light { float color[3]; @@ -1222,23 +1274,28 @@ private: float z_far; float proj_info[4]; - + float ao_color[3]; uint32_t max_giprobes; + uint32_t high_quality_vct; - uint32_t use_sdfgi; uint32_t orthogonal; - - float ao_color[3]; - uint32_t pad; + uint32_t pad[2]; float cam_rotation[12]; }; RID sdfgi_ubo; - enum { - MODE_MAX = 1 + enum Mode { + MODE_GIPROBE, + MODE_SDFGI, + MODE_COMBINED, + MODE_HALF_RES_GIPROBE, + MODE_HALF_RES_SDFGI, + MODE_HALF_RES_COMBINED, + MODE_MAX }; + bool half_resolution = false; GiShaderRD shader; RID shader_version; RID pipelines[MODE_MAX]; @@ -1263,14 +1320,23 @@ private: struct Cluster { /* Scene State UBO */ - struct ReflectionData { //should always be 128 bytes + enum { + REFLECTION_AMBIENT_DISABLED = 0, + REFLECTION_AMBIENT_ENVIRONMENT = 1, + REFLECTION_AMBIENT_COLOR = 2, + }; + + struct ReflectionData { float box_extents[3]; float index; float box_offset[3]; uint32_t mask; - float params[4]; // intensity, 0, interior , boxproject float ambient[3]; // ambient color, + float intensity; + bool exterior; + bool box_project; uint32_t ambient_mode; + uint32_t pad; float local_matrix[16]; // up to here for spot and omni, rest is for directional }; @@ -1279,10 +1345,15 @@ private: float inv_radius; float direction[3]; float size; - uint16_t attenuation_energy[2]; //16 bits attenuation, then energy - uint8_t color_specular[4]; //rgb color, a specular (8 bit unorm) - uint16_t cone_attenuation_angle[2]; // attenuation and angle, (16bit float) - uint8_t shadow_color_enabled[4]; //shadow rgb color, a>0.5 enabled (8bit unorm) + + float color[3]; + float attenuation; + + float cone_attenuation; + float cone_angle; + float specular_amount; + uint32_t shadow_enabled; + float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv float shadow_matrix[16]; float shadow_bias; @@ -1346,18 +1417,39 @@ private: float normal_fade; }; + template <class T> + struct InstanceSort { + float depth; + T *instance; + bool operator<(const InstanceSort &p_sort) const { + return depth < p_sort.depth; + } + }; + ReflectionData *reflections; + InstanceSort<ReflectionProbeInstance> *reflection_sort; uint32_t max_reflections; RID reflection_buffer; uint32_t max_reflection_probes_per_instance; + uint32_t reflection_count = 0; DecalData *decals; + InstanceSort<DecalInstance> *decal_sort; uint32_t max_decals; RID decal_buffer; + uint32_t decal_count; - LightData *lights; + LightData *omni_lights; + LightData *spot_lights; + + InstanceSort<LightInstance> *omni_light_sort; + InstanceSort<LightInstance> *spot_light_sort; uint32_t max_lights; - RID light_buffer; + RID omni_light_buffer; + RID spot_light_buffer; + uint32_t omni_light_count = 0; + uint32_t spot_light_count = 0; + RID *lights_instances; Rect2i *lights_shadow_rect_cache; uint32_t lights_shadow_rect_cache_count = 0; @@ -1366,8 +1458,6 @@ private: uint32_t max_directional_lights; RID directional_light_buffer; - LightClusterBuilder builder; - } cluster; struct VolumetricFog { @@ -1397,7 +1487,7 @@ private: }; struct VolumetricFogShader { - struct PushConstant { + struct ParamsUBO { float fog_frustum_size_begin[2]; float fog_frustum_size_end[2]; @@ -1415,13 +1505,21 @@ private: float detail_spread; float gi_inject; uint32_t max_gi_probes; - uint32_t pad; + uint32_t cluster_type_size; + + float screen_size[2]; + uint32_t cluster_shift; + uint32_t cluster_width; + + uint32_t cluster_pad[3]; + uint32_t max_cluster_element_count_div_32; float cam_rotation[12]; }; VolumetricFogShaderRD shader; + RID params_ubo; RID shader_version; RID pipelines[VOLUMETRIC_FOG_SHADER_MAX]; @@ -1446,11 +1544,17 @@ private: float weight; }; + uint32_t max_cluster_elements = 512; + bool low_end = false; + public: + virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance) = 0; + virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance) = 0; + /* SHADOW ATLAS API */ RID shadow_atlas_create(); - void shadow_atlas_set_size(RID p_atlas, int p_size); + void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = false); void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision); bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version); _FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) { @@ -1471,7 +1575,7 @@ public: return Size2(atlas->size, atlas->size); } - void directional_shadow_atlas_set_size(int p_size); + void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false); int get_directional_light_shadow_size(RID p_light_intance); void set_directional_shadow_count(int p_count); @@ -1490,7 +1594,7 @@ public: virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const; virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const; virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const; - virtual void sdfgi_update_probes(RID p_render_buffers, RID p_environment, const RID *p_directional_light_instances, uint32_t p_directional_light_count, const RID *p_positional_light_instances, uint32_t p_positional_light_count); + virtual void sdfgi_update_probes(RID p_render_buffers, RID p_environment, const Vector<RID> &p_directional_lights, const RID *p_positional_light_instances, uint32_t p_positional_light_count); RID sdfgi_get_ubo() const { return gi.sdfgi_ubo; } /* SKY API */ @@ -1555,8 +1659,8 @@ public: virtual void environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size); void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance); - void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness); - void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size); + void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect); + void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to); bool environment_is_ssao_enabled(RID p_env) const; float environment_get_ssao_ao_affect(RID p_env) const; float environment_get_ssao_light_affect(RID p_env) const; @@ -1566,12 +1670,13 @@ public: virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias); virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count); virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames); + virtual void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update); void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality); RS::EnvironmentSSRRoughnessQuality environment_get_ssr_roughness_quality() const; void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale); - void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) {} + void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction); virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size); @@ -1716,6 +1821,8 @@ public: virtual RID reflection_atlas_create(); virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count); + virtual int reflection_atlas_get_size(RID p_ref_atlas) const; + _FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) { ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_ref_atlas); ERR_FAIL_COND_V(!atlas, RID()); @@ -1794,10 +1901,25 @@ public: return decal->transform; } + virtual RID lightmap_instance_create(RID p_lightmap); + virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform); + _FORCE_INLINE_ bool lightmap_instance_is_valid(RID p_lightmap_instance) { + return lightmap_instance_owner.getornull(p_lightmap_instance) != nullptr; + } + + _FORCE_INLINE_ RID lightmap_instance_get_lightmap(RID p_lightmap_instance) { + LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap_instance); + return li->lightmap; + } + _FORCE_INLINE_ Transform lightmap_instance_get_transform(RID p_lightmap_instance) { + LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap_instance); + return li->transform; + } + RID gi_probe_instance_create(RID p_base); void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform); bool gi_probe_needs_update(RID p_probe) const; - void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects); + void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects); void gi_probe_set_quality(RS::GIProbeQuality p_quality) { gi_probe_quality = p_quality; } @@ -1847,11 +1969,14 @@ public: */ RID render_buffers_create(); void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding); + void gi_set_use_half_resolution(bool p_enable); RID render_buffers_get_ao_texture(RID p_render_buffers); RID render_buffers_get_back_buffer_texture(RID p_render_buffers); RID render_buffers_get_gi_probe_buffer(RID p_render_buffers); RID render_buffers_get_default_gi_probe_buffer(); + RID render_buffers_get_gi_ambient_texture(RID p_render_buffers); + RID render_buffers_get_gi_reflection_texture(RID p_render_buffers); uint32_t render_buffers_get_sdfgi_cascade_count(RID p_render_buffers) const; bool render_buffers_is_sdfgi_enabled(RID p_render_buffers) const; @@ -1872,16 +1997,16 @@ public: float render_buffers_get_volumetric_fog_end(RID p_render_buffers); float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers); - void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_shadow_atlas, RID p_camera_effects, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); + void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold); - void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count); + void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0); - void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region); + void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region); - void render_sdfgi(RID p_render_buffers, int p_region, InstanceBase **p_cull_result, int p_cull_count); - void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const RID **p_positional_light_cull_result, const uint32_t *p_positional_light_cull_count); + void render_sdfgi(RID p_render_buffers, int p_region, const PagedArray<GeometryInstance *> &p_instances); + void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result); - void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, InstanceBase **p_cull_result, int p_cull_count); + void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances); virtual void set_scene_pass(uint64_t p_pass) { scene_pass = p_pass; @@ -1932,18 +2057,19 @@ public: virtual void set_time(double p_time, double p_step); - RID get_cluster_builder_texture(); - RID get_cluster_builder_indices_buffer(); RID get_reflection_probe_buffer(); - RID get_positional_light_buffer(); + RID get_omni_light_buffer(); + RID get_spot_light_buffer(); RID get_directional_light_buffer(); RID get_decal_buffer(); int get_max_directional_lights() const; void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir); - RasterizerSceneRD(RasterizerStorageRD *p_storage); - ~RasterizerSceneRD(); + bool is_low_end() const; + + RendererSceneRenderRD(RendererStorageRD *p_storage); + ~RendererSceneRenderRD(); }; #endif // RASTERIZER_SCENE_RD_H diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index 10c9293d67..6d4343e183 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_storage_rd.cpp */ +/* renderer_storage_rd.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rasterizer_storage_rd.h" +#include "renderer_storage_rd.h" -#include "core/engine.h" +#include "core/config/engine.h" +#include "core/config/project_settings.h" #include "core/io/resource_loader.h" -#include "core/project_settings.h" -#include "rasterizer_rd.h" +#include "renderer_compositor_rd.h" #include "servers/rendering/shader_language.h" -Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format) { +Ref<Image> RendererStorageRD::_validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format) { Ref<Image> image = p_image->duplicate(); switch (p_image->get_format()) { @@ -318,7 +318,7 @@ Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_ima r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; } break; //unsigned float bc6hu - case Image::FORMAT_PVRTC2: { + case Image::FORMAT_PVRTC1_2: { //this is not properly supported by MoltekVK it seems, so best to use ETC2 if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { r_format.format = RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; @@ -336,7 +336,7 @@ Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_ima r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; } break; //pvrtc - case Image::FORMAT_PVRTC2A: { + case Image::FORMAT_PVRTC1_2A: { //this is not properly supported by MoltekVK it seems, so best to use ETC2 if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { r_format.format = RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; @@ -353,7 +353,7 @@ Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_ima r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; } break; - case Image::FORMAT_PVRTC4: { + case Image::FORMAT_PVRTC1_4: { //this is not properly supported by MoltekVK it seems, so best to use ETC2 if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { r_format.format = RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; @@ -370,7 +370,7 @@ Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_ima r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; } break; - case Image::FORMAT_PVRTC4A: { + case Image::FORMAT_PVRTC1_4A: { //this is not properly supported by MoltekVK it seems, so best to use ETC2 if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { r_format.format = RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; @@ -535,9 +535,9 @@ Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_ima return image; } -RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) { +RID RendererStorageRD::texture_2d_create(const Ref<Image> &p_image) { ERR_FAIL_COND_V(p_image.is_null(), RID()); - ERR_FAIL_COND_V(p_image->empty(), RID()); + ERR_FAIL_COND_V(p_image->is_empty(), RID()); TextureToRDFormat ret_format; Ref<Image> image = _validate_texture_format(p_image, ret_format); @@ -567,7 +567,7 @@ RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) { rd_format.depth = 1; rd_format.array_layers = 1; rd_format.mipmaps = texture.mipmaps; - rd_format.type = texture.rd_type; + rd_format.texture_type = texture.rd_type; rd_format.samples = RD::TEXTURE_SAMPLES_1; rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { @@ -605,7 +605,7 @@ RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) { return texture_owner.make_rid(texture); } -RID RasterizerStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) { +RID RendererStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) { ERR_FAIL_COND_V(p_layers.size() == 0, RID()); ERR_FAIL_COND_V(p_layered_type == RS::TEXTURE_LAYERED_CUBEMAP && p_layers.size() != 6, RID()); @@ -620,7 +620,7 @@ RID RasterizerStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_l Image::Format valid_format = Image::FORMAT_MAX; for (int i = 0; i < p_layers.size(); i++) { - ERR_FAIL_COND_V(p_layers[i]->empty(), RID()); + ERR_FAIL_COND_V(p_layers[i]->is_empty(), RID()); if (i == 0) { valid_width = p_layers[i]->get_width(); @@ -675,7 +675,7 @@ RID RasterizerStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_l rd_format.depth = 1; rd_format.array_layers = texture.layers; rd_format.mipmaps = texture.mipmaps; - rd_format.type = texture.rd_type; + rd_format.texture_type = texture.rd_type; rd_format.samples = RD::TEXTURE_SAMPLES_1; rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { @@ -715,7 +715,7 @@ RID RasterizerStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_l return texture_owner.make_rid(texture); } -RID RasterizerStorageRD::texture_3d_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) { +RID RendererStorageRD::texture_3d_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) { ERR_FAIL_COND_V(p_data.size() == 0, RID()); Image::Image3DValidateError verr = Image::validate_3d_image(p_format, p_width, p_height, p_depth, p_mipmaps, p_data); if (verr != Image::VALIDATE_3D_OK) { @@ -793,7 +793,7 @@ RID RasterizerStorageRD::texture_3d_create(Image::Format p_format, int p_width, rd_format.depth = texture.depth; rd_format.array_layers = 1; rd_format.mipmaps = texture.mipmaps; - rd_format.type = texture.rd_type; + rd_format.texture_type = texture.rd_type; rd_format.samples = RD::TEXTURE_SAMPLES_1; rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { @@ -831,7 +831,7 @@ RID RasterizerStorageRD::texture_3d_create(Image::Format p_format, int p_width, return texture_owner.make_rid(texture); } -RID RasterizerStorageRD::texture_proxy_create(RID p_base) { +RID RendererStorageRD::texture_proxy_create(RID p_base) { Texture *tex = texture_owner.getornull(p_base); ERR_FAIL_COND_V(!tex, RID()); Texture proxy_tex = *tex; @@ -854,8 +854,8 @@ RID RasterizerStorageRD::texture_proxy_create(RID p_base) { return rid; } -void RasterizerStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate) { - ERR_FAIL_COND(p_image.is_null() || p_image->empty()); +void RendererStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate) { + ERR_FAIL_COND(p_image.is_null() || p_image->is_empty()); Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); @@ -873,18 +873,18 @@ void RasterizerStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_ TextureToRDFormat f; Ref<Image> validated = _validate_texture_format(p_image, f); - RD::get_singleton()->texture_update(tex->rd_texture, p_layer, validated->get_data(), !p_immediate); + RD::get_singleton()->texture_update(tex->rd_texture, p_layer, validated->get_data()); } -void RasterizerStorageRD::texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer) { +void RendererStorageRD::texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer) { _texture_2d_update(p_texture, p_image, p_layer, true); } -void RasterizerStorageRD::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) { +void RendererStorageRD::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) { _texture_2d_update(p_texture, p_image, p_layer, false); } -void RasterizerStorageRD::texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) { +void RendererStorageRD::texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); ERR_FAIL_COND(tex->type != Texture::TYPE_3D); @@ -918,10 +918,10 @@ void RasterizerStorageRD::texture_3d_update(RID p_texture, const Vector<Ref<Imag } } - RD::get_singleton()->texture_update(tex->rd_texture, 0, all_data, true); + RD::get_singleton()->texture_update(tex->rd_texture, 0, all_data); } -void RasterizerStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) { +void RendererStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); ERR_FAIL_COND(!tex->is_proxy); @@ -961,7 +961,7 @@ void RasterizerStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) { } //these two APIs can be used together or in combination with the others. -RID RasterizerStorageRD::texture_2d_placeholder_create() { +RID RendererStorageRD::texture_2d_placeholder_create() { //this could be better optimized to reuse an existing image , done this way //for now to get it working Ref<Image> image; @@ -977,7 +977,7 @@ RID RasterizerStorageRD::texture_2d_placeholder_create() { return texture_2d_create(image); } -RID RasterizerStorageRD::texture_2d_layered_placeholder_create(RS::TextureLayeredType p_layered_type) { +RID RendererStorageRD::texture_2d_layered_placeholder_create(RS::TextureLayeredType p_layered_type) { //this could be better optimized to reuse an existing image , done this way //for now to get it working Ref<Image> image; @@ -1003,7 +1003,7 @@ RID RasterizerStorageRD::texture_2d_layered_placeholder_create(RS::TextureLayere return texture_2d_layered_create(images, p_layered_type); } -RID RasterizerStorageRD::texture_3d_placeholder_create() { +RID RendererStorageRD::texture_3d_placeholder_create() { //this could be better optimized to reuse an existing image , done this way //for now to get it working Ref<Image> image; @@ -1025,7 +1025,7 @@ RID RasterizerStorageRD::texture_3d_placeholder_create() { return texture_3d_create(Image::FORMAT_RGBA8, 4, 4, 4, false, images); } -Ref<Image> RasterizerStorageRD::texture_2d_get(RID p_texture) const { +Ref<Image> RendererStorageRD::texture_2d_get(RID p_texture) const { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!tex, Ref<Image>()); @@ -1039,7 +1039,7 @@ Ref<Image> RasterizerStorageRD::texture_2d_get(RID p_texture) const { Ref<Image> image; image.instance(); image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data); - ERR_FAIL_COND_V(image->empty(), Ref<Image>()); + ERR_FAIL_COND_V(image->is_empty(), Ref<Image>()); if (tex->format != tex->validated_format) { image->convert(tex->format); } @@ -1053,7 +1053,7 @@ Ref<Image> RasterizerStorageRD::texture_2d_get(RID p_texture) const { return image; } -Ref<Image> RasterizerStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) const { +Ref<Image> RendererStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) const { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!tex, Ref<Image>()); @@ -1062,7 +1062,7 @@ Ref<Image> RasterizerStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) Ref<Image> image; image.instance(); image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data); - ERR_FAIL_COND_V(image->empty(), Ref<Image>()); + ERR_FAIL_COND_V(image->is_empty(), Ref<Image>()); if (tex->format != tex->validated_format) { image->convert(tex->format); } @@ -1070,7 +1070,7 @@ Ref<Image> RasterizerStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) return image; } -Vector<Ref<Image>> RasterizerStorageRD::texture_3d_get(RID p_texture) const { +Vector<Ref<Image>> RendererStorageRD::texture_3d_get(RID p_texture) const { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!tex, Vector<Ref<Image>>()); ERR_FAIL_COND_V(tex->type != Texture::TYPE_3D, Vector<Ref<Image>>()); @@ -1090,7 +1090,7 @@ Vector<Ref<Image>> RasterizerStorageRD::texture_3d_get(RID p_texture) const { Ref<Image> img; img.instance(); img->create(bs.size.width, bs.size.height, false, tex->validated_format, sub_region); - ERR_FAIL_COND_V(img->empty(), Vector<Ref<Image>>()); + ERR_FAIL_COND_V(img->is_empty(), Vector<Ref<Image>>()); if (tex->format != tex->validated_format) { img->convert(tex->format); } @@ -1101,7 +1101,7 @@ Vector<Ref<Image>> RasterizerStorageRD::texture_3d_get(RID p_texture) const { return ret; } -void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) { +void RendererStorageRD::texture_replace(RID p_texture, RID p_by_texture) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); ERR_FAIL_COND(tex->proxy_to.is_valid()); //can't replace proxy @@ -1150,7 +1150,7 @@ void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) { } } -void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width, int p_height) { +void RendererStorageRD::texture_set_size_override(RID p_texture, int p_width, int p_height) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); ERR_FAIL_COND(tex->type != Texture::TYPE_2D); @@ -1158,53 +1158,53 @@ void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width, tex->height_2d = p_height; } -void RasterizerStorageRD::texture_set_path(RID p_texture, const String &p_path) { +void RendererStorageRD::texture_set_path(RID p_texture, const String &p_path) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); tex->path = p_path; } -String RasterizerStorageRD::texture_get_path(RID p_texture) const { +String RendererStorageRD::texture_get_path(RID p_texture) const { return String(); } -void RasterizerStorageRD::texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { +void RendererStorageRD::texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); tex->detect_3d_callback_ud = p_userdata; tex->detect_3d_callback = p_callback; } -void RasterizerStorageRD::texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { +void RendererStorageRD::texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); tex->detect_normal_callback_ud = p_userdata; tex->detect_normal_callback = p_callback; } -void RasterizerStorageRD::texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) { +void RendererStorageRD::texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); tex->detect_roughness_callback_ud = p_userdata; tex->detect_roughness_callback = p_callback; } -void RasterizerStorageRD::texture_debug_usage(List<RS::TextureInfo> *r_info) { +void RendererStorageRD::texture_debug_usage(List<RS::TextureInfo> *r_info) { } -void RasterizerStorageRD::texture_set_proxy(RID p_proxy, RID p_base) { +void RendererStorageRD::texture_set_proxy(RID p_proxy, RID p_base) { } -void RasterizerStorageRD::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) { +void RendererStorageRD::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) { } -Size2 RasterizerStorageRD::texture_size_with_proxy(RID p_proxy) { +Size2 RendererStorageRD::texture_size_with_proxy(RID p_proxy) { return texture_2d_get_size(p_proxy); } /* CANVAS TEXTURE */ -void RasterizerStorageRD::CanvasTexture::clear_sets() { +void RendererStorageRD::CanvasTexture::clear_sets() { if (cleared_cache) { return; } @@ -1219,22 +1219,22 @@ void RasterizerStorageRD::CanvasTexture::clear_sets() { cleared_cache = true; } -RasterizerStorageRD::CanvasTexture::~CanvasTexture() { +RendererStorageRD::CanvasTexture::~CanvasTexture() { clear_sets(); } -RID RasterizerStorageRD::canvas_texture_create() { +RID RendererStorageRD::canvas_texture_create() { return canvas_texture_owner.make_rid(memnew(CanvasTexture)); } -void RasterizerStorageRD::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) { +void RendererStorageRD::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) { CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture); switch (p_channel) { case RS::CANVAS_TEXTURE_CHANNEL_DIFFUSE: { ct->diffuse = p_texture; } break; case RS::CANVAS_TEXTURE_CHANNEL_NORMAL: { - ct->normalmap = p_texture; + ct->normal_map = p_texture; } break; case RS::CANVAS_TEXTURE_CHANNEL_SPECULAR: { ct->specular = p_texture; @@ -1244,7 +1244,7 @@ void RasterizerStorageRD::canvas_texture_set_channel(RID p_canvas_texture, RS::C ct->clear_sets(); } -void RasterizerStorageRD::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess) { +void RendererStorageRD::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess) { CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture); ct->specular_color.r = p_specular_color.r; ct->specular_color.g = p_specular_color.g; @@ -1253,19 +1253,19 @@ void RasterizerStorageRD::canvas_texture_set_shading_parameters(RID p_canvas_tex ct->clear_sets(); } -void RasterizerStorageRD::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) { +void RendererStorageRD::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) { CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture); ct->texture_filter = p_filter; ct->clear_sets(); } -void RasterizerStorageRD::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) { +void RendererStorageRD::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) { CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture); ct->texture_repeat = p_repeat; ct->clear_sets(); } -bool RasterizerStorageRD::canvas_texture_get_unifom_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular) { +bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular) { CanvasTexture *ct = nullptr; Texture *t = texture_owner.getornull(p_texture); @@ -1298,7 +1298,7 @@ bool RasterizerStorageRD::canvas_texture_get_unifom_set(RID p_texture, RS::Canva Vector<RD::Uniform> uniforms; { //diffuse RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; t = texture_owner.getornull(ct->diffuse); @@ -1313,10 +1313,10 @@ bool RasterizerStorageRD::canvas_texture_get_unifom_set(RID p_texture, RS::Canva } { //normal RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; - t = texture_owner.getornull(ct->normalmap); + t = texture_owner.getornull(ct->normal_map); if (!t) { u.ids.push_back(texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL)); ct->use_normal_cache = false; @@ -1328,7 +1328,7 @@ bool RasterizerStorageRD::canvas_texture_get_unifom_set(RID p_texture, RS::Canva } { //specular RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; t = texture_owner.getornull(ct->specular); @@ -1343,7 +1343,7 @@ bool RasterizerStorageRD::canvas_texture_get_unifom_set(RID p_texture, RS::Canva } { //sampler RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 3; u.ids.push_back(sampler_rd_get_default(filter, repeat)); uniforms.push_back(u); @@ -1365,7 +1365,7 @@ bool RasterizerStorageRD::canvas_texture_get_unifom_set(RID p_texture, RS::Canva /* SHADER API */ -RID RasterizerStorageRD::shader_create() { +RID RendererStorageRD::shader_create() { Shader shader; shader.data = nullptr; shader.type = SHADER_TYPE_MAX; @@ -1373,7 +1373,7 @@ RID RasterizerStorageRD::shader_create() { return shader_owner.make_rid(shader); } -void RasterizerStorageRD::shader_set_code(RID p_shader, const String &p_code) { +void RendererStorageRD::shader_set_code(RID p_shader, const String &p_code) { Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND(!shader); @@ -1438,18 +1438,18 @@ void RasterizerStorageRD::shader_set_code(RID p_shader, const String &p_code) { for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) { Material *material = E->get(); - material->instance_dependency.instance_notify_changed(false, true); + material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); _material_queue_update(material, true, true); } } -String RasterizerStorageRD::shader_get_code(RID p_shader) const { +String RendererStorageRD::shader_get_code(RID p_shader) const { Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND_V(!shader, String()); return shader->code; } -void RasterizerStorageRD::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const { +void RendererStorageRD::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const { Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND(!shader); if (shader->data) { @@ -1457,7 +1457,7 @@ void RasterizerStorageRD::shader_get_param_list(RID p_shader, List<PropertyInfo> } } -void RasterizerStorageRD::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) { +void RendererStorageRD::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) { Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND(!shader); @@ -1475,7 +1475,7 @@ void RasterizerStorageRD::shader_set_default_texture_param(RID p_shader, const S } } -RID RasterizerStorageRD::shader_get_default_texture_param(RID p_shader, const StringName &p_name) const { +RID RendererStorageRD::shader_get_default_texture_param(RID p_shader, const StringName &p_name) const { Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND_V(!shader, RID()); if (shader->default_texture_parameter.has(p_name)) { @@ -1485,7 +1485,7 @@ RID RasterizerStorageRD::shader_get_default_texture_param(RID p_shader, const St return RID(); } -Variant RasterizerStorageRD::shader_get_param_default(RID p_shader, const StringName &p_param) const { +Variant RendererStorageRD::shader_get_param_default(RID p_shader, const StringName &p_param) const { Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND_V(!shader, Variant()); if (shader->data) { @@ -1494,14 +1494,23 @@ Variant RasterizerStorageRD::shader_get_param_default(RID p_shader, const String return Variant(); } -void RasterizerStorageRD::shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function) { +void RendererStorageRD::shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function) { ERR_FAIL_INDEX(p_shader_type, SHADER_TYPE_MAX); shader_data_request_func[p_shader_type] = p_function; } +RS::ShaderNativeSourceCode RendererStorageRD::shader_get_native_source_code(RID p_shader) const { + Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND_V(!shader, RS::ShaderNativeSourceCode()); + if (shader->data) { + return shader->data->get_native_source_code(); + } + return RS::ShaderNativeSourceCode(); +} + /* COMMON MATERIAL API */ -RID RasterizerStorageRD::material_create() { +RID RendererStorageRD::material_create() { Material material; material.data = nullptr; material.shader = nullptr; @@ -1519,7 +1528,7 @@ RID RasterizerStorageRD::material_create() { return id; } -void RasterizerStorageRD::_material_queue_update(Material *material, bool p_uniform, bool p_texture) { +void RendererStorageRD::_material_queue_update(Material *material, bool p_uniform, bool p_texture) { if (material->update_requested) { return; } @@ -1531,7 +1540,7 @@ void RasterizerStorageRD::_material_queue_update(Material *material, bool p_unif material->texture_dirty = material->texture_dirty || p_texture; } -void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) { +void RendererStorageRD::material_set_shader(RID p_material, RID p_shader) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); @@ -1547,7 +1556,8 @@ void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) { } if (p_shader.is_null()) { - material->instance_dependency.instance_notify_changed(false, true); + material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); + material->shader_id = 0; return; } @@ -1555,6 +1565,7 @@ void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) { ERR_FAIL_COND(!shader); material->shader = shader; material->shader_type = shader->type; + material->shader_id = p_shader.get_local_index(); shader->owners.insert(material); if (shader->type == SHADER_TYPE_MAX) { @@ -1568,11 +1579,11 @@ void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) { material->data->set_next_pass(material->next_pass); material->data->set_render_priority(material->priority); //updating happens later - material->instance_dependency.instance_notify_changed(false, true); + material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); _material_queue_update(material, true, true); } -void RasterizerStorageRD::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) { +void RendererStorageRD::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); @@ -1590,7 +1601,7 @@ void RasterizerStorageRD::material_set_param(RID p_material, const StringName &p } } -Variant RasterizerStorageRD::material_get_param(RID p_material, const StringName &p_param) const { +Variant RendererStorageRD::material_get_param(RID p_material, const StringName &p_param) const { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND_V(!material, Variant()); if (material->params.has(p_param)) { @@ -1600,7 +1611,7 @@ Variant RasterizerStorageRD::material_get_param(RID p_material, const StringName } } -void RasterizerStorageRD::material_set_next_pass(RID p_material, RID p_next_material) { +void RendererStorageRD::material_set_next_pass(RID p_material, RID p_next_material) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); @@ -1613,10 +1624,10 @@ void RasterizerStorageRD::material_set_next_pass(RID p_material, RID p_next_mate material->data->set_next_pass(p_next_material); } - material->instance_dependency.instance_notify_changed(false, true); + material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); } -void RasterizerStorageRD::material_set_render_priority(RID p_material, int priority) { +void RendererStorageRD::material_set_render_priority(RID p_material, int priority) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); material->priority = priority; @@ -1625,7 +1636,7 @@ void RasterizerStorageRD::material_set_render_priority(RID p_material, int prior } } -bool RasterizerStorageRD::material_is_animated(RID p_material) { +bool RendererStorageRD::material_is_animated(RID p_material) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND_V(!material, false); if (material->shader && material->shader->data) { @@ -1638,7 +1649,7 @@ bool RasterizerStorageRD::material_is_animated(RID p_material) { return false; //by default nothing is animated } -bool RasterizerStorageRD::material_casts_shadows(RID p_material) { +bool RendererStorageRD::material_casts_shadows(RID p_material) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND_V(!material, true); if (material->shader && material->shader->data) { @@ -1651,7 +1662,7 @@ bool RasterizerStorageRD::material_casts_shadows(RID p_material) { return true; //by default everything casts shadows } -void RasterizerStorageRD::material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) { +void RendererStorageRD::material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); if (material->shader && material->shader->data) { @@ -1663,16 +1674,16 @@ void RasterizerStorageRD::material_get_instance_shader_parameters(RID p_material } } -void RasterizerStorageRD::material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) { +void RendererStorageRD::material_update_dependency(RID p_material, DependencyTracker *p_instance) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); - p_instance->update_dependency(&material->instance_dependency); + p_instance->update_dependency(&material->dependency); if (material->next_pass.is_valid()) { material_update_dependency(material->next_pass, p_instance); } } -void RasterizerStorageRD::material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function) { +void RendererStorageRD::material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function) { ERR_FAIL_INDEX(p_shader_type, SHADER_TYPE_MAX); material_data_request_func[p_shader_type] = p_function; } @@ -2119,7 +2130,7 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, } } -void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) { +void RendererStorageRD::MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) { bool uses_global_buffer = false; for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = p_uniforms.front(); E; E = E->next()) { @@ -2133,7 +2144,7 @@ void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringNa if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) { //this is a global variable, get the index to it - RasterizerStorageRD *rs = base_singleton; + RendererStorageRD *rs = base_singleton; GlobalVariables::Variable *gv = rs->global_variables.variables.getptr(E->key()); uint32_t index = 0; @@ -2180,7 +2191,7 @@ void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringNa } if (uses_global_buffer != (global_buffer_E != nullptr)) { - RasterizerStorageRD *rs = base_singleton; + RendererStorageRD *rs = base_singleton; if (uses_global_buffer) { global_buffer_E = rs->global_variables.materials_using_buffer.push_back(self); } else { @@ -2190,16 +2201,16 @@ void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringNa } } -RasterizerStorageRD::MaterialData::~MaterialData() { +RendererStorageRD::MaterialData::~MaterialData() { if (global_buffer_E) { //unregister global buffers - RasterizerStorageRD *rs = base_singleton; + RendererStorageRD *rs = base_singleton; rs->global_variables.materials_using_buffer.erase(global_buffer_E); } if (global_texture_E) { //unregister global textures - RasterizerStorageRD *rs = base_singleton; + RendererStorageRD *rs = base_singleton; for (Map<StringName, uint64_t>::Element *E = used_global_textures.front(); E; E = E->next()) { GlobalVariables::Variable *v = rs->global_variables.variables.getptr(E->key()); @@ -2212,11 +2223,11 @@ RasterizerStorageRD::MaterialData::~MaterialData() { } } -void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) { - RasterizerStorageRD *singleton = (RasterizerStorageRD *)RasterizerStorage::base_singleton; +void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) { + RendererStorageRD *singleton = (RendererStorageRD *)RendererStorage::base_singleton; #ifdef TOOLS_ENABLED Texture *roughness_detect_texture = nullptr; - RS::TextureDetectRoughnessChannel roughness_channel = RS::TEXTURE_DETECT_ROUGNHESS_R; + RS::TextureDetectRoughnessChannel roughness_channel = RS::TEXTURE_DETECT_ROUGHNESS_R; Texture *normal_detect_texture = nullptr; #endif @@ -2229,7 +2240,7 @@ void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Va RID texture; if (p_texture_uniforms[i].global) { - RasterizerStorageRD *rs = base_singleton; + RendererStorageRD *rs = base_singleton; uses_global_textures = true; @@ -2330,7 +2341,7 @@ void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Va { //for textures no longer used, unregister them List<Map<StringName, uint64_t>::Element *> to_delete; - RasterizerStorageRD *rs = base_singleton; + RendererStorageRD *rs = base_singleton; for (Map<StringName, uint64_t>::Element *E = used_global_textures.front(); E; E = E->next()) { if (E->get() != global_textures_pass) { @@ -2359,7 +2370,7 @@ void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Va } } -void RasterizerStorageRD::material_force_update_textures(RID p_material, ShaderType p_shader_type) { +void RendererStorageRD::material_force_update_textures(RID p_material, ShaderType p_shader_type) { Material *material = material_owner.getornull(p_material); if (material->shader_type != p_shader_type) { return; @@ -2369,7 +2380,7 @@ void RasterizerStorageRD::material_force_update_textures(RID p_material, ShaderT } } -void RasterizerStorageRD::_update_queued_materials() { +void RendererStorageRD::_update_queued_materials() { Material *material = material_update_list; while (material) { Material *next = material->update_next; @@ -2388,23 +2399,32 @@ void RasterizerStorageRD::_update_queued_materials() { /* MESH API */ -RID RasterizerStorageRD::mesh_create() { +RID RendererStorageRD::mesh_create() { return mesh_owner.make_rid(Mesh()); } -/// Returns stride -void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) { +void RendererStorageRD::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) { + ERR_FAIL_COND(p_blend_shape_count < 0); + Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!mesh); - //ensure blend shape consistency - ERR_FAIL_COND(mesh->blend_shape_count && p_surface.blend_shapes.size() != (int)mesh->blend_shape_count); - ERR_FAIL_COND(mesh->blend_shape_count && p_surface.bone_aabbs.size() != mesh->bone_aabbs.size()); + ERR_FAIL_COND(mesh->surface_count > 0); //surfaces already exist + + mesh->blend_shape_count = p_blend_shape_count; +} + +/// Returns stride +void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND(!mesh); #ifdef DEBUG_ENABLED //do a validation, to catch errors first { uint32_t stride = 0; + uint32_t attrib_stride = 0; + uint32_t skin_stride = 0; for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) { if ((p_surface.format & (1 << i))) { @@ -2418,59 +2438,59 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_ } break; case RS::ARRAY_NORMAL: { - if (p_surface.format & RS::ARRAY_COMPRESS_NORMAL) { - stride += sizeof(int8_t) * 4; - } else { - stride += sizeof(float) * 4; - } + stride += sizeof(int32_t); } break; case RS::ARRAY_TANGENT: { - if (p_surface.format & RS::ARRAY_COMPRESS_TANGENT) { - stride += sizeof(int8_t) * 4; - } else { - stride += sizeof(float) * 4; - } + stride += sizeof(int32_t); } break; case RS::ARRAY_COLOR: { - if (p_surface.format & RS::ARRAY_COMPRESS_COLOR) { - stride += sizeof(int8_t) * 4; - } else { - stride += sizeof(float) * 4; - } - + attrib_stride += sizeof(int16_t) * 4; } break; case RS::ARRAY_TEX_UV: { - if (p_surface.format & RS::ARRAY_COMPRESS_TEX_UV) { - stride += sizeof(int16_t) * 2; - } else { - stride += sizeof(float) * 2; - } + attrib_stride += sizeof(float) * 2; } break; case RS::ARRAY_TEX_UV2: { - if (p_surface.format & RS::ARRAY_COMPRESS_TEX_UV2) { - stride += sizeof(int16_t) * 2; - } else { - stride += sizeof(float) * 2; - } + attrib_stride += sizeof(float) * 2; } break; - case RS::ARRAY_BONES: { - //assumed weights too - - //unique format, internally 16 bits, exposed as single array for 32 - - stride += sizeof(int32_t) * 4; + case RS::ARRAY_CUSTOM0: + case RS::ARRAY_CUSTOM1: + case RS::ARRAY_CUSTOM2: + case RS::ARRAY_CUSTOM3: { + int idx = i - RS::ARRAY_CUSTOM0; + uint32_t fmt_shift[RS::ARRAY_CUSTOM_COUNT] = { RS::ARRAY_FORMAT_CUSTOM0_SHIFT, RS::ARRAY_FORMAT_CUSTOM1_SHIFT, RS::ARRAY_FORMAT_CUSTOM2_SHIFT, RS::ARRAY_FORMAT_CUSTOM3_SHIFT }; + uint32_t fmt = (p_surface.format >> fmt_shift[idx]) & RS::ARRAY_FORMAT_CUSTOM_MASK; + uint32_t fmtsize[RS::ARRAY_CUSTOM_MAX] = { 4, 4, 4, 8, 4, 8, 12, 16 }; + attrib_stride += fmtsize[fmt]; } break; + case RS::ARRAY_WEIGHTS: + case RS::ARRAY_BONES: { + //uses a separate array + bool use_8 = p_surface.format & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS; + skin_stride += sizeof(int16_t) * (use_8 ? 16 : 8); + } break; } } } int expected_size = stride * p_surface.vertex_count; - ERR_FAIL_COND_MSG(expected_size != p_surface.vertex_data.size(), "Size of data provided (" + itos(p_surface.vertex_data.size()) + ") does not match expected (" + itos(expected_size) + ")"); + ERR_FAIL_COND_MSG(expected_size != p_surface.vertex_data.size(), "Size of vertex data provided (" + itos(p_surface.vertex_data.size()) + ") does not match expected (" + itos(expected_size) + ")"); + + int bs_expected_size = expected_size * mesh->blend_shape_count; + + ERR_FAIL_COND_MSG(bs_expected_size != p_surface.blend_shape_data.size(), "Size of blend shape data provided (" + itos(p_surface.blend_shape_data.size()) + ") does not match expected (" + itos(bs_expected_size) + ")"); + + int expected_attrib_size = attrib_stride * p_surface.vertex_count; + ERR_FAIL_COND_MSG(expected_attrib_size != p_surface.attribute_data.size(), "Size of attribute data provided (" + itos(p_surface.attribute_data.size()) + ") does not match expected (" + itos(expected_attrib_size) + ")"); + + if ((p_surface.format & RS::ARRAY_FORMAT_WEIGHTS) && (p_surface.format & RS::ARRAY_FORMAT_BONES)) { + expected_size = skin_stride * p_surface.vertex_count; + ERR_FAIL_COND_MSG(expected_size != p_surface.skin_data.size(), "Size of skin data provided (" + itos(p_surface.skin_data.size()) + ") does not match expected (" + itos(expected_size) + ")"); + } } #endif @@ -2480,9 +2500,25 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_ s->format = p_surface.format; s->primitive = p_surface.primitive; - s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data); + bool use_as_storage = (p_surface.skin_data.size() || mesh->blend_shape_count > 0); + + s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data, use_as_storage); + s->vertex_buffer_size = p_surface.vertex_data.size(); + + if (p_surface.attribute_data.size()) { + s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.attribute_data.size(), p_surface.attribute_data); + } + if (p_surface.skin_data.size()) { + s->skin_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.skin_data.size(), p_surface.skin_data, use_as_storage); + s->skin_buffer_size = p_surface.skin_data.size(); + } + s->vertex_count = p_surface.vertex_count; + if (p_surface.format & RS::ARRAY_FORMAT_BONES) { + mesh->has_bone_weights = true; + } + if (p_surface.index_count) { bool is_index_16 = p_surface.vertex_count <= 65536; @@ -2505,21 +2541,54 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_ s->aabb = p_surface.aabb; s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them. - for (int i = 0; i < p_surface.blend_shapes.size(); i++) { - if (p_surface.blend_shapes[i].size() != p_surface.vertex_data.size()) { - memdelete(s); - ERR_FAIL_COND(p_surface.blend_shapes[i].size() != p_surface.vertex_data.size()); - } - RID vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.blend_shapes[i].size(), p_surface.blend_shapes[i]); - s->blend_shapes.push_back(vertex_buffer); + if (mesh->blend_shape_count > 0) { + s->blend_shape_buffer = RD::get_singleton()->storage_buffer_create(p_surface.blend_shape_data.size(), p_surface.blend_shape_data); } - mesh->blend_shape_count = p_surface.blend_shapes.size(); + if (use_as_storage) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.binding = 0; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(s->vertex_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 1; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + if (s->skin_buffer.is_valid()) { + u.ids.push_back(s->skin_buffer); + } else { + u.ids.push_back(default_rd_storage_buffer); + } + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 2; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + if (s->blend_shape_buffer.is_valid()) { + u.ids.push_back(s->blend_shape_buffer); + } else { + u.ids.push_back(default_rd_storage_buffer); + } + uniforms.push_back(u); + } + + s->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_SURFACE); + } if (mesh->surface_count == 0) { mesh->bone_aabbs = p_surface.bone_aabbs; mesh->aabb = p_surface.aabb; } else { + if (mesh->bone_aabbs.size() < p_surface.bone_aabbs.size()) { + // ArrayMesh::_surface_set_data only allocates bone_aabbs up to max_bone + // Each surface may affect different numbers of bones. + mesh->bone_aabbs.resize(p_surface.bone_aabbs.size()); + } for (int i = 0; i < p_surface.bone_aabbs.size(); i++) { mesh->bone_aabbs.write[i].merge_with(p_surface.bone_aabbs[i]); } @@ -2532,18 +2601,30 @@ void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_ mesh->surfaces[mesh->surface_count] = s; mesh->surface_count++; - mesh->instance_dependency.instance_notify_changed(true, true); + for (List<MeshInstance *>::Element *E = mesh->instances.front(); E; E = E->next()) { + //update instances + MeshInstance *mi = E->get(); + _mesh_instance_add_surface(mi, mesh, mesh->surface_count - 1); + } + + mesh->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); + + for (Set<Mesh *>::Element *E = mesh->shadow_owners.front(); E; E = E->next()) { + Mesh *shadow_owner = E->get(); + shadow_owner->shadow_mesh = RID(); + shadow_owner->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); + } mesh->material_cache.clear(); } -int RasterizerStorageRD::mesh_get_blend_shape_count(RID p_mesh) const { +int RendererStorageRD::mesh_get_blend_shape_count(RID p_mesh) const { const Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, -1); return mesh->blend_shape_count; } -void RasterizerStorageRD::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) { +void RendererStorageRD::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!mesh); ERR_FAIL_INDEX((int)p_mode, 2); @@ -2551,13 +2632,13 @@ void RasterizerStorageRD::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMo mesh->blend_shape_mode = p_mode; } -RS::BlendShapeMode RasterizerStorageRD::mesh_get_blend_shape_mode(RID p_mesh) const { +RS::BlendShapeMode RendererStorageRD::mesh_get_blend_shape_mode(RID p_mesh) const { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, RS::BLEND_SHAPE_MODE_NORMALIZED); return mesh->blend_shape_mode; } -void RasterizerStorageRD::mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) { +void RendererStorageRD::mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!mesh); ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count); @@ -2568,17 +2649,17 @@ void RasterizerStorageRD::mesh_surface_update_region(RID p_mesh, int p_surface, RD::get_singleton()->buffer_update(mesh->surfaces[p_surface]->vertex_buffer, p_offset, data_size, r); } -void RasterizerStorageRD::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) { +void RendererStorageRD::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!mesh); ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count); mesh->surfaces[p_surface]->material = p_material; - mesh->instance_dependency.instance_notify_changed(false, true); + mesh->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); mesh->material_cache.clear(); } -RID RasterizerStorageRD::mesh_surface_get_material(RID p_mesh, int p_surface) const { +RID RendererStorageRD::mesh_surface_get_material(RID p_mesh, int p_surface) const { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, RID()); ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RID()); @@ -2586,7 +2667,7 @@ RID RasterizerStorageRD::mesh_surface_get_material(RID p_mesh, int p_surface) co return mesh->surfaces[p_surface]->material; } -RS::SurfaceData RasterizerStorageRD::mesh_get_surface(RID p_mesh, int p_surface) const { +RS::SurfaceData RendererStorageRD::mesh_get_surface(RID p_mesh, int p_surface) const { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, RS::SurfaceData()); ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RS::SurfaceData()); @@ -2596,6 +2677,12 @@ RS::SurfaceData RasterizerStorageRD::mesh_get_surface(RID p_mesh, int p_surface) RS::SurfaceData sd; sd.format = s.format; sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer); + if (s.attribute_buffer.is_valid()) { + sd.attribute_data = RD::get_singleton()->buffer_get_data(s.attribute_buffer); + } + if (s.skin_buffer.is_valid()) { + sd.skin_data = RD::get_singleton()->buffer_get_data(s.skin_buffer); + } sd.vertex_count = s.vertex_count; sd.index_count = s.index_count; sd.primitive = s.primitive; @@ -2613,33 +2700,32 @@ RS::SurfaceData RasterizerStorageRD::mesh_get_surface(RID p_mesh, int p_surface) sd.bone_aabbs = s.bone_aabbs; - for (int i = 0; i < s.blend_shapes.size(); i++) { - Vector<uint8_t> bs = RD::get_singleton()->buffer_get_data(s.blend_shapes[i]); - sd.blend_shapes.push_back(bs); + if (s.blend_shape_buffer.is_valid()) { + sd.blend_shape_data = RD::get_singleton()->buffer_get_data(s.blend_shape_buffer); } return sd; } -int RasterizerStorageRD::mesh_get_surface_count(RID p_mesh) const { +int RendererStorageRD::mesh_get_surface_count(RID p_mesh) const { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, 0); return mesh->surface_count; } -void RasterizerStorageRD::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) { +void RendererStorageRD::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!mesh); mesh->custom_aabb = p_aabb; } -AABB RasterizerStorageRD::mesh_get_custom_aabb(RID p_mesh) const { +AABB RendererStorageRD::mesh_get_custom_aabb(RID p_mesh) const { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, AABB()); return mesh->custom_aabb; } -AABB RasterizerStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) { +AABB RendererStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, AABB()); @@ -2744,12 +2830,37 @@ AABB RasterizerStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) { return aabb; } -void RasterizerStorageRD::mesh_clear(RID p_mesh) { +void RendererStorageRD::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND(!mesh); + + Mesh *shadow_mesh = mesh_owner.getornull(mesh->shadow_mesh); + if (shadow_mesh) { + shadow_mesh->shadow_owners.erase(mesh); + } + mesh->shadow_mesh = p_shadow_mesh; + + shadow_mesh = mesh_owner.getornull(mesh->shadow_mesh); + + if (shadow_mesh) { + shadow_mesh->shadow_owners.insert(mesh); + } + + mesh->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); +} + +void RendererStorageRD::mesh_clear(RID p_mesh) { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!mesh); for (uint32_t i = 0; i < mesh->surface_count; i++) { Mesh::Surface &s = *mesh->surfaces[i]; RD::get_singleton()->free(s.vertex_buffer); //clears arrays as dependency automatically, including all versions + if (s.attribute_buffer.is_valid()) { + RD::get_singleton()->free(s.attribute_buffer); + } + if (s.skin_buffer.is_valid()) { + RD::get_singleton()->free(s.skin_buffer); + } if (s.versions) { memfree(s.versions); //reallocs, so free with memfree. } @@ -2765,12 +2876,8 @@ void RasterizerStorageRD::mesh_clear(RID p_mesh) { memdelete_arr(s.lods); } - for (int32_t j = 0; j < s.blend_shapes.size(); j++) { - RD::get_singleton()->free(s.blend_shapes[j]); - } - - if (s.blend_shape_base_buffer.is_valid()) { - RD::get_singleton()->free(s.blend_shape_base_buffer); + if (s.blend_shape_buffer.is_valid()) { + RD::get_singleton()->free(s.blend_shape_buffer); } memdelete(mesh->surfaces[i]); @@ -2782,22 +2889,237 @@ void RasterizerStorageRD::mesh_clear(RID p_mesh) { mesh->surfaces = nullptr; mesh->surface_count = 0; mesh->material_cache.clear(); - mesh->instance_dependency.instance_notify_changed(true, true); + //clear instance data + for (List<MeshInstance *>::Element *E = mesh->instances.front(); E; E = E->next()) { + MeshInstance *mi = E->get(); + _mesh_instance_clear(mi); + } + mesh->has_bone_weights = false; + mesh->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); + + for (Set<Mesh *>::Element *E = mesh->shadow_owners.front(); E; E = E->next()) { + Mesh *shadow_owner = E->get(); + shadow_owner->shadow_mesh = RID(); + shadow_owner->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); + } +} + +bool RendererStorageRD::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh, false); + + return mesh->blend_shape_count > 0 || (mesh->has_bone_weights && p_has_skeleton); } -void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Surface *s, uint32_t p_input_mask) { - uint32_t version = s->version_count; - s->version_count++; - s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count); +/* MESH INSTANCE */ + +RID RendererStorageRD::mesh_instance_create(RID p_base) { + Mesh *mesh = mesh_owner.getornull(p_base); + ERR_FAIL_COND_V(!mesh, RID()); + + MeshInstance *mi = memnew(MeshInstance); + + mi->mesh = mesh; + + for (uint32_t i = 0; i < mesh->surface_count; i++) { + _mesh_instance_add_surface(mi, mesh, i); + } + + mi->I = mesh->instances.push_back(mi); + + mi->dirty = true; + + return mesh_instance_owner.make_rid(mi); +} +void RendererStorageRD::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) { + MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance); + if (mi->skeleton == p_skeleton) { + return; + } + mi->skeleton = p_skeleton; + mi->skeleton_version = 0; + mi->dirty = true; +} - Mesh::Surface::Version &v = s->versions[version]; +void RendererStorageRD::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) { + MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance); + ERR_FAIL_COND(!mi); + ERR_FAIL_INDEX(p_shape, (int)mi->blend_weights.size()); + mi->blend_weights[p_shape] = p_weight; + mi->weights_dirty = true; + //will be eventually updated +} +void RendererStorageRD::_mesh_instance_clear(MeshInstance *mi) { + for (uint32_t i = 0; i < mi->surfaces.size(); i++) { + if (mi->surfaces[i].vertex_buffer.is_valid()) { + RD::get_singleton()->free(mi->surfaces[i].vertex_buffer); + } + if (mi->surfaces[i].versions) { + for (uint32_t j = 0; j < mi->surfaces[i].version_count; j++) { + RD::get_singleton()->free(mi->surfaces[i].versions[j].vertex_array); + } + memfree(mi->surfaces[i].versions); + } + } + mi->surfaces.clear(); + + if (mi->blend_weights_buffer.is_valid()) { + RD::get_singleton()->free(mi->blend_weights_buffer); + } + mi->blend_weights.clear(); + mi->weights_dirty = false; + mi->skeleton_version = 0; +} + +void RendererStorageRD::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface) { + if (mesh->blend_shape_count > 0 && mi->blend_weights_buffer.is_null()) { + mi->blend_weights.resize(mesh->blend_shape_count); + for (uint32_t i = 0; i < mi->blend_weights.size(); i++) { + mi->blend_weights[i] = 0; + } + mi->blend_weights_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * mi->blend_weights.size(), mi->blend_weights.to_byte_array()); + mi->weights_dirty = true; + } + + MeshInstance::Surface s; + if (mesh->blend_shape_count > 0 || (mesh->surfaces[p_surface]->format & RS::ARRAY_FORMAT_BONES)) { + //surface warrants transform + s.vertex_buffer = RD::get_singleton()->vertex_buffer_create(mesh->surfaces[p_surface]->vertex_buffer_size, Vector<uint8_t>(), true); + + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.binding = 1; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(s.vertex_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 2; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + if (mi->blend_weights_buffer.is_valid()) { + u.ids.push_back(mi->blend_weights_buffer); + } else { + u.ids.push_back(default_rd_storage_buffer); + } + uniforms.push_back(u); + } + s.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_INSTANCE); + } + + mi->surfaces.push_back(s); + mi->dirty = true; +} + +void RendererStorageRD::mesh_instance_check_for_update(RID p_mesh_instance) { + MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance); + + bool needs_update = mi->dirty; + + if (mi->weights_dirty && !mi->weight_update_list.in_list()) { + dirty_mesh_instance_weights.add(&mi->weight_update_list); + needs_update = true; + } + + if (mi->array_update_list.in_list()) { + return; + } + + if (!needs_update && mi->skeleton.is_valid()) { + Skeleton *sk = skeleton_owner.getornull(mi->skeleton); + if (sk && sk->version != mi->skeleton_version) { + needs_update = true; + } + } + + if (needs_update) { + dirty_mesh_instance_arrays.add(&mi->array_update_list); + } +} + +void RendererStorageRD::update_mesh_instances() { + while (dirty_mesh_instance_weights.first()) { + MeshInstance *mi = dirty_mesh_instance_weights.first()->self(); + + if (mi->blend_weights_buffer.is_valid()) { + RD::get_singleton()->buffer_update(mi->blend_weights_buffer, 0, mi->blend_weights.size() * sizeof(float), mi->blend_weights.ptr()); + } + dirty_mesh_instance_weights.remove(&mi->weight_update_list); + mi->weights_dirty = false; + } + if (dirty_mesh_instance_arrays.first() == nullptr) { + return; //nothing to do + } + + //process skeletons and blend shapes + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + + while (dirty_mesh_instance_arrays.first()) { + MeshInstance *mi = dirty_mesh_instance_arrays.first()->self(); + + Skeleton *sk = skeleton_owner.getornull(mi->skeleton); + + for (uint32_t i = 0; i < mi->surfaces.size(); i++) { + if (mi->surfaces[i].uniform_set == RID() || mi->mesh->surfaces[i]->uniform_set == RID()) { + continue; + } + + bool array_is_2d = mi->mesh->surfaces[i]->format & RS::ARRAY_FLAG_USE_2D_VERTICES; + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, skeleton_shader.pipeline[array_is_2d ? SkeletonShader::SHADER_MODE_2D : SkeletonShader::SHADER_MODE_3D]); + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mi->surfaces[i].uniform_set, SkeletonShader::UNIFORM_SET_INSTANCE); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mi->mesh->surfaces[i]->uniform_set, SkeletonShader::UNIFORM_SET_SURFACE); + if (sk && sk->uniform_set_mi.is_valid()) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sk->uniform_set_mi, SkeletonShader::UNIFORM_SET_SKELETON); + } else { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, skeleton_shader.default_skeleton_uniform_set, SkeletonShader::UNIFORM_SET_SKELETON); + } + + SkeletonShader::PushConstant push_constant; + + push_constant.has_normal = mi->mesh->surfaces[i]->format & RS::ARRAY_FORMAT_NORMAL; + push_constant.has_tangent = mi->mesh->surfaces[i]->format & RS::ARRAY_FORMAT_TANGENT; + push_constant.has_skeleton = sk != nullptr && sk->use_2d == array_is_2d && (mi->mesh->surfaces[i]->format & RS::ARRAY_FORMAT_BONES); + push_constant.has_blend_shape = mi->mesh->blend_shape_count > 0; + + push_constant.vertex_count = mi->mesh->surfaces[i]->vertex_count; + push_constant.vertex_stride = (mi->mesh->surfaces[i]->vertex_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4; + push_constant.skin_stride = (mi->mesh->surfaces[i]->skin_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4; + push_constant.skin_weight_offset = (mi->mesh->surfaces[i]->format & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 4 : 2; + + push_constant.blend_shape_count = mi->mesh->blend_shape_count; + push_constant.normalized_blend_shapes = mi->mesh->blend_shape_mode == RS::BLEND_SHAPE_MODE_NORMALIZED; + push_constant.pad0 = 0; + push_constant.pad1 = 0; + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SkeletonShader::PushConstant)); + + //dispatch without barrier, so all is done at the same time + RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.vertex_count, 1, 1, 64, 1, 1); + } + + mi->dirty = false; + if (sk) { + mi->skeleton_version = sk->version; + } + dirty_mesh_instance_arrays.remove(&mi->array_update_list); + } + + RD::get_singleton()->compute_list_end(); +} + +void RendererStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis) { Vector<RD::VertexAttribute> attributes; Vector<RID> buffers; uint32_t stride = 0; + uint32_t attribute_stride = 0; + uint32_t skin_stride = 0; - for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) { + for (int i = 0; i < RS::ARRAY_INDEX; i++) { RD::VertexAttribute vd; RID buffer; vd.location = i; @@ -2805,6 +3127,7 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su if (!(s->format & (1 << i))) { // Not supplied by surface, use default value buffer = mesh_default_rd_buffers[i]; + vd.stride = 0; switch (i) { case RS::ARRAY_VERTEX: { vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; @@ -2827,20 +3150,31 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su case RS::ARRAY_TEX_UV2: { vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; } break; + case RS::ARRAY_CUSTOM0: + case RS::ARRAY_CUSTOM1: + case RS::ARRAY_CUSTOM2: + case RS::ARRAY_CUSTOM3: { + //assumed weights too + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + } break; case RS::ARRAY_BONES: { //assumed weights too vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; } break; + case RS::ARRAY_WEIGHTS: { + //assumed weights too + vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; + } break; } } else { //Supplied, use it - vd.offset = stride; - vd.stride = 1; //mark that it needs a stride set - buffer = s->vertex_buffer; + vd.stride = 1; //mark that it needs a stride set (default uses 0) switch (i) { case RS::ARRAY_VERTEX: { + vd.offset = stride; + if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) { vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; stride += sizeof(float) * 2; @@ -2849,71 +3183,92 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su stride += sizeof(float) * 3; } + if (mis) { + buffer = mis->vertex_buffer; + } else { + buffer = s->vertex_buffer; + } + } break; case RS::ARRAY_NORMAL: { - if (s->format & RS::ARRAY_COMPRESS_NORMAL) { - vd.format = RD::DATA_FORMAT_R8G8B8A8_SNORM; - stride += sizeof(int8_t) * 4; + vd.offset = stride; + + vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32; + + stride += sizeof(uint32_t); + if (mis) { + buffer = mis->vertex_buffer; } else { - vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; - stride += sizeof(float) * 4; + buffer = s->vertex_buffer; } - } break; case RS::ARRAY_TANGENT: { - if (s->format & RS::ARRAY_COMPRESS_TANGENT) { - vd.format = RD::DATA_FORMAT_R8G8B8A8_SNORM; - stride += sizeof(int8_t) * 4; + vd.offset = stride; + + vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32; + stride += sizeof(uint32_t); + if (mis) { + buffer = mis->vertex_buffer; } else { - vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; - stride += sizeof(float) * 4; + buffer = s->vertex_buffer; } - } break; case RS::ARRAY_COLOR: { - if (s->format & RS::ARRAY_COMPRESS_COLOR) { - vd.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; - stride += sizeof(int8_t) * 4; - } else { - vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; - stride += sizeof(float) * 4; - } + vd.offset = attribute_stride; + vd.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + attribute_stride += sizeof(int16_t) * 4; + buffer = s->attribute_buffer; } break; case RS::ARRAY_TEX_UV: { - if (s->format & RS::ARRAY_COMPRESS_TEX_UV) { - vd.format = RD::DATA_FORMAT_R16G16_SFLOAT; - stride += sizeof(int16_t) * 2; - } else { - vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; - stride += sizeof(float) * 2; - } + vd.offset = attribute_stride; + + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + attribute_stride += sizeof(float) * 2; + buffer = s->attribute_buffer; } break; case RS::ARRAY_TEX_UV2: { - if (s->format & RS::ARRAY_COMPRESS_TEX_UV2) { - vd.format = RD::DATA_FORMAT_R16G16_SFLOAT; - stride += sizeof(int16_t) * 2; - } else { - vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; - stride += sizeof(float) * 2; - } + vd.offset = attribute_stride; + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + attribute_stride += sizeof(float) * 2; + buffer = s->attribute_buffer; + } break; + case RS::ARRAY_CUSTOM0: + case RS::ARRAY_CUSTOM1: + case RS::ARRAY_CUSTOM2: + case RS::ARRAY_CUSTOM3: { + vd.offset = attribute_stride; + + int idx = i - RS::ARRAY_CUSTOM0; + uint32_t fmt_shift[RS::ARRAY_CUSTOM_COUNT] = { RS::ARRAY_FORMAT_CUSTOM0_SHIFT, RS::ARRAY_FORMAT_CUSTOM1_SHIFT, RS::ARRAY_FORMAT_CUSTOM2_SHIFT, RS::ARRAY_FORMAT_CUSTOM3_SHIFT }; + uint32_t fmt = (s->format >> fmt_shift[idx]) & RS::ARRAY_FORMAT_CUSTOM_MASK; + uint32_t fmtsize[RS::ARRAY_CUSTOM_MAX] = { 4, 4, 4, 8, 4, 8, 12, 16 }; + RD::DataFormat fmtrd[RS::ARRAY_CUSTOM_MAX] = { RD::DATA_FORMAT_R8G8B8A8_UNORM, RD::DATA_FORMAT_R8G8B8A8_SNORM, RD::DATA_FORMAT_R16G16_SFLOAT, RD::DATA_FORMAT_R16G16B16A16_SFLOAT, RD::DATA_FORMAT_R32_SFLOAT, RD::DATA_FORMAT_R32G32_SFLOAT, RD::DATA_FORMAT_R32G32B32_SFLOAT, RD::DATA_FORMAT_R32G32B32A32_SFLOAT }; + vd.format = fmtrd[fmt]; + attribute_stride += fmtsize[fmt]; + buffer = s->attribute_buffer; } break; case RS::ARRAY_BONES: { - //assumed weights too + vd.offset = skin_stride; - //unique format, internally 16 bits, exposed as single array for 32 - - vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; - stride += sizeof(int32_t) * 4; + vd.format = RD::DATA_FORMAT_R16G16B16A16_UINT; + skin_stride += sizeof(int16_t) * 4; + buffer = s->skin_buffer; + } break; + case RS::ARRAY_WEIGHTS: { + vd.offset = skin_stride; + vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM; + skin_stride += sizeof(int16_t) * 4; + buffer = s->skin_buffer; } break; } } if (!(p_input_mask & (1 << i))) { - continue; // Shader does not need this, skip it + continue; // Shader does not need this, skip it (but computing stride was important anyway) } attributes.push_back(vd); @@ -2922,8 +3277,17 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su //update final stride for (int i = 0; i < attributes.size(); i++) { - if (attributes[i].stride == 1) { + if (attributes[i].stride == 0) { + continue; //default location + } + int loc = attributes[i].location; + + if (loc < RS::ARRAY_COLOR) { attributes.write[i].stride = stride; + } else if (loc < RS::ARRAY_BONES) { + attributes.write[i].stride = attribute_stride; + } else { + attributes.write[i].stride = skin_stride; } } @@ -2934,11 +3298,11 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su ////////////////// MULTIMESH -RID RasterizerStorageRD::multimesh_create() { +RID RendererStorageRD::multimesh_create() { return multimesh_owner.make_rid(MultiMesh()); } -void RasterizerStorageRD::multimesh_allocate(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) { +void RendererStorageRD::multimesh_allocate(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); @@ -2976,15 +3340,17 @@ void RasterizerStorageRD::multimesh_allocate(RID p_multimesh, int p_instances, R if (multimesh->instances) { multimesh->buffer = RD::get_singleton()->storage_buffer_create(multimesh->instances * multimesh->stride_cache * 4); } + + multimesh->dependency.changed_notify(DEPENDENCY_CHANGED_MULTIMESH); } -int RasterizerStorageRD::multimesh_get_instance_count(RID p_multimesh) const { +int RendererStorageRD::multimesh_get_instance_count(RID p_multimesh) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, 0); return multimesh->instances; } -void RasterizerStorageRD::multimesh_set_mesh(RID p_multimesh, RID p_mesh) { +void RendererStorageRD::multimesh_set_mesh(RID p_multimesh, RID p_mesh) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); if (multimesh->mesh == p_mesh) { @@ -3009,12 +3375,12 @@ void RasterizerStorageRD::multimesh_set_mesh(RID p_multimesh, RID p_mesh) { } } - multimesh->instance_dependency.instance_notify_changed(true, true); + multimesh->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); } #define MULTIMESH_DIRTY_REGION_SIZE 512 -void RasterizerStorageRD::_multimesh_make_local(MultiMesh *multimesh) const { +void RendererStorageRD::_multimesh_make_local(MultiMesh *multimesh) const { if (multimesh->data_cache.size() > 0) { return; //already local } @@ -3043,7 +3409,7 @@ void RasterizerStorageRD::_multimesh_make_local(MultiMesh *multimesh) const { multimesh->data_cache_used_dirty_regions = 0; } -void RasterizerStorageRD::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb) { +void RendererStorageRD::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb) { uint32_t region_index = p_index / MULTIMESH_DIRTY_REGION_SIZE; #ifdef DEBUG_ENABLED uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; @@ -3065,7 +3431,7 @@ void RasterizerStorageRD::_multimesh_mark_dirty(MultiMesh *multimesh, int p_inde } } -void RasterizerStorageRD::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb) { +void RendererStorageRD::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb) { if (p_data) { uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; @@ -3088,7 +3454,7 @@ void RasterizerStorageRD::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p } } -void RasterizerStorageRD::_multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances) { +void RendererStorageRD::_multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances) { ERR_FAIL_COND(multimesh->mesh.is_null()); AABB aabb; AABB mesh_aabb = mesh_get_aabb(multimesh->mesh); @@ -3130,7 +3496,7 @@ void RasterizerStorageRD::_multimesh_re_create_aabb(MultiMesh *multimesh, const multimesh->aabb = aabb; } -void RasterizerStorageRD::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) { +void RendererStorageRD::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_INDEX(p_index, multimesh->instances); @@ -3160,7 +3526,7 @@ void RasterizerStorageRD::multimesh_instance_set_transform(RID p_multimesh, int _multimesh_mark_dirty(multimesh, p_index, true); } -void RasterizerStorageRD::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) { +void RendererStorageRD::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_INDEX(p_index, multimesh->instances); @@ -3186,7 +3552,7 @@ void RasterizerStorageRD::multimesh_instance_set_transform_2d(RID p_multimesh, i _multimesh_mark_dirty(multimesh, p_index, true); } -void RasterizerStorageRD::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) { +void RendererStorageRD::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_INDEX(p_index, multimesh->instances); @@ -3208,7 +3574,7 @@ void RasterizerStorageRD::multimesh_instance_set_color(RID p_multimesh, int p_in _multimesh_mark_dirty(multimesh, p_index, false); } -void RasterizerStorageRD::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) { +void RendererStorageRD::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_INDEX(p_index, multimesh->instances); @@ -3230,14 +3596,14 @@ void RasterizerStorageRD::multimesh_instance_set_custom_data(RID p_multimesh, in _multimesh_mark_dirty(multimesh, p_index, false); } -RID RasterizerStorageRD::multimesh_get_mesh(RID p_multimesh) const { +RID RendererStorageRD::multimesh_get_mesh(RID p_multimesh) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, RID()); return multimesh->mesh; } -Transform RasterizerStorageRD::multimesh_instance_get_transform(RID p_multimesh, int p_index) const { +Transform RendererStorageRD::multimesh_instance_get_transform(RID p_multimesh, int p_index) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, Transform()); ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform()); @@ -3268,7 +3634,7 @@ Transform RasterizerStorageRD::multimesh_instance_get_transform(RID p_multimesh, return t; } -Transform2D RasterizerStorageRD::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const { +Transform2D RendererStorageRD::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, Transform2D()); ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform2D()); @@ -3293,7 +3659,7 @@ Transform2D RasterizerStorageRD::multimesh_instance_get_transform_2d(RID p_multi return t; } -Color RasterizerStorageRD::multimesh_instance_get_color(RID p_multimesh, int p_index) const { +Color RendererStorageRD::multimesh_instance_get_color(RID p_multimesh, int p_index) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, Color()); ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color()); @@ -3316,7 +3682,7 @@ Color RasterizerStorageRD::multimesh_instance_get_color(RID p_multimesh, int p_i return c; } -Color RasterizerStorageRD::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const { +Color RendererStorageRD::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, Color()); ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color()); @@ -3339,14 +3705,14 @@ Color RasterizerStorageRD::multimesh_instance_get_custom_data(RID p_multimesh, i return c; } -void RasterizerStorageRD::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) { +void RendererStorageRD::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache)); { const float *r = p_buffer.ptr(); - RD::get_singleton()->buffer_update(multimesh->buffer, 0, p_buffer.size() * sizeof(float), r, false); + RD::get_singleton()->buffer_update(multimesh->buffer, 0, p_buffer.size() * sizeof(float), r); multimesh->buffer_set = true; } @@ -3368,11 +3734,11 @@ void RasterizerStorageRD::multimesh_set_buffer(RID p_multimesh, const Vector<flo const float *data = p_buffer.ptr(); _multimesh_re_create_aabb(multimesh, data, multimesh->instances); - multimesh->instance_dependency.instance_notify_changed(true, false); + multimesh->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } } -Vector<float> RasterizerStorageRD::multimesh_get_buffer(RID p_multimesh) const { +Vector<float> RendererStorageRD::multimesh_get_buffer(RID p_multimesh) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, Vector<float>()); if (multimesh->buffer.is_null()) { @@ -3395,7 +3761,7 @@ Vector<float> RasterizerStorageRD::multimesh_get_buffer(RID p_multimesh) const { } } -void RasterizerStorageRD::multimesh_set_visible_instances(RID p_multimesh, int p_visible) { +void RendererStorageRD::multimesh_set_visible_instances(RID p_multimesh, int p_visible) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_COND(p_visible < -1 || p_visible > multimesh->instances); @@ -3409,24 +3775,26 @@ void RasterizerStorageRD::multimesh_set_visible_instances(RID p_multimesh, int p } multimesh->visible_instances = p_visible; + + multimesh->dependency.changed_notify(DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES); } -int RasterizerStorageRD::multimesh_get_visible_instances(RID p_multimesh) const { +int RendererStorageRD::multimesh_get_visible_instances(RID p_multimesh) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, 0); return multimesh->visible_instances; } -AABB RasterizerStorageRD::multimesh_get_aabb(RID p_multimesh) const { +AABB RendererStorageRD::multimesh_get_aabb(RID p_multimesh) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, AABB()); if (multimesh->aabb_dirty) { - const_cast<RasterizerStorageRD *>(this)->_update_dirty_multimeshes(); + const_cast<RendererStorageRD *>(this)->_update_dirty_multimeshes(); } return multimesh->aabb; } -void RasterizerStorageRD::_update_dirty_multimeshes() { +void RendererStorageRD::_update_dirty_multimeshes() { while (multimesh_dirty_list) { MultiMesh *multimesh = multimesh_dirty_list; @@ -3443,14 +3811,14 @@ void RasterizerStorageRD::_update_dirty_multimeshes() { if (multimesh->data_cache_used_dirty_regions > 32 || multimesh->data_cache_used_dirty_regions > visible_region_count / 2) { //if there too many dirty regions, or represent the majority of regions, just copy all, else transfer cost piles up too much - RD::get_singleton()->buffer_update(multimesh->buffer, 0, MIN(visible_region_count * region_size, multimesh->instances * multimesh->stride_cache * sizeof(float)), data, false); + RD::get_singleton()->buffer_update(multimesh->buffer, 0, MIN(visible_region_count * region_size, multimesh->instances * multimesh->stride_cache * sizeof(float)), data); } else { //not that many regions? update them all for (uint32_t i = 0; i < visible_region_count; i++) { if (multimesh->data_cache_dirty_regions[i]) { uint64_t offset = i * region_size; uint64_t size = multimesh->stride_cache * multimesh->instances * sizeof(float); - RD::get_singleton()->buffer_update(multimesh->buffer, offset, MIN(region_size, size - offset), &data[i * region_size], false); + RD::get_singleton()->buffer_update(multimesh->buffer, offset, MIN(region_size, size - offset), &data[i * region_size]); } } } @@ -3466,7 +3834,7 @@ void RasterizerStorageRD::_update_dirty_multimeshes() { //aabb is dirty.. _multimesh_re_create_aabb(multimesh, data, visible_instances); multimesh->aabb_dirty = false; - multimesh->instance_dependency.instance_notify_changed(true, false); + multimesh->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } } @@ -3481,25 +3849,25 @@ void RasterizerStorageRD::_update_dirty_multimeshes() { /* PARTICLES */ -RID RasterizerStorageRD::particles_create() { +RID RendererStorageRD::particles_create() { return particles_owner.make_rid(Particles()); } -void RasterizerStorageRD::particles_set_emitting(RID p_particles, bool p_emitting) { +void RendererStorageRD::particles_set_emitting(RID p_particles, bool p_emitting) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->emitting = p_emitting; } -bool RasterizerStorageRD::particles_get_emitting(RID p_particles) { +bool RendererStorageRD::particles_get_emitting(RID p_particles) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, false); return particles->emitting; } -void RasterizerStorageRD::_particles_free_data(Particles *particles) { +void RendererStorageRD::_particles_free_data(Particles *particles) { if (!particles->particle_buffer.is_valid()) { return; } @@ -3526,7 +3894,7 @@ void RasterizerStorageRD::_particles_free_data(Particles *particles) { } } -void RasterizerStorageRD::particles_set_amount(RID p_particles, int p_amount) { +void RendererStorageRD::particles_set_amount(RID p_particles, int p_amount) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); @@ -3549,14 +3917,14 @@ void RasterizerStorageRD::particles_set_amount(RID p_particles, int p_amount) { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(particles->particle_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; u.ids.push_back(particles->particle_instance_buffer); uniforms.push_back(u); @@ -3572,111 +3940,111 @@ void RasterizerStorageRD::particles_set_amount(RID p_particles, int p_amount) { particles->clear = true; } -void RasterizerStorageRD::particles_set_lifetime(RID p_particles, float p_lifetime) { +void RendererStorageRD::particles_set_lifetime(RID p_particles, float p_lifetime) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->lifetime = p_lifetime; } -void RasterizerStorageRD::particles_set_one_shot(RID p_particles, bool p_one_shot) { +void RendererStorageRD::particles_set_one_shot(RID p_particles, bool p_one_shot) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->one_shot = p_one_shot; } -void RasterizerStorageRD::particles_set_pre_process_time(RID p_particles, float p_time) { +void RendererStorageRD::particles_set_pre_process_time(RID p_particles, float p_time) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->pre_process_time = p_time; } -void RasterizerStorageRD::particles_set_explosiveness_ratio(RID p_particles, float p_ratio) { +void RendererStorageRD::particles_set_explosiveness_ratio(RID p_particles, float p_ratio) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->explosiveness = p_ratio; } -void RasterizerStorageRD::particles_set_randomness_ratio(RID p_particles, float p_ratio) { +void RendererStorageRD::particles_set_randomness_ratio(RID p_particles, float p_ratio) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->randomness = p_ratio; } -void RasterizerStorageRD::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) { +void RendererStorageRD::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->custom_aabb = p_aabb; - particles->instance_dependency.instance_notify_changed(true, false); + particles->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -void RasterizerStorageRD::particles_set_speed_scale(RID p_particles, float p_scale) { +void RendererStorageRD::particles_set_speed_scale(RID p_particles, float p_scale) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->speed_scale = p_scale; } -void RasterizerStorageRD::particles_set_use_local_coordinates(RID p_particles, bool p_enable) { +void RendererStorageRD::particles_set_use_local_coordinates(RID p_particles, bool p_enable) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->use_local_coords = p_enable; } -void RasterizerStorageRD::particles_set_fixed_fps(RID p_particles, int p_fps) { +void RendererStorageRD::particles_set_fixed_fps(RID p_particles, int p_fps) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->fixed_fps = p_fps; } -void RasterizerStorageRD::particles_set_fractional_delta(RID p_particles, bool p_enable) { +void RendererStorageRD::particles_set_fractional_delta(RID p_particles, bool p_enable) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->fractional_delta = p_enable; } -void RasterizerStorageRD::particles_set_collision_base_size(RID p_particles, float p_size) { +void RendererStorageRD::particles_set_collision_base_size(RID p_particles, float p_size) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->collision_base_size = p_size; } -void RasterizerStorageRD::particles_set_process_material(RID p_particles, RID p_material) { +void RendererStorageRD::particles_set_process_material(RID p_particles, RID p_material) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->process_material = p_material; } -void RasterizerStorageRD::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) { +void RendererStorageRD::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->draw_order = p_order; } -void RasterizerStorageRD::particles_set_draw_passes(RID p_particles, int p_passes) { +void RendererStorageRD::particles_set_draw_passes(RID p_particles, int p_passes) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->draw_passes.resize(p_passes); } -void RasterizerStorageRD::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) { +void RendererStorageRD::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); ERR_FAIL_INDEX(p_pass, particles->draw_passes.size()); particles->draw_passes.write[p_pass] = p_mesh; } -void RasterizerStorageRD::particles_restart(RID p_particles) { +void RendererStorageRD::particles_restart(RID p_particles) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->restart_request = true; } -void RasterizerStorageRD::_particles_allocate_emission_buffer(Particles *particles) { +void RendererStorageRD::_particles_allocate_emission_buffer(Particles *particles) { ERR_FAIL_COND(particles->emission_buffer != nullptr); particles->emission_buffer_data.resize(sizeof(ParticleEmissionBuffer::Data) * particles->amount + sizeof(uint32_t) * 4); @@ -3693,7 +4061,7 @@ void RasterizerStorageRD::_particles_allocate_emission_buffer(Particles *particl } } -void RasterizerStorageRD::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) { +void RendererStorageRD::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); ERR_FAIL_COND(p_particles == p_subemitter_particles); @@ -3706,7 +4074,7 @@ void RasterizerStorageRD::particles_set_subemitter(RID p_particles, RID p_subemi } } -void RasterizerStorageRD::particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { +void RendererStorageRD::particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); ERR_FAIL_COND(particles->amount == 0); @@ -3749,7 +4117,7 @@ void RasterizerStorageRD::particles_emit(RID p_particles, const Transform &p_tra } } -void RasterizerStorageRD::particles_request_process(RID p_particles) { +void RendererStorageRD::particles_request_process(RID p_particles) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); @@ -3760,7 +4128,7 @@ void RasterizerStorageRD::particles_request_process(RID p_particles) { } } -AABB RasterizerStorageRD::particles_get_current_aabb(RID p_particles) { +AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) { const Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, AABB()); @@ -3804,28 +4172,28 @@ AABB RasterizerStorageRD::particles_get_current_aabb(RID p_particles) { return aabb; } -AABB RasterizerStorageRD::particles_get_aabb(RID p_particles) const { +AABB RendererStorageRD::particles_get_aabb(RID p_particles) const { const Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, AABB()); return particles->custom_aabb; } -void RasterizerStorageRD::particles_set_emission_transform(RID p_particles, const Transform &p_transform) { +void RendererStorageRD::particles_set_emission_transform(RID p_particles, const Transform &p_transform) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->emission_transform = p_transform; } -int RasterizerStorageRD::particles_get_draw_passes(RID p_particles) const { +int RendererStorageRD::particles_get_draw_passes(RID p_particles) const { const Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, 0); return particles->draw_passes.size(); } -RID RasterizerStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { +RID RendererStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { const Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, RID()); ERR_FAIL_INDEX_V(p_pass, particles->draw_passes.size(), RID()); @@ -3833,36 +4201,34 @@ RID RasterizerStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pas return particles->draw_passes[p_pass]; } -void RasterizerStorageRD::particles_add_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance) { +void RendererStorageRD::particles_add_collision(RID p_particles, RID p_particles_collision_instance) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); - ERR_FAIL_COND(p_instance->base_type != RS::INSTANCE_PARTICLES_COLLISION); - - particles->collisions.insert(p_instance); + particles->collisions.insert(p_particles_collision_instance); } -void RasterizerStorageRD::particles_remove_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance) { +void RendererStorageRD::particles_remove_collision(RID p_particles, RID p_particles_collision_instance) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); - particles->collisions.erase(p_instance); + particles->collisions.erase(p_particles_collision_instance); } -void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_delta) { +void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta) { if (p_particles->particles_material_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_particles->particles_material_uniform_set)) { Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(p_particles->frame_params_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(p_particles->particle_buffer); uniforms.push_back(u); @@ -3870,7 +4236,7 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; if (p_particles->emission_storage_buffer.is_valid()) { u.ids.push_back(p_particles->emission_storage_buffer); @@ -3881,7 +4247,7 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 3; Particles *sub_emitter = particles_owner.getornull(p_particles->sub_emitter); if (sub_emitter) { @@ -3918,7 +4284,7 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del p_particles->phase = new_phase; - frame_params.time = RasterizerRD::singleton->get_total_time(); + frame_params.time = RendererCompositorRD::singleton->get_total_time(); frame_params.delta = p_delta * p_particles->speed_scale; frame_params.random_seed = p_particles->random_seed; frame_params.explosiveness = p_particles->explosiveness; @@ -3946,9 +4312,15 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del to_particles = p_particles->emission_transform.affine_inverse(); } uint32_t collision_3d_textures_used = 0; - for (const Set<RasterizerScene::InstanceBase *>::Element *E = p_particles->collisions.front(); E; E = E->next()) { - ParticlesCollision *pc = particles_collision_owner.getornull(E->get()->base); - Transform to_collider = E->get()->transform; + for (const Set<RID>::Element *E = p_particles->collisions.front(); E; E = E->next()) { + ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(E->get()); + if (!pci || !pci->active) { + continue; + } + ParticlesCollision *pc = particles_collision_owner.getornull(pci->collision); + ERR_CONTINUE(!pc); + + Transform to_collider = pci->transform; if (p_particles->use_local_coords) { to_collider = to_particles * to_collider; } @@ -4088,7 +4460,7 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; for (uint32_t i = 0; i < ParticlesFrameParams::MAX_3D_TEXTURES; i++) { RID rd_tex; @@ -4108,7 +4480,7 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; if (collision_heightmap_texture.is_valid()) { u.ids.push_back(collision_heightmap_texture); @@ -4137,7 +4509,7 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del if (sub_emitter && sub_emitter->emission_storage_buffer.is_valid()) { // print_line("updating subemitter buffer"); int32_t zero[4] = { 0, sub_emitter->amount, 0, 0 }; - RD::get_singleton()->buffer_update(sub_emitter->emission_storage_buffer, 0, sizeof(uint32_t) * 4, zero, true); + RD::get_singleton()->buffer_update(sub_emitter->emission_storage_buffer, 0, sizeof(uint32_t) * 4, zero); push_constant.can_emit = true; if (sub_emitter->emitting) { @@ -4155,13 +4527,13 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del } if (p_particles->emission_buffer && p_particles->emission_buffer->particle_count) { - RD::get_singleton()->buffer_update(p_particles->emission_storage_buffer, 0, sizeof(uint32_t) * 4 + sizeof(ParticleEmissionBuffer::Data) * p_particles->emission_buffer->particle_count, p_particles->emission_buffer, true); + RD::get_singleton()->buffer_update(p_particles->emission_storage_buffer, 0, sizeof(uint32_t) * 4 + sizeof(ParticleEmissionBuffer::Data) * p_particles->emission_buffer->particle_count, p_particles->emission_buffer); p_particles->emission_buffer->particle_count = 0; } p_particles->clear = false; - RD::get_singleton()->buffer_update(p_particles->frame_params_buffer, 0, sizeof(ParticlesFrameParams), &frame_params, true); + RD::get_singleton()->buffer_update(p_particles->frame_params_buffer, 0, sizeof(ParticlesFrameParams), &frame_params); ParticlesMaterialData *m = (ParticlesMaterialData *)material_get_data(p_particles->process_material, SHADER_TYPE_PARTICLES); if (!m) { @@ -4188,7 +4560,7 @@ void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_del RD::get_singleton()->compute_list_end(); } -void RasterizerStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &p_axis) { +void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &p_axis) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); @@ -4209,7 +4581,7 @@ void RasterizerStorageRD::particles_set_view_axis(RID p_particles, const Vector3 { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(particles->particles_sort_buffer); uniforms.push_back(u); @@ -4254,7 +4626,7 @@ void RasterizerStorageRD::particles_set_view_axis(RID p_particles, const Vector3 RD::get_singleton()->compute_list_end(); } -void RasterizerStorageRD::update_particles() { +void RendererStorageRD::update_particles() { while (particle_update_list) { //use transform feedback to process particles @@ -4289,7 +4661,7 @@ void RasterizerStorageRD::update_particles() { particles->inactive = false; particles->inactive_time = 0; } else { - particles->inactive_time += particles->speed_scale * RasterizerRD::singleton->get_frame_delta_time(); + particles->inactive_time += particles->speed_scale * RendererCompositorRD::singleton->get_frame_delta_time(); if (particles->inactive_time > particles->lifetime * 1.2) { particles->inactive = true; continue; @@ -4323,7 +4695,7 @@ void RasterizerStorageRD::update_particles() { frame_time = 1.0 / particles->fixed_fps; decr = frame_time; } - float delta = RasterizerRD::singleton->get_frame_delta_time(); + float delta = RendererCompositorRD::singleton->get_frame_delta_time(); if (delta > 0.1) { //avoid recursive stalls if fps goes below 10 delta = 0.1; } else if (delta <= 0.0) { //unlikely but.. @@ -4342,7 +4714,7 @@ void RasterizerStorageRD::update_particles() { if (zero_time_scale) _particles_process(particles, 0.0); else - _particles_process(particles, RasterizerRD::singleton->get_frame_delta_time()); + _particles_process(particles, RendererCompositorRD::singleton->get_frame_delta_time()); } //copy particles to instance buffer @@ -4361,11 +4733,11 @@ void RasterizerStorageRD::update_particles() { RD::get_singleton()->compute_list_end(); } - particles->instance_dependency.instance_notify_changed(true, false); //make sure shadows are updated + particles->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } } -bool RasterizerStorageRD::particles_is_inactive(RID p_particles) const { +bool RendererStorageRD::particles_is_inactive(RID p_particles) const { const Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, false); return !particles->emitting && particles->inactive; @@ -4373,7 +4745,7 @@ bool RasterizerStorageRD::particles_is_inactive(RID p_particles) const { /* SKY SHADER */ -void RasterizerStorageRD::ParticlesShaderData::set_code(const String &p_code) { +void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) { //compile code = p_code; @@ -4421,7 +4793,7 @@ void RasterizerStorageRD::ParticlesShaderData::set_code(const String &p_code) { valid = true; } -void RasterizerStorageRD::ParticlesShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { +void RendererStorageRD::ParticlesShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { if (!p_texture.is_valid()) { default_texture_params.erase(p_name); } else { @@ -4429,7 +4801,7 @@ void RasterizerStorageRD::ParticlesShaderData::set_default_texture_param(const S } } -void RasterizerStorageRD::ParticlesShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { +void RendererStorageRD::ParticlesShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { Map<int, StringName> order; for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { @@ -4451,13 +4823,13 @@ void RasterizerStorageRD::ParticlesShaderData::get_param_list(List<PropertyInfo> } } -void RasterizerStorageRD::ParticlesShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const { +void RendererStorageRD::ParticlesShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; } - RasterizerStorage::InstanceShaderParam p; + RendererStorage::InstanceShaderParam p; p.info = ShaderLanguage::uniform_to_property_info(E->get()); p.info.name = E->key(); //supply name p.index = E->get().instance_index; @@ -4466,7 +4838,7 @@ void RasterizerStorageRD::ParticlesShaderData::get_instance_param_list(List<Rast } } -bool RasterizerStorageRD::ParticlesShaderData::is_param_texture(const StringName &p_param) const { +bool RendererStorageRD::ParticlesShaderData::is_param_texture(const StringName &p_param) const { if (!uniforms.has(p_param)) { return false; } @@ -4474,15 +4846,15 @@ bool RasterizerStorageRD::ParticlesShaderData::is_param_texture(const StringName return uniforms[p_param].texture_order >= 0; } -bool RasterizerStorageRD::ParticlesShaderData::is_animated() const { +bool RendererStorageRD::ParticlesShaderData::is_animated() const { return false; } -bool RasterizerStorageRD::ParticlesShaderData::casts_shadows() const { +bool RendererStorageRD::ParticlesShaderData::casts_shadows() const { return false; } -Variant RasterizerStorageRD::ParticlesShaderData::get_default_parameter(const StringName &p_parameter) const { +Variant RendererStorageRD::ParticlesShaderData::get_default_parameter(const StringName &p_parameter) const { if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; @@ -4491,23 +4863,27 @@ Variant RasterizerStorageRD::ParticlesShaderData::get_default_parameter(const St return Variant(); } -RasterizerStorageRD::ParticlesShaderData::ParticlesShaderData() { +RS::ShaderNativeSourceCode RendererStorageRD::ParticlesShaderData::get_native_source_code() const { + return base_singleton->particles_shader.shader.version_get_native_source_code(version); +} + +RendererStorageRD::ParticlesShaderData::ParticlesShaderData() { valid = false; } -RasterizerStorageRD::ParticlesShaderData::~ParticlesShaderData() { +RendererStorageRD::ParticlesShaderData::~ParticlesShaderData() { //pipeline variants will clear themselves if shader is gone if (version.is_valid()) { base_singleton->particles_shader.shader.version_free(version); } } -RasterizerStorageRD::ShaderData *RasterizerStorageRD::_create_particles_shader_func() { +RendererStorageRD::ShaderData *RendererStorageRD::_create_particles_shader_func() { ParticlesShaderData *shader_data = memnew(ParticlesShaderData); return shader_data; } -void RasterizerStorageRD::ParticlesMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { +void RendererStorageRD::ParticlesMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { uniform_set_updated = true; if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { @@ -4568,7 +4944,7 @@ void RasterizerStorageRD::ParticlesMaterialData::update_parameters(const Map<Str { if (shader_data->ubo_size) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 0; u.ids.push_back(uniform_buffer); uniforms.push_back(u); @@ -4577,7 +4953,7 @@ void RasterizerStorageRD::ParticlesMaterialData::update_parameters(const Map<Str const RID *textures = texture_cache.ptrw(); for (uint32_t i = 0; i < tex_uniform_count; i++) { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1 + i; u.ids.push_back(textures[i]); uniforms.push_back(u); @@ -4587,7 +4963,7 @@ void RasterizerStorageRD::ParticlesMaterialData::update_parameters(const Map<Str uniform_set = RD::get_singleton()->uniform_set_create(uniforms, base_singleton->particles_shader.shader.version_get_shader(shader_data->version, 0), 3); } -RasterizerStorageRD::ParticlesMaterialData::~ParticlesMaterialData() { +RendererStorageRD::ParticlesMaterialData::~ParticlesMaterialData() { if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { RD::get_singleton()->free(uniform_set); } @@ -4597,7 +4973,7 @@ RasterizerStorageRD::ParticlesMaterialData::~ParticlesMaterialData() { } } -RasterizerStorageRD::MaterialData *RasterizerStorageRD::_create_particles_material_func(ParticlesShaderData *p_shader) { +RendererStorageRD::MaterialData *RendererStorageRD::_create_particles_material_func(ParticlesShaderData *p_shader) { ParticlesMaterialData *material_data = memnew(ParticlesMaterialData); material_data->shader_data = p_shader; material_data->last_frame = false; @@ -4608,11 +4984,11 @@ RasterizerStorageRD::MaterialData *RasterizerStorageRD::_create_particles_materi /* PARTICLES COLLISION API */ -RID RasterizerStorageRD::particles_collision_create() { +RID RendererStorageRD::particles_collision_create() { return particles_collision_owner.make_rid(ParticlesCollision()); } -RID RasterizerStorageRD::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const { +RID RendererStorageRD::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND_V(!particles_collision, RID()); ERR_FAIL_COND_V(particles_collision->type != RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE, RID()); @@ -4633,7 +5009,7 @@ RID RasterizerStorageRD::particles_collision_get_heightfield_framebuffer(RID p_p tf.format = RD::DATA_FORMAT_D32_SFLOAT; tf.width = size.x; tf.height = size.y; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; particles_collision->heightfield_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); @@ -4647,7 +5023,7 @@ RID RasterizerStorageRD::particles_collision_get_heightfield_framebuffer(RID p_p return particles_collision->heightfield_fb; } -void RasterizerStorageRD::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) { +void RendererStorageRD::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); @@ -4660,66 +5036,66 @@ void RasterizerStorageRD::particles_collision_set_collision_type(RID p_particles particles_collision->heightfield_texture = RID(); } particles_collision->type = p_type; - particles_collision->instance_dependency.instance_notify_changed(true, false); + particles_collision->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -void RasterizerStorageRD::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) { +void RendererStorageRD::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->cull_mask = p_cull_mask; } -void RasterizerStorageRD::particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius) { +void RendererStorageRD::particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->radius = p_radius; - particles_collision->instance_dependency.instance_notify_changed(true, false); + particles_collision->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -void RasterizerStorageRD::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) { +void RendererStorageRD::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->extents = p_extents; - particles_collision->instance_dependency.instance_notify_changed(true, false); + particles_collision->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -void RasterizerStorageRD::particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength) { +void RendererStorageRD::particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->attractor_strength = p_strength; } -void RasterizerStorageRD::particles_collision_set_attractor_directionality(RID p_particles_collision, float p_directionality) { +void RendererStorageRD::particles_collision_set_attractor_directionality(RID p_particles_collision, float p_directionality) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->attractor_directionality = p_directionality; } -void RasterizerStorageRD::particles_collision_set_attractor_attenuation(RID p_particles_collision, float p_curve) { +void RendererStorageRD::particles_collision_set_attractor_attenuation(RID p_particles_collision, float p_curve) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->attractor_attenuation = p_curve; } -void RasterizerStorageRD::particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) { +void RendererStorageRD::particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->field_texture = p_texture; } -void RasterizerStorageRD::particles_collision_height_field_update(RID p_particles_collision) { +void RendererStorageRD::particles_collision_height_field_update(RID p_particles_collision) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); - particles_collision->instance_dependency.instance_notify_changed(true, false); + particles_collision->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -void RasterizerStorageRD::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) { +void RendererStorageRD::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); @@ -4735,7 +5111,7 @@ void RasterizerStorageRD::particles_collision_set_height_field_resolution(RID p_ } } -AABB RasterizerStorageRD::particles_collision_get_aabb(RID p_particles_collision) const { +AABB RendererStorageRD::particles_collision_get_aabb(RID p_particles_collision) const { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND_V(!particles_collision, AABB()); @@ -4758,25 +5134,41 @@ AABB RasterizerStorageRD::particles_collision_get_aabb(RID p_particles_collision return AABB(); } -Vector3 RasterizerStorageRD::particles_collision_get_extents(RID p_particles_collision) const { +Vector3 RendererStorageRD::particles_collision_get_extents(RID p_particles_collision) const { const ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND_V(!particles_collision, Vector3()); return particles_collision->extents; } -bool RasterizerStorageRD::particles_collision_is_heightfield(RID p_particles_collision) const { +bool RendererStorageRD::particles_collision_is_heightfield(RID p_particles_collision) const { const ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND_V(!particles_collision, false); return particles_collision->type == RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE; } +RID RendererStorageRD::particles_collision_instance_create(RID p_collision) { + ParticlesCollisionInstance pci; + pci.collision = p_collision; + return particles_collision_instance_owner.make_rid(pci); +} +void RendererStorageRD::particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform) { + ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(p_collision_instance); + ERR_FAIL_COND(!pci); + pci->transform = p_transform; +} +void RendererStorageRD::particles_collision_instance_set_active(RID p_collision_instance, bool p_active) { + ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(p_collision_instance); + ERR_FAIL_COND(!pci); + pci->active = p_active; +} + /* SKELETON API */ -RID RasterizerStorageRD::skeleton_create() { +RID RendererStorageRD::skeleton_create() { return skeleton_owner.make_rid(Skeleton()); } -void RasterizerStorageRD::_skeleton_make_dirty(Skeleton *skeleton) { +void RendererStorageRD::_skeleton_make_dirty(Skeleton *skeleton) { if (!skeleton->dirty) { skeleton->dirty = true; skeleton->dirty_list = skeleton_dirty_list; @@ -4784,7 +5176,7 @@ void RasterizerStorageRD::_skeleton_make_dirty(Skeleton *skeleton) { } } -void RasterizerStorageRD::skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton) { +void RendererStorageRD::skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton) { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND(!skeleton); ERR_FAIL_COND(p_bones < 0); @@ -4801,6 +5193,7 @@ void RasterizerStorageRD::skeleton_allocate(RID p_skeleton, int p_bones, bool p_ RD::get_singleton()->free(skeleton->buffer); skeleton->buffer = RID(); skeleton->data.resize(0); + skeleton->uniform_set_mi = RID(); } if (skeleton->size) { @@ -4809,17 +5202,31 @@ void RasterizerStorageRD::skeleton_allocate(RID p_skeleton, int p_bones, bool p_ zeromem(skeleton->data.ptrw(), skeleton->data.size() * sizeof(float)); _skeleton_make_dirty(skeleton); + + { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.binding = 0; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(skeleton->buffer); + uniforms.push_back(u); + } + skeleton->uniform_set_mi = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_SKELETON); + } } + + skeleton->dependency.changed_notify(DEPENDENCY_CHANGED_SKELETON_DATA); } -int RasterizerStorageRD::skeleton_get_bone_count(RID p_skeleton) const { +int RendererStorageRD::skeleton_get_bone_count(RID p_skeleton) const { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND_V(!skeleton, 0); return skeleton->size; } -void RasterizerStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) { +void RendererStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND(!skeleton); @@ -4844,7 +5251,7 @@ void RasterizerStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone _skeleton_make_dirty(skeleton); } -Transform RasterizerStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { +Transform RendererStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND_V(!skeleton, Transform()); @@ -4871,7 +5278,7 @@ Transform RasterizerStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p return t; } -void RasterizerStorageRD::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) { +void RendererStorageRD::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND(!skeleton); @@ -4892,7 +5299,7 @@ void RasterizerStorageRD::skeleton_bone_set_transform_2d(RID p_skeleton, int p_b _skeleton_make_dirty(skeleton); } -Transform2D RasterizerStorageRD::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const { +Transform2D RendererStorageRD::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND_V(!skeleton, Transform2D()); @@ -4912,7 +5319,7 @@ Transform2D RasterizerStorageRD::skeleton_bone_get_transform_2d(RID p_skeleton, return t; } -void RasterizerStorageRD::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) { +void RendererStorageRD::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND(!skeleton->use_2d); @@ -4920,17 +5327,19 @@ void RasterizerStorageRD::skeleton_set_base_transform_2d(RID p_skeleton, const T skeleton->base_transform_2d = p_base_transform; } -void RasterizerStorageRD::_update_dirty_skeletons() { +void RendererStorageRD::_update_dirty_skeletons() { while (skeleton_dirty_list) { Skeleton *skeleton = skeleton_dirty_list; if (skeleton->size) { - RD::get_singleton()->buffer_update(skeleton->buffer, 0, skeleton->data.size() * sizeof(float), skeleton->data.ptr(), false); + RD::get_singleton()->buffer_update(skeleton->buffer, 0, skeleton->data.size() * sizeof(float), skeleton->data.ptr()); } skeleton_dirty_list = skeleton->dirty_list; - skeleton->instance_dependency.instance_notify_changed(true, false); + skeleton->dependency.changed_notify(DEPENDENCY_CHANGED_SKELETON_BONES); + + skeleton->version++; skeleton->dirty = false; skeleton->dirty_list = nullptr; @@ -4941,7 +5350,7 @@ void RasterizerStorageRD::_update_dirty_skeletons() { /* LIGHT */ -RID RasterizerStorageRD::light_create(RS::LightType p_type) { +RID RendererStorageRD::light_create(RS::LightType p_type) { Light light; light.type = p_type; @@ -4950,29 +5359,32 @@ RID RasterizerStorageRD::light_create(RS::LightType p_type) { light.param[RS::LIGHT_PARAM_SPECULAR] = 0.5; light.param[RS::LIGHT_PARAM_RANGE] = 1.0; light.param[RS::LIGHT_PARAM_SIZE] = 0.0; + light.param[RS::LIGHT_PARAM_ATTENUATION] = 1.0; light.param[RS::LIGHT_PARAM_SPOT_ANGLE] = 45; + light.param[RS::LIGHT_PARAM_SPOT_ATTENUATION] = 1.0; light.param[RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE] = 0; light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET] = 0.1; light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET] = 0.3; light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6; light.param[RS::LIGHT_PARAM_SHADOW_FADE_START] = 0.8; - light.param[RS::LIGHT_PARAM_SHADOW_BIAS] = 0.02; light.param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 1.0; + light.param[RS::LIGHT_PARAM_SHADOW_BIAS] = 0.02; + light.param[RS::LIGHT_PARAM_SHADOW_BLUR] = 0; light.param[RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE] = 20.0; - light.param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] = 0.05; light.param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE] = 1.0; + light.param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] = 0.05; return light_owner.make_rid(light); } -void RasterizerStorageRD::light_set_color(RID p_light, const Color &p_color) { +void RendererStorageRD::light_set_color(RID p_light, const Color &p_color) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->color = p_color; } -void RasterizerStorageRD::light_set_param(RID p_light, RS::LightParam p_param, float p_value) { +void RendererStorageRD::light_set_param(RID p_light, RS::LightParam p_param, float p_value) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); ERR_FAIL_INDEX(p_param, RS::LIGHT_PARAM_MAX); @@ -4988,7 +5400,7 @@ void RasterizerStorageRD::light_set_param(RID p_light, RS::LightParam p_param, f case RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE: case RS::LIGHT_PARAM_SHADOW_BIAS: { light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } break; default: { } @@ -4997,22 +5409,22 @@ void RasterizerStorageRD::light_set_param(RID p_light, RS::LightParam p_param, f light->param[p_param] = p_value; } -void RasterizerStorageRD::light_set_shadow(RID p_light, bool p_enabled) { +void RendererStorageRD::light_set_shadow(RID p_light, bool p_enabled) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->shadow = p_enabled; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } -void RasterizerStorageRD::light_set_shadow_color(RID p_light, const Color &p_color) { +void RendererStorageRD::light_set_shadow_color(RID p_light, const Color &p_color) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->shadow_color = p_color; } -void RasterizerStorageRD::light_set_projector(RID p_light, RID p_texture) { +void RendererStorageRD::light_set_projector(RID p_light, RID p_texture) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); @@ -5031,138 +5443,152 @@ void RasterizerStorageRD::light_set_projector(RID p_light, RID p_texture) { } } -void RasterizerStorageRD::light_set_negative(RID p_light, bool p_enable) { +void RendererStorageRD::light_set_negative(RID p_light, bool p_enable) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->negative = p_enable; } -void RasterizerStorageRD::light_set_cull_mask(RID p_light, uint32_t p_mask) { +void RendererStorageRD::light_set_cull_mask(RID p_light, uint32_t p_mask) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->cull_mask = p_mask; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } -void RasterizerStorageRD::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) { +void RendererStorageRD::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->reverse_cull = p_enabled; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } -void RasterizerStorageRD::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) { +void RendererStorageRD::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->bake_mode = p_bake_mode; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } -void RasterizerStorageRD::light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) { +void RendererStorageRD::light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->max_sdfgi_cascade = p_cascade; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } -void RasterizerStorageRD::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) { +void RendererStorageRD::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->omni_shadow_mode = p_mode; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } -RS::LightOmniShadowMode RasterizerStorageRD::light_omni_get_shadow_mode(RID p_light) { +RS::LightOmniShadowMode RendererStorageRD::light_omni_get_shadow_mode(RID p_light) { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_OMNI_SHADOW_CUBE); return light->omni_shadow_mode; } -void RasterizerStorageRD::light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) { +void RendererStorageRD::light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->directional_shadow_mode = p_mode; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } -void RasterizerStorageRD::light_directional_set_blend_splits(RID p_light, bool p_enable) { +void RendererStorageRD::light_directional_set_blend_splits(RID p_light, bool p_enable) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->directional_blend_splits = p_enable; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } -bool RasterizerStorageRD::light_directional_get_blend_splits(RID p_light) const { +bool RendererStorageRD::light_directional_get_blend_splits(RID p_light) const { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, false); return light->directional_blend_splits; } -RS::LightDirectionalShadowMode RasterizerStorageRD::light_directional_get_shadow_mode(RID p_light) { +void RendererStorageRD::light_directional_set_sky_only(RID p_light, bool p_sky_only) { + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->directional_sky_only = p_sky_only; +} + +bool RendererStorageRD::light_directional_is_sky_only(RID p_light) const { + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, false); + + return light->directional_sky_only; +} + +RS::LightDirectionalShadowMode RendererStorageRD::light_directional_get_shadow_mode(RID p_light) { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL); return light->directional_shadow_mode; } -void RasterizerStorageRD::light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) { +void RendererStorageRD::light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); light->directional_range_mode = p_range_mode; } -RS::LightDirectionalShadowDepthRangeMode RasterizerStorageRD::light_directional_get_shadow_depth_range_mode(RID p_light) const { +RS::LightDirectionalShadowDepthRangeMode RendererStorageRD::light_directional_get_shadow_depth_range_mode(RID p_light) const { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE); return light->directional_range_mode; } -uint32_t RasterizerStorageRD::light_get_max_sdfgi_cascade(RID p_light) { +uint32_t RendererStorageRD::light_get_max_sdfgi_cascade(RID p_light) { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, 0); return light->max_sdfgi_cascade; } -RS::LightBakeMode RasterizerStorageRD::light_get_bake_mode(RID p_light) { +RS::LightBakeMode RendererStorageRD::light_get_bake_mode(RID p_light) { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_BAKE_DISABLED); return light->bake_mode; } -uint64_t RasterizerStorageRD::light_get_version(RID p_light) const { +uint64_t RendererStorageRD::light_get_version(RID p_light) const { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, 0); return light->version; } -AABB RasterizerStorageRD::light_get_aabb(RID p_light) const { +AABB RendererStorageRD::light_get_aabb(RID p_light) const { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, AABB()); @@ -5186,56 +5612,56 @@ AABB RasterizerStorageRD::light_get_aabb(RID p_light) const { /* REFLECTION PROBE */ -RID RasterizerStorageRD::reflection_probe_create() { +RID RendererStorageRD::reflection_probe_create() { return reflection_probe_owner.make_rid(ReflectionProbe()); } -void RasterizerStorageRD::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) { +void RendererStorageRD::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->update_mode = p_mode; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } -void RasterizerStorageRD::reflection_probe_set_intensity(RID p_probe, float p_intensity) { +void RendererStorageRD::reflection_probe_set_intensity(RID p_probe, float p_intensity) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->intensity = p_intensity; } -void RasterizerStorageRD::reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) { +void RendererStorageRD::reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->ambient_mode = p_mode; } -void RasterizerStorageRD::reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) { +void RendererStorageRD::reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->ambient_color = p_color; } -void RasterizerStorageRD::reflection_probe_set_ambient_energy(RID p_probe, float p_energy) { +void RendererStorageRD::reflection_probe_set_ambient_energy(RID p_probe, float p_energy) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->ambient_color_energy = p_energy; } -void RasterizerStorageRD::reflection_probe_set_max_distance(RID p_probe, float p_distance) { +void RendererStorageRD::reflection_probe_set_max_distance(RID p_probe, float p_distance) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->max_distance = p_distance; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } -void RasterizerStorageRD::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { +void RendererStorageRD::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); @@ -5243,49 +5669,49 @@ void RasterizerStorageRD::reflection_probe_set_extents(RID p_probe, const Vector return; } reflection_probe->extents = p_extents; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } -void RasterizerStorageRD::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) { +void RendererStorageRD::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->origin_offset = p_offset; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } -void RasterizerStorageRD::reflection_probe_set_as_interior(RID p_probe, bool p_enable) { +void RendererStorageRD::reflection_probe_set_as_interior(RID p_probe, bool p_enable) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->interior = p_enable; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } -void RasterizerStorageRD::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) { +void RendererStorageRD::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->box_projection = p_enable; } -void RasterizerStorageRD::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) { +void RendererStorageRD::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->enable_shadows = p_enable; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } -void RasterizerStorageRD::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) { +void RendererStorageRD::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->cull_mask = p_layers; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } -void RasterizerStorageRD::reflection_probe_set_resolution(RID p_probe, int p_resolution) { +void RendererStorageRD::reflection_probe_set_resolution(RID p_probe, int p_resolution) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND(!reflection_probe); ERR_FAIL_COND(p_resolution < 32); @@ -5293,7 +5719,16 @@ void RasterizerStorageRD::reflection_probe_set_resolution(RID p_probe, int p_res reflection_probe->resolution = p_resolution; } -AABB RasterizerStorageRD::reflection_probe_get_aabb(RID p_probe) const { +void RendererStorageRD::reflection_probe_set_lod_threshold(RID p_probe, float p_ratio) { + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->lod_threshold = p_ratio; + + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); +} + +AABB RendererStorageRD::reflection_probe_get_aabb(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, AABB()); @@ -5304,107 +5739,114 @@ AABB RasterizerStorageRD::reflection_probe_get_aabb(RID p_probe) const { return aabb; } -RS::ReflectionProbeUpdateMode RasterizerStorageRD::reflection_probe_get_update_mode(RID p_probe) const { +RS::ReflectionProbeUpdateMode RendererStorageRD::reflection_probe_get_update_mode(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, RS::REFLECTION_PROBE_UPDATE_ALWAYS); return reflection_probe->update_mode; } -uint32_t RasterizerStorageRD::reflection_probe_get_cull_mask(RID p_probe) const { +uint32_t RendererStorageRD::reflection_probe_get_cull_mask(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, 0); return reflection_probe->cull_mask; } -Vector3 RasterizerStorageRD::reflection_probe_get_extents(RID p_probe) const { +Vector3 RendererStorageRD::reflection_probe_get_extents(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, Vector3()); return reflection_probe->extents; } -Vector3 RasterizerStorageRD::reflection_probe_get_origin_offset(RID p_probe) const { +Vector3 RendererStorageRD::reflection_probe_get_origin_offset(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, Vector3()); return reflection_probe->origin_offset; } -bool RasterizerStorageRD::reflection_probe_renders_shadows(RID p_probe) const { +bool RendererStorageRD::reflection_probe_renders_shadows(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, false); return reflection_probe->enable_shadows; } -float RasterizerStorageRD::reflection_probe_get_origin_max_distance(RID p_probe) const { +float RendererStorageRD::reflection_probe_get_origin_max_distance(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, 0); return reflection_probe->max_distance; } -int RasterizerStorageRD::reflection_probe_get_resolution(RID p_probe) const { +float RendererStorageRD::reflection_probe_get_lod_threshold(RID p_probe) const { + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, 0); + + return reflection_probe->lod_threshold; +} + +int RendererStorageRD::reflection_probe_get_resolution(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, 0); return reflection_probe->resolution; } -float RasterizerStorageRD::reflection_probe_get_intensity(RID p_probe) const { +float RendererStorageRD::reflection_probe_get_intensity(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, 0); return reflection_probe->intensity; } -bool RasterizerStorageRD::reflection_probe_is_interior(RID p_probe) const { +bool RendererStorageRD::reflection_probe_is_interior(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, false); return reflection_probe->interior; } -bool RasterizerStorageRD::reflection_probe_is_box_projection(RID p_probe) const { +bool RendererStorageRD::reflection_probe_is_box_projection(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, false); return reflection_probe->box_projection; } -RS::ReflectionProbeAmbientMode RasterizerStorageRD::reflection_probe_get_ambient_mode(RID p_probe) const { +RS::ReflectionProbeAmbientMode RendererStorageRD::reflection_probe_get_ambient_mode(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, RS::REFLECTION_PROBE_AMBIENT_DISABLED); return reflection_probe->ambient_mode; } -Color RasterizerStorageRD::reflection_probe_get_ambient_color(RID p_probe) const { +Color RendererStorageRD::reflection_probe_get_ambient_color(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, Color()); return reflection_probe->ambient_color; } -float RasterizerStorageRD::reflection_probe_get_ambient_color_energy(RID p_probe) const { +float RendererStorageRD::reflection_probe_get_ambient_color_energy(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, 0); return reflection_probe->ambient_color_energy; } -RID RasterizerStorageRD::decal_create() { +RID RendererStorageRD::decal_create() { return decal_owner.make_rid(Decal()); } -void RasterizerStorageRD::decal_set_extents(RID p_decal, const Vector3 &p_extents) { +void RendererStorageRD::decal_set_extents(RID p_decal, const Vector3 &p_extents) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->extents = p_extents; - decal->instance_dependency.instance_notify_changed(true, false); + decal->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -void RasterizerStorageRD::decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) { +void RendererStorageRD::decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); ERR_FAIL_INDEX(p_type, RS::DECAL_TEXTURE_MAX); @@ -5425,35 +5867,35 @@ void RasterizerStorageRD::decal_set_texture(RID p_decal, RS::DecalTexture p_type texture_add_to_decal_atlas(decal->textures[p_type]); } - decal->instance_dependency.instance_notify_changed(false, true); + decal->dependency.changed_notify(DEPENDENCY_CHANGED_DECAL); } -void RasterizerStorageRD::decal_set_emission_energy(RID p_decal, float p_energy) { +void RendererStorageRD::decal_set_emission_energy(RID p_decal, float p_energy) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->emission_energy = p_energy; } -void RasterizerStorageRD::decal_set_albedo_mix(RID p_decal, float p_mix) { +void RendererStorageRD::decal_set_albedo_mix(RID p_decal, float p_mix) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->albedo_mix = p_mix; } -void RasterizerStorageRD::decal_set_modulate(RID p_decal, const Color &p_modulate) { +void RendererStorageRD::decal_set_modulate(RID p_decal, const Color &p_modulate) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->modulate = p_modulate; } -void RasterizerStorageRD::decal_set_cull_mask(RID p_decal, uint32_t p_layers) { +void RendererStorageRD::decal_set_cull_mask(RID p_decal, uint32_t p_layers) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->cull_mask = p_layers; - decal->instance_dependency.instance_notify_changed(true, false); + decal->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -void RasterizerStorageRD::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) { +void RendererStorageRD::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->distance_fade = p_enabled; @@ -5461,31 +5903,31 @@ void RasterizerStorageRD::decal_set_distance_fade(RID p_decal, bool p_enabled, f decal->distance_fade_length = p_length; } -void RasterizerStorageRD::decal_set_fade(RID p_decal, float p_above, float p_below) { +void RendererStorageRD::decal_set_fade(RID p_decal, float p_above, float p_below) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->upper_fade = p_above; decal->lower_fade = p_below; } -void RasterizerStorageRD::decal_set_normal_fade(RID p_decal, float p_fade) { +void RendererStorageRD::decal_set_normal_fade(RID p_decal, float p_fade) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->normal_fade = p_fade; } -AABB RasterizerStorageRD::decal_get_aabb(RID p_decal) const { +AABB RendererStorageRD::decal_get_aabb(RID p_decal) const { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND_V(!decal, AABB()); return AABB(-decal->extents, decal->extents * 2.0); } -RID RasterizerStorageRD::gi_probe_create() { +RID RendererStorageRD::gi_probe_create() { return gi_probe_owner.make_rid(GIProbe()); } -void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) { +void RendererStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); @@ -5528,7 +5970,7 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t tf.width = gi_probe->octree_size.x; tf.height = gi_probe->octree_size.y; tf.depth = gi_probe->octree_size.z; - tf.type = RD::TEXTURE_TYPE_3D; + tf.texture_type = RD::TEXTURE_TYPE_3D; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; Vector<Vector<uint8_t>> s; s.push_back(p_distance_field); @@ -5549,7 +5991,6 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t } RID shared_tex; { - RD::TextureView tv; tv.format_override = RD::DATA_FORMAT_R8_UINT; shared_tex = RD::get_singleton()->texture_create_shared(tv, gi_probe->sdf_texture); @@ -5558,21 +5999,21 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; u.ids.push_back(gi_probe->octree_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; u.ids.push_back(gi_probe->data_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_IMAGE; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; u.binding = 3; u.ids.push_back(shared_tex); uniforms.push_back(u); @@ -5608,23 +6049,23 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t gi_probe->version++; gi_probe->data_version++; - gi_probe->instance_dependency.instance_notify_changed(true, false); + gi_probe->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -AABB RasterizerStorageRD::gi_probe_get_bounds(RID p_gi_probe) const { +AABB RendererStorageRD::gi_probe_get_bounds(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, AABB()); return gi_probe->bounds; } -Vector3i RasterizerStorageRD::gi_probe_get_octree_size(RID p_gi_probe) const { +Vector3i RendererStorageRD::gi_probe_get_octree_size(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, Vector3i()); return gi_probe->octree_size; } -Vector<uint8_t> RasterizerStorageRD::gi_probe_get_octree_cells(RID p_gi_probe) const { +Vector<uint8_t> RendererStorageRD::gi_probe_get_octree_cells(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>()); @@ -5634,7 +6075,7 @@ Vector<uint8_t> RasterizerStorageRD::gi_probe_get_octree_cells(RID p_gi_probe) c return Vector<uint8_t>(); } -Vector<uint8_t> RasterizerStorageRD::gi_probe_get_data_cells(RID p_gi_probe) const { +Vector<uint8_t> RendererStorageRD::gi_probe_get_data_cells(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>()); @@ -5644,7 +6085,7 @@ Vector<uint8_t> RasterizerStorageRD::gi_probe_get_data_cells(RID p_gi_probe) con return Vector<uint8_t>(); } -Vector<uint8_t> RasterizerStorageRD::gi_probe_get_distance_field(RID p_gi_probe) const { +Vector<uint8_t> RendererStorageRD::gi_probe_get_distance_field(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>()); @@ -5654,21 +6095,21 @@ Vector<uint8_t> RasterizerStorageRD::gi_probe_get_distance_field(RID p_gi_probe) return Vector<uint8_t>(); } -Vector<int> RasterizerStorageRD::gi_probe_get_level_counts(RID p_gi_probe) const { +Vector<int> RendererStorageRD::gi_probe_get_level_counts(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, Vector<int>()); return gi_probe->level_counts; } -Transform RasterizerStorageRD::gi_probe_get_to_cell_xform(RID p_gi_probe) const { +Transform RendererStorageRD::gi_probe_get_to_cell_xform(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, Transform()); return gi_probe->to_cell_xform; } -void RasterizerStorageRD::gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) { +void RendererStorageRD::gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); @@ -5676,14 +6117,14 @@ void RasterizerStorageRD::gi_probe_set_dynamic_range(RID p_gi_probe, float p_ran gi_probe->version++; } -float RasterizerStorageRD::gi_probe_get_dynamic_range(RID p_gi_probe) const { +float RendererStorageRD::gi_probe_get_dynamic_range(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->dynamic_range; } -void RasterizerStorageRD::gi_probe_set_propagation(RID p_gi_probe, float p_range) { +void RendererStorageRD::gi_probe_set_propagation(RID p_gi_probe, float p_range) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); @@ -5691,98 +6132,98 @@ void RasterizerStorageRD::gi_probe_set_propagation(RID p_gi_probe, float p_range gi_probe->version++; } -float RasterizerStorageRD::gi_probe_get_propagation(RID p_gi_probe) const { +float RendererStorageRD::gi_probe_get_propagation(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->propagation; } -void RasterizerStorageRD::gi_probe_set_energy(RID p_gi_probe, float p_energy) { +void RendererStorageRD::gi_probe_set_energy(RID p_gi_probe, float p_energy) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); gi_probe->energy = p_energy; } -float RasterizerStorageRD::gi_probe_get_energy(RID p_gi_probe) const { +float RendererStorageRD::gi_probe_get_energy(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->energy; } -void RasterizerStorageRD::gi_probe_set_ao(RID p_gi_probe, float p_ao) { +void RendererStorageRD::gi_probe_set_ao(RID p_gi_probe, float p_ao) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); gi_probe->ao = p_ao; } -float RasterizerStorageRD::gi_probe_get_ao(RID p_gi_probe) const { +float RendererStorageRD::gi_probe_get_ao(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->ao; } -void RasterizerStorageRD::gi_probe_set_ao_size(RID p_gi_probe, float p_strength) { +void RendererStorageRD::gi_probe_set_ao_size(RID p_gi_probe, float p_strength) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); gi_probe->ao_size = p_strength; } -float RasterizerStorageRD::gi_probe_get_ao_size(RID p_gi_probe) const { +float RendererStorageRD::gi_probe_get_ao_size(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->ao_size; } -void RasterizerStorageRD::gi_probe_set_bias(RID p_gi_probe, float p_bias) { +void RendererStorageRD::gi_probe_set_bias(RID p_gi_probe, float p_bias) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); gi_probe->bias = p_bias; } -float RasterizerStorageRD::gi_probe_get_bias(RID p_gi_probe) const { +float RendererStorageRD::gi_probe_get_bias(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->bias; } -void RasterizerStorageRD::gi_probe_set_normal_bias(RID p_gi_probe, float p_normal_bias) { +void RendererStorageRD::gi_probe_set_normal_bias(RID p_gi_probe, float p_normal_bias) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); gi_probe->normal_bias = p_normal_bias; } -float RasterizerStorageRD::gi_probe_get_normal_bias(RID p_gi_probe) const { +float RendererStorageRD::gi_probe_get_normal_bias(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->normal_bias; } -void RasterizerStorageRD::gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) { +void RendererStorageRD::gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); gi_probe->anisotropy_strength = p_strength; } -float RasterizerStorageRD::gi_probe_get_anisotropy_strength(RID p_gi_probe) const { +float RendererStorageRD::gi_probe_get_anisotropy_strength(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->anisotropy_strength; } -void RasterizerStorageRD::gi_probe_set_interior(RID p_gi_probe, bool p_enable) { +void RendererStorageRD::gi_probe_set_interior(RID p_gi_probe, bool p_enable) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); gi_probe->interior = p_enable; } -void RasterizerStorageRD::gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) { +void RendererStorageRD::gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); @@ -5790,43 +6231,43 @@ void RasterizerStorageRD::gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_en gi_probe->version++; } -bool RasterizerStorageRD::gi_probe_is_using_two_bounces(RID p_gi_probe) const { +bool RendererStorageRD::gi_probe_is_using_two_bounces(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, false); return gi_probe->use_two_bounces; } -bool RasterizerStorageRD::gi_probe_is_interior(RID p_gi_probe) const { +bool RendererStorageRD::gi_probe_is_interior(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->interior; } -uint32_t RasterizerStorageRD::gi_probe_get_version(RID p_gi_probe) { +uint32_t RendererStorageRD::gi_probe_get_version(RID p_gi_probe) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->version; } -uint32_t RasterizerStorageRD::gi_probe_get_data_version(RID p_gi_probe) { +uint32_t RendererStorageRD::gi_probe_get_data_version(RID p_gi_probe) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, 0); return gi_probe->data_version; } -RID RasterizerStorageRD::gi_probe_get_octree_buffer(RID p_gi_probe) const { +RID RendererStorageRD::gi_probe_get_octree_buffer(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, RID()); return gi_probe->octree_buffer; } -RID RasterizerStorageRD::gi_probe_get_data_buffer(RID p_gi_probe) const { +RID RendererStorageRD::gi_probe_get_data_buffer(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, RID()); return gi_probe->data_buffer; } -RID RasterizerStorageRD::gi_probe_get_sdf_texture(RID p_gi_probe) { +RID RendererStorageRD::gi_probe_get_sdf_texture(RID p_gi_probe) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, RID()); @@ -5835,11 +6276,11 @@ RID RasterizerStorageRD::gi_probe_get_sdf_texture(RID p_gi_probe) { /* LIGHTMAP API */ -RID RasterizerStorageRD::lightmap_create() { +RID RendererStorageRD::lightmap_create() { return lightmap_owner.make_rid(Lightmap()); } -void RasterizerStorageRD::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) { +void RendererStorageRD::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND(!lm); @@ -5887,19 +6328,19 @@ void RasterizerStorageRD::lightmap_set_textures(RID p_lightmap, RID p_light, boo } } -void RasterizerStorageRD::lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) { +void RendererStorageRD::lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND(!lm); lm->bounds = p_bounds; } -void RasterizerStorageRD::lightmap_set_probe_interior(RID p_lightmap, bool p_interior) { +void RendererStorageRD::lightmap_set_probe_interior(RID p_lightmap, bool p_interior) { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND(!lm); lm->interior = p_interior; } -void RasterizerStorageRD::lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) { +void RendererStorageRD::lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND(!lm); @@ -5915,36 +6356,36 @@ void RasterizerStorageRD::lightmap_set_probe_capture_data(RID p_lightmap, const lm->tetrahedra = p_tetrahedra; } -PackedVector3Array RasterizerStorageRD::lightmap_get_probe_capture_points(RID p_lightmap) const { +PackedVector3Array RendererStorageRD::lightmap_get_probe_capture_points(RID p_lightmap) const { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND_V(!lm, PackedVector3Array()); return lm->points; } -PackedColorArray RasterizerStorageRD::lightmap_get_probe_capture_sh(RID p_lightmap) const { +PackedColorArray RendererStorageRD::lightmap_get_probe_capture_sh(RID p_lightmap) const { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND_V(!lm, PackedColorArray()); return lm->point_sh; } -PackedInt32Array RasterizerStorageRD::lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const { +PackedInt32Array RendererStorageRD::lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND_V(!lm, PackedInt32Array()); return lm->tetrahedra; } -PackedInt32Array RasterizerStorageRD::lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const { +PackedInt32Array RendererStorageRD::lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND_V(!lm, PackedInt32Array()); return lm->bsp_tree; } -void RasterizerStorageRD::lightmap_set_probe_capture_update_speed(float p_speed) { +void RendererStorageRD::lightmap_set_probe_capture_update_speed(float p_speed) { lightmap_probe_capture_update_speed = p_speed; } -void RasterizerStorageRD::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) { +void RendererStorageRD::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) { Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND(!lm); @@ -5994,13 +6435,13 @@ void RasterizerStorageRD::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p } } -bool RasterizerStorageRD::lightmap_is_interior(RID p_lightmap) const { +bool RendererStorageRD::lightmap_is_interior(RID p_lightmap) const { const Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND_V(!lm, false); return lm->interior; } -AABB RasterizerStorageRD::lightmap_get_aabb(RID p_lightmap) const { +AABB RendererStorageRD::lightmap_get_aabb(RID p_lightmap) const { const Lightmap *lm = lightmap_owner.getornull(p_lightmap); ERR_FAIL_COND_V(!lm, AABB()); return lm->bounds; @@ -6008,7 +6449,7 @@ AABB RasterizerStorageRD::lightmap_get_aabb(RID p_lightmap) const { /* RENDER TARGET API */ -void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { +void RendererStorageRD::_clear_render_target(RenderTarget *rt) { //free in reverse dependency order if (rt->framebuffer.is_valid()) { RD::get_singleton()->free(rt->framebuffer); @@ -6030,11 +6471,13 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { rt->backbuffer_uniform_set = RID(); //chain deleted } + _render_target_clear_sdf(rt); + rt->framebuffer = RID(); rt->color = RID(); } -void RasterizerStorageRD::_update_render_target(RenderTarget *rt) { +void RendererStorageRD::_update_render_target(RenderTarget *rt) { if (rt->texture.is_null()) { //create a placeholder until updated rt->texture = texture_2d_placeholder_create(); @@ -6061,7 +6504,7 @@ void RasterizerStorageRD::_update_render_target(RenderTarget *rt) { rd_format.depth = 1; rd_format.array_layers = 1; rd_format.mipmaps = 1; - rd_format.type = RD::TEXTURE_TYPE_2D; + rd_format.texture_type = RD::TEXTURE_TYPE_2D; rd_format.samples = RD::TEXTURE_SAMPLES_1; rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; rd_format.shareable_formats.push_back(rt->color_format); @@ -6122,7 +6565,7 @@ void RasterizerStorageRD::_update_render_target(RenderTarget *rt) { } } -void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { +void RendererStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { ERR_FAIL_COND(rt->backbuffer.is_valid()); uint32_t mipmaps_required = Image::get_image_required_mipmaps(rt->size.width, rt->size.height, Image::FORMAT_RGBA8); @@ -6130,7 +6573,7 @@ void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { tf.format = rt->color_format; tf.width = rt->size.width; tf.height = rt->size.height; - tf.type = RD::TEXTURE_TYPE_2D; + tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; tf.mipmaps = mipmaps_required; @@ -6170,7 +6613,7 @@ void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { } } -RID RasterizerStorageRD::render_target_create() { +RID RendererStorageRD::render_target_create() { RenderTarget render_target; render_target.was_used = false; @@ -6183,11 +6626,11 @@ RID RasterizerStorageRD::render_target_create() { return render_target_owner.make_rid(render_target); } -void RasterizerStorageRD::render_target_set_position(RID p_render_target, int p_x, int p_y) { +void RendererStorageRD::render_target_set_position(RID p_render_target, int p_x, int p_y) { //unused for this render target } -void RasterizerStorageRD::render_target_set_size(RID p_render_target, int p_width, int p_height) { +void RendererStorageRD::render_target_set_size(RID p_render_target, int p_width, int p_height) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); rt->size.x = p_width; @@ -6195,63 +6638,63 @@ void RasterizerStorageRD::render_target_set_size(RID p_render_target, int p_widt _update_render_target(rt); } -RID RasterizerStorageRD::render_target_get_texture(RID p_render_target) { +RID RendererStorageRD::render_target_get_texture(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->texture; } -void RasterizerStorageRD::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { +void RendererStorageRD::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { } -void RasterizerStorageRD::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) { +void RendererStorageRD::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); rt->flags[p_flag] = p_value; _update_render_target(rt); } -bool RasterizerStorageRD::render_target_was_used(RID p_render_target) { +bool RendererStorageRD::render_target_was_used(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, false); return rt->was_used; } -void RasterizerStorageRD::render_target_set_as_unused(RID p_render_target) { +void RendererStorageRD::render_target_set_as_unused(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); rt->was_used = false; } -Size2 RasterizerStorageRD::render_target_get_size(RID p_render_target) { +Size2 RendererStorageRD::render_target_get_size(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, Size2()); return rt->size; } -RID RasterizerStorageRD::render_target_get_rd_framebuffer(RID p_render_target) { +RID RendererStorageRD::render_target_get_rd_framebuffer(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->framebuffer; } -RID RasterizerStorageRD::render_target_get_rd_texture(RID p_render_target) { +RID RendererStorageRD::render_target_get_rd_texture(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->color; } -RID RasterizerStorageRD::render_target_get_rd_backbuffer(RID p_render_target) { +RID RendererStorageRD::render_target_get_rd_backbuffer(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->backbuffer; } -RID RasterizerStorageRD::render_target_get_rd_backbuffer_framebuffer(RID p_render_target) { +RID RendererStorageRD::render_target_get_rd_backbuffer_framebuffer(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); @@ -6262,32 +6705,32 @@ RID RasterizerStorageRD::render_target_get_rd_backbuffer_framebuffer(RID p_rende return rt->backbuffer_fb; } -void RasterizerStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) { +void RendererStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); rt->clear_requested = true; rt->clear_color = p_clear_color; } -bool RasterizerStorageRD::render_target_is_clear_requested(RID p_render_target) { +bool RendererStorageRD::render_target_is_clear_requested(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, false); return rt->clear_requested; } -Color RasterizerStorageRD::render_target_get_clear_request_color(RID p_render_target) { +Color RendererStorageRD::render_target_get_clear_request_color(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, Color()); return rt->clear_color; } -void RasterizerStorageRD::render_target_disable_clear_request(RID p_render_target) { +void RendererStorageRD::render_target_disable_clear_request(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); rt->clear_requested = false; } -void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) { +void RendererStorageRD::render_target_do_clear_request(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); if (!rt->clear_requested) { @@ -6300,7 +6743,276 @@ void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) { rt->clear_requested = false; } -void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) { +void RendererStorageRD::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + if (rt->sdf_oversize == p_size && rt->sdf_scale == p_scale) { + return; + } + + rt->sdf_oversize = p_size; + rt->sdf_scale = p_scale; + + _render_target_clear_sdf(rt); +} + +Rect2i RendererStorageRD::_render_target_get_sdf_rect(const RenderTarget *rt) const { + Size2i margin; + int scale; + switch (rt->sdf_oversize) { + case RS::VIEWPORT_SDF_OVERSIZE_100_PERCENT: { + scale = 100; + } break; + case RS::VIEWPORT_SDF_OVERSIZE_120_PERCENT: { + scale = 120; + } break; + case RS::VIEWPORT_SDF_OVERSIZE_150_PERCENT: { + scale = 150; + } break; + case RS::VIEWPORT_SDF_OVERSIZE_200_PERCENT: { + scale = 200; + } break; + default: { + } + } + + margin = (rt->size * scale / 100) - rt->size; + + Rect2i r(Vector2i(), rt->size); + r.position -= margin; + r.size += margin * 2; + + return r; +} + +Rect2i RendererStorageRD::render_target_get_sdf_rect(RID p_render_target) const { + const RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, Rect2i()); + + return _render_target_get_sdf_rect(rt); +} + +RID RendererStorageRD::render_target_get_sdf_texture(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + if (rt->sdf_buffer_read.is_null()) { + // no texture, create a dummy one for the 2D uniform set + RD::TextureFormat tformat; + tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + tformat.width = 4; + tformat.height = 4; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; + tformat.texture_type = RD::TEXTURE_TYPE_2D; + + Vector<uint8_t> pv; + pv.resize(16 * 4); + zeromem(pv.ptrw(), 16 * 4); + Vector<Vector<uint8_t>> vpv; + + rt->sdf_buffer_read = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + } + + return rt->sdf_buffer_read; +} + +void RendererStorageRD::_render_target_allocate_sdf(RenderTarget *rt) { + ERR_FAIL_COND(rt->sdf_buffer_write_fb.is_valid()); + if (rt->sdf_buffer_read.is_valid()) { + RD::get_singleton()->free(rt->sdf_buffer_read); + rt->sdf_buffer_read = RID(); + } + + Size2i size = _render_target_get_sdf_rect(rt).size; + + RD::TextureFormat tformat; + tformat.format = RD::DATA_FORMAT_R8_UNORM; + tformat.width = size.width; + tformat.height = size.height; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tformat.texture_type = RD::TEXTURE_TYPE_2D; + + rt->sdf_buffer_write = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + + { + Vector<RID> write_fb; + write_fb.push_back(rt->sdf_buffer_write); + rt->sdf_buffer_write_fb = RD::get_singleton()->framebuffer_create(write_fb); + } + + int scale; + switch (rt->sdf_scale) { + case RS::VIEWPORT_SDF_SCALE_100_PERCENT: { + scale = 100; + } break; + case RS::VIEWPORT_SDF_SCALE_50_PERCENT: { + scale = 50; + } break; + case RS::VIEWPORT_SDF_SCALE_25_PERCENT: { + scale = 25; + } break; + default: { + scale = 100; + } break; + } + + rt->process_size = size * scale / 100; + rt->process_size.x = MAX(rt->process_size.x, 1); + rt->process_size.y = MAX(rt->process_size.y, 1); + + tformat.format = RD::DATA_FORMAT_R16G16_UINT; + tformat.width = rt->process_size.width; + tformat.height = rt->process_size.height; + tformat.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; + + rt->sdf_buffer_process[0] = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + rt->sdf_buffer_process[1] = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + + tformat.format = RD::DATA_FORMAT_R16_UNORM; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + + rt->sdf_buffer_read = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + + { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 1; + u.ids.push_back(rt->sdf_buffer_write); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 2; + u.ids.push_back(rt->sdf_buffer_read); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 3; + u.ids.push_back(rt->sdf_buffer_process[0]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 4; + u.ids.push_back(rt->sdf_buffer_process[1]); + uniforms.push_back(u); + } + + rt->sdf_buffer_process_uniform_sets[0] = RD::get_singleton()->uniform_set_create(uniforms, rt_sdf.shader.version_get_shader(rt_sdf.shader_version, 0), 0); + SWAP(uniforms.write[2].ids.write[0], uniforms.write[3].ids.write[0]); + rt->sdf_buffer_process_uniform_sets[1] = RD::get_singleton()->uniform_set_create(uniforms, rt_sdf.shader.version_get_shader(rt_sdf.shader_version, 0), 0); + } +} + +void RendererStorageRD::_render_target_clear_sdf(RenderTarget *rt) { + if (rt->sdf_buffer_read.is_valid()) { + RD::get_singleton()->free(rt->sdf_buffer_read); + rt->sdf_buffer_read = RID(); + } + if (rt->sdf_buffer_write_fb.is_valid()) { + RD::get_singleton()->free(rt->sdf_buffer_write); + RD::get_singleton()->free(rt->sdf_buffer_process[0]); + RD::get_singleton()->free(rt->sdf_buffer_process[1]); + rt->sdf_buffer_write = RID(); + rt->sdf_buffer_write_fb = RID(); + rt->sdf_buffer_process[0] = RID(); + rt->sdf_buffer_process[1] = RID(); + rt->sdf_buffer_process_uniform_sets[0] = RID(); + rt->sdf_buffer_process_uniform_sets[1] = RID(); + } +} + +RID RendererStorageRD::render_target_get_sdf_framebuffer(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + + if (rt->sdf_buffer_write_fb.is_null()) { + _render_target_allocate_sdf(rt); + } + + return rt->sdf_buffer_write_fb; +} +void RendererStorageRD::render_target_sdf_process(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + ERR_FAIL_COND(rt->sdf_buffer_write_fb.is_null()); + + RenderTargetSDF::PushConstant push_constant; + + Rect2i r = _render_target_get_sdf_rect(rt); + + push_constant.size[0] = r.size.width; + push_constant.size[1] = r.size.height; + push_constant.stride = 0; + push_constant.shift = 0; + push_constant.base_size[0] = r.size.width; + push_constant.base_size[1] = r.size.height; + + bool shrink = false; + + switch (rt->sdf_scale) { + case RS::VIEWPORT_SDF_SCALE_50_PERCENT: { + push_constant.size[0] >>= 1; + push_constant.size[1] >>= 1; + push_constant.shift = 1; + shrink = true; + } break; + case RS::VIEWPORT_SDF_SCALE_25_PERCENT: { + push_constant.size[0] >>= 2; + push_constant.size[1] >>= 2; + push_constant.shift = 2; + shrink = true; + } break; + default: { + }; + } + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + + /* Load */ + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, rt_sdf.pipelines[shrink ? RenderTargetSDF::SHADER_LOAD_SHRINK : RenderTargetSDF::SHADER_LOAD]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rt->sdf_buffer_process_uniform_sets[1], 0); //fill [0] + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RenderTargetSDF::PushConstant)); + + RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1, 8, 8, 1); + + /* Process */ + + int stride = nearest_power_of_2_templated(MAX(push_constant.size[0], push_constant.size[1]) / 2); + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, rt_sdf.pipelines[RenderTargetSDF::SHADER_PROCESS]); + + RD::get_singleton()->compute_list_add_barrier(compute_list); + bool swap = false; + + //jumpflood + while (stride > 0) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rt->sdf_buffer_process_uniform_sets[swap ? 1 : 0], 0); + push_constant.stride = stride; + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RenderTargetSDF::PushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1, 8, 8, 1); + stride /= 2; + swap = !swap; + RD::get_singleton()->compute_list_add_barrier(compute_list); + } + + /* Store */ + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, rt_sdf.pipelines[shrink ? RenderTargetSDF::SHADER_STORE_SHRINK : RenderTargetSDF::SHADER_STORE]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rt->sdf_buffer_process_uniform_sets[swap ? 1 : 0], 0); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(RenderTargetSDF::PushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.size[0], push_constant.size[1], 1, 8, 8, 1); + + RD::get_singleton()->compute_list_end(); +} + +void RendererStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); if (!rt->backbuffer.is_valid()) { @@ -6311,7 +7023,7 @@ void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, if (p_region == Rect2i()) { region.size = rt->size; } else { - region = Rect2i(Size2i(), rt->size).clip(p_region); + region = Rect2i(Size2i(), rt->size).intersection(p_region); if (region.size == Size2i()) { return; //nothing to do } @@ -6340,7 +7052,7 @@ void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, } } -void RasterizerStorageRD::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) { +void RendererStorageRD::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); if (!rt->backbuffer.is_valid()) { @@ -6351,7 +7063,7 @@ void RasterizerStorageRD::render_target_clear_back_buffer(RID p_render_target, c if (p_region == Rect2i()) { region.size = rt->size; } else { - region = Rect2i(Size2i(), rt->size).clip(p_region); + region = Rect2i(Size2i(), rt->size).intersection(p_region); if (region.size == Size2i()) { return; //nothing to do } @@ -6361,7 +7073,7 @@ void RasterizerStorageRD::render_target_clear_back_buffer(RID p_render_target, c effects.set_color(rt->backbuffer_mipmap0, p_color, region, true); } -void RasterizerStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region) { +void RendererStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); if (!rt->backbuffer.is_valid()) { @@ -6372,7 +7084,7 @@ void RasterizerStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_tar if (p_region == Rect2i()) { region.size = rt->size; } else { - region = Rect2i(Size2i(), rt->size).clip(p_region); + region = Rect2i(Size2i(), rt->size).intersection(p_region); if (region.size == Size2i()) { return; //nothing to do } @@ -6393,70 +7105,70 @@ void RasterizerStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_tar } } -RID RasterizerStorageRD::render_target_get_framebuffer_uniform_set(RID p_render_target) { +RID RendererStorageRD::render_target_get_framebuffer_uniform_set(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->framebuffer_uniform_set; } -RID RasterizerStorageRD::render_target_get_backbuffer_uniform_set(RID p_render_target) { +RID RendererStorageRD::render_target_get_backbuffer_uniform_set(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->backbuffer_uniform_set; } -void RasterizerStorageRD::render_target_set_framebuffer_uniform_set(RID p_render_target, RID p_uniform_set) { +void RendererStorageRD::render_target_set_framebuffer_uniform_set(RID p_render_target, RID p_uniform_set) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); rt->framebuffer_uniform_set = p_uniform_set; } -void RasterizerStorageRD::render_target_set_backbuffer_uniform_set(RID p_render_target, RID p_uniform_set) { +void RendererStorageRD::render_target_set_backbuffer_uniform_set(RID p_render_target, RID p_uniform_set) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); rt->backbuffer_uniform_set = p_uniform_set; } -void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) { +void RendererStorageRD::base_update_dependency(RID p_base, DependencyTracker *p_instance) { if (mesh_owner.owns(p_base)) { Mesh *mesh = mesh_owner.getornull(p_base); - p_instance->update_dependency(&mesh->instance_dependency); + p_instance->update_dependency(&mesh->dependency); } else if (multimesh_owner.owns(p_base)) { MultiMesh *multimesh = multimesh_owner.getornull(p_base); - p_instance->update_dependency(&multimesh->instance_dependency); + p_instance->update_dependency(&multimesh->dependency); if (multimesh->mesh.is_valid()) { base_update_dependency(multimesh->mesh, p_instance); } } else if (reflection_probe_owner.owns(p_base)) { ReflectionProbe *rp = reflection_probe_owner.getornull(p_base); - p_instance->update_dependency(&rp->instance_dependency); + p_instance->update_dependency(&rp->dependency); } else if (decal_owner.owns(p_base)) { Decal *decal = decal_owner.getornull(p_base); - p_instance->update_dependency(&decal->instance_dependency); + p_instance->update_dependency(&decal->dependency); } else if (gi_probe_owner.owns(p_base)) { GIProbe *gip = gi_probe_owner.getornull(p_base); - p_instance->update_dependency(&gip->instance_dependency); + p_instance->update_dependency(&gip->dependency); } else if (lightmap_owner.owns(p_base)) { Lightmap *lm = lightmap_owner.getornull(p_base); - p_instance->update_dependency(&lm->instance_dependency); + p_instance->update_dependency(&lm->dependency); } else if (light_owner.owns(p_base)) { Light *l = light_owner.getornull(p_base); - p_instance->update_dependency(&l->instance_dependency); + p_instance->update_dependency(&l->dependency); } else if (particles_owner.owns(p_base)) { Particles *p = particles_owner.getornull(p_base); - p_instance->update_dependency(&p->instance_dependency); + p_instance->update_dependency(&p->dependency); } else if (particles_collision_owner.owns(p_base)) { ParticlesCollision *pc = particles_collision_owner.getornull(p_base); - p_instance->update_dependency(&pc->instance_dependency); + p_instance->update_dependency(&pc->dependency); } } -void RasterizerStorageRD::skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) { +void RendererStorageRD::skeleton_update_dependency(RID p_skeleton, DependencyTracker *p_instance) { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND(!skeleton); - p_instance->update_dependency(&skeleton->instance_dependency); + p_instance->update_dependency(&skeleton->dependency); } -RS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const { +RS::InstanceType RendererStorageRD::get_base_type(RID p_rid) const { if (mesh_owner.owns(p_rid)) { return RS::INSTANCE_MESH; } @@ -6488,7 +7200,7 @@ RS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const { return RS::INSTANCE_NONE; } -void RasterizerStorageRD::texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp) { +void RendererStorageRD::texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp) { if (!decal_atlas.textures.has(p_texture)) { DecalAtlas::Texture t; t.users = 1; @@ -6504,7 +7216,7 @@ void RasterizerStorageRD::texture_add_to_decal_atlas(RID p_texture, bool p_panor } } -void RasterizerStorageRD::texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp) { +void RendererStorageRD::texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp) { DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture); ERR_FAIL_COND(!t); t->users--; @@ -6518,15 +7230,15 @@ void RasterizerStorageRD::texture_remove_from_decal_atlas(RID p_texture, bool p_ } } -RID RasterizerStorageRD::decal_atlas_get_texture() const { +RID RendererStorageRD::decal_atlas_get_texture() const { return decal_atlas.texture; } -RID RasterizerStorageRD::decal_atlas_get_texture_srgb() const { +RID RendererStorageRD::decal_atlas_get_texture_srgb() const { return decal_atlas.texture_srgb; } -void RasterizerStorageRD::_update_decal_atlas() { +void RendererStorageRD::_update_decal_atlas() { if (!decal_atlas.dirty) { return; //nothing to do } @@ -6653,12 +7365,13 @@ void RasterizerStorageRD::_update_decal_atlas() { tformat.width = decal_atlas.size.width; tformat.height = decal_atlas.size.height; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; - tformat.type = RD::TEXTURE_TYPE_2D; + tformat.texture_type = RD::TEXTURE_TYPE_2D; tformat.mipmaps = decal_atlas.mipmaps; tformat.shareable_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM); tformat.shareable_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB); decal_atlas.texture = RD::get_singleton()->texture_create(tformat, RD::TextureView()); + RD::get_singleton()->texture_clear(decal_atlas.texture, Color(0, 0, 0, 0), 0, decal_atlas.mipmaps, 0, 1); { //create the framebuffer @@ -6713,12 +7426,12 @@ void RasterizerStorageRD::_update_decal_atlas() { prev_texture = mm.texture; } } else { - RD::get_singleton()->texture_clear(mm.texture, clear_color, 0, 1, 0, 1, false); + RD::get_singleton()->texture_clear(mm.texture, clear_color, 0, 1, 0, 1); } } } -int32_t RasterizerStorageRD::_global_variable_allocate(uint32_t p_elements) { +int32_t RendererStorageRD::_global_variable_allocate(uint32_t p_elements) { int32_t idx = 0; while (idx + p_elements <= global_variables.buffer_size) { if (global_variables.buffer_usage[idx].elements == 0) { @@ -6744,7 +7457,7 @@ int32_t RasterizerStorageRD::_global_variable_allocate(uint32_t p_elements) { return -1; } -void RasterizerStorageRD::_global_variable_store_in_buffer(int32_t p_index, RS::GlobalVariableType p_type, const Variant &p_value) { +void RendererStorageRD::_global_variable_store_in_buffer(int32_t p_index, RS::GlobalVariableType p_type, const Variant &p_value) { switch (p_type) { case RS::GLOBAL_VAR_TYPE_BOOL: { GlobalVariables::Value &bv = global_variables.buffer_values[p_index]; @@ -7021,7 +7734,7 @@ void RasterizerStorageRD::_global_variable_store_in_buffer(int32_t p_index, RS:: } } -void RasterizerStorageRD::_global_variable_mark_buffer_dirty(int32_t p_index, int32_t p_elements) { +void RendererStorageRD::_global_variable_mark_buffer_dirty(int32_t p_index, int32_t p_elements) { int32_t prev_chunk = -1; for (int32_t i = 0; i < p_elements; i++) { @@ -7037,7 +7750,7 @@ void RasterizerStorageRD::_global_variable_mark_buffer_dirty(int32_t p_index, in } } -void RasterizerStorageRD::global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) { +void RendererStorageRD::global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) { ERR_FAIL_COND(global_variables.variables.has(p_name)); GlobalVariables::Variable gv; gv.type = p_type; @@ -7075,7 +7788,7 @@ void RasterizerStorageRD::global_variable_add(const StringName &p_name, RS::Glob global_variables.variables[p_name] = gv; } -void RasterizerStorageRD::global_variable_remove(const StringName &p_name) { +void RendererStorageRD::global_variable_remove(const StringName &p_name) { if (!global_variables.variables.has(p_name)) { return; } @@ -7091,7 +7804,7 @@ void RasterizerStorageRD::global_variable_remove(const StringName &p_name) { global_variables.variables.erase(p_name); } -Vector<StringName> RasterizerStorageRD::global_variable_get_list() const { +Vector<StringName> RendererStorageRD::global_variable_get_list() const { if (!Engine::get_singleton()->is_editor_hint()) { ERR_FAIL_V_MSG(Vector<StringName>(), "This function should never be used outside the editor, it can severely damage performance."); } @@ -7105,7 +7818,7 @@ Vector<StringName> RasterizerStorageRD::global_variable_get_list() const { return names; } -void RasterizerStorageRD::global_variable_set(const StringName &p_name, const Variant &p_value) { +void RendererStorageRD::global_variable_set(const StringName &p_name, const Variant &p_value) { ERR_FAIL_COND(!global_variables.variables.has(p_name)); GlobalVariables::Variable &gv = global_variables.variables[p_name]; gv.value = p_value; @@ -7125,7 +7838,7 @@ void RasterizerStorageRD::global_variable_set(const StringName &p_name, const Va } } -void RasterizerStorageRD::global_variable_set_override(const StringName &p_name, const Variant &p_value) { +void RendererStorageRD::global_variable_set_override(const StringName &p_name, const Variant &p_value) { if (!global_variables.variables.has(p_name)) { return; //variable may not exist } @@ -7153,7 +7866,7 @@ void RasterizerStorageRD::global_variable_set_override(const StringName &p_name, } } -Variant RasterizerStorageRD::global_variable_get(const StringName &p_name) const { +Variant RendererStorageRD::global_variable_get(const StringName &p_name) const { if (!Engine::get_singleton()->is_editor_hint()) { ERR_FAIL_V_MSG(Variant(), "This function should never be used outside the editor, it can severely damage performance."); } @@ -7165,7 +7878,7 @@ Variant RasterizerStorageRD::global_variable_get(const StringName &p_name) const return global_variables.variables[p_name].value; } -RS::GlobalVariableType RasterizerStorageRD::global_variable_get_type_internal(const StringName &p_name) const { +RS::GlobalVariableType RendererStorageRD::global_variable_get_type_internal(const StringName &p_name) const { if (!global_variables.variables.has(p_name)) { return RS::GLOBAL_VAR_TYPE_MAX; } @@ -7173,7 +7886,7 @@ RS::GlobalVariableType RasterizerStorageRD::global_variable_get_type_internal(co return global_variables.variables[p_name].type; } -RS::GlobalVariableType RasterizerStorageRD::global_variable_get_type(const StringName &p_name) const { +RS::GlobalVariableType RendererStorageRD::global_variable_get_type(const StringName &p_name) const { if (!Engine::get_singleton()->is_editor_hint()) { ERR_FAIL_V_MSG(RS::GLOBAL_VAR_TYPE_MAX, "This function should never be used outside the editor, it can severely damage performance."); } @@ -7181,7 +7894,7 @@ RS::GlobalVariableType RasterizerStorageRD::global_variable_get_type(const Strin return global_variable_get_type_internal(p_name); } -void RasterizerStorageRD::global_variables_load_settings(bool p_load_textures) { +void RendererStorageRD::global_variables_load_settings(bool p_load_textures) { List<PropertyInfo> settings; ProjectSettings::get_singleton()->get_property_list(&settings); @@ -7262,15 +7975,15 @@ void RasterizerStorageRD::global_variables_load_settings(bool p_load_textures) { } } -void RasterizerStorageRD::global_variables_clear() { +void RendererStorageRD::global_variables_clear() { global_variables.variables.clear(); //not right but for now enough } -RID RasterizerStorageRD::global_variables_get_storage_buffer() const { +RID RendererStorageRD::global_variables_get_storage_buffer() const { return global_variables.buffer; } -int32_t RasterizerStorageRD::global_variables_instance_allocate(RID p_instance) { +int32_t RendererStorageRD::global_variables_instance_allocate(RID p_instance) { ERR_FAIL_COND_V(global_variables.instance_buffer_pos.has(p_instance), -1); int32_t pos = _global_variable_allocate(ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES); global_variables.instance_buffer_pos[p_instance] = pos; //save anyway @@ -7279,7 +7992,7 @@ int32_t RasterizerStorageRD::global_variables_instance_allocate(RID p_instance) return pos; } -void RasterizerStorageRD::global_variables_instance_free(RID p_instance) { +void RendererStorageRD::global_variables_instance_free(RID p_instance) { ERR_FAIL_COND(!global_variables.instance_buffer_pos.has(p_instance)); int32_t pos = global_variables.instance_buffer_pos[p_instance]; if (pos >= 0) { @@ -7288,7 +8001,7 @@ void RasterizerStorageRD::global_variables_instance_free(RID p_instance) { global_variables.instance_buffer_pos.erase(p_instance); } -void RasterizerStorageRD::global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) { +void RendererStorageRD::global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) { if (!global_variables.instance_buffer_pos.has(p_instance)) { return; //just not allocated, ignore } @@ -7331,7 +8044,7 @@ void RasterizerStorageRD::global_variables_instance_update(RID p_instance, int p _global_variable_mark_buffer_dirty(pos, 1); } -void RasterizerStorageRD::_update_global_variables() { +void RendererStorageRD::_update_global_variables() { if (global_variables.buffer_dirty_region_count > 0) { uint32_t total_regions = global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE; if (total_regions / global_variables.buffer_dirty_region_count <= 4) { @@ -7381,7 +8094,7 @@ void RasterizerStorageRD::_update_global_variables() { } } -void RasterizerStorageRD::update_dirty_resources() { +void RendererStorageRD::update_dirty_resources() { _update_global_variables(); //must do before materials, so it can queue them for update _update_queued_materials(); _update_dirty_multimeshes(); @@ -7389,7 +8102,7 @@ void RasterizerStorageRD::update_dirty_resources() { _update_decal_atlas(); } -bool RasterizerStorageRD::has_os_feature(const String &p_feature) const { +bool RendererStorageRD::has_os_feature(const String &p_feature) const { if (p_feature == "rgtc" && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC5_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT)) { return true; } @@ -7413,7 +8126,7 @@ bool RasterizerStorageRD::has_os_feature(const String &p_feature) const { return false; } -bool RasterizerStorageRD::free(RID p_rid) { +bool RendererStorageRD::free(RID p_rid) { if (texture_owner.owns(p_rid)) { Texture *t = texture_owner.getornull(p_rid); @@ -7474,28 +8187,49 @@ bool RasterizerStorageRD::free(RID p_rid) { _update_queued_materials(); } material_set_shader(p_rid, RID()); //clean up shader - material->instance_dependency.instance_notify_deleted(p_rid); + material->dependency.deleted_notify(p_rid); + material_owner.free(p_rid); } else if (mesh_owner.owns(p_rid)) { mesh_clear(p_rid); + mesh_set_shadow_mesh(p_rid, RID()); Mesh *mesh = mesh_owner.getornull(p_rid); - mesh->instance_dependency.instance_notify_deleted(p_rid); + mesh->dependency.deleted_notify(p_rid); + if (mesh->instances.size()) { + ERR_PRINT("deleting mesh with active instances"); + } + if (mesh->shadow_owners.size()) { + for (Set<Mesh *>::Element *E = mesh->shadow_owners.front(); E; E = E->next()) { + Mesh *shadow_owner = E->get(); + shadow_owner->shadow_mesh = RID(); + shadow_owner->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); + } + } mesh_owner.free(p_rid); + } else if (mesh_instance_owner.owns(p_rid)) { + MeshInstance *mi = mesh_instance_owner.getornull(p_rid); + _mesh_instance_clear(mi); + mi->mesh->instances.erase(mi->I); + mi->I = nullptr; + + mesh_instance_owner.free(p_rid); + memdelete(mi); + } else if (multimesh_owner.owns(p_rid)) { _update_dirty_multimeshes(); multimesh_allocate(p_rid, 0, RS::MULTIMESH_TRANSFORM_2D); MultiMesh *multimesh = multimesh_owner.getornull(p_rid); - multimesh->instance_dependency.instance_notify_deleted(p_rid); + multimesh->dependency.deleted_notify(p_rid); multimesh_owner.free(p_rid); } else if (skeleton_owner.owns(p_rid)) { _update_dirty_skeletons(); skeleton_allocate(p_rid, 0); Skeleton *skeleton = skeleton_owner.getornull(p_rid); - skeleton->instance_dependency.instance_notify_deleted(p_rid); + skeleton->dependency.deleted_notify(p_rid); skeleton_owner.free(p_rid); } else if (reflection_probe_owner.owns(p_rid)) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_rid); - reflection_probe->instance_dependency.instance_notify_deleted(p_rid); + reflection_probe->dependency.deleted_notify(p_rid); reflection_probe_owner.free(p_rid); } else if (decal_owner.owns(p_rid)) { Decal *decal = decal_owner.getornull(p_rid); @@ -7504,30 +8238,30 @@ bool RasterizerStorageRD::free(RID p_rid) { texture_remove_from_decal_atlas(decal->textures[i]); } } - decal->instance_dependency.instance_notify_deleted(p_rid); + decal->dependency.deleted_notify(p_rid); decal_owner.free(p_rid); } else if (gi_probe_owner.owns(p_rid)) { gi_probe_allocate(p_rid, Transform(), AABB(), Vector3i(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<int>()); //deallocate GIProbe *gi_probe = gi_probe_owner.getornull(p_rid); - gi_probe->instance_dependency.instance_notify_deleted(p_rid); + gi_probe->dependency.deleted_notify(p_rid); gi_probe_owner.free(p_rid); } else if (lightmap_owner.owns(p_rid)) { lightmap_set_textures(p_rid, RID(), false); Lightmap *lightmap = lightmap_owner.getornull(p_rid); - lightmap->instance_dependency.instance_notify_deleted(p_rid); + lightmap->dependency.deleted_notify(p_rid); lightmap_owner.free(p_rid); } else if (light_owner.owns(p_rid)) { light_set_projector(p_rid, RID()); //clear projector // delete the texture Light *light = light_owner.getornull(p_rid); - light->instance_dependency.instance_notify_deleted(p_rid); + light->dependency.deleted_notify(p_rid); light_owner.free(p_rid); } else if (particles_owner.owns(p_rid)) { Particles *particles = particles_owner.getornull(p_rid); _particles_free_data(particles); - particles->instance_dependency.instance_notify_deleted(p_rid); + particles->dependency.deleted_notify(p_rid); particles_owner.free(p_rid); } else if (particles_collision_owner.owns(p_rid)) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_rid); @@ -7535,8 +8269,10 @@ bool RasterizerStorageRD::free(RID p_rid) { if (particles_collision->heightfield_texture.is_valid()) { RD::get_singleton()->free(particles_collision->heightfield_texture); } - particles_collision->instance_dependency.instance_notify_deleted(p_rid); + particles_collision->dependency.deleted_notify(p_rid); particles_collision_owner.free(p_rid); + } else if (particles_collision_instance_owner.owns(p_rid)) { + particles_collision_instance_owner.free(p_rid); } else if (render_target_owner.owns(p_rid)) { RenderTarget *rt = render_target_owner.getornull(p_rid); @@ -7556,41 +8292,41 @@ bool RasterizerStorageRD::free(RID p_rid) { return true; } -RasterizerEffectsRD *RasterizerStorageRD::get_effects() { +EffectsRD *RendererStorageRD::get_effects() { return &effects; } -void RasterizerStorageRD::capture_timestamps_begin() { - RD::get_singleton()->capture_timestamp("Frame Begin", false); +void RendererStorageRD::capture_timestamps_begin() { + RD::get_singleton()->capture_timestamp("Frame Begin"); } -void RasterizerStorageRD::capture_timestamp(const String &p_name) { - RD::get_singleton()->capture_timestamp(p_name, true); +void RendererStorageRD::capture_timestamp(const String &p_name) { + RD::get_singleton()->capture_timestamp(p_name); } -uint32_t RasterizerStorageRD::get_captured_timestamps_count() const { +uint32_t RendererStorageRD::get_captured_timestamps_count() const { return RD::get_singleton()->get_captured_timestamps_count(); } -uint64_t RasterizerStorageRD::get_captured_timestamps_frame() const { +uint64_t RendererStorageRD::get_captured_timestamps_frame() const { return RD::get_singleton()->get_captured_timestamps_frame(); } -uint64_t RasterizerStorageRD::get_captured_timestamp_gpu_time(uint32_t p_index) const { +uint64_t RendererStorageRD::get_captured_timestamp_gpu_time(uint32_t p_index) const { return RD::get_singleton()->get_captured_timestamp_gpu_time(p_index); } -uint64_t RasterizerStorageRD::get_captured_timestamp_cpu_time(uint32_t p_index) const { +uint64_t RendererStorageRD::get_captured_timestamp_cpu_time(uint32_t p_index) const { return RD::get_singleton()->get_captured_timestamp_cpu_time(p_index); } -String RasterizerStorageRD::get_captured_timestamp_name(uint32_t p_index) const { +String RendererStorageRD::get_captured_timestamp_name(uint32_t p_index) const { return RD::get_singleton()->get_captured_timestamp_name(p_index); } -RasterizerStorageRD *RasterizerStorageRD::base_singleton = nullptr; +RendererStorageRD *RendererStorageRD::base_singleton = nullptr; -RasterizerStorageRD::RasterizerStorageRD() { +RendererStorageRD::RendererStorageRD() { base_singleton = this; for (int i = 0; i < SHADER_TYPE_MAX; i++) { @@ -7616,7 +8352,7 @@ RasterizerStorageRD::RasterizerStorageRD() { tformat.width = 4; tformat.height = 4; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_2D; + tformat.texture_type = RD::TEXTURE_TYPE_2D; Vector<uint8_t> pv; pv.resize(16 * 4); @@ -7708,7 +8444,7 @@ RasterizerStorageRD::RasterizerStorageRD() { tformat.height = 4; tformat.array_layers = 6; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_CUBE_ARRAY; + tformat.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY; Vector<uint8_t> pv; pv.resize(16 * 4); @@ -7736,7 +8472,7 @@ RasterizerStorageRD::RasterizerStorageRD() { tformat.height = 4; tformat.array_layers = 6; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_CUBE; + tformat.texture_type = RD::TEXTURE_TYPE_CUBE; Vector<uint8_t> pv; pv.resize(16 * 4); @@ -7756,6 +8492,34 @@ RasterizerStorageRD::RasterizerStorageRD() { } } + { //create default cubemap white array + + RD::TextureFormat tformat; + tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + tformat.width = 4; + tformat.height = 4; + tformat.array_layers = 6; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; + tformat.texture_type = RD::TEXTURE_TYPE_CUBE; + + Vector<uint8_t> pv; + pv.resize(16 * 4); + for (int i = 0; i < 16; i++) { + pv.set(i * 4 + 0, 255); + pv.set(i * 4 + 1, 255); + pv.set(i * 4 + 2, 255); + pv.set(i * 4 + 3, 255); + } + + { + Vector<Vector<uint8_t>> vpv; + for (int i = 0; i < 6; i++) { + vpv.push_back(pv); + } + default_rd_textures[DEFAULT_RD_TEXTURE_CUBEMAP_WHITE] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + } + } + { //create default 3D RD::TextureFormat tformat; @@ -7764,7 +8528,7 @@ RasterizerStorageRD::RasterizerStorageRD() { tformat.height = 4; tformat.depth = 4; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_3D; + tformat.texture_type = RD::TEXTURE_TYPE_3D; Vector<uint8_t> pv; pv.resize(64 * 4); @@ -7790,7 +8554,7 @@ RasterizerStorageRD::RasterizerStorageRD() { tformat.height = 4; tformat.array_layers = 1; tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; - tformat.type = RD::TEXTURE_TYPE_2D_ARRAY; + tformat.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; Vector<uint8_t> pv; pv.resize(16 * 4); @@ -7951,6 +8715,19 @@ RasterizerStorageRD::RasterizerStorageRD() { mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV2] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); } + for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) { + buffer.resize(sizeof(float) * 4); + { + uint8_t *w = buffer.ptrw(); + float *fptr = (float *)w; + fptr[0] = 0.0; + fptr[1] = 0.0; + fptr[2] = 0.0; + fptr[3] = 0.0; + } + mesh_default_rd_buffers[DEFAULT_RD_BUFFER_CUSTOM0 + i] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer); + } + { //bones buffer.resize(sizeof(uint32_t) * 4); { @@ -8013,8 +8790,8 @@ RasterizerStorageRD::RasterizerStorageRD() { particles_modes.push_back(""); particles_shader.shader.initialize(particles_modes, String()); } - shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_PARTICLES, _create_particles_shader_funcs); - material_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_PARTICLES, _create_particles_material_funcs); + shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_PARTICLES, _create_particles_shader_funcs); + material_set_data_request_function(RendererStorageRD::SHADER_TYPE_PARTICLES, _create_particles_material_funcs); { ShaderCompilerRD::DefaultIdentifierActions actions; @@ -8044,7 +8821,7 @@ RasterizerStorageRD::RasterizerStorageRD() { actions.renames["RESTART_VELOCITY"] = "restart_velocity"; actions.renames["RESTART_COLOR"] = "restart_color"; actions.renames["RESTART_CUSTOM"] = "restart_custom"; - actions.renames["emit_particle"] = "emit_particle"; + actions.renames["emit_subparticle"] = "emit_subparticle"; actions.renames["COLLIDED"] = "collided"; actions.renames["COLLISION_NORMAL"] = "collision_normal"; actions.renames["COLLISION_DEPTH"] = "collision_depth"; @@ -8075,14 +8852,14 @@ RasterizerStorageRD::RasterizerStorageRD() { particles_shader.default_material = material_create(); material_set_shader(particles_shader.default_material, particles_shader.default_shader); - ParticlesMaterialData *md = (ParticlesMaterialData *)material_get_data(particles_shader.default_material, RasterizerStorageRD::SHADER_TYPE_PARTICLES); + ParticlesMaterialData *md = (ParticlesMaterialData *)material_get_data(particles_shader.default_material, RendererStorageRD::SHADER_TYPE_PARTICLES); particles_shader.default_shader_rd = particles_shader.shader.version_get_shader(md->shader_data->version, 0); Vector<RD::Uniform> uniforms; { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 1; u.ids.resize(12); RID *ids_ptr = u.ids.ptrw(); @@ -8103,7 +8880,7 @@ RasterizerStorageRD::RasterizerStorageRD() { { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; u.ids.push_back(global_variables_get_storage_buffer()); uniforms.push_back(u); @@ -8128,9 +8905,51 @@ RasterizerStorageRD::RasterizerStorageRD() { particles_shader.copy_pipelines[i] = RD::get_singleton()->compute_pipeline_create(particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, i)); } } + + { + Vector<String> sdf_modes; + sdf_modes.push_back("\n#define MODE_LOAD\n"); + sdf_modes.push_back("\n#define MODE_LOAD_SHRINK\n"); + sdf_modes.push_back("\n#define MODE_PROCESS\n"); + sdf_modes.push_back("\n#define MODE_PROCESS_OPTIMIZED\n"); + sdf_modes.push_back("\n#define MODE_STORE\n"); + sdf_modes.push_back("\n#define MODE_STORE_SHRINK\n"); + + rt_sdf.shader.initialize(sdf_modes); + + rt_sdf.shader_version = rt_sdf.shader.version_create(); + + for (int i = 0; i < RenderTargetSDF::SHADER_MAX; i++) { + rt_sdf.pipelines[i] = RD::get_singleton()->compute_pipeline_create(rt_sdf.shader.version_get_shader(rt_sdf.shader_version, i)); + } + } + { + Vector<String> skeleton_modes; + skeleton_modes.push_back("\n#define MODE_2D\n"); + skeleton_modes.push_back(""); + + skeleton_shader.shader.initialize(skeleton_modes); + skeleton_shader.version = skeleton_shader.shader.version_create(); + for (int i = 0; i < SkeletonShader::SHADER_MODE_MAX; i++) { + skeleton_shader.version_shader[i] = skeleton_shader.shader.version_get_shader(skeleton_shader.version, i); + skeleton_shader.pipeline[i] = RD::get_singleton()->compute_pipeline_create(skeleton_shader.version_shader[i]); + } + + { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.binding = 0; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(default_rd_storage_buffer); + uniforms.push_back(u); + } + skeleton_shader.default_skeleton_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_SKELETON); + } + } } -RasterizerStorageRD::~RasterizerStorageRD() { +RendererStorageRD::~RendererStorageRD() { memdelete_arr(global_variables.buffer_values); memdelete_arr(global_variables.buffer_usage); memdelete_arr(global_variables.buffer_dirty_regions); @@ -8155,6 +8974,9 @@ RasterizerStorageRD::~RasterizerStorageRD() { giprobe_sdf_shader.version_free(giprobe_sdf_shader_version); particles_shader.copy_shader.version_free(particles_shader.copy_shader_version); + rt_sdf.shader.version_free(rt_sdf.shader_version); + + skeleton_shader.shader.version_free(skeleton_shader.version); RenderingServer::get_singleton()->free(particles_shader.default_material); RenderingServer::get_singleton()->free(particles_shader.default_shader); diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index 321bff9fdd..aa7195232a 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer_storage_rd.h */ +/* renderer_storage_rd.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,19 +28,23 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RASTERIZER_STORAGE_RD_H -#define RASTERIZER_STORAGE_RD_H - -#include "core/rid_owner.h" -#include "servers/rendering/rasterizer.h" -#include "servers/rendering/rasterizer_rd/rasterizer_effects_rd.h" -#include "servers/rendering/rasterizer_rd/shader_compiler_rd.h" -#include "servers/rendering/rasterizer_rd/shaders/giprobe_sdf.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/particles.glsl.gen.h" -#include "servers/rendering/rasterizer_rd/shaders/particles_copy.glsl.gen.h" +#ifndef RENDERING_SERVER_STORAGE_RD_H +#define RENDERING_SERVER_STORAGE_RD_H + +#include "core/templates/list.h" +#include "core/templates/local_vector.h" +#include "core/templates/rid_owner.h" +#include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_rd/effects_rd.h" +#include "servers/rendering/renderer_rd/shader_compiler_rd.h" +#include "servers/rendering/renderer_rd/shaders/canvas_sdf.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/particles.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/particles_copy.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/skeleton.glsl.gen.h" +#include "servers/rendering/renderer_scene_render.h" #include "servers/rendering/rendering_device.h" - -class RasterizerStorageRD : public RasterizerStorage { +class RendererStorageRD : public RendererStorage { public: static _FORCE_INLINE_ void store_transform(const Transform &p_mtx, float *p_array) { p_array[0] = p_mtx.basis.elements[0][0]; @@ -91,6 +95,21 @@ public: p_array[11] = 0; } + static _FORCE_INLINE_ void store_transform_transposed_3x4(const Transform &p_mtx, float *p_array) { + p_array[0] = p_mtx.basis.elements[0][0]; + p_array[1] = p_mtx.basis.elements[0][1]; + p_array[2] = p_mtx.basis.elements[0][2]; + p_array[3] = p_mtx.origin.x; + p_array[4] = p_mtx.basis.elements[1][0]; + p_array[5] = p_mtx.basis.elements[1][1]; + p_array[6] = p_mtx.basis.elements[1][2]; + p_array[7] = p_mtx.origin.y; + p_array[8] = p_mtx.basis.elements[2][0]; + p_array[9] = p_mtx.basis.elements[2][1]; + p_array[10] = p_mtx.basis.elements[2][2]; + p_array[11] = p_mtx.origin.z; + } + static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { @@ -123,6 +142,8 @@ public: virtual bool is_animated() const = 0; virtual bool casts_shadows() const = 0; virtual Variant get_default_parameter(const StringName &p_parameter) const = 0; + virtual RS::ShaderNativeSourceCode get_native_source_code() const { return RS::ShaderNativeSourceCode(); } + virtual ~ShaderData() {} }; @@ -138,7 +159,7 @@ public: virtual ~MaterialData(); private: - friend class RasterizerStorageRD; + friend class RendererStorageRD; RID self; List<RID>::Element *global_buffer_E = nullptr; List<RID>::Element *global_texture_E = nullptr; @@ -155,6 +176,7 @@ public: DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER, DEFAULT_RD_TEXTURE_CUBEMAP_BLACK, DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK, + DEFAULT_RD_TEXTURE_CUBEMAP_WHITE, DEFAULT_RD_TEXTURE_3D_WHITE, DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE, DEFAULT_RD_TEXTURE_2D_UINT, @@ -168,6 +190,10 @@ public: DEFAULT_RD_BUFFER_COLOR, DEFAULT_RD_BUFFER_TEX_UV, DEFAULT_RD_BUFFER_TEX_UV2, + DEFAULT_RD_BUFFER_CUSTOM0, + DEFAULT_RD_BUFFER_CUSTOM1, + DEFAULT_RD_BUFFER_CUSTOM2, + DEFAULT_RD_BUFFER_CUSTOM3, DEFAULT_RD_BUFFER_BONES, DEFAULT_RD_BUFFER_WEIGHTS, DEFAULT_RD_BUFFER_MAX, @@ -178,7 +204,7 @@ private: struct CanvasTexture { RID diffuse; - RID normalmap; + RID normal_map; RID specular; Color specular_color = Color(1, 1, 1, 1); float shininess = 1.0; @@ -351,6 +377,7 @@ private: Shader *shader; //shortcut to shader data and type ShaderType shader_type; + uint32_t shader_id = 0; bool update_requested; bool uniform_dirty; bool texture_dirty; @@ -358,7 +385,7 @@ private: Map<StringName, Variant> params; int32_t priority; RID next_pass; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; }; MaterialDataRequestFunction material_data_request_func[SHADER_TYPE_MAX]; @@ -370,13 +397,19 @@ private: /* Mesh */ + struct MeshInstance; + struct Mesh { struct Surface { RS::PrimitiveType primitive = RS::PRIMITIVE_POINTS; uint32_t format = 0; RID vertex_buffer; + RID attribute_buffer; + RID skin_buffer; uint32_t vertex_count = 0; + uint32_t vertex_buffer_size = 0; + uint32_t skin_buffer_size = 0; // A different pipeline needs to be allocated // depending on the inputs available in the @@ -412,8 +445,7 @@ private: Vector<AABB> bone_aabbs; - Vector<RID> blend_shapes; - RID blend_shape_base_buffer; //source buffer goes here when using blend shapes, and main one is uncompressed + RID blend_shape_buffer; RID material; @@ -425,6 +457,8 @@ private: uint32_t particles_render_index = 0; uint64_t particles_render_pass = 0; + + RID uniform_set; }; uint32_t blend_shape_count = 0; @@ -435,17 +469,93 @@ private: Vector<AABB> bone_aabbs; + bool has_bone_weights = false; + AABB aabb; AABB custom_aabb; Vector<RID> material_cache; - RasterizerScene::InstanceDependency instance_dependency; + List<MeshInstance *> instances; + + RID shadow_mesh; + Set<Mesh *> shadow_owners; + + Dependency dependency; }; mutable RID_Owner<Mesh> mesh_owner; - void _mesh_surface_generate_version_for_input_mask(Mesh::Surface *s, uint32_t p_input_mask); + struct MeshInstance { + Mesh *mesh; + RID skeleton; + struct Surface { + RID vertex_buffer; + RID uniform_set; + + Mesh::Surface::Version *versions = nullptr; //allocated on demand + uint32_t version_count = 0; + }; + LocalVector<Surface> surfaces; + LocalVector<float> blend_weights; + + RID blend_weights_buffer; + List<MeshInstance *>::Element *I = nullptr; //used to erase itself + uint64_t skeleton_version = 0; + bool dirty = false; + bool weights_dirty = false; + SelfList<MeshInstance> weight_update_list; + SelfList<MeshInstance> array_update_list; + MeshInstance() : + weight_update_list(this), array_update_list(this) {} + }; + + void _mesh_instance_clear(MeshInstance *mi); + void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface); + + mutable RID_PtrOwner<MeshInstance> mesh_instance_owner; + + SelfList<MeshInstance>::List dirty_mesh_instance_weights; + SelfList<MeshInstance>::List dirty_mesh_instance_arrays; + + struct SkeletonShader { + struct PushConstant { + uint32_t has_normal; + uint32_t has_tangent; + uint32_t has_skeleton; + uint32_t has_blend_shape; + + uint32_t vertex_count; + uint32_t vertex_stride; + uint32_t skin_stride; + uint32_t skin_weight_offset; + + uint32_t blend_shape_count; + uint32_t normalized_blend_shapes; + uint32_t pad0; + uint32_t pad1; + }; + + enum { + UNIFORM_SET_INSTANCE = 0, + UNIFORM_SET_SURFACE = 1, + UNIFORM_SET_SKELETON = 2, + }; + enum { + SHADER_MODE_2D, + SHADER_MODE_3D, + SHADER_MODE_MAX + }; + + SkeletonShaderRD shader; + RID version; + RID version_shader[SHADER_MODE_MAX]; + RID pipeline[SHADER_MODE_MAX]; + + RID default_skeleton_uniform_set; + } skeleton_shader; + + void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis = nullptr); RID mesh_default_rd_buffers[DEFAULT_RD_BUFFER_MAX]; @@ -474,7 +584,7 @@ private: bool dirty = false; MultiMesh *dirty_list = nullptr; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; }; mutable RID_Owner<MultiMesh> multimesh_owner; @@ -645,7 +755,7 @@ private: ParticleEmissionBuffer *emission_buffer = nullptr; RID emission_storage_buffer; - Set<RasterizerScene::InstanceBase *> collisions; + Set<RID> collisions; Particles() : inactive(true), @@ -672,7 +782,7 @@ private: clear(true) { } - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; ParticlesFrameParams frame_params; }; @@ -727,7 +837,7 @@ private: bool valid; RID version; - //RenderPipelineVertexFormatCacheRD pipelines[SKY_VERSION_MAX]; + //PipelineCacheRD pipelines[SKY_VERSION_MAX]; Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; @@ -745,17 +855,19 @@ private: virtual void set_code(const String &p_Code); virtual void set_default_texture_param(const StringName &p_name, RID p_texture); virtual void get_param_list(List<PropertyInfo> *p_param_list) const; - virtual void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const; + virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; virtual bool is_param_texture(const StringName &p_param) const; virtual bool is_animated() const; virtual bool casts_shadows() const; virtual Variant get_default_parameter(const StringName &p_parameter) const; + virtual RS::ShaderNativeSourceCode get_native_source_code() const; + ParticlesShaderData(); virtual ~ParticlesShaderData(); }; ShaderData *_create_particles_shader_func(); - static RasterizerStorageRD::ShaderData *_create_particles_shader_funcs() { + static RendererStorageRD::ShaderData *_create_particles_shader_funcs() { return base_singleton->_create_particles_shader_func(); } @@ -775,7 +887,7 @@ private: }; MaterialData *_create_particles_material_func(ParticlesShaderData *p_shader); - static RasterizerStorageRD::MaterialData *_create_particles_material_funcs(ShaderData *p_shader) { + static RendererStorageRD::MaterialData *_create_particles_material_funcs(ShaderData *p_shader) { return base_singleton->_create_particles_material_func(static_cast<ParticlesShaderData *>(p_shader)); } @@ -800,11 +912,19 @@ private: RS::ParticlesCollisionHeightfieldResolution heightfield_resolution = RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_1024; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; }; mutable RID_Owner<ParticlesCollision> particles_collision_owner; + struct ParticlesCollisionInstance { + RID collision; + Transform transform; + bool active = false; + }; + + mutable RID_Owner<ParticlesCollisionInstance> particles_collision_instance_owner; + /* Skeleton */ struct Skeleton { @@ -818,8 +938,11 @@ private: Transform2D base_transform_2d; RID uniform_set_3d; + RID uniform_set_mi; + + uint64_t version = 1; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; }; mutable RID_Owner<Skeleton> skeleton_owner; @@ -848,9 +971,10 @@ private: RS::LightDirectionalShadowMode directional_shadow_mode = RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; RS::LightDirectionalShadowDepthRangeMode directional_range_mode = RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE; bool directional_blend_splits = false; + bool directional_sky_only = false; uint64_t version = 0; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; }; mutable RID_Owner<Light> light_owner; @@ -871,8 +995,9 @@ private: bool box_projection = false; bool enable_shadows = false; uint32_t cull_mask = (1 << 20) - 1; + float lod_threshold = 0.01; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; }; mutable RID_Owner<ReflectionProbe> reflection_probe_owner; @@ -893,7 +1018,7 @@ private: float distance_fade_length = 1; float normal_fade = 0.0; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; }; mutable RID_Owner<Decal> decal_owner; @@ -931,7 +1056,7 @@ private: uint32_t version = 1; uint32_t data_version = 1; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; }; GiprobeSdfShaderRD giprobe_sdf_shader; @@ -960,7 +1085,7 @@ private: int32_t over = EMPTY_LEAF, under = EMPTY_LEAF; }; - RasterizerScene::InstanceDependency instance_dependency; + Dependency dependency; }; bool using_lightmap_array; //high end uses this @@ -1002,6 +1127,15 @@ private: RID framebuffer_uniform_set; RID backbuffer_uniform_set; + RID sdf_buffer_write; + RID sdf_buffer_write_fb; + RID sdf_buffer_process[2]; + RID sdf_buffer_read; + RID sdf_buffer_process_uniform_sets[2]; + RS::ViewportSDFOversize sdf_oversize = RS::VIEWPORT_SDF_OVERSIZE_120_PERCENT; + RS::ViewportSDFScale sdf_scale = RS::VIEWPORT_SDF_SCALE_50_PERCENT; + Size2i process_size; + //texture generated for this owner (nor RD). RID texture; bool was_used; @@ -1011,11 +1145,38 @@ private: Color clear_color; }; - RID_Owner<RenderTarget> render_target_owner; + mutable RID_Owner<RenderTarget> render_target_owner; void _clear_render_target(RenderTarget *rt); void _update_render_target(RenderTarget *rt); void _create_render_target_backbuffer(RenderTarget *rt); + void _render_target_allocate_sdf(RenderTarget *rt); + void _render_target_clear_sdf(RenderTarget *rt); + Rect2i _render_target_get_sdf_rect(const RenderTarget *rt) const; + + struct RenderTargetSDF { + enum { + SHADER_LOAD, + SHADER_LOAD_SHRINK, + SHADER_PROCESS, + SHADER_PROCESS_OPTIMIZED, + SHADER_STORE, + SHADER_STORE_SHRINK, + SHADER_MAX + }; + + struct PushConstant { + int32_t size[2]; + int32_t stride; + int32_t shift; + int32_t base_size[2]; + int32_t pad[2]; + }; + + CanvasSdfShaderRD shader; + RID shader_version; + RID pipelines[SHADER_MAX]; + } rt_sdf; /* GLOBAL SHADER VARIABLES */ @@ -1085,7 +1246,7 @@ private: void _update_global_variables(); /* EFFECTS */ - RasterizerEffectsRD effects; + EffectsRD effects; public: /* TEXTURE API */ @@ -1185,7 +1346,7 @@ public: virtual void canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter); virtual void canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat); - bool canvas_texture_get_unifom_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular); + bool canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular); /* SHADER API */ @@ -1200,6 +1361,8 @@ public: Variant shader_get_param_default(RID p_shader, const StringName &p_param) const; void shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function); + virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const; + /* COMMON MATERIAL API */ RID material_create(); @@ -1217,11 +1380,16 @@ public: void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters); - void material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance); + void material_update_dependency(RID p_material, DependencyTracker *p_instance); void material_force_update_textures(RID p_material, ShaderType p_shader_type); void material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function); + _FORCE_INLINE_ uint32_t material_get_shader_id(RID p_material) { + Material *material = material_owner.getornull(p_material); + return material->shader_id; + } + _FORCE_INLINE_ MaterialData *material_get_data(RID p_material, ShaderType p_shader_type) { Material *material = material_owner.getornull(p_material); if (!material || material->shader_type != p_shader_type) { @@ -1235,6 +1403,8 @@ public: virtual RID mesh_create(); + virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count); + /// Return stride virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface); @@ -1256,9 +1426,20 @@ public: virtual AABB mesh_get_custom_aabb(RID p_mesh) const; virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()); + virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh); virtual void mesh_clear(RID p_mesh); + virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton); + + /* MESH INSTANCE */ + + virtual RID mesh_instance_create(RID p_base); + virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton); + virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight); + virtual void mesh_instance_check_for_update(RID p_mesh_instance); + virtual void update_mesh_instances(); + _FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, nullptr); @@ -1266,7 +1447,7 @@ public: if (r_surface_count == 0) { return nullptr; } - if (mesh->material_cache.empty()) { + if (mesh->material_cache.is_empty()) { mesh->material_cache.resize(mesh->surface_count); for (uint32_t i = 0; i < r_surface_count; i++) { mesh->material_cache.write[i] = mesh->surfaces[i]->material; @@ -1276,22 +1457,57 @@ public: return mesh->material_cache.ptr(); } - _FORCE_INLINE_ RS::PrimitiveType mesh_surface_get_primitive(RID p_mesh, uint32_t p_surface_index) { + _FORCE_INLINE_ void *mesh_get_surface(RID p_mesh, uint32_t p_surface_index) { Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, RS::PRIMITIVE_MAX); - ERR_FAIL_UNSIGNED_INDEX_V(p_surface_index, mesh->surface_count, RS::PRIMITIVE_MAX); + ERR_FAIL_COND_V(!mesh, nullptr); + ERR_FAIL_UNSIGNED_INDEX_V(p_surface_index, mesh->surface_count, nullptr); - return mesh->surfaces[p_surface_index]->primitive; + return mesh->surfaces[p_surface_index]; } - _FORCE_INLINE_ void mesh_surface_get_arrays_and_format(RID p_mesh, uint32_t p_surface_index, uint32_t p_input_mask, RID &r_vertex_array_rd, RID &r_index_array_rd, RD::VertexFormatID &r_vertex_format) { + _FORCE_INLINE_ RID mesh_get_shadow_mesh(RID p_mesh) { Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!mesh); - ERR_FAIL_UNSIGNED_INDEX(p_surface_index, mesh->surface_count); + ERR_FAIL_COND_V(!mesh, RID()); - Mesh::Surface *s = mesh->surfaces[p_surface_index]; + return mesh->shadow_mesh; + } + + _FORCE_INLINE_ RS::PrimitiveType mesh_surface_get_primitive(void *p_surface) { + Mesh::Surface *surface = reinterpret_cast<Mesh::Surface *>(p_surface); + return surface->primitive; + } + + _FORCE_INLINE_ bool mesh_surface_has_lod(void *p_surface) const { + Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); + return s->lod_count > 0; + } - r_index_array_rd = s->index_array; + _FORCE_INLINE_ RID mesh_surface_get_index_array(void *p_surface) const { + Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); + + return s->index_array; + } + + _FORCE_INLINE_ RID mesh_surface_get_index_array_with_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_lod_threshold) const { + Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); + + int32_t current_lod = -1; + for (uint32_t i = 0; i < s->lod_count; i++) { + float screen_size = s->lods[i].edge_length * p_model_scale / p_distance_threshold; + if (screen_size > p_lod_threshold) { + break; + } + current_lod = i; + } + if (current_lod == -1) { + return s->index_array; + } else { + return s->lods[current_lod].index_array; + } + } + + _FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint32_t p_input_mask, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { + Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); s->version_lock.lock(); @@ -1308,9 +1524,11 @@ public: return; } - uint32_t version = s->version_count; //gets added at the end + uint32_t version = s->version_count; + s->version_count++; + s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count); - _mesh_surface_generate_version_for_input_mask(s, p_input_mask); + _mesh_surface_generate_version_for_input_mask(s->versions[version], s, p_input_mask); r_vertex_format = s->versions[version].vertex_format; r_vertex_array_rd = s->versions[version].vertex_array; @@ -1318,6 +1536,42 @@ public: s->version_lock.unlock(); } + _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { + MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance); + ERR_FAIL_COND(!mi); + Mesh *mesh = mi->mesh; + ERR_FAIL_UNSIGNED_INDEX(p_surface_index, mesh->surface_count); + + MeshInstance::Surface *mis = &mi->surfaces[p_surface_index]; + Mesh::Surface *s = mesh->surfaces[p_surface_index]; + + s->version_lock.lock(); + + //there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way + + for (uint32_t i = 0; i < mis->version_count; i++) { + if (mis->versions[i].input_mask != p_input_mask) { + continue; + } + //we have this version, hooray + r_vertex_format = mis->versions[i].vertex_format; + r_vertex_array_rd = mis->versions[i].vertex_array; + s->version_lock.unlock(); + return; + } + + uint32_t version = mis->version_count; + mis->version_count++; + mis->versions = (Mesh::Surface::Version *)memrealloc(mis->versions, sizeof(Mesh::Surface::Version) * mis->version_count); + + _mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, mis); + + r_vertex_format = mis->versions[version].vertex_format; + r_vertex_array_rd = mis->versions[version].vertex_array; + + s->version_lock.unlock(); + } + _FORCE_INLINE_ RID mesh_get_default_rd_buffer(DefaultRDBuffer p_buffer) { ERR_FAIL_INDEX_V(p_buffer, DEFAULT_RD_BUFFER_MAX, RID()); return mesh_default_rd_buffers[p_buffer]; @@ -1418,7 +1672,7 @@ public: if (!multimesh->uniform_set_3d.is_valid()) { Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(multimesh->buffer); uniforms.push_back(u); @@ -1456,6 +1710,10 @@ public: void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform); Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const; + _FORCE_INLINE_ bool skeleton_is_valid(RID p_skeleton) { + return skeleton_owner.getornull(p_skeleton) != nullptr; + } + _FORCE_INLINE_ RID skeleton_get_3d_uniform_set(RID p_skeleton, RID p_shader, uint32_t p_set) const { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND_V(!skeleton, RID()); @@ -1466,7 +1724,7 @@ public: if (!skeleton->uniform_set_3d.is_valid()) { Vector<RD::Uniform> uniforms; RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(skeleton->buffer); uniforms.push_back(u); @@ -1499,6 +1757,8 @@ public: void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode); void light_directional_set_blend_splits(RID p_light, bool p_enable); bool light_directional_get_blend_splits(RID p_light) const; + void light_directional_set_sky_only(RID p_light, bool p_sky_only); + bool light_directional_is_sky_only(RID p_light) const; void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode); RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const; @@ -1597,6 +1857,7 @@ public: void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable); void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers); void reflection_probe_set_resolution(RID p_probe, int p_resolution); + void reflection_probe_set_lod_threshold(RID p_probe, float p_ratio); AABB reflection_probe_get_aabb(RID p_probe) const; RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const; @@ -1604,6 +1865,8 @@ public: Vector3 reflection_probe_get_extents(RID p_probe) const; Vector3 reflection_probe_get_origin_offset(RID p_probe) const; float reflection_probe_get_origin_max_distance(RID p_probe) const; + float reflection_probe_get_lod_threshold(RID p_probe) const; + int reflection_probe_get_resolution(RID p_probe) const; bool reflection_probe_renders_shadows(RID p_probe) const; @@ -1614,8 +1877,8 @@ public: Color reflection_probe_get_ambient_color(RID p_probe) const; float reflection_probe_get_ambient_color_energy(RID p_probe) const; - void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance); - void skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance); + void base_update_dependency(RID p_base, DependencyTracker *p_instance); + void skeleton_update_dependency(RID p_skeleton, DependencyTracker *p_instance); /* DECAL API */ @@ -1764,7 +2027,11 @@ public: _FORCE_INLINE_ float lightmap_get_probe_capture_update_speed() const { return lightmap_probe_capture_update_speed; } - + _FORCE_INLINE_ RID lightmap_get_texture(RID p_lightmap) const { + const Lightmap *lm = lightmap_owner.getornull(p_lightmap); + ERR_FAIL_COND_V(!lm, RID()); + return lm->light_texture; + } _FORCE_INLINE_ int32_t lightmap_get_array_index(RID p_lightmap) const { ERR_FAIL_COND_V(!using_lightmap_array, -1); //only for arrays const Lightmap *lm = lightmap_owner.getornull(p_lightmap); @@ -1853,7 +2120,7 @@ public: { RD::Uniform u; - u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 0; u.ids.push_back(particles->particle_instance_buffer); uniforms.push_back(u); @@ -1865,8 +2132,8 @@ public: return particles->particles_transforms_buffer_uniform_set; } - virtual void particles_add_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance); - virtual void particles_remove_collision(RID p_particles, RasterizerScene::InstanceBase *p_instance); + virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance); + virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance); /* PARTICLES COLLISION */ @@ -1886,6 +2153,11 @@ public: virtual bool particles_collision_is_heightfield(RID p_particles_collision) const; RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const; + //used from 2D and 3D + virtual RID particles_collision_instance_create(RID p_collision); + virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform); + virtual void particles_collision_instance_set_active(RID p_collision_instance, bool p_active); + /* GLOBAL VARIABLES API */ virtual void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value); @@ -1929,6 +2201,12 @@ public: virtual void render_target_disable_clear_request(RID p_render_target); virtual void render_target_do_clear_request(RID p_render_target); + virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale); + RID render_target_get_sdf_texture(RID p_render_target); + RID render_target_get_sdf_framebuffer(RID p_render_target); + void render_target_sdf_process(RID p_render_target); + virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const; + Size2 render_target_get_size(RID p_render_target); RID render_target_get_rd_framebuffer(RID p_render_target); RID render_target_get_rd_texture(RID p_render_target); @@ -1969,12 +2247,12 @@ public: RID get_default_rd_storage_buffer() { return default_rd_storage_buffer; } - static RasterizerStorageRD *base_singleton; + static RendererStorageRD *base_singleton; - RasterizerEffectsRD *get_effects(); + EffectsRD *get_effects(); - RasterizerStorageRD(); - ~RasterizerStorageRD(); + RendererStorageRD(); + ~RendererStorageRD(); }; #endif // RASTERIZER_STORAGE_RD_H diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp index 0a0c343e57..e77141b26c 100644 --- a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp +++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,9 +30,9 @@ #include "shader_compiler_rd.h" +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" -#include "rasterizer_storage_rd.h" +#include "renderer_storage_rd.h" #include "servers/rendering_server.h" #define SL ShaderLanguage @@ -671,7 +671,6 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } /* for(Map<StringName,SL::ShaderNode::Uniform>::Element *E=pnode->uniforms.front();E;E=E->next()) { - if (SL::is_sampler_type(E->get().type)) { continue; } @@ -921,7 +920,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge if (adnode->datatype == SL::TYPE_STRUCT) { declaration += _mkid(adnode->struct_name); } else { - declaration = _prestr(adnode->precision) + _typestr(adnode->datatype); + declaration += _prestr(adnode->precision) + _typestr(adnode->datatype); } for (int i = 0; i < adnode->declarations.size(); i++) { if (i > 0) { @@ -931,7 +930,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } declaration += _mkid(adnode->declarations[i].name); declaration += "["; - declaration += itos(adnode->declarations[i].size); + if (adnode->size_expression != nullptr) { + declaration += _dump_node_code(adnode->size_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + } else { + declaration += itos(adnode->declarations[i].size); + } declaration += "]"; int sz = adnode->declarations[i].initializer.size(); if (sz > 0) { @@ -987,12 +990,13 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge if (anode->call_expression != nullptr) { code += "."; code += _dump_node_code(anode->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning, false); - } - - if (anode->index_expression != nullptr) { + } else if (anode->index_expression != nullptr) { code += "["; code += _dump_node_code(anode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += "]"; + } else if (anode->assign_expression != nullptr) { + code += "="; + code += _dump_node_code(anode->assign_expression, p_level, r_gen_code, p_actions, p_default_actions, true, false); } if (anode->name == time_name) { @@ -1073,6 +1077,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } else if (onode->op == SL::OP_CONSTRUCT) { code += String(vnode->name); } else { + if (p_actions.usage_flag_pointers.has(vnode->name) && !used_flag_pointers.has(vnode->name)) { + *p_actions.usage_flag_pointers[vnode->name] = true; + used_flag_pointers.insert(vnode->name); + } + if (internal_functions.has(vnode->name)) { code += vnode->name; is_texture_func = texture_functions.has(vnode->name); @@ -1225,8 +1234,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge code += "["; code += _dump_node_code(mnode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += "]"; + } else if (mnode->assign_expression != nullptr) { + code += "="; + code += _dump_node_code(mnode->assign_expression, p_level, r_gen_code, p_actions, p_default_actions, true, false); } - } break; } @@ -1234,7 +1245,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } ShaderLanguage::DataType ShaderCompilerRD::_get_variable_type(const StringName &p_type) { - RS::GlobalVariableType gvt = ((RasterizerStorageRD *)(RasterizerStorage::base_singleton))->global_variable_get_type_internal(p_type); + RS::GlobalVariableType gvt = ((RendererStorageRD *)(RendererStorage::base_singleton))->global_variable_get_type_internal(p_type); return RS::global_variable_type_get_shader_datatype(gvt); } @@ -1329,8 +1340,8 @@ ShaderCompilerRD::ShaderCompilerRD() { actions[RS::SHADER_SPATIAL].renames["FRAGCOORD"] = "gl_FragCoord"; actions[RS::SHADER_SPATIAL].renames["FRONT_FACING"] = "gl_FrontFacing"; - actions[RS::SHADER_SPATIAL].renames["NORMALMAP"] = "normalmap"; - actions[RS::SHADER_SPATIAL].renames["NORMALMAP_DEPTH"] = "normaldepth"; + actions[RS::SHADER_SPATIAL].renames["NORMAL_MAP"] = "normal_map"; + actions[RS::SHADER_SPATIAL].renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; actions[RS::SHADER_SPATIAL].renames["ALBEDO"] = "albedo"; actions[RS::SHADER_SPATIAL].renames["ALPHA"] = "alpha"; actions[RS::SHADER_SPATIAL].renames["METALLIC"] = "metallic"; @@ -1376,8 +1387,8 @@ ShaderCompilerRD::ShaderCompilerRD() { actions[RS::SHADER_SPATIAL].usage_defines["AO_LIGHT_AFFECT"] = "#define ENABLE_AO\n"; actions[RS::SHADER_SPATIAL].usage_defines["UV"] = "#define ENABLE_UV_INTERP\n"; actions[RS::SHADER_SPATIAL].usage_defines["UV2"] = "#define ENABLE_UV2_INTERP\n"; - actions[RS::SHADER_SPATIAL].usage_defines["NORMALMAP"] = "#define ENABLE_NORMALMAP\n"; - actions[RS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP"; + actions[RS::SHADER_SPATIAL].usage_defines["NORMAL_MAP"] = "#define ENABLE_NORMAL_MAP\n"; + actions[RS::SHADER_SPATIAL].usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP"; actions[RS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n"; actions[RS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; actions[RS::SHADER_SPATIAL].usage_defines["ALPHA_SCISSOR"] = "#define ALPHA_SCISSOR_USED\n"; diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.h b/servers/rendering/renderer_rd/shader_compiler_rd.h index 565520ec65..d127d8e01c 100644 --- a/servers/rendering/rasterizer_rd/shader_compiler_rd.h +++ b/servers/rendering/renderer_rd/shader_compiler_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,7 +31,7 @@ #ifndef SHADER_COMPILER_RD_H #define SHADER_COMPILER_RD_H -#include "core/pair.h" +#include "core/templates/pair.h" #include "servers/rendering/shader_language.h" #include "servers/rendering/shader_types.h" #include "servers/rendering_server.h" diff --git a/servers/rendering/rasterizer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index 8c57651263..2ae22a8a38 100644 --- a/servers/rendering/rasterizer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,8 +30,8 @@ #include "shader_rd.h" -#include "core/string_builder.h" -#include "rasterizer_rd.h" +#include "core/string/string_builder.h" +#include "renderer_compositor_rd.h" #include "servers/rendering/rendering_device.h" void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name) { @@ -199,6 +199,10 @@ void ShaderRD::_clear_version(Version *p_version) { } void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { + if (!variants_enabled[p_variant]) { + return; //variant is disabled, return + } + Vector<RD::ShaderStageData> stages; String error; @@ -347,6 +351,127 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { } } +RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_version) { + Version *version = version_owner.getornull(p_version); + RS::ShaderNativeSourceCode source_code; + ERR_FAIL_COND_V(!version, source_code); + + source_code.versions.resize(variant_defines.size()); + + for (int i = 0; i < source_code.versions.size(); i++) { + if (!is_compute) { + //vertex stage + + StringBuilder builder; + + builder.append(vertex_codev.get_data()); // version info (if exists) + builder.append("\n"); //make sure defines begin at newline + builder.append(general_defines.get_data()); + builder.append(variant_defines[i].get_data()); + + for (int j = 0; j < version->custom_defines.size(); j++) { + builder.append(version->custom_defines[j].get_data()); + } + + builder.append(vertex_code0.get_data()); //first part of vertex + + builder.append(version->uniforms.get_data()); //uniforms (same for vertex and fragment) + + builder.append(vertex_code1.get_data()); //second part of vertex + + builder.append(version->vertex_globals.get_data()); // vertex globals + + builder.append(vertex_code2.get_data()); //third part of vertex + + builder.append(version->vertex_code.get_data()); // code + + builder.append(vertex_code3.get_data()); //fourth of vertex + + RS::ShaderNativeSourceCode::Version::Stage stage; + stage.name = "vertex"; + stage.code = builder.as_string(); + + source_code.versions.write[i].stages.push_back(stage); + } + + if (!is_compute) { + //fragment stage + + StringBuilder builder; + + builder.append(fragment_codev.get_data()); // version info (if exists) + builder.append("\n"); //make sure defines begin at newline + + builder.append(general_defines.get_data()); + builder.append(variant_defines[i].get_data()); + for (int j = 0; j < version->custom_defines.size(); j++) { + builder.append(version->custom_defines[j].get_data()); + } + + builder.append(fragment_code0.get_data()); //first part of fragment + + builder.append(version->uniforms.get_data()); //uniforms (same for fragment and fragment) + + builder.append(fragment_code1.get_data()); //first part of fragment + + builder.append(version->fragment_globals.get_data()); // fragment globals + + builder.append(fragment_code2.get_data()); //third part of fragment + + builder.append(version->fragment_light.get_data()); // fragment light + + builder.append(fragment_code3.get_data()); //fourth part of fragment + + builder.append(version->fragment_code.get_data()); // fragment code + + builder.append(fragment_code4.get_data()); //fourth part of fragment + + RS::ShaderNativeSourceCode::Version::Stage stage; + stage.name = "fragment"; + stage.code = builder.as_string(); + + source_code.versions.write[i].stages.push_back(stage); + } + + if (is_compute) { + //compute stage + + StringBuilder builder; + + builder.append(compute_codev.get_data()); // version info (if exists) + builder.append("\n"); //make sure defines begin at newline + builder.append(general_defines.get_data()); + builder.append(variant_defines[i].get_data()); + + for (int j = 0; j < version->custom_defines.size(); j++) { + builder.append(version->custom_defines[j].get_data()); + } + + builder.append(compute_code0.get_data()); //first part of compute + + builder.append(version->uniforms.get_data()); //uniforms (same for compute and fragment) + + builder.append(compute_code1.get_data()); //second part of compute + + builder.append(version->compute_globals.get_data()); // compute globals + + builder.append(compute_code2.get_data()); //third part of compute + + builder.append(version->compute_code.get_data()); // code + + builder.append(compute_code3.get_data()); //fourth of compute + + RS::ShaderNativeSourceCode::Version::Stage stage; + stage.name = "compute"; + stage.code = builder.as_string(); + + source_code.versions.write[i].stages.push_back(stage); + } + } + + return source_code; +} + void ShaderRD::_compile_version(Version *p_version) { _clear_version(p_version); @@ -356,7 +481,7 @@ void ShaderRD::_compile_version(Version *p_version) { p_version->variants = memnew_arr(RID, variant_defines.size()); #if 1 - RasterizerRD::thread_work_pool.do_work(variant_defines.size(), this, &ShaderRD::_compile_variant, p_version); + RendererThreadPool::singleton->thread_work_pool.do_work(variant_defines.size(), this, &ShaderRD::_compile_variant, p_version); #else for (int i = 0; i < variant_defines.size(); i++) { _compile_variant(i, p_version); @@ -365,6 +490,9 @@ void ShaderRD::_compile_version(Version *p_version) { bool all_valid = true; for (int i = 0; i < variant_defines.size(); i++) { + if (!variants_enabled[i]) { + continue; //disabled + } if (p_version->variants[i].is_null()) { all_valid = false; break; @@ -374,6 +502,9 @@ void ShaderRD::_compile_version(Version *p_version) { if (!all_valid) { //clear versions if they exist for (int i = 0; i < variant_defines.size(); i++) { + if (!variants_enabled[i]) { + continue; //disabled + } if (!p_version->variants[i].is_null()) { RD::get_singleton()->free(p_version->variants[i]); } @@ -454,12 +585,26 @@ bool ShaderRD::version_free(RID p_version) { return true; } +void ShaderRD::set_variant_enabled(int p_variant, bool p_enabled) { + ERR_FAIL_COND(version_owner.get_rid_count() > 0); //versions exist + ERR_FAIL_INDEX(p_variant, variants_enabled.size()); + variants_enabled.write[p_variant] = p_enabled; +} + +bool ShaderRD::is_variant_enabled(int p_variant) const { + ERR_FAIL_INDEX_V(p_variant, variants_enabled.size(), false); + return variants_enabled[p_variant]; +} + void ShaderRD::initialize(const Vector<String> &p_variant_defines, const String &p_general_defines) { ERR_FAIL_COND(variant_defines.size()); ERR_FAIL_COND(p_variant_defines.size() == 0); + general_defines = p_general_defines.utf8(); + for (int i = 0; i < p_variant_defines.size(); i++) { variant_defines.push_back(p_variant_defines[i].utf8()); + variants_enabled.push_back(true); } } diff --git a/servers/rendering/rasterizer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h index d9bb068ba6..a3474c6f93 100644 --- a/servers/rendering/rasterizer_rd/shader_rd.h +++ b/servers/rendering/renderer_rd/shader_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,11 +31,12 @@ #ifndef SHADER_RD_H #define SHADER_RD_H -#include "core/hash_map.h" -#include "core/map.h" #include "core/os/mutex.h" -#include "core/rid_owner.h" -#include "core/variant.h" +#include "core/templates/hash_map.h" +#include "core/templates/map.h" +#include "core/templates/rid_owner.h" +#include "core/variant/variant.h" +#include "servers/rendering_server.h" #include <stdio.h> /** @@ -46,6 +47,7 @@ class ShaderRD { //versions CharString general_defines; Vector<CharString> variant_defines; + Vector<bool> variants_enabled; struct Version { CharString uniforms; @@ -109,6 +111,7 @@ public: _FORCE_INLINE_ RID version_get_shader(RID p_version, int p_variant) { ERR_FAIL_INDEX_V(p_variant, variant_defines.size(), RID()); + ERR_FAIL_COND_V(!variants_enabled[p_variant], RID()); Version *version = version_owner.getornull(p_version); ERR_FAIL_COND_V(!version, RID()); @@ -128,6 +131,11 @@ public: bool version_free(RID p_version); + void set_variant_enabled(int p_variant, bool p_enabled); + bool is_variant_enabled(int p_variant) const; + + RS::ShaderNativeSourceCode version_get_native_source_code(RID p_version); + void initialize(const Vector<String> &p_variant_defines, const String &p_general_defines = ""); virtual ~ShaderRD(); }; diff --git a/servers/rendering/rasterizer_rd/shaders/SCsub b/servers/rendering/renderer_rd/shaders/SCsub index 9d531d63ad..1b0197c1c1 100644 --- a/servers/rendering/rasterizer_rd/shaders/SCsub +++ b/servers/rendering/renderer_rd/shaders/SCsub @@ -5,12 +5,13 @@ Import("env") if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("canvas.glsl") env.RD_GLSL("canvas_occlusion.glsl") + env.RD_GLSL("canvas_sdf.glsl") env.RD_GLSL("copy.glsl") env.RD_GLSL("copy_to_fb.glsl") env.RD_GLSL("cubemap_roughness.glsl") env.RD_GLSL("cubemap_downsampler.glsl") env.RD_GLSL("cubemap_filter.glsl") - env.RD_GLSL("scene_high_end.glsl") + env.RD_GLSL("scene_forward.glsl") env.RD_GLSL("sky.glsl") env.RD_GLSL("tonemap.glsl") env.RD_GLSL("cube_to_dp.glsl") @@ -20,8 +21,10 @@ if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("luminance_reduce.glsl") env.RD_GLSL("bokeh_dof.glsl") env.RD_GLSL("ssao.glsl") - env.RD_GLSL("ssao_minify.glsl") + env.RD_GLSL("ssao_downsample.glsl") + env.RD_GLSL("ssao_importance_map.glsl") env.RD_GLSL("ssao_blur.glsl") + env.RD_GLSL("ssao_interleave.glsl") env.RD_GLSL("roughness_limiter.glsl") env.RD_GLSL("screen_space_reflection.glsl") env.RD_GLSL("screen_space_reflection_filter.glsl") @@ -40,3 +43,7 @@ if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("particles.glsl") env.RD_GLSL("particles_copy.glsl") env.RD_GLSL("sort.glsl") + env.RD_GLSL("skeleton.glsl") + env.RD_GLSL("cluster_render.glsl") + env.RD_GLSL("cluster_store.glsl") + env.RD_GLSL("cluster_debug.glsl") diff --git a/servers/rendering/rasterizer_rd/shaders/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl index 63f086a83d..63f086a83d 100644 --- a/servers/rendering/rasterizer_rd/shaders/bokeh_dof.glsl +++ b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index b382c0d85f..3b39edc70e 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -9,7 +9,8 @@ layout(location = 0) in vec2 vertex_attrib; layout(location = 3) in vec4 color_attrib; layout(location = 4) in vec2 uv_attrib; -layout(location = 6) in uvec4 bones_attrib; +layout(location = 10) in uvec4 bone_attrib; +layout(location = 11) in vec4 weight_attrib; #endif @@ -61,6 +62,7 @@ void main() { color = vec4(unpackHalf2x16(draw_data.colors[4]), unpackHalf2x16(draw_data.colors[5])); } uvec4 bones = uvec4(0, 0, 0, 0); + vec4 bone_weights = vec4(0.0); #elif defined(USE_ATTRIBUTES) @@ -68,7 +70,8 @@ void main() { vec4 color = color_attrib; vec2 uv = uv_attrib; - uvec4 bones = bones_attrib; + uvec4 bones = bone_attrib; + vec4 bone_weights = weight_attrib; #else vec2 vertex_base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); @@ -233,6 +236,30 @@ MATERIAL_UNIFORMS } material; #endif +vec2 screen_uv_to_sdf(vec2 p_uv) { + return canvas_data.screen_to_sdf * p_uv; +} + +float texture_sdf(vec2 p_sdf) { + vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw; + float d = texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv).r; + d = d * SDF_MAX_LENGTH - 1.0; + return d * canvas_data.tex_to_sdf; +} + +vec2 texture_sdf_normal(vec2 p_sdf) { + vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw; + + const float EPSILON = 0.001; + return normalize(vec2( + texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv + vec2(EPSILON, 0.0)).r - texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv - vec2(EPSILON, 0.0)).r, + texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv + vec2(0.0, EPSILON)).r - texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv - vec2(0.0, EPSILON)).r)); +} + +vec2 sdf_to_screen_uv(vec2 p_sdf) { + return p_sdf * canvas_data.sdf_to_screen; +} + /* clang-format off */ FRAGMENT_SHADER_GLOBALS /* clang-format on */ @@ -249,7 +276,7 @@ vec4 light_compute( inout vec4 shadow_modulate, vec2 screen_uv, vec2 uv, - vec4 color) { + vec4 color, bool is_directional) { vec4 light = vec4(0.0); /* clang-format off */ LIGHT_SHADER_CODE @@ -302,6 +329,99 @@ float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, flo #endif +#ifdef USE_LIGHTING + +vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 light_color, vec4 specular_shininess, bool specular_shininess_used) { + float cNdotL = max(0.0, dot(normal, light_vec)); + + if (specular_shininess_used) { + //blinn + vec3 view = vec3(0.0, 0.0, 1.0); // not great but good enough + vec3 half_vec = normalize(view + light_vec); + + float cNdotV = max(dot(normal, view), 0.0); + float cNdotH = max(dot(normal, half_vec), 0.0); + float cVdotH = max(dot(view, half_vec), 0.0); + float cLdotH = max(dot(light_vec, half_vec), 0.0); + float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25; + float blinn = pow(cNdotH, shininess); + blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); + float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); + + return specular_shininess.rgb * light_color * s + light_color * base_color * cNdotL; + } else { + return light_color * base_color * cNdotL; + } +} + +//float distance = length(shadow_pos); +vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv +#ifdef LIGHT_SHADER_CODE_USED + , + vec3 shadow_modulate +#endif +) { + float shadow; + uint shadow_mode = light_array.data[light_base].flags & LIGHT_FLAGS_FILTER_MASK; + + if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) { + shadow = textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x; + } else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) { + vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0); + shadow = 0.0; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x; + shadow /= 5.0; + } else { //PCF13 + vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0); + shadow = 0.0; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 6.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 5.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 4.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 3.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 3.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 4.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 5.0, 0.0).x; + shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 6.0, 0.0).x; + shadow /= 13.0; + } + + vec4 shadow_color = unpackUnorm4x8(light_array.data[light_base].shadow_color); +#ifdef LIGHT_SHADER_CODE_USED + shadow_color.rgb *= shadow_modulate; +#endif + + shadow_color.a *= light_color.a; //respect light alpha + + return mix(light_color, shadow_color, shadow); +} + +void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) { + uint blend_mode = light_array.data[light_base].flags & LIGHT_FLAGS_BLEND_MASK; + + switch (blend_mode) { + case LIGHT_FLAGS_BLEND_MODE_ADD: { + color.rgb += light_color.rgb * light_color.a; + } break; + case LIGHT_FLAGS_BLEND_MODE_SUB: { + color.rgb -= light_color.rgb * light_color.a; + } break; + case LIGHT_FLAGS_BLEND_MODE_MIX: { + color.rgb = mix(color.rgb, light_color.rgb, light_color.a); + } break; + } +} + +#endif + void main() { vec4 color = color_interp; vec2 uv = uv_interp; @@ -332,6 +452,7 @@ void main() { color *= texture(sampler2D(color_texture, texture_sampler), uv); uint light_count = (draw_data.flags >> FLAGS_LIGHT_COUNT_SHIFT) & 0xF; //max 16 lights + bool using_light = light_count > 0 || canvas_data.directional_light_count > 0; vec3 normal; @@ -341,7 +462,7 @@ void main() { bool normal_used = false; #endif - if (normal_used || (light_count > 0 && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) { + if (normal_used || (using_light && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) { normal.xy = texture(sampler2D(normal_texture, texture_sampler), uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); normal_used = true; @@ -358,7 +479,7 @@ void main() { bool specular_shininess_used = false; #endif - if (specular_shininess_used || (light_count > 0 && normal_used && bool(draw_data.flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) { + 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_used = true; @@ -376,9 +497,9 @@ void main() { vec2 shadow_vertex = vertex; { - float normal_depth = 1.0; + float normal_map_depth = 1.0; -#if defined(NORMALMAP_USED) +#if defined(NORMAL_MAP_USED) vec3 normal_map = vec3(0.0, 0.0, 1.0); normal_used = true; #endif @@ -389,8 +510,8 @@ FRAGMENT_SHADER_CODE /* clang-format on */ -#if defined(NORMALMAP_USED) - normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_depth); +#if defined(NORMAL_MAP_USED) + normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_map_depth); #endif } @@ -401,13 +522,57 @@ FRAGMENT_SHADER_CODE normal = normalize((canvas_data.canvas_normal_transform * vec4(normal, 0.0)).xyz); } - vec4 base_color = color; + vec3 base_color = color.rgb; if (bool(draw_data.flags & FLAGS_USING_LIGHT_MASK)) { color = vec4(0.0); //invisible by default due to using light mask } +#ifdef MODE_LIGHT_ONLY + color = vec4(0.0); +#else color *= canvas_data.canvas_modulation; -#ifdef USE_LIGHTING +#endif + +#if defined(USE_LIGHTING) && !defined(MODE_UNSHADED) + + // Directional Lights + + for (uint i = 0; i < canvas_data.directional_light_count; i++) { + uint light_base = i; + + vec2 direction = light_array.data[light_base].position; + vec4 light_color = light_array.data[light_base].color; + +#ifdef LIGHT_SHADER_CODE_USED + + vec4 shadow_modulate = vec4(1.0); + light_color = light_compute(light_vertex, vec3(direction, light_array.data[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, true); +#else + + if (normal_used) { + vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_array.data[light_base].height)); + light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used); + } +#endif + + if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) { + vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations. + + vec4 shadow_uv = vec4(shadow_pos.x, light_array.data[light_base].shadow_y_ofs, shadow_pos.y * light_array.data[light_base].shadow_zfar_inv, 1.0); + + light_color = light_shadow_compute(light_base, light_color, shadow_uv +#ifdef LIGHT_SHADER_CODE_USED + , + shadow_modulate.rgb +#endif + ); + } + + light_blend_compute(light_base, light_color, color.rgb); + } + + // Positional Lights + for (uint i = 0; i < MAX_LIGHTS_PER_ITEM; i++) { if (i >= light_count) { break; @@ -440,7 +605,7 @@ FRAGMENT_SHADER_CODE vec3 light_position = vec3(light_array.data[light_base].position, light_array.data[light_base].height); light_color.rgb *= light_base_color.rgb; - light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, color, uv); + light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, false); #else light_color.rgb *= light_base_color.rgb * light_base_color.a; @@ -451,24 +616,7 @@ FRAGMENT_SHADER_CODE vec3 light_vec = normalize(light_pos - pos); float cNdotL = max(0.0, dot(normal, light_vec)); - if (specular_shininess_used) { - //blinn - vec3 view = vec3(0.0, 0.0, 1.0); // not great but good enough - vec3 half_vec = normalize(view + light_vec); - - float cNdotV = max(dot(normal, view), 0.0); - float cNdotH = max(dot(normal, half_vec), 0.0); - float cVdotH = max(dot(view, half_vec), 0.0); - float cLdotH = max(dot(light_vec, half_vec), 0.0); - float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25; - float blinn = pow(cNdotH, shininess); - blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); - - light_color.rgb = specular_shininess.rgb * light_base_color.rgb * s + light_color.rgb * cNdotL; - } else { - light_color.rgb *= cNdotL; - } + light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used); } #endif if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) { @@ -506,69 +654,17 @@ FRAGMENT_SHADER_CODE distance *= light_array.data[light_base].shadow_zfar_inv; //float distance = length(shadow_pos); - float shadow; - uint shadow_mode = light_array.data[light_base].flags & LIGHT_FLAGS_FILTER_MASK; - vec4 shadow_uv = vec4(tex_ofs, light_array.data[light_base].shadow_y_ofs, distance, 1.0); - if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) { - shadow = textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x; - } else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) { - vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0); - shadow = 0.0; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x; - shadow /= 5.0; - } else { //PCF13 - vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0); - shadow = 0.0; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 6.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 5.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 4.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 3.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 3.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 4.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 5.0, 0.0).x; - shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 6.0, 0.0).x; - shadow /= 13.0; - } - - vec4 shadow_color = unpackUnorm4x8(light_array.data[light_base].shadow_color); + light_color = light_shadow_compute(light_base, light_color, shadow_uv #ifdef LIGHT_SHADER_CODE_USED - shadow_color *= shadow_modulate; + , + shadow_modulate.rgb #endif - - shadow_color.a *= light_color.a; //respect light alpha - - light_color = mix(light_color, shadow_color, shadow); - //light_color = mix(light_color, shadow_color, shadow); + ); } - uint blend_mode = light_array.data[light_base].flags & LIGHT_FLAGS_BLEND_MASK; - - switch (blend_mode) { - case LIGHT_FLAGS_BLEND_MODE_ADD: { - color.rgb += light_color.rgb * light_color.a; - } break; - case LIGHT_FLAGS_BLEND_MODE_SUB: { - color.rgb -= light_color.rgb * light_color.a; - } break; - case LIGHT_FLAGS_BLEND_MODE_MIX: { - color.rgb = mix(color.rgb, light_color.rgb, light_color.a); - } break; - case LIGHT_FLAGS_BLEND_MODE_MASK: { - light_color.a *= base_color.a; - color.rgb = mix(color.rgb, light_color.rgb, light_color.a); - } break; - } + light_blend_compute(light_base, light_color, color.rgb); } #endif diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl b/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl index 421282cd4d..5c25235c58 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl @@ -2,6 +2,8 @@ #version 450 +VERSION_DEFINES + layout(location = 0) in highp vec3 vertex; layout(push_constant, binding = 0, std430) uniform Constants { @@ -13,12 +15,16 @@ layout(push_constant, binding = 0, std430) uniform Constants { } constants; +#ifdef MODE_SHADOW layout(location = 0) out highp float depth; +#endif void main() { highp vec4 vtx = vec4(vertex, 1.0) * mat4(constants.modelview[0], constants.modelview[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); - depth = dot(constants.direction, vtx.xy); +#ifdef MODE_SHADOW + depth = dot(constants.direction, vtx.xy); +#endif gl_Position = constants.projection * vtx; } @@ -26,6 +32,8 @@ void main() { #version 450 +VERSION_DEFINES + layout(push_constant, binding = 0, std430) uniform Constants { mat4 projection; mat2x4 modelview; @@ -35,9 +43,17 @@ layout(push_constant, binding = 0, std430) uniform Constants { } constants; +#ifdef MODE_SHADOW layout(location = 0) in highp float depth; layout(location = 0) out highp float distance_buf; +#else +layout(location = 0) out highp float sdf_buf; +#endif void main() { +#ifdef MODE_SHADOW distance_buf = depth / constants.z_far; +#else + sdf_buf = 1.0; +#endif } diff --git a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl new file mode 100644 index 0000000000..302ad03b41 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl @@ -0,0 +1,135 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(r8, set = 0, binding = 1) uniform restrict readonly image2D src_pixels; +layout(r16, set = 0, binding = 2) uniform restrict writeonly image2D dst_sdf; + +layout(rg16i, set = 0, binding = 3) uniform restrict readonly iimage2D src_process; +layout(rg16i, set = 0, binding = 4) uniform restrict writeonly iimage2D dst_process; + +layout(push_constant, binding = 0, std430) uniform Params { + ivec2 size; + int stride; + int shift; + ivec2 base_size; + uvec2 pad; +} +params; + +#define SDF_MAX_LENGTH 16384.0 + +void main() { + ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(pos, params.size))) { //too large, do nothing + return; + } + +#ifdef MODE_LOAD + + bool solid = imageLoad(src_pixels, pos).r > 0.5; + imageStore(dst_process, pos, solid ? ivec4(pos, 0, 0) : ivec4(ivec2(32767), 0, 0)); +#endif + +#ifdef MODE_LOAD_SHRINK + + int s = 1 << params.shift; + ivec2 base = pos << params.shift; + ivec2 center = base + ivec2(params.shift); + + ivec2 rel = ivec2(32767); + float d = 1e20; + for (int i = 0; i < s; i++) { + for (int j = 0; j < s; j++) { + ivec2 src_pos = base + ivec2(i, j); + if (any(greaterThanEqual(src_pos, params.base_size))) { + continue; + } + bool solid = imageLoad(src_pixels, src_pos).r > 0.5; + if (solid) { + float dist = length(vec2(src_pos - center)); + if (dist < d) { + d = dist; + rel = src_pos; + } + } + } + } + + imageStore(dst_process, pos, ivec4(rel, 0, 0)); +#endif + +#ifdef MODE_PROCESS + + ivec2 base = pos << params.shift; + ivec2 center = base + ivec2(params.shift); + + ivec2 rel = imageLoad(src_process, pos).xy; + + if (center != rel) { + //only process if it does not point to itself + const int ofs_table_size = 8; + const ivec2 ofs_table[ofs_table_size] = ivec2[]( + ivec2(-1, -1), + ivec2(0, -1), + ivec2(+1, -1), + + ivec2(-1, 0), + ivec2(+1, 0), + + ivec2(-1, +1), + ivec2(0, +1), + ivec2(+1, +1)); + + float dist = length(vec2(rel - center)); + for (int i = 0; i < ofs_table_size; i++) { + ivec2 src_pos = pos + ofs_table[i] * params.stride; + if (any(lessThan(src_pos, ivec2(0))) || any(greaterThanEqual(src_pos, params.size))) { + continue; + } + ivec2 src_rel = imageLoad(src_process, src_pos).xy; + float src_dist = length(vec2(src_rel - center)); + if (src_dist < dist) { + dist = src_dist; + rel = src_rel; + } + } + } + + imageStore(dst_process, pos, ivec4(rel, 0, 0)); +#endif + +#ifdef MODE_STORE + + ivec2 rel = imageLoad(src_process, pos).xy; + float d = length(vec2(rel - pos)); + if (d > 0.01) { + d += 1.0; //make it signed + } + d /= SDF_MAX_LENGTH; + d = clamp(d, 0.0, 1.0); + imageStore(dst_sdf, pos, vec4(d)); + +#endif + +#ifdef MODE_STORE_SHRINK + + ivec2 base = pos << params.shift; + ivec2 center = base + ivec2(params.shift); + + ivec2 rel = imageLoad(src_process, pos).xy; + float d = length(vec2(rel - center)); + + if (d > 0.01) { + d += 1.0; //make it signed + } + d /= SDF_MAX_LENGTH; + d = clamp(d, 0.0, 1.0); + imageStore(dst_sdf, pos, vec4(d)); + +#endif +} diff --git a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl index 1a226a87d3..cf7678ea31 100644 --- a/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl @@ -3,6 +3,8 @@ #define M_PI 3.14159265359 +#define SDF_MAX_LENGTH 16384.0 + #define FLAGS_INSTANCING_STRIDE_MASK 0xF #define FLAGS_INSTANCING_ENABLED (1 << 4) #define FLAGS_INSTANCING_HAS_COLORS (1 << 5) @@ -24,6 +26,19 @@ #define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 26) #define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27) +#define SAMPLER_NEAREST_CLAMP 0 +#define SAMPLER_LINEAR_CLAMP 1 +#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2 +#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5 +#define SAMPLER_NEAREST_REPEAT 6 +#define SAMPLER_LINEAR_REPEAT 7 +#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8 +#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 + // Push Constant layout(push_constant, binding = 0, std430) uniform DrawData { @@ -68,7 +83,14 @@ layout(set = 0, binding = 1, std140) uniform CanvasData { float time; bool use_pixel_snap; - //uint light_count; + vec4 sdf_to_tex; + vec2 screen_to_sdf; + vec2 sdf_to_screen; + + uint directional_light_count; + float tex_to_sdf; + uint pad1; + uint pad2; } canvas_data; @@ -112,10 +134,11 @@ layout(set = 0, binding = 4) uniform texture2D shadow_atlas_texture; layout(set = 0, binding = 5) uniform sampler shadow_sampler; layout(set = 0, binding = 6) uniform texture2D screen_texture; +layout(set = 0, binding = 7) uniform texture2D sdf_texture; -layout(set = 0, binding = 7) uniform sampler material_samplers[12]; +layout(set = 0, binding = 8) uniform sampler material_samplers[12]; -layout(set = 0, binding = 8, std430) restrict readonly buffer GlobalVariableData { +layout(set = 0, binding = 9, std430) restrict readonly buffer GlobalVariableData { vec4 data[]; } global_variables; diff --git a/servers/rendering/rasterizer_rd/shaders/cluster_data_inc.glsl b/servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl index e723468dd8..3a4bf4da07 100644 --- a/servers/rendering/rasterizer_rd/shaders/cluster_data_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl @@ -6,12 +6,18 @@ struct LightData { //this structure needs to be as packed as possible vec3 position; float inv_radius; + vec3 direction; float size; - uint attenuation_energy; //attenuation - uint color_specular; //rgb color, a specular (8 bit unorm) - uint cone_attenuation_angle; // attenuation and angle, (16bit float) - uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm) + + vec3 color; + float attenuation; + + float cone_attenuation; + float cone_angle; + float specular_amount; + bool shadow_enabled; + vec4 atlas_rect; // rect in the shadow atlas mat4 shadow_matrix; float shadow_bias; @@ -34,9 +40,13 @@ struct ReflectionData { float index; vec3 box_offset; uint mask; - vec4 params; // intensity, 0, interior , boxproject vec3 ambient; // ambient color + float intensity; + bool exterior; + bool box_project; uint ambient_mode; + uint pad; + //0-8 is intensity,8-9 is ambient, mode mat4 local_matrix; // up to here for spot and omni, rest is for directional // notes: for ambientblend, use distance to edge to blend between already existing global environment }; diff --git a/servers/rendering/renderer_rd/shaders/cluster_debug.glsl b/servers/rendering/renderer_rd/shaders/cluster_debug.glsl new file mode 100644 index 0000000000..70a875192c --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/cluster_debug.glsl @@ -0,0 +1,115 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +const vec3 usage_gradient[33] = vec3[]( // 1 (none) + 32 + vec3(0.14, 0.17, 0.23), + vec3(0.24, 0.44, 0.83), + vec3(0.23, 0.57, 0.84), + vec3(0.22, 0.71, 0.84), + vec3(0.22, 0.85, 0.83), + vec3(0.21, 0.85, 0.72), + vec3(0.21, 0.85, 0.57), + vec3(0.20, 0.85, 0.42), + vec3(0.20, 0.85, 0.27), + vec3(0.27, 0.86, 0.19), + vec3(0.51, 0.85, 0.19), + vec3(0.57, 0.86, 0.19), + vec3(0.62, 0.85, 0.19), + vec3(0.67, 0.86, 0.20), + vec3(0.73, 0.85, 0.20), + vec3(0.78, 0.85, 0.20), + vec3(0.83, 0.85, 0.20), + vec3(0.85, 0.82, 0.20), + vec3(0.85, 0.76, 0.20), + vec3(0.85, 0.81, 0.20), + vec3(0.85, 0.65, 0.20), + vec3(0.84, 0.60, 0.21), + vec3(0.84, 0.56, 0.21), + vec3(0.84, 0.51, 0.21), + vec3(0.84, 0.46, 0.21), + vec3(0.84, 0.41, 0.21), + vec3(0.84, 0.36, 0.21), + vec3(0.84, 0.31, 0.21), + vec3(0.84, 0.27, 0.21), + vec3(0.83, 0.22, 0.22), + vec3(0.83, 0.22, 0.27), + vec3(0.83, 0.22, 0.32), + vec3(1.00, 0.63, 0.70)); +layout(push_constant, binding = 0, std430) uniform Params { + uvec2 screen_size; + uvec2 cluster_screen_size; + + uint cluster_shift; + uint cluster_type; + float z_near; + float z_far; + + bool orthogonal; + uint max_cluster_element_count_div_32; + uint pad1; + uint pad2; +} +params; + +layout(set = 0, binding = 1, std430) buffer restrict readonly ClusterData { + uint data[]; +} +cluster_data; + +layout(rgba16f, set = 0, binding = 2) uniform restrict writeonly image2D screen_buffer; +layout(set = 0, binding = 3) uniform texture2D depth_buffer; +layout(set = 0, binding = 4) uniform sampler depth_buffer_sampler; + +void main() { + uvec2 screen_pos = gl_GlobalInvocationID.xy; + if (any(greaterThanEqual(screen_pos, params.screen_size))) { + return; + } + + uvec2 cluster_pos = screen_pos >> params.cluster_shift; + + uint offset = cluster_pos.y * params.cluster_screen_size.x + cluster_pos.x; + offset += params.cluster_screen_size.x * params.cluster_screen_size.y * params.cluster_type; + offset *= (params.max_cluster_element_count_div_32 + 32); + + //depth buffers generally can't be accessed via image API + float depth = texelFetch(sampler2D(depth_buffer, depth_buffer_sampler), ivec2(screen_pos), 0).r * 2.0 - 1.0; + + if (params.orthogonal) { + depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + } else { + depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); + } + depth /= params.z_far; + + uint slice = uint(clamp(floor(depth * 32.0), 0.0, 31.0)); + uint slice_minmax = cluster_data.data[offset + params.max_cluster_element_count_div_32 + slice]; + uint item_min = slice_minmax & 0xFFFF; + uint item_max = slice_minmax >> 16; + + uint item_count = 0; + for (uint i = 0; i < params.max_cluster_element_count_div_32; i++) { + uint slice_bits = cluster_data.data[offset + i]; + while (slice_bits != 0) { + uint bit = findLSB(slice_bits); + uint item = i * 32 + bit; + if ((item >= item_min && item < item_max)) { + item_count++; + } + slice_bits &= ~(1 << bit); + } + } + + item_count = min(item_count, 32); + + vec3 color = usage_gradient[item_count]; + + color = mix(color * 1.2, color * 0.3, float(slice) / 31.0); + + imageStore(screen_buffer, ivec2(screen_pos), vec4(color, 1.0)); +} diff --git a/servers/rendering/renderer_rd/shaders/cluster_render.glsl b/servers/rendering/renderer_rd/shaders/cluster_render.glsl new file mode 100644 index 0000000000..8723ea78e4 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/cluster_render.glsl @@ -0,0 +1,168 @@ +#[vertex] + +#version 450 + +VERSION_DEFINES + +layout(location = 0) in vec3 vertex_attrib; + +layout(location = 0) out float depth_interp; +layout(location = 1) out flat uint element_index; + +layout(push_constant, binding = 0, std430) uniform Params { + uint base_index; + uint pad0; + uint pad1; + uint pad2; +} +params; + +layout(set = 0, binding = 1, std140) uniform State { + mat4 projection; + + float inv_z_far; + uint screen_to_clusters_shift; // shift to obtain coordinates in block indices + uint cluster_screen_width; // + uint cluster_data_size; // how much data for a single cluster takes + + uint cluster_depth_offset; + uint pad0; + uint pad1; + uint pad2; +} +state; + +struct RenderElement { + uint type; //0-4 + bool touches_near; + bool touches_far; + uint original_index; + mat3x4 transform_inv; + vec3 scale; + uint pad; +}; + +layout(set = 0, binding = 2, std430) buffer restrict readonly RenderElements { + RenderElement data[]; +} +render_elements; + +void main() { + element_index = params.base_index + gl_InstanceIndex; + + vec3 vertex = vertex_attrib; + vertex *= render_elements.data[element_index].scale; + + vertex = vec4(vertex, 1.0) * render_elements.data[element_index].transform_inv; + depth_interp = -vertex.z; + + gl_Position = state.projection * vec4(vertex, 1.0); +} + +#[fragment] + +#version 450 + +VERSION_DEFINES + +#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic) && defined(GL_KHR_shader_subgroup_vote) + +#extension GL_KHR_shader_subgroup_ballot : enable +#extension GL_KHR_shader_subgroup_arithmetic : enable +#extension GL_KHR_shader_subgroup_vote : enable + +#define USE_SUBGROUPS +#endif + +layout(location = 0) in float depth_interp; +layout(location = 1) in flat uint element_index; + +layout(set = 0, binding = 1, std140) uniform State { + mat4 projection; + float inv_z_far; + uint screen_to_clusters_shift; // shift to obtain coordinates in block indices + uint cluster_screen_width; // + uint cluster_data_size; // how much data for a single cluster takes + uint cluster_depth_offset; + uint pad0; + uint pad1; + uint pad2; +} +state; + +//cluster data is layout linearly, each cell contains the follow information: +// - list of bits for every element to mark as used, so (max_elem_count/32)*4 uints +// - a uint for each element to mark the depth bits used when rendering (0-31) + +layout(set = 0, binding = 3, std430) buffer restrict ClusterRender { + uint data[]; +} +cluster_render; + +void main() { + //convert from screen to cluster + uvec2 cluster = uvec2(gl_FragCoord.xy) >> state.screen_to_clusters_shift; + + //get linear cluster offset from screen poss + uint cluster_offset = cluster.x + state.cluster_screen_width * cluster.y; + //multiply by data size to position at the beginning of the element list for this cluster + cluster_offset *= state.cluster_data_size; + + //find the current element in the list and plot the bit to mark it as used + uint usage_write_offset = cluster_offset + (element_index >> 5); + uint usage_write_bit = 1 << (element_index & 0x1F); + +#ifdef USE_SUBGROUPS + + uint cluster_thread_group_index; + + if (!gl_HelperInvocation) { + //http://advances.realtimerendering.com/s2017/2017_Sig_Improved_Culling_final.pdf + + uvec4 mask; + + while (true) { + // find the cluster offset of the first active thread + // threads that did break; go inactive and no longer count + uint first = subgroupBroadcastFirst(cluster_offset); + // update the mask for thread that match this cluster + mask = subgroupBallot(first == cluster_offset); + if (first == cluster_offset) { + // This thread belongs to the group of threads that match this offset, + // so exit the loop. + break; + } + } + + cluster_thread_group_index = subgroupBallotExclusiveBitCount(mask); + + if (cluster_thread_group_index == 0) { + atomicOr(cluster_render.data[usage_write_offset], usage_write_bit); + } + } +#else + if (!gl_HelperInvocation) { + atomicOr(cluster_render.data[usage_write_offset], usage_write_bit); + } +#endif + //find the current element in the depth usage list and mark the current depth as used + float unit_depth = depth_interp * state.inv_z_far; + + uint z_bit = clamp(uint(floor(unit_depth * 32.0)), 0, 31); + + uint z_write_offset = cluster_offset + state.cluster_depth_offset + element_index; + uint z_write_bit = 1 << z_bit; + +#ifdef USE_SUBGROUPS + if (!gl_HelperInvocation) { + z_write_bit = subgroupOr(z_write_bit); //merge all Zs + if (cluster_thread_group_index == 0) { + atomicOr(cluster_render.data[z_write_offset], z_write_bit); + } + } +#else + if (!gl_HelperInvocation) { + atomicOr(cluster_render.data[z_write_offset], z_write_bit); + } +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/cluster_store.glsl b/servers/rendering/renderer_rd/shaders/cluster_store.glsl new file mode 100644 index 0000000000..5be0893c4f --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/cluster_store.glsl @@ -0,0 +1,119 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(push_constant, binding = 0, std430) uniform Params { + uint cluster_render_data_size; // how much data for a single cluster takes + uint max_render_element_count_div_32; //divided by 32 + uvec2 cluster_screen_size; + uint render_element_count_div_32; //divided by 32 + + uint max_cluster_element_count_div_32; //divided by 32 + uint pad1; + uint pad2; +} +params; + +layout(set = 0, binding = 1, std430) buffer restrict readonly ClusterRender { + uint data[]; +} +cluster_render; + +layout(set = 0, binding = 2, std430) buffer restrict ClusterStore { + uint data[]; +} +cluster_store; + +struct RenderElement { + uint type; //0-4 + bool touches_near; + bool touches_far; + uint original_index; + mat3x4 transform_inv; + vec3 scale; + uint pad; +}; + +layout(set = 0, binding = 3, std430) buffer restrict readonly RenderElements { + RenderElement data[]; +} +render_elements; + +void main() { + uvec2 pos = gl_GlobalInvocationID.xy; + if (any(greaterThanEqual(pos, params.cluster_screen_size))) { + return; + } + + //counter for each type of render_element + + //base offset for this cluster + uint base_offset = (pos.x + params.cluster_screen_size.x * pos.y); + uint src_offset = base_offset * params.cluster_render_data_size; + + uint render_element_offset = 0; + + //check all render_elements and see which one was written to + while (render_element_offset < params.render_element_count_div_32) { + uint bits = cluster_render.data[src_offset + render_element_offset]; + while (bits != 0) { + //if bits exist, check the render_element + uint index_bit = findLSB(bits); + uint index = render_element_offset * 32 + index_bit; + uint type = render_elements.data[index].type; + + uint z_range_offset = src_offset + params.max_render_element_count_div_32 + index; + uint z_range = cluster_render.data[z_range_offset]; + + //if object was written, z was written, but check just in case + if (z_range != 0) { //should always be > 0 + + uint from_z = findLSB(z_range); + uint to_z = findMSB(z_range) + 1; + + if (render_elements.data[index].touches_near) { + from_z = 0; + } + + if (render_elements.data[index].touches_far) { + to_z = 32; + } + + // find cluster offset in the buffer used for indexing in the renderer + uint dst_offset = (base_offset + type * (params.cluster_screen_size.x * params.cluster_screen_size.y)) * (params.max_cluster_element_count_div_32 + 32); + + uint orig_index = render_elements.data[index].original_index; + //store this index in the Z slices by setting the relevant bit + for (uint i = from_z; i < to_z; i++) { + uint slice_ofs = dst_offset + params.max_cluster_element_count_div_32 + i; + + uint minmax = cluster_store.data[slice_ofs]; + + if (minmax == 0) { + minmax = 0xFFFF; //min 0, max 0xFFFF + } + + uint elem_min = min(orig_index, minmax & 0xFFFF); + uint elem_max = max(orig_index + 1, minmax >> 16); //always store plus one, so zero means range is empty when not written to + + minmax = elem_min | (elem_max << 16); + cluster_store.data[slice_ofs] = minmax; + } + + uint store_word = orig_index >> 5; + uint store_bit = orig_index & 0x1F; + + //store the actual render_element index at the end, so the rendering code can reference it + cluster_store.data[dst_offset + store_word] |= 1 << store_bit; + } + + bits &= ~(1 << index_bit); //clear the bit to continue iterating + } + + render_element_offset++; + } +} diff --git a/servers/rendering/rasterizer_rd/shaders/copy.glsl b/servers/rendering/renderer_rd/shaders/copy.glsl index cdd35dfb3f..cdd35dfb3f 100644 --- a/servers/rendering/rasterizer_rd/shaders/copy.glsl +++ b/servers/rendering/renderer_rd/shaders/copy.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl b/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl index 9751e13b4e..9751e13b4e 100644 --- a/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl +++ b/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl index 54d67db6c6..c3ac0bee57 100644 --- a/servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl +++ b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl @@ -1,33 +1,48 @@ -#[compute] +#[vertex] #version 450 VERSION_DEFINES -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; +layout(push_constant, binding = 1, std430) uniform Params { + float z_far; + float z_near; + bool z_flip; + uint pad; + vec4 screen_rect; +} +params; + +layout(location = 0) out vec2 uv_interp; + +void main() { + vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); + uv_interp = base_arr[gl_VertexIndex]; + vec2 screen_pos = uv_interp * params.screen_rect.zw + params.screen_rect.xy; + gl_Position = vec4(screen_pos * 2.0 - 1.0, 0.0, 1.0); +} + +#[fragment] + +#version 450 + +VERSION_DEFINES + +layout(location = 0) in vec2 uv_interp; layout(set = 0, binding = 0) uniform samplerCube source_cube; layout(push_constant, binding = 1, std430) uniform Params { - ivec2 screen_size; - ivec2 offset; - float bias; float z_far; float z_near; bool z_flip; + uint pad; + vec4 screen_rect; } params; -layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D depth_buffer; - void main() { - ivec2 pos = ivec2(gl_GlobalInvocationID.xy); - if (any(greaterThan(pos, params.screen_size))) { //too large, do nothing - return; - } - - vec2 pixel_size = 1.0 / vec2(params.screen_size); - vec2 uv = (vec2(pos) + 0.5) * pixel_size; + vec2 uv = uv_interp; vec3 normal = vec3(uv * 2.0 - 1.0, 0.0); @@ -65,5 +80,5 @@ void main() { float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); depth = (linear_depth * depth_fix) / params.z_far; - imageStore(depth_buffer, pos + params.offset, vec4(depth)); + gl_FragDepth = depth; } diff --git a/servers/rendering/rasterizer_rd/shaders/cubemap_downsampler.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl index 7f269b7af3..7f269b7af3 100644 --- a/servers/rendering/rasterizer_rd/shaders/cubemap_downsampler.glsl +++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/cubemap_filter.glsl b/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl index 987545fb76..987545fb76 100644 --- a/servers/rendering/rasterizer_rd/shaders/cubemap_filter.glsl +++ b/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/cubemap_roughness.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl index 5cbb00baa4..5cbb00baa4 100644 --- a/servers/rendering/rasterizer_rd/shaders/cubemap_roughness.glsl +++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/gi.glsl b/servers/rendering/renderer_rd/shaders/gi.glsl index 8011dadc72..35522103df 100644 --- a/servers/rendering/rasterizer_rd/shaders/gi.glsl +++ b/servers/rendering/renderer_rd/shaders/gi.glsl @@ -97,13 +97,12 @@ layout(push_constant, binding = 0, std430) uniform Params { vec4 proj_info; + vec3 ao_color; uint max_giprobes; + bool high_quality_vct; - bool use_sdfgi; bool orthogonal; - - vec3 ao_color; - uint pad; + uint pad[2]; mat3x4 cam_rotation; } @@ -331,7 +330,7 @@ void sdfgi_process(vec3 vertex, vec3 normal, vec3 reflection, float roughness, o } ambient_light.rgb = diffuse; -#if 1 + if (roughness < 0.2) { vec3 pos_to_uvw = 1.0 / sdfgi.grid_size; vec4 light_accum = vec4(0.0); @@ -363,7 +362,6 @@ void sdfgi_process(vec3 vertex, vec3 normal, vec3 reflection, float roughness, o //ray_pos += ray_dir * (bias / sdfgi.cascades[cascade].to_cell); //bias to avoid self occlusion ray_pos += (ray_dir * 1.0 / max(abs_ray_dir.x, max(abs_ray_dir.y, abs_ray_dir.z)) + cam_normal * 1.4) * bias / sdfgi.cascades[cascade].to_cell; } - float softness = 0.2 + min(1.0, roughness * 5.0) * 4.0; //approximation to roughness so it does not seem like a hard fade while (length(ray_pos) < max_distance) { for (uint i = 0; i < sdfgi.max_cascades; i++) { @@ -434,8 +432,6 @@ void sdfgi_process(vec3 vertex, vec3 normal, vec3 reflection, float roughness, o } } -#endif - reflection_light.rgb = specular; ambient_light.rgb *= sdfgi.energy; @@ -597,35 +593,24 @@ vec4 fetch_normal_and_roughness(ivec2 pos) { return normal_roughness; } -void main() { - // Pixel being shaded - ivec2 pos = ivec2(gl_GlobalInvocationID.xy); - if (any(greaterThanEqual(pos, params.screen_size))) { //too large, do nothing - return; - } - - vec3 vertex = reconstruct_position(pos); - vertex.y = -vertex.y; - +void process_gi(ivec2 pos, vec3 vertex, inout vec4 ambient_light, inout vec4 reflection_light) { vec4 normal_roughness = fetch_normal_and_roughness(pos); - vec3 normal = normal_roughness.xyz; - vec4 ambient_light = vec4(0.0), reflection_light = vec4(0.0); + vec3 normal = normal_roughness.xyz; if (normal.length() > 0.5) { //valid normal, can do GI float roughness = normal_roughness.w; - vertex = mat3(params.cam_rotation) * vertex; normal = normalize(mat3(params.cam_rotation) * normal); - vec3 reflection = normalize(reflect(normalize(vertex), normal)); - if (params.use_sdfgi) { - sdfgi_process(vertex, normal, reflection, roughness, ambient_light, reflection_light); - } +#ifdef USE_SDFGI + sdfgi_process(vertex, normal, reflection, roughness, ambient_light, reflection_light); +#endif - if (params.max_giprobes > 0) { +#ifdef USE_GIPROBES + { uvec2 giprobe_tex = texelFetch(usampler2D(giprobe_buffer, linear_sampler), pos, 0).rg; roughness *= roughness; //find arbitrary tangent and bitangent, then build a matrix @@ -648,16 +633,40 @@ void main() { spec_accum /= blend_accum; } - if (params.use_sdfgi) { - reflection_light = blend_color(spec_accum, reflection_light); - ambient_light = blend_color(amb_accum, ambient_light); - } else { - reflection_light = spec_accum; - ambient_light = amb_accum; - } +#ifdef USE_SDFGI + reflection_light = blend_color(spec_accum, reflection_light); + ambient_light = blend_color(amb_accum, ambient_light); +#else + reflection_light = spec_accum; + ambient_light = amb_accum; +#endif } +#endif + } +} + +void main() { + ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + +#ifdef MODE_HALF_RES + pos <<= 1; +#endif + if (any(greaterThanEqual(pos, params.screen_size))) { //too large, do nothing + return; } + vec4 ambient_light = vec4(0.0); + vec4 reflection_light = vec4(0.0); + + vec3 vertex = reconstruct_position(pos); + vertex.y = -vertex.y; + + process_gi(pos, vertex, ambient_light, reflection_light); + +#ifdef MODE_HALF_RES + pos >>= 1; +#endif + imageStore(ambient_buffer, pos, ambient_light); imageStore(reflection_buffer, pos, reflection_light); } diff --git a/servers/rendering/rasterizer_rd/shaders/giprobe.glsl b/servers/rendering/renderer_rd/shaders/giprobe.glsl index ea4237a45e..4f4753d147 100644 --- a/servers/rendering/rasterizer_rd/shaders/giprobe.glsl +++ b/servers/rendering/renderer_rd/shaders/giprobe.glsl @@ -208,6 +208,15 @@ float raymarch(float distance, float distance_adv, vec3 from, vec3 direction) { return occlusion; //max(0.0,distance); } +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} + bool compute_light_vector(uint light, vec3 pos, out float attenuation, out vec3 light_pos) { if (lights.data[light].type == LIGHT_TYPE_DIRECTIONAL) { light_pos = pos - lights.data[light].direction * length(vec3(params.limits)); @@ -220,7 +229,7 @@ bool compute_light_vector(uint light, vec3 pos, out float attenuation, out vec3 return false; } - attenuation = pow(clamp(1.0 - distance / lights.data[light].radius, 0.0001, 1.0), lights.data[light].attenuation); + attenuation = get_omni_attenuation(distance, 1.0 / lights.data[light].radius, lights.data[light].attenuation); if (lights.data[light].type == LIGHT_TYPE_SPOT) { vec3 rel = normalize(pos - light_pos); diff --git a/servers/rendering/rasterizer_rd/shaders/giprobe_debug.glsl b/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl index 515cc35507..515cc35507 100644 --- a/servers/rendering/rasterizer_rd/shaders/giprobe_debug.glsl +++ b/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/giprobe_sdf.glsl b/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl index 5b3dec0ee7..5b3dec0ee7 100644 --- a/servers/rendering/rasterizer_rd/shaders/giprobe_sdf.glsl +++ b/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/giprobe_write.glsl b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl index 9c794f1bcc..9c794f1bcc 100644 --- a/servers/rendering/rasterizer_rd/shaders/giprobe_write.glsl +++ b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/luminance_reduce.glsl b/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl index 8a11c35b78..8a11c35b78 100644 --- a/servers/rendering/rasterizer_rd/shaders/luminance_reduce.glsl +++ b/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl index 926c7ef9fc..cb6d8dc7f6 100644 --- a/servers/rendering/rasterizer_rd/shaders/particles.glsl +++ b/servers/rendering/renderer_rd/shaders/particles.glsl @@ -173,7 +173,7 @@ uint hash(uint x) { return x; } -bool emit_particle(mat4 p_xform, vec3 p_velocity, vec4 p_color, vec4 p_custom, uint p_flags) { +bool emit_subparticle(mat4 p_xform, vec3 p_velocity, vec4 p_color, vec4 p_custom, uint p_flags) { if (!params.can_emit) { return false; } diff --git a/servers/rendering/rasterizer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl index 6c782b6045..6c782b6045 100644 --- a/servers/rendering/rasterizer_rd/shaders/particles_copy.glsl +++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl diff --git a/servers/rendering/renderer_rd/shaders/resolve.glsl b/servers/rendering/renderer_rd/shaders/resolve.glsl new file mode 100644 index 0000000000..e83c4ca93b --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/resolve.glsl @@ -0,0 +1,220 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +#ifdef MODE_RESOLVE_GI +layout(set = 0, binding = 0) uniform sampler2DMS source_depth; +layout(set = 0, binding = 1) uniform sampler2DMS source_normal_roughness; + +layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D dest_depth; +layout(rgba8, set = 1, binding = 1) uniform restrict writeonly image2D dest_normal_roughness; + +#ifdef GIPROBE_RESOLVE +layout(set = 2, binding = 0) uniform usampler2DMS source_giprobe; +layout(rg8ui, set = 3, binding = 0) uniform restrict writeonly uimage2D dest_giprobe; +#endif + +#endif + +layout(push_constant, binding = 16, std430) uniform Params { + ivec2 screen_size; + int sample_count; + uint pad; +} +params; + +void main() { + // Pixel being shaded + ivec2 pos = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(pos, params.screen_size))) { //too large, do nothing + return; + } + +#ifdef MODE_RESOLVE_GI + + float best_depth = 1e20; + vec4 best_normal_roughness = vec4(0.0); +#ifdef GIPROBE_RESOLVE + uvec2 best_giprobe; +#endif + +#if 0 + + for(int i=0;i<params.sample_count;i++) { + float depth = texelFetch(source_depth,pos,i).r; + if (depth < best_depth) { //use the depth closest to camera + best_depth = depth; + best_normal_roughness = texelFetch(source_normal_roughness,pos,i); + +#ifdef GIPROBE_RESOLVE + best_giprobe = texelFetch(source_giprobe,pos,i).rg; +#endif + } + } + +#else + +#if 1 + + vec4 group1; + vec4 group2; + vec4 group3; + vec4 group4; + int best_index = 0; + + //2X + group1.x = texelFetch(source_depth, pos, 0).r; + group1.y = texelFetch(source_depth, pos, 1).r; + + //4X + if (params.sample_count >= 4) { + group1.z = texelFetch(source_depth, pos, 2).r; + group1.w = texelFetch(source_depth, pos, 3).r; + } + //8X + if (params.sample_count >= 8) { + group2.x = texelFetch(source_depth, pos, 4).r; + group2.y = texelFetch(source_depth, pos, 5).r; + group2.z = texelFetch(source_depth, pos, 6).r; + group2.w = texelFetch(source_depth, pos, 7).r; + } + //16X + if (params.sample_count >= 16) { + group3.x = texelFetch(source_depth, pos, 8).r; + group3.y = texelFetch(source_depth, pos, 9).r; + group3.z = texelFetch(source_depth, pos, 10).r; + group3.w = texelFetch(source_depth, pos, 11).r; + + group4.x = texelFetch(source_depth, pos, 12).r; + group4.y = texelFetch(source_depth, pos, 13).r; + group4.z = texelFetch(source_depth, pos, 14).r; + group4.w = texelFetch(source_depth, pos, 15).r; + } + + if (params.sample_count == 2) { + best_index = (pos.x & 1) ^ ((pos.y >> 1) & 1); //not much can be done here + } else if (params.sample_count == 4) { + vec4 freq = vec4(equal(group1, vec4(group1.x))); + freq += vec4(equal(group1, vec4(group1.y))); + freq += vec4(equal(group1, vec4(group1.z))); + freq += vec4(equal(group1, vec4(group1.w))); + + float min_f = freq.x; + best_index = 0; + if (freq.y < min_f) { + best_index = 1; + min_f = freq.y; + } + if (freq.z < min_f) { + best_index = 2; + min_f = freq.z; + } + if (freq.w < min_f) { + best_index = 3; + } + } else if (params.sample_count == 8) { + vec4 freq0 = vec4(equal(group1, vec4(group1.x))); + vec4 freq1 = vec4(equal(group2, vec4(group1.x))); + freq0 += vec4(equal(group1, vec4(group1.y))); + freq1 += vec4(equal(group2, vec4(group1.y))); + freq0 += vec4(equal(group1, vec4(group1.z))); + freq1 += vec4(equal(group2, vec4(group1.z))); + freq0 += vec4(equal(group1, vec4(group1.w))); + freq1 += vec4(equal(group2, vec4(group1.w))); + freq0 += vec4(equal(group1, vec4(group2.x))); + freq1 += vec4(equal(group2, vec4(group2.x))); + freq0 += vec4(equal(group1, vec4(group2.y))); + freq1 += vec4(equal(group2, vec4(group2.y))); + freq0 += vec4(equal(group1, vec4(group2.z))); + freq1 += vec4(equal(group2, vec4(group2.z))); + freq0 += vec4(equal(group1, vec4(group2.w))); + freq1 += vec4(equal(group2, vec4(group2.w))); + + float min_f0 = freq0.x; + int best_index0 = 0; + if (freq0.y < min_f0) { + best_index0 = 1; + min_f0 = freq0.y; + } + if (freq0.z < min_f0) { + best_index0 = 2; + min_f0 = freq0.z; + } + if (freq0.w < min_f0) { + best_index0 = 3; + min_f0 = freq0.w; + } + + float min_f1 = freq1.x; + int best_index1 = 4; + if (freq1.y < min_f1) { + best_index1 = 5; + min_f1 = freq1.y; + } + if (freq1.z < min_f1) { + best_index1 = 6; + min_f1 = freq1.z; + } + if (freq1.w < min_f1) { + best_index1 = 7; + min_f1 = freq1.w; + } + + best_index = mix(best_index0, best_index1, min_f0 < min_f1); + } + +#else + float depths[16]; + int depth_indices[16]; + int depth_amount[16]; + int depth_count = 0; + + for (int i = 0; i < params.sample_count; i++) { + float depth = texelFetch(source_depth, pos, i).r; + int depth_index = -1; + for (int j = 0; j < depth_count; j++) { + if (abs(depths[j] - depth) < 0.000001) { + depth_index = j; + break; + } + } + + if (depth_index == -1) { + depths[depth_count] = depth; + depth_indices[depth_count] = i; + depth_amount[depth_count] = 1; + depth_count += 1; + } else { + depth_amount[depth_index] += 1; + } + } + + int depth_least = 0xFFFF; + int best_index = 0; + for (int j = 0; j < depth_count; j++) { + if (depth_amount[j] < depth_least) { + best_index = depth_indices[j]; + depth_least = depth_amount[j]; + } + } +#endif + best_depth = texelFetch(source_depth, pos, best_index).r; + best_normal_roughness = texelFetch(source_normal_roughness, pos, best_index); +#ifdef GIPROBE_RESOLVE + best_giprobe = texelFetch(source_giprobe, pos, best_index).rg; +#endif + +#endif + + imageStore(dest_depth, pos, vec4(best_depth)); + imageStore(dest_normal_roughness, pos, vec4(best_normal_roughness)); +#ifdef GIPROBE_RESOLVE + imageStore(dest_giprobe, pos, uvec4(best_giprobe, 0, 0)); +#endif + +#endif +} diff --git a/servers/rendering/rasterizer_rd/shaders/roughness_limiter.glsl b/servers/rendering/renderer_rd/shaders/roughness_limiter.glsl index 464895928a..464895928a 100644 --- a/servers/rendering/rasterizer_rd/shaders/roughness_limiter.glsl +++ b/servers/rendering/renderer_rd/shaders/roughness_limiter.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/renderer_rd/shaders/scene_forward.glsl index 455a3d4a3a..ea203c8abe 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward.glsl @@ -4,13 +4,19 @@ VERSION_DEFINES -#include "scene_high_end_inc.glsl" +#include "scene_forward_inc.glsl" /* INPUT ATTRIBS */ layout(location = 0) in vec3 vertex_attrib; + +//only for pure render depth when normal is not used + +#ifdef NORMAL_USED layout(location = 1) in vec3 normal_attrib; -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#endif + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) layout(location = 2) in vec4 tangent_attrib; #endif @@ -18,30 +24,59 @@ layout(location = 2) in vec4 tangent_attrib; layout(location = 3) in vec4 color_attrib; #endif +#ifdef UV_USED layout(location = 4) in vec2 uv_attrib; +#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) || defined(MODE_RENDER_MATERIAL) layout(location = 5) in vec2 uv2_attrib; #endif -layout(location = 6) in uvec4 bone_attrib; // always bound, even if unused +#if defined(CUSTOM0_USED) +layout(location = 6) in vec4 custom0_attrib; +#endif + +#if defined(CUSTOM1_USED) +layout(location = 7) in vec4 custom1_attrib; +#endif + +#if defined(CUSTOM2_USED) +layout(location = 8) in vec4 custom2_attrib; +#endif + +#if defined(CUSTOM3_USED) +layout(location = 9) in vec4 custom3_attrib; +#endif + +#if defined(BONES_USED) +layout(location = 10) in uvec4 bone_attrib; +#endif + +#if defined(WEIGHTS_USED) +layout(location = 11) in vec4 weight_attrib; +#endif /* Varyings */ layout(location = 0) out vec3 vertex_interp; + +#ifdef NORMAL_USED layout(location = 1) out vec3 normal_interp; +#endif #if defined(COLOR_USED) layout(location = 2) out vec4 color_interp; #endif +#ifdef UV_USED layout(location = 3) out vec2 uv_interp; +#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) layout(location = 4) out vec2 uv2_interp; #endif -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) layout(location = 5) out vec3 tangent_interp; layout(location = 6) out vec3 binormal_interp; #endif @@ -62,8 +97,6 @@ VERTEX_SHADER_GLOBALS invariant gl_Position; -layout(location = 7) flat out uint instance_index; - #ifdef MODE_DUAL_PARABOLOID layout(location = 8) out float dp_clip; @@ -71,22 +104,27 @@ layout(location = 8) out float dp_clip; #endif void main() { - instance_index = draw_call.instance_index; vec4 instance_custom = vec4(0.0); #if defined(COLOR_USED) color_interp = color_attrib; #endif - mat4 world_matrix = instances.data[instance_index].transform; - mat3 world_normal_matrix = mat3(instances.data[instance_index].normal_transform); + mat4 world_matrix = draw_call.transform; - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH)) { + mat3 world_normal_matrix; + if (bool(draw_call.flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) { + world_normal_matrix = inverse(mat3(world_matrix)); + } else { + world_normal_matrix = mat3(world_matrix); + } + + if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH)) { //multimesh, instances are for it - uint offset = (instances.data[instance_index].flags >> INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT) & INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK; + uint offset = (draw_call.flags >> INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT) & INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK; offset *= gl_InstanceIndex; mat4 matrix; - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { + if (bool(draw_call.flags & INSTANCE_FLAGS_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 { @@ -94,14 +132,14 @@ void main() { offset += 3; } - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { + if (bool(draw_call.flags & INSTANCE_FLAGS_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 (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { instance_custom = transforms.data[offset]; } @@ -109,22 +147,21 @@ void main() { matrix = transpose(matrix); world_matrix = world_matrix * matrix; world_normal_matrix = world_normal_matrix * mat3(matrix); - - } else { - //not a multimesh, instances are for multiple draw calls - instance_index += gl_InstanceIndex; } vec3 vertex = vertex_attrib; - vec3 normal = normal_attrib; +#ifdef NORMAL_USED + vec3 normal = normal_attrib * 2.0 - 1.0; +#endif -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) - vec3 tangent = tangent_attrib.xyz; - float binormalf = tangent_attrib.a; +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0; + float binormalf = tangent_attrib.a * 2.0 - 1.0; vec3 binormal = normalize(cross(normal, tangent) * binormalf); #endif - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_SKELETON)) { +#if 0 + if (bool(draw_call.flags & INSTANCE_FLAGS_SKELETON)) { //multimesh, instances are for it uvec2 bones_01 = uvec2(bone_attrib.x & 0xFFFF, bone_attrib.x >> 16) * 3; @@ -141,14 +178,17 @@ void main() { vertex = (vec4(vertex, 1.0) * m).xyz; normal = (vec4(normal, 0.0) * m).xyz; -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) tangent = (vec4(tangent, 0.0) * m).xyz; binormal = (vec4(binormal, 0.0) * m).xyz; #endif } +#endif +#ifdef UV_USED uv_interp = uv_attrib; +#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) uv2_interp = uv2_attrib; @@ -167,7 +207,7 @@ void main() { normal = world_normal_matrix * normal; -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) tangent = world_normal_matrix * tangent; binormal = world_normal_matrix * binormal; @@ -192,10 +232,13 @@ VERTEX_SHADER_CODE #if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED) vertex = (modelview * vec4(vertex, 1.0)).xyz; +#ifdef NORMAL_USED normal = modelview_normal * normal; #endif -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#endif + +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) binormal = modelview_normal * binormal; tangent = modelview_normal * tangent; @@ -207,7 +250,7 @@ VERTEX_SHADER_CODE vertex = (scene_data.inv_camera_matrix * vec4(vertex, 1.0)).xyz; normal = mat3(scene_data.inverse_normal_matrix) * normal; -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) binormal = mat3(scene_data.camera_inverse_binormal_matrix) * binormal; tangent = mat3(scene_data.camera_inverse_tangent_matrix) * tangent; @@ -215,9 +258,11 @@ VERTEX_SHADER_CODE #endif vertex_interp = vertex; +#ifdef NORMAL_USED normal_interp = normal; +#endif -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) tangent_interp = tangent; binormal_interp = binormal; #endif @@ -227,7 +272,6 @@ VERTEX_SHADER_CODE #ifdef MODE_DUAL_PARABOLOID vertex_interp.z *= scene_data.dual_paraboloid_side; - normal_interp.z *= scene_data.dual_paraboloid_side; dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias @@ -260,7 +304,7 @@ VERTEX_SHADER_CODE #endif #ifdef MODE_RENDER_MATERIAL if (scene_data.material_uv2_mode) { - gl_Position.xy = (uv2_attrib.xy + draw_call.bake_uv2_offset) * 2.0 - 1.0; + gl_Position.xy = (uv2_attrib.xy + draw_call.lightmap_uv_scale.xy) * 2.0 - 1.0; gl_Position.z = 0.00001; gl_Position.w = 1.0; } @@ -273,30 +317,33 @@ VERTEX_SHADER_CODE VERSION_DEFINES -#include "scene_high_end_inc.glsl" +#include "scene_forward_inc.glsl" /* Varyings */ layout(location = 0) in vec3 vertex_interp; + +#ifdef NORMAL_USED layout(location = 1) in vec3 normal_interp; +#endif #if defined(COLOR_USED) layout(location = 2) in vec4 color_interp; #endif +#ifdef UV_USED layout(location = 3) in vec2 uv_interp; +#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) layout(location = 4) in vec2 uv2_interp; #endif -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) layout(location = 5) in vec3 tangent_interp; layout(location = 6) in vec3 binormal_interp; #endif -layout(location = 7) flat in uint instance_index; - #ifdef MODE_DUAL_PARABOLOID layout(location = 8) in float dp_clip; @@ -305,8 +352,7 @@ layout(location = 8) in float dp_clip; //defines to keep compatibility with vertex -#define world_matrix instances.data[instance_index].transform -#define world_normal_matrix instances.data[instance_index].normal_transform +#define world_matrix draw_call.transform #define projection_matrix scene_data.projection_matrix #if defined(ENABLE_SSS) && defined(ENABLE_TRANSMITTANCE) @@ -361,6 +407,65 @@ layout(location = 0) out vec4 frag_color; #endif // RENDER DEPTH +#ifdef ALPHA_HASH_USED + +float hash_2d(vec2 p) { + return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) * + (0.1 + abs(sin(13.0 * p.y + p.x)))); +} + +float hash_3d(vec3 p) { + return hash_2d(vec2(hash_2d(p.xy), p.z)); +} + +float compute_alpha_hash_threshold(vec3 pos, float hash_scale) { + vec3 dx = dFdx(pos); + vec3 dy = dFdx(pos); + float delta_max_sqr = max(length(dx), length(dy)); + float pix_scale = 1.0 / (hash_scale * delta_max_sqr); + + vec2 pix_scales = + vec2(exp2(floor(log2(pix_scale))), exp2(ceil(log2(pix_scale)))); + + vec2 a_thresh = vec2(hash_3d(floor(pix_scales.x * pos.xyz)), + hash_3d(floor(pix_scales.y * pos.xyz))); + + float lerp_factor = fract(log2(pix_scale)); + + float a_interp = (1.0 - lerp_factor) * a_thresh.x + lerp_factor * a_thresh.y; + + float min_lerp = min(lerp_factor, 1.0 - lerp_factor); + + vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)), + (a_interp - 0.5 * min_lerp) / (1.0 - min_lerp), + 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) / + (2.0 * min_lerp * (1.0 - min_lerp)))); + + float alpha_hash_threshold = + (lerp_factor < (1.0 - min_lerp)) ? ((lerp_factor < min_lerp) ? cases.x : cases.y) : cases.z; + + return clamp(alpha_hash_threshold, 0.0, 1.0); +} + +#endif // ALPHA_HASH_USED + +#ifdef ALPHA_ANTIALIASING_EDGE_USED + +float calc_mip_level(vec2 texture_coord) { + vec2 dx = dFdx(texture_coord); + vec2 dy = dFdy(texture_coord); + float delta_max_sqr = max(dot(dx, dx), dot(dy, dy)); + return max(0.0, 0.5 * log2(delta_max_sqr)); +} + +float compute_alpha_antialiasing_edge(float input_alpha, vec2 texture_coord, float alpha_edge) { + input_alpha *= 1.0 + max(0, calc_mip_level(texture_coord)) * 0.25; // 0.25 mip scale, magic number + input_alpha = (input_alpha - alpha_edge) / max(fwidth(input_alpha), 0.0001) + 0.5; + return clamp(input_alpha, 0.0, 1.0); +} + +#endif // ALPHA_ANTIALIASING_USED + // This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. // We're dividing this factor off because the overall term we'll end up looks like // (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): @@ -436,7 +541,7 @@ vec3 F0(float metallic, float specular, vec3 albedo) { return mix(vec3(dielectric), albedo, vec3(metallic)); } -void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float attenuation, vec3 shadow_attenuation, vec3 diffuse_color, float roughness, float metallic, float specular, float specular_blob_intensity, +void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount, #ifdef LIGHT_BACKLIGHT_USED vec3 backlight, #endif @@ -448,7 +553,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte float transmittance_z, #endif #ifdef LIGHT_RIM_USED - float rim, float rim_tint, + float rim, float rim_tint, vec3 rim_color, #endif #ifdef LIGHT_CLEARCOAT_USED float clearcoat, float clearcoat_gloss, @@ -456,6 +561,9 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte #ifdef LIGHT_ANISOTROPY_USED vec3 B, vec3 T, float anisotropy, #endif +#ifdef USE_SOFT_SHADOWS + float A, +#endif #ifdef USE_SHADOW_TO_OPACITY inout float alpha, #endif @@ -465,7 +573,6 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte // light is written by the light shader vec3 normal = N; - vec3 albedo = diffuse_color; vec3 light = L; vec3 view = V; @@ -476,7 +583,12 @@ LIGHT_SHADER_CODE /* clang-format on */ #else + +#ifdef USE_SOFT_SHADOWS float NdotL = min(A + dot(N, L), 1.0); +#else + float NdotL = dot(N, L); +#endif float cNdotL = max(NdotL, 0.0); // clamped NdotL float NdotV = dot(N, V); float cNdotV = max(NdotV, 0.0); @@ -486,14 +598,25 @@ LIGHT_SHADER_CODE #endif #if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) +#ifdef USE_SOFT_SHADOWS float cNdotH = clamp(A + dot(N, H), 0.0, 1.0); +#else + float cNdotH = clamp(dot(N, H), 0.0, 1.0); +#endif #endif #if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) +#ifdef USE_SOFT_SHADOWS float cLdotH = clamp(A + dot(L, H), 0.0, 1.0); +#else + float cLdotH = clamp(dot(L, H), 0.0, 1.0); +#endif #endif + float metallic = unpackUnorm4x8(orms).z; if (metallic < 1.0) { + float roughness = unpackUnorm4x8(orms).y; + #if defined(DIFFUSE_OREN_NAYAR) vec3 diffuse_brdf_NL; #else @@ -503,23 +626,6 @@ LIGHT_SHADER_CODE #if defined(DIFFUSE_LAMBERT_WRAP) // energy conserving lambert wrap shader diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); - -#elif defined(DIFFUSE_OREN_NAYAR) - - { - // see http://mimosa-pudica.net/improved-oren-nayar.html - float LdotV = dot(L, V); - - float s = LdotV - NdotL * NdotV; - float t = mix(1.0, max(NdotL, NdotV), step(0.0, s)); - - float sigma2 = roughness * roughness; // TODO: this needs checking - vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13)); - float B = 0.45 * sigma2 / (sigma2 + 0.09); - - diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI); - } - #elif defined(DIFFUSE_TOON) diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL); @@ -547,15 +653,15 @@ LIGHT_SHADER_CODE diffuse_brdf_NL = cNdotL * (1.0 / M_PI); #endif - diffuse_light += light_color * diffuse_color * shadow_attenuation * diffuse_brdf_NL * attenuation; + diffuse_light += light_color * diffuse_brdf_NL * attenuation; #if defined(LIGHT_BACKLIGHT_USED) - diffuse_light += light_color * diffuse_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation; + diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation; #endif #if defined(LIGHT_RIM_USED) float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); - diffuse_light += rim_light * rim * mix(vec3(1.0), diffuse_color, rim_tint) * light_color; + diffuse_light += rim_light * rim * mix(vec3(1.0), rim_color, rim_tint) * light_color; #endif #ifdef LIGHT_TRANSMITTANCE_USED @@ -573,7 +679,7 @@ LIGHT_SHADER_CODE vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); - diffuse_light += profile * transmittance_color.a * diffuse_color * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI) * attenuation; + diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI); } #else @@ -583,7 +689,7 @@ LIGHT_SHADER_CODE fade = pow(max(0.0, 1.0 - fade), transmittance_curve); fade *= clamp(transmittance_boost - NdotL, 0.0, 1.0); - diffuse_light += diffuse_color * transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade * attenuation; + diffuse_light += transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade; } #endif //SSS_MODE_SKIN @@ -591,6 +697,7 @@ LIGHT_SHADER_CODE #endif //LIGHT_TRANSMITTANCE_USED } + float roughness = unpackUnorm4x8(orms).y; if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely // D @@ -603,7 +710,7 @@ LIGHT_SHADER_CODE blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); float intensity = blinn; - specular_light += light_color * shadow_attenuation * intensity * specular_blob_intensity * attenuation; + specular_light += light_color * intensity * attenuation * specular_amount; #elif defined(SPECULAR_PHONG) @@ -614,7 +721,7 @@ LIGHT_SHADER_CODE phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); - specular_light += light_color * shadow_attenuation * intensity * specular_blob_intensity * attenuation; + specular_light += light_color * intensity * attenuation * specular_amount; #elif defined(SPECULAR_TOON) @@ -623,7 +730,7 @@ LIGHT_SHADER_CODE float mid = 1.0 - roughness; mid *= mid; float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; - diffuse_light += light_color * shadow_attenuation * intensity * specular_blob_intensity * attenuation; // write to diffuse_light, as in toon shading you generally want no reflection + diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection #elif defined(SPECULAR_DISABLED) // none.. @@ -648,13 +755,12 @@ LIGHT_SHADER_CODE float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); #endif // F - vec3 f0 = F0(metallic, specular, diffuse_color); float cLdotH5 = SchlickFresnel(cLdotH); vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); vec3 specular_brdf_NL = cNdotL * D * F * G; - specular_light += specular_brdf_NL * light_color * shadow_attenuation * specular_blob_intensity * attenuation; + specular_light += specular_brdf_NL * light_color * attenuation * specular_amount; #endif #if defined(LIGHT_CLEARCOAT_USED) @@ -668,12 +774,12 @@ LIGHT_SHADER_CODE float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; - specular_light += clearcoat_specular_brdf_NL * light_color * shadow_attenuation * specular_blob_intensity * attenuation; + specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount; #endif } #ifdef USE_SHADOW_TO_OPACITY - alpha = min(alpha, clamp(1.0 - length(shadow_attenuation * attenuation), 0.0, 1.0)); + alpha = min(alpha, clamp(1.0 - attenuation), 0.0, 1.0)); #endif #endif //defined(USE_LIGHT_SHADER_CODE) @@ -786,70 +892,39 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex #endif //USE_NO_SHADOWS -void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity, -#ifdef LIGHT_BACKLIGHT_USED - vec3 backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - vec4 transmittance_color, - float transmittance_depth, - float transmittance_curve, - float transmittance_boost, -#endif -#ifdef LIGHT_RIM_USED - float rim, float rim_tint, -#endif -#ifdef LIGHT_CLEARCOAT_USED - float clearcoat, float clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - vec3 binormal, vec3 tangent, float anisotropy, -#endif -#ifdef USE_SHADOW_TO_OPACITY - inout float alpha, -#endif - inout vec3 diffuse_light, inout vec3 specular_light) { - - vec3 light_rel_vec = lights.data[idx].position - vertex; - float light_length = length(light_rel_vec); - float normalized_distance = light_length * lights.data[idx].inv_radius; - vec2 attenuation_energy = unpackHalf2x16(lights.data[idx].attenuation_energy); - float omni_attenuation = pow(max(1.0 - normalized_distance, 0.0), attenuation_energy.x); - float light_attenuation = omni_attenuation; - vec3 shadow_attenuation = vec3(1.0); - vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular); - color_specular.rgb *= attenuation_energy.y; - float size_A = 0.0; - - if (lights.data[idx].size > 0.0) { - float t = lights.data[idx].size / max(0.001, light_length); - size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); - } - -#ifdef LIGHT_TRANSMITTANCE_USED - float transmittance_z = transmittance_depth; //no transmittance by default -#endif +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} +float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { #ifndef USE_NO_SHADOWS - vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[idx].shadow_color_enabled); - if (shadow_color_enabled.w > 0.5) { + if (omni_lights.data[idx].shadow_enabled) { // there is a shadowmap + vec3 light_rel_vec = omni_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + vec4 v = vec4(vertex, 1.0); - vec4 splane = (lights.data[idx].shadow_matrix * v); + vec4 splane = (omni_lights.data[idx].shadow_matrix * v); float shadow_len = length(splane.xyz); //need to remember shadow len from here { - vec3 nofs = normal_interp * lights.data[idx].shadow_normal_bias / lights.data[idx].inv_radius; + vec3 nofs = normal_interp * omni_lights.data[idx].shadow_normal_bias / omni_lights.data[idx].inv_radius; nofs *= (1.0 - max(0.0, dot(normalize(light_rel_vec), normalize(normal_interp)))); v.xyz += nofs; - splane = (lights.data[idx].shadow_matrix * v); + splane = (omni_lights.data[idx].shadow_matrix * v); } float shadow; - if (lights.data[idx].soft_shadow_size > 0.0) { +#ifdef USE_SOFT_SHADOWS + if (omni_lights.data[idx].soft_shadow_size > 0.0) { //soft shadow //find blocker @@ -869,10 +944,10 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); vec3 tangent = normalize(cross(v0, normal)); vec3 bitangent = normalize(cross(tangent, normal)); - float z_norm = shadow_len * lights.data[idx].inv_radius; + float z_norm = shadow_len * omni_lights.data[idx].inv_radius; - tangent *= lights.data[idx].soft_shadow_size * lights.data[idx].soft_shadow_scale; - bitangent *= lights.data[idx].soft_shadow_size * lights.data[idx].soft_shadow_scale; + tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; + bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy; @@ -880,7 +955,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; pos = normalize(pos); - vec4 uv_rect = lights.data[idx].atlas_rect; + vec4 uv_rect = omni_lights.data[idx].atlas_rect; if (pos.z >= 0.0) { pos.z += 1.0; @@ -908,7 +983,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v tangent *= penumbra; bitangent *= penumbra; - z_norm -= lights.data[idx].inv_radius * lights.data[idx].shadow_bias; + z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias; shadow = 0.0; for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { @@ -916,7 +991,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y; pos = normalize(pos); - vec4 uv_rect = lights.data[idx].atlas_rect; + vec4 uv_rect = omni_lights.data[idx].atlas_rect; if (pos.z >= 0.0) { pos.z += 1.0; @@ -939,8 +1014,9 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v shadow = 1.0; } } else { +#endif splane.xyz = normalize(splane.xyz); - vec4 clamp_rect = lights.data[idx].atlas_rect; + vec4 clamp_rect = omni_lights.data[idx].atlas_rect; if (splane.z >= 0.0) { splane.z += 1.0; @@ -954,101 +1030,149 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v splane.xy /= splane.z; splane.xy = splane.xy * 0.5 + 0.5; - splane.z = (shadow_len - lights.data[idx].shadow_bias) * lights.data[idx].inv_radius; + splane.z = (shadow_len - omni_lights.data[idx].shadow_bias) * omni_lights.data[idx].inv_radius; splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; splane.w = 1.0; //needed? i think it should be 1 already - shadow = sample_pcf_shadow(shadow_atlas, lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane); + shadow = sample_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane); +#ifdef USE_SOFT_SHADOWS } +#endif + return shadow; + } +#endif + + return 1.0; +} + +void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, +#ifdef LIGHT_BACKLIGHT_USED + vec3 backlight, +#endif #ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 clamp_rect = lights.data[idx].atlas_rect; + vec4 transmittance_color, + float transmittance_depth, + float transmittance_curve, + float transmittance_boost, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, vec3 rim_color, +#endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 binormal, vec3 tangent, float anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + inout float alpha, +#endif + inout vec3 diffuse_light, inout vec3 specular_light) { + vec3 light_rel_vec = omni_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + float omni_attenuation = get_omni_attenuation(light_length, omni_lights.data[idx].inv_radius, omni_lights.data[idx].attenuation); + float light_attenuation = omni_attenuation; + vec3 color = omni_lights.data[idx].color; - //redo shadowmapping, but shrink the model a bit to avoid arctifacts - splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0)); +#ifdef USE_SOFT_SHADOWS + float size_A = 0.0; - shadow_len = length(splane.xyz); - splane = normalize(splane.xyz); + if (omni_lights.data[idx].size > 0.0) { + float t = omni_lights.data[idx].size / max(0.001, light_length); + size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } +#endif - if (splane.z >= 0.0) { - splane.z += 1.0; +#ifdef LIGHT_TRANSMITTANCE_USED + float transmittance_z = transmittance_depth; //no transmittance by default + transmittance_color.a *= light_attenuation; + { + vec4 clamp_rect = omni_lights.data[idx].atlas_rect; - } else { - splane.z = 1.0 - splane.z; - } + //redo shadowmapping, but shrink the model a bit to avoid arctifacts + vec4 splane = (omni_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * omni_lights.data[idx].transmittance_bias, 1.0)); - splane.xy /= splane.z; - splane.xy = splane.xy * 0.5 + 0.5; - splane.z = shadow_len * lights.data[idx].inv_radius; - splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; - splane.w = 1.0; //needed? i think it should be 1 already + shadow_len = length(splane.xyz); + splane = normalize(splane.xyz); - float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; - transmittance_z = (splane.z - shadow_z) / lights.data[idx].inv_radius; + if (splane.z >= 0.0) { + splane.z += 1.0; + + } else { + splane.z = 1.0 - splane.z; } -#endif - vec3 no_shadow = vec3(1.0); + splane.xy /= splane.z; + splane.xy = splane.xy * 0.5 + 0.5; + splane.z = shadow_len * omni_lights.data[idx].inv_radius; + splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + splane.w = 1.0; //needed? i think it should be 1 already - if (lights.data[idx].projector_rect != vec4(0.0)) { - vec3 local_v = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz; - local_v = normalize(local_v); + float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; + transmittance_z = (splane.z - shadow_z) / omni_lights.data[idx].inv_radius; + } +#endif - vec4 atlas_rect = lights.data[idx].projector_rect; +#if 0 - if (local_v.z >= 0.0) { - local_v.z += 1.0; - atlas_rect.y += atlas_rect.w; + if (omni_lights.data[idx].projector_rect != vec4(0.0)) { + vec3 local_v = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz; + local_v = normalize(local_v); - } else { - local_v.z = 1.0 - local_v.z; - } + vec4 atlas_rect = omni_lights.data[idx].projector_rect; - local_v.xy /= local_v.z; - local_v.xy = local_v.xy * 0.5 + 0.5; - vec2 proj_uv = local_v.xy * atlas_rect.zw; + if (local_v.z >= 0.0) { + local_v.z += 1.0; + atlas_rect.y += atlas_rect.w; - vec2 proj_uv_ddx; - vec2 proj_uv_ddy; - { - vec3 local_v_ddx = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz; - local_v_ddx = normalize(local_v_ddx); + } else { + local_v.z = 1.0 - local_v.z; + } - if (local_v_ddx.z >= 0.0) { - local_v_ddx.z += 1.0; - } else { - local_v_ddx.z = 1.0 - local_v_ddx.z; - } + local_v.xy /= local_v.z; + local_v.xy = local_v.xy * 0.5 + 0.5; + vec2 proj_uv = local_v.xy * atlas_rect.zw; - local_v_ddx.xy /= local_v_ddx.z; - local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5; + vec2 proj_uv_ddx; + vec2 proj_uv_ddy; + { + vec3 local_v_ddx = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz; + local_v_ddx = normalize(local_v_ddx); - proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv; + if (local_v_ddx.z >= 0.0) { + local_v_ddx.z += 1.0; + } else { + local_v_ddx.z = 1.0 - local_v_ddx.z; + } - vec3 local_v_ddy = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz; - local_v_ddy = normalize(local_v_ddy); + local_v_ddx.xy /= local_v_ddx.z; + local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5; - if (local_v_ddy.z >= 0.0) { - local_v_ddy.z += 1.0; - } else { - local_v_ddy.z = 1.0 - local_v_ddy.z; - } + proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv; - local_v_ddy.xy /= local_v_ddy.z; - local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5; + vec3 local_v_ddy = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz; + local_v_ddy = normalize(local_v_ddy); - proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv; + if (local_v_ddy.z >= 0.0) { + local_v_ddy.z += 1.0; + } else { + local_v_ddy.z = 1.0 - local_v_ddy.z; } - vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy); - no_shadow = mix(no_shadow, proj.rgb, proj.a); + local_v_ddy.xy /= local_v_ddy.z; + local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5; + + proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv; } - shadow_attenuation = mix(shadow_color_enabled.rgb, no_shadow, shadow); + vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy); + no_shadow = mix(no_shadow, proj.rgb, proj.a); } -#endif //USE_NO_SHADOWS +#endif - light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity, + light_attenuation *= shadow; + + light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1060,7 +1184,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v transmittance_z, #endif #ifdef LIGHT_RIM_USED - rim * omni_attenuation, rim_tint, + rim * omni_attenuation, rim_tint, rim_color, #endif #ifdef LIGHT_CLEARCOAT_USED clearcoat, clearcoat_gloss, @@ -1068,6 +1192,9 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v #ifdef LIGHT_ANISOTROPY_USED binormal, tangent, anisotropy, #endif +#ifdef USE_SOFT_SHADOWS + size_A, +#endif #ifdef USE_SHADOW_TO_OPACITY alpha, #endif @@ -1075,90 +1202,39 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v specular_light); } -void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity, -#ifdef LIGHT_BACKLIGHT_USED - vec3 backlight, -#endif -#ifdef LIGHT_TRANSMITTANCE_USED - vec4 transmittance_color, - float transmittance_depth, - float transmittance_curve, - float transmittance_boost, -#endif -#ifdef LIGHT_RIM_USED - float rim, float rim_tint, -#endif -#ifdef LIGHT_CLEARCOAT_USED - float clearcoat, float clearcoat_gloss, -#endif -#ifdef LIGHT_ANISOTROPY_USED - vec3 binormal, vec3 tangent, float anisotropy, -#endif -#ifdef USE_SHADOW_TO_OPACITY - inout float alpha, -#endif - inout vec3 diffuse_light, - inout vec3 specular_light) { - - vec3 light_rel_vec = lights.data[idx].position - vertex; - float light_length = length(light_rel_vec); - float normalized_distance = light_length * lights.data[idx].inv_radius; - vec2 attenuation_energy = unpackHalf2x16(lights.data[idx].attenuation_energy); - float spot_attenuation = pow(max(1.0 - normalized_distance, 0.001), attenuation_energy.x); - vec3 spot_dir = lights.data[idx].direction; - vec2 spot_att_angle = unpackHalf2x16(lights.data[idx].cone_attenuation_angle); - float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_att_angle.y); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_att_angle.y)); - spot_attenuation *= 1.0 - pow(spot_rim, spot_att_angle.x); - float light_attenuation = spot_attenuation; - vec3 shadow_attenuation = vec3(1.0); - vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular); - color_specular.rgb *= attenuation_energy.y; - - float size_A = 0.0; - - if (lights.data[idx].size > 0.0) { - float t = lights.data[idx].size / max(0.001, light_length); - size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); - } -/* - if (lights.data[idx].atlas_rect!=vec4(0.0)) { - //use projector texture - } - */ -#ifdef LIGHT_TRANSMITTANCE_USED - float transmittance_z = transmittance_depth; -#endif - +float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { #ifndef USE_NO_SHADOWS - vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[idx].shadow_color_enabled); - if (shadow_color_enabled.w > 0.5) { + if (spot_lights.data[idx].shadow_enabled) { + vec3 light_rel_vec = spot_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + vec3 spot_dir = spot_lights.data[idx].direction; //there is a shadowmap vec4 v = vec4(vertex, 1.0); - v.xyz -= spot_dir * lights.data[idx].shadow_bias; + v.xyz -= spot_dir * spot_lights.data[idx].shadow_bias; - float z_norm = dot(spot_dir, -light_rel_vec) * lights.data[idx].inv_radius; + float z_norm = dot(spot_dir, -light_rel_vec) * spot_lights.data[idx].inv_radius; float depth_bias_scale = 1.0 / (max(0.0001, z_norm)); //the closer to the light origin, the more you have to offset to reach 1px in the map - vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * lights.data[idx].shadow_normal_bias * depth_bias_scale; + vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * spot_lights.data[idx].shadow_normal_bias * depth_bias_scale; normal_bias -= spot_dir * dot(spot_dir, normal_bias); //only XY, no Z v.xyz += normal_bias; //adjust with bias - z_norm = dot(spot_dir, v.xyz - lights.data[idx].position) * lights.data[idx].inv_radius; + z_norm = dot(spot_dir, v.xyz - spot_lights.data[idx].position) * spot_lights.data[idx].inv_radius; float shadow; - vec4 splane = (lights.data[idx].shadow_matrix * v); + vec4 splane = (spot_lights.data[idx].shadow_matrix * v); splane /= splane.w; - if (lights.data[idx].soft_shadow_size > 0.0) { +#ifdef USE_SOFT_SHADOWS + if (spot_lights.data[idx].soft_shadow_size > 0.0) { //soft shadow //find blocker - vec2 shadow_uv = splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy; + vec2 shadow_uv = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy; float blocker_count = 0.0; float blocker_average = 0.0; @@ -1171,11 +1247,11 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr)); } - float uv_size = lights.data[idx].soft_shadow_size * z_norm * lights.data[idx].soft_shadow_scale; - vec2 clamp_max = lights.data[idx].atlas_rect.xy + lights.data[idx].atlas_rect.zw; + float uv_size = spot_lights.data[idx].soft_shadow_size * z_norm * spot_lights.data[idx].soft_shadow_scale; + vec2 clamp_max = spot_lights.data[idx].atlas_rect.xy + spot_lights.data[idx].atlas_rect.zw; for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; - suv = clamp(suv, lights.data[idx].atlas_rect.xy, clamp_max); + suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max); float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r; if (d < z_norm) { blocker_average += d; @@ -1192,7 +1268,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v shadow = 0.0; for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) { vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size; - suv = clamp(suv, lights.data[idx].atlas_rect.xy, clamp_max); + suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max); shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0)); } @@ -1204,54 +1280,93 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v } } else { +#endif //hard shadow - vec4 shadow_uv = vec4(splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy, z_norm, 1.0); + vec4 shadow_uv = vec4(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z, 1.0); - shadow = sample_pcf_shadow(shadow_atlas, lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv); + shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv); +#ifdef USE_SOFT_SHADOWS } +#endif - vec3 no_shadow = vec3(1.0); + return shadow; + } - if (lights.data[idx].projector_rect != vec4(0.0)) { - splane = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0)); - splane /= splane.w; +#endif //USE_NO_SHADOWS - vec2 proj_uv = splane.xy * lights.data[idx].projector_rect.zw; + return 1.0; +} - //ensure we have proper mipmaps - vec4 splane_ddx = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)); - splane_ddx /= splane_ddx.w; - vec2 proj_uv_ddx = splane_ddx.xy * lights.data[idx].projector_rect.zw - proj_uv; +void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, +#ifdef LIGHT_BACKLIGHT_USED + vec3 backlight, +#endif +#ifdef LIGHT_TRANSMITTANCE_USED + vec4 transmittance_color, + float transmittance_depth, + float transmittance_curve, + float transmittance_boost, +#endif +#ifdef LIGHT_RIM_USED + float rim, float rim_tint, vec3 rim_color, +#endif +#ifdef LIGHT_CLEARCOAT_USED + float clearcoat, float clearcoat_gloss, +#endif +#ifdef LIGHT_ANISOTROPY_USED + vec3 binormal, vec3 tangent, float anisotropy, +#endif +#ifdef USE_SHADOW_TO_OPACITY + inout float alpha, +#endif + inout vec3 diffuse_light, + inout vec3 specular_light) { + vec3 light_rel_vec = spot_lights.data[idx].position - vertex; + float light_length = length(light_rel_vec); + float spot_attenuation = get_omni_attenuation(light_length, spot_lights.data[idx].inv_radius, spot_lights.data[idx].attenuation); + vec3 spot_dir = spot_lights.data[idx].direction; + float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[idx].cone_angle); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[idx].cone_angle)); + spot_attenuation *= 1.0 - pow(spot_rim, spot_lights.data[idx].cone_attenuation); + float light_attenuation = spot_attenuation; + vec3 color = spot_lights.data[idx].color; + float specular_amount = spot_lights.data[idx].specular_amount; - vec4 splane_ddy = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)); - splane_ddy /= splane_ddy.w; - vec2 proj_uv_ddy = splane_ddy.xy * lights.data[idx].projector_rect.zw - proj_uv; +#ifdef USE_SOFT_SHADOWS + float size_A = 0.0; - vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + lights.data[idx].projector_rect.xy, proj_uv_ddx, proj_uv_ddy); - no_shadow = mix(no_shadow, proj.rgb, proj.a); - } + if (spot_lights.data[idx].size > 0.0) { + float t = spot_lights.data[idx].size / max(0.001, light_length); + size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t)); + } +#endif - shadow_attenuation = mix(shadow_color_enabled.rgb, no_shadow, shadow); + /* + if (spot_lights.data[idx].atlas_rect!=vec4(0.0)) { + //use projector texture + } + */ #ifdef LIGHT_TRANSMITTANCE_USED - { - splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0)); - splane /= splane.w; - splane.xy = splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy; - - float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; - //reconstruct depth - shadow_z /= lights.data[idx].inv_radius; - //distance to light plane - float z = dot(spot_dir, -light_rel_vec); - transmittance_z = z - shadow_z; - } -#endif //LIGHT_TRANSMITTANCE_USED + float transmittance_z = transmittance_depth; + transmittance_color.a *= light_attenuation; + { + splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * spot_lights.data[idx].transmittance_bias, 1.0)); + splane /= splane.w; + splane.xy = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy; + + float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; + //reconstruct depth + shadow_z /= spot_lights.data[idx].inv_radius; + //distance to light plane + float z = dot(spot_dir, -light_rel_vec); + transmittance_z = z - shadow_z; } +#endif //LIGHT_TRANSMITTANCE_USED -#endif //USE_NO_SHADOWS + light_attenuation *= shadow; - light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity, + light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1263,7 +1378,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v transmittance_z, #endif #ifdef LIGHT_RIM_USED - rim * spot_attenuation, rim_tint, + rim * spot_attenuation, rim_tint, rim_color, #endif #ifdef LIGHT_CLEARCOAT_USED clearcoat, clearcoat_gloss, @@ -1271,6 +1386,9 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v #ifdef LIGHT_ANISOTROPY_USED binormal, tangent, anisotropy, #endif +#ifdef USE_SOFT_SHADOW + size_A, +#endif #ifdef USE_SHADOW_TO_OPACITY alpha, #endif @@ -1294,11 +1412,11 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughnes blend *= blend; blend = max(0.0, 1.0 - blend); - if (reflections.data[ref_index].params.x > 0.0) { // compute reflection + if (reflections.data[ref_index].intensity > 0.0) { // compute reflection vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz; - if (reflections.data[ref_index].params.w > 0.5) { //box project + if (reflections.data[ref_index].box_project) { //box project vec3 nrdir = normalize(local_ref_vec); vec3 rbmax = (box_extents - local_pos) / nrdir; @@ -1315,11 +1433,11 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughnes reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb; - if (reflections.data[ref_index].params.z < 0.5) { + if (reflections.data[ref_index].exterior) { reflection.rgb = mix(specular_light, reflection.rgb, blend); } - reflection.rgb *= reflections.data[ref_index].params.x; + reflection.rgb *= reflections.data[ref_index].intensity; //intensity reflection.a = blend; reflection.rgb *= reflection.a; @@ -1338,7 +1456,7 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughnes ambient_out.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_amb_vec, reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb; ambient_out.a = blend; - if (reflections.data[ref_index].params.z < 0.5) { //interior + if (reflections.data[ref_index].exterior) { ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); } @@ -1349,7 +1467,7 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughnes vec4 ambient_out; ambient_out.a = blend; ambient_out.rgb = reflections.data[ref_index].ambient; - if (reflections.data[ref_index].params.z < 0.5) { + if (reflections.data[ref_index].exterior) { ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend); } ambient_out.rgb *= ambient_out.a; @@ -1468,8 +1586,6 @@ void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 out_spec += vec4(irr_light.rgb * blend, blend); } -#endif //USE_FORWARD_GI - vec2 octahedron_wrap(vec2 v) { vec2 signVal; signVal.x = v.x >= 0.0 ? 1.0 : -1.0; @@ -1603,10 +1719,14 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal } } +#endif //USE_FORWARD_GI + #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) #ifndef MODE_RENDER_DEPTH +#ifndef LOW_END_MODE + vec4 volumetric_fog_process(vec2 screen_uv, float z) { vec3 fog_pos = vec3(screen_uv, z * scene_data.volumetric_fog_inv_length); if (fog_pos.z < 0.0) { @@ -1617,6 +1737,7 @@ vec4 volumetric_fog_process(vec2 screen_uv, float z) { return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos); } +#endif vec4 fog_process(vec3 vertex) { vec3 fog_color = scene_data.fog_light_color; @@ -1664,7 +1785,43 @@ vec4 fog_process(vec3 vertex) { return vec4(fog_color, fog_amount); } +void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) { + uint item_min_max = cluster_buffer.data[p_offset]; + item_min = item_min_max & 0xFFFF; + item_max = item_min_max >> 16; + ; + + item_from = item_min >> 5; + item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements +} + +uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) { + int local_min = clamp(int(z_min) - int(i) * 32, 0, 31); + int mask_width = min(int(z_max) - int(z_min), 32 - local_min); + return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width); +} + +float blur_shadow(float shadow) { + return shadow; +#if 0 + //disabling for now, will investigate later + float interp_shadow = shadow; + if (gl_HelperInvocation) { + interp_shadow = -4.0; // technically anything below -4 will do but just to make sure + } + + uvec2 fc2 = uvec2(gl_FragCoord.xy); + interp_shadow -= dFdx(interp_shadow) * (float(fc2.x & 1) - 0.5); + interp_shadow -= dFdy(interp_shadow) * (float(fc2.y & 1) - 0.5); + + if (interp_shadow >= 0.0) { + shadow = interp_shadow; + } + return shadow; #endif +} + +#endif //!MODE_RENDER DEPTH void main() { #ifdef MODE_DUAL_PARABOLOID @@ -1692,9 +1849,7 @@ void main() { float clearcoat_gloss = 0.0; float anisotropy = 0.0; vec2 anisotropy_flow = vec2(1.0, 0.0); -#if defined(CUSTOM_FOG_USED) - vec4 custom_fog = vec4(0.0); -#endif + vec4 fog = vec4(0.0); #if defined(CUSTOM_RADIANCE_USED) vec4 custom_radiance = vec4(0.0); #endif @@ -1702,24 +1857,20 @@ void main() { vec4 custom_irradiance = vec4(0.0); #endif -#if defined(AO_USED) float ao = 1.0; float ao_light_affect = 0.0; -#endif float alpha = 1.0; -#if defined(ALPHA_SCISSOR_USED) - float alpha_scissor = 0.5; -#endif - -#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) +#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) vec3 binormal = normalize(binormal_interp); vec3 tangent = normalize(tangent_interp); #else vec3 binormal = vec3(0.0); vec3 tangent = vec3(0.0); #endif + +#ifdef NORMAL_USED vec3 normal = normalize(normal_interp); #if defined(DO_SIDE_CHECK) @@ -1728,7 +1879,11 @@ void main() { } #endif +#endif //NORMAL_USED + +#ifdef UV_USED vec2 uv = uv_interp; +#endif #if defined(UV2_USED) || defined(USE_LIGHTMAP) vec2 uv2 = uv2_interp; @@ -1738,17 +1893,30 @@ void main() { vec4 color = color_interp; #endif -#if defined(NORMALMAP_USED) +#if defined(NORMAL_MAP_USED) - vec3 normalmap = vec3(0.5); + vec3 normal_map = vec3(0.5); #endif - float normaldepth = 1.0; + float normal_map_depth = 1.0; vec2 screen_uv = gl_FragCoord.xy * scene_data.screen_pixel_size + scene_data.screen_pixel_size * 0.5; //account for center float sss_strength = 0.0; +#ifdef ALPHA_SCISSOR_USED + float alpha_scissor_threshold = 1.0; +#endif // ALPHA_SCISSOR_USED + +#ifdef ALPHA_HASH_USED + float alpha_hash_scale = 1.0; +#endif // ALPHA_HASH_USED + +#ifdef ALPHA_ANTIALIASING_EDGE_USED + float alpha_antialiasing_edge = 0.0; + vec2 alpha_texture_coordinate = vec2(0.0, 0.0); +#endif // ALPHA_ANTIALIASING_EDGE_USED + { /* clang-format off */ @@ -1757,7 +1925,7 @@ FRAGMENT_SHADER_CODE /* clang-format on */ } -#if defined(LIGHT_TRANSMITTANCE_USED) +#ifdef LIGHT_TRANSMITTANCE_USED #ifdef SSS_MODE_SKIN transmittance_color.a = sss_strength; #else @@ -1765,34 +1933,52 @@ FRAGMENT_SHADER_CODE #endif #endif -#if !defined(USE_SHADOW_TO_OPACITY) +#ifndef USE_SHADOW_TO_OPACITY -#if defined(ALPHA_SCISSOR_USED) - if (alpha < alpha_scissor) { +#ifdef ALPHA_SCISSOR_USED + if (alpha < alpha_scissor_threshold) { discard; } #endif // ALPHA_SCISSOR_USED -#ifdef USE_OPAQUE_PREPASS +// alpha hash can be used in unison with alpha antialiasing +#ifdef ALPHA_HASH_USED + if (alpha < compute_alpha_hash_threshold(vertex, alpha_hash_scale)) { + discard; + } +#endif // ALPHA_HASH_USED + +// If we are not edge antialiasing, we need to remove the output alpha channel from scissor and hash +#if (defined(ALPHA_SCISSOR_USED) || defined(ALPHA_HASH_USED)) && !defined(ALPHA_ANTIALIASING_EDGE_USED) + alpha = 1.0; +#endif + +#ifdef ALPHA_ANTIALIASING_EDGE_USED +// If alpha scissor is used, we must further the edge threshold, otherwise we wont get any edge feather +#ifdef ALPHA_SCISSOR_USED + alpha_antialiasing_edge = clamp(alpha_scissor_threshold + alpha_antialiasing_edge, 0.0, 1.0); +#endif + alpha = compute_alpha_antialiasing_edge(alpha, alpha_texture_coordinate, alpha_antialiasing_edge); +#endif // ALPHA_ANTIALIASING_EDGE_USED +#ifdef USE_OPAQUE_PREPASS if (alpha < opaque_prepass_threshold) { discard; } - #endif // USE_OPAQUE_PREPASS #endif // !USE_SHADOW_TO_OPACITY -#if defined(NORMALMAP_USED) +#ifdef NORMAL_MAP_USED - normalmap.xy = normalmap.xy * 2.0 - 1.0; - normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. + normal_map.xy = normal_map.xy * 2.0 - 1.0; + normal_map.z = sqrt(max(0.0, 1.0 - dot(normal_map.xy, normal_map.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. - normal = normalize(mix(normal, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)); + normal = normalize(mix(normal, tangent * normal_map.x + binormal * normal_map.y + normal * normal_map.z, normal_map_depth)); #endif -#if defined(LIGHT_ANISOTROPY_USED) +#ifdef LIGHT_ANISOTROPY_USED if (anisotropy > 0.01) { //rotation matrix @@ -1810,80 +1996,151 @@ FRAGMENT_SHADER_CODE discard; } #endif + + /////////////////////// FOG ////////////////////// +#ifndef MODE_RENDER_DEPTH + +#ifndef CUSTOM_FOG_USED + // fog must be processed as early as possible and then packed. + // to maximize VGPR usage + // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. + + if (scene_data.fog_enabled) { + fog = fog_process(vertex); + } + +#ifndef LOW_END_MODE + if (scene_data.volumetric_fog_enabled) { + vec4 volumetric_fog = volumetric_fog_process(screen_uv, -vertex.z); + if (scene_data.fog_enabled) { + //must use the full blending equation here to blend fogs + vec4 res; + float sa = 1.0 - volumetric_fog.a; + res.a = fog.a * sa + volumetric_fog.a; + if (res.a == 0.0) { + res.rgb = vec3(0.0); + } else { + res.rgb = (fog.rgb * fog.a * sa + volumetric_fog.rgb * volumetric_fog.a) / res.a; + } + fog = res; + } else { + fog = volumetric_fog; + } + } +#endif //!LOW_END_MODE +#endif //!CUSTOM_FOG_USED + + uint fog_rg = packHalf2x16(fog.rg); + uint fog_ba = packHalf2x16(fog.ba); + +#endif //!MODE_RENDER_DEPTH + /////////////////////// DECALS //////////////////////////////// #ifndef MODE_RENDER_DEPTH - uvec4 cluster_cell = texture(usampler3D(cluster_texture, material_samplers[SAMPLER_NEAREST_CLAMP]), vec3(screen_uv, (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near))); + uvec2 cluster_pos = uvec2(gl_FragCoord.xy) >> scene_data.cluster_shift; + uint cluster_offset = (scene_data.cluster_width * cluster_pos.y + cluster_pos.x) * (scene_data.max_cluster_element_count_div_32 + 32); + + uint cluster_z = uint(clamp((-vertex.z / scene_data.z_far) * 32.0, 0.0, 31.0)); + //used for interpolating anything cluster related vec3 vertex_ddx = dFdx(vertex); vec3 vertex_ddy = dFdy(vertex); { // process decals - uint decal_count = cluster_cell.w >> CLUSTER_COUNTER_SHIFT; - uint decal_pointer = cluster_cell.w & CLUSTER_POINTER_MASK; + uint cluster_decal_offset = cluster_offset + scene_data.cluster_type_size * 2; - //do outside for performance and avoiding arctifacts + uint item_min; + uint item_max; + uint item_from; + uint item_to; - for (uint i = 0; i < decal_count; i++) { - uint decal_index = cluster_data.indices[decal_pointer + i]; - if (!bool(decals.data[decal_index].mask & instances.data[instance_index].layer_mask)) { - continue; //not masked - } + cluster_get_item_range(cluster_decal_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); - vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz; - if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) { - continue; //out of decal - } +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif - //we need ddx/ddy for mipmaps, so simulate them - vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz; - vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz; + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_decal_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif - float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade); + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + uint decal_index = 32 * i + bit; - if (decals.data[decal_index].normal_fade > 0.0) { - fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5); - } + if (!bool(decals.data[decal_index].mask & draw_call.layer_mask)) { + continue; //not masked + } - if (decals.data[decal_index].albedo_rect != vec4(0.0)) { - //has albedo - vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw); - decal_albedo *= decals.data[decal_index].modulate; - decal_albedo.a *= fade; - albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix); - - if (decals.data[decal_index].normal_rect != vec4(0.0)) { - vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz; - decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software - decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy))); - //convert to view space, use xzy because y is up - decal_normal = (decals.data[decal_index].normal_xform * decal_normal.xzy).xyz; - - normal = normalize(mix(normal, decal_normal, decal_albedo.a)); + vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz; + if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) { + continue; //out of decal } - if (decals.data[decal_index].orm_rect != vec4(0.0)) { - vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz; -#if defined(AO_USED) - ao = mix(ao, decal_orm.r, decal_albedo.a); -#endif - roughness = mix(roughness, decal_orm.g, decal_albedo.a); - metallic = mix(metallic, decal_orm.b, decal_albedo.a); + //we need ddx/ddy for mipmaps, so simulate them + vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz; + vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz; + + float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade); + + if (decals.data[decal_index].normal_fade > 0.0) { + fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5); } - } - if (decals.data[decal_index].emission_rect != vec4(0.0)) { - //emission is additive, so its independent from albedo - emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade; + if (decals.data[decal_index].albedo_rect != vec4(0.0)) { + //has albedo + vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw); + decal_albedo *= decals.data[decal_index].modulate; + decal_albedo.a *= fade; + albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix); + + if (decals.data[decal_index].normal_rect != vec4(0.0)) { + vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz; + decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software + decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy))); + //convert to view space, use xzy because y is up + decal_normal = (decals.data[decal_index].normal_xform * decal_normal.xzy).xyz; + + normal = normalize(mix(normal, decal_normal, decal_albedo.a)); + } + + if (decals.data[decal_index].orm_rect != vec4(0.0)) { + vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz; + ao = mix(ao, decal_orm.r, decal_albedo.a); + roughness = mix(roughness, decal_orm.g, decal_albedo.a); + metallic = mix(metallic, decal_orm.b, decal_albedo.a); + } + } + + if (decals.data[decal_index].emission_rect != vec4(0.0)) { + //emission is additive, so its independent from albedo + emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade; + } } } } + //pack albedo until needed again, saves 2 VGPRs in the meantime + #endif //not render depth /////////////////////// LIGHTING ////////////////////////////// +#ifdef NORMAL_USED if (scene_data.roughness_limiter_enabled) { //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf float roughness2 = roughness * roughness; @@ -1893,6 +2150,7 @@ FRAGMENT_SHADER_CODE float filteredRoughness2 = min(1.0, roughness2 + kernelRoughness2); roughness = sqrt(filteredRoughness2); } +#endif //apply energy conservation vec3 specular_light = vec3(0.0, 0.0, 0.0); @@ -1946,19 +2204,14 @@ FRAGMENT_SHADER_CODE //radiance - float specular_blob_intensity = 1.0; - -#if defined(SPECULAR_TOON) - specular_blob_intensity *= specular * 2.0; -#endif - +/// GI /// #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) #ifdef USE_LIGHTMAP //lightmap - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE)) { //has lightmap capture - uint index = instances.data[instance_index].gi_offset; + if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE)) { //has lightmap capture + uint index = draw_call.gi_offset; vec3 wnormal = mat3(scene_data.camera_matrix) * normal; const float c1 = 0.429043; @@ -1977,12 +2230,12 @@ FRAGMENT_SHADER_CODE 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y + 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z); - } else if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap - bool uses_sh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP); - uint ofs = instances.data[instance_index].gi_offset & 0xFFF; + } else if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap + bool uses_sh = bool(draw_call.flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP); + uint ofs = draw_call.gi_offset & 0xFFFF; vec3 uvw; - uvw.xy = uv2 * instances.data[instance_index].lightmap_uv_scale.zw + instances.data[instance_index].lightmap_uv_scale.xy; - uvw.z = float((instances.data[instance_index].gi_offset >> 12) & 0xFF); + uvw.xy = uv2 * draw_call.lightmap_uv_scale.zw + draw_call.lightmap_uv_scale.xy; + uvw.z = float((draw_call.gi_offset >> 16) & 0xFFFF); if (uses_sh) { uvw.z *= 4.0; //SH textures use 4 times more data @@ -1991,7 +2244,7 @@ FRAGMENT_SHADER_CODE vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb; vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb; - uint idx = instances.data[instance_index].gi_offset >> 20; + uint idx = draw_call.gi_offset >> 20; vec3 n = normalize(lightmaps.data[idx].normal_xform * normal); ambient_light += lm_light_l0 * 0.282095f; @@ -2011,7 +2264,7 @@ FRAGMENT_SHADER_CODE } #elif defined(USE_FORWARD_GI) - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SDFGI)) { //has lightmap capture + if (bool(draw_call.flags & INSTANCE_FLAGS_USE_SDFGI)) { //has lightmap capture //make vertex orientation the world one, but still align to camera vec3 cam_pos = mat3(scene_data.camera_matrix) * vertex; @@ -2083,9 +2336,9 @@ FRAGMENT_SHADER_CODE } } - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes + if (bool(draw_call.flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes - uint index1 = instances.data[instance_index].gi_offset & 0xFFFF; + uint index1 = draw_call.gi_offset & 0xFFFF; vec3 ref_vec = normalize(reflect(normalize(vertex), normal)); //find arbitrary tangent and bitangent, then build a matrix vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); @@ -2097,7 +2350,7 @@ FRAGMENT_SHADER_CODE vec4 spec_accum = vec4(0.0); gi_probe_compute(index1, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum); - uint index2 = instances.data[instance_index].gi_offset >> 16; + uint index2 = draw_call.gi_offset >> 16; if (index2 != 0xFFFF) { gi_probe_compute(index2, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum); @@ -2114,38 +2367,21 @@ FRAGMENT_SHADER_CODE specular_light = spec_accum.rgb; ambient_light = amb_accum.rgb; } -#else - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers +#elif !defined(LOW_END_MODE) - ivec2 coord; + if (bool(draw_call.flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers - if (scene_data.gi_upscale_for_msaa) { - /* - //find the closest depth to upscale from, based on neighbours - ivec2 base_coord = ivec2(gl_FragCoord.xy); - float z_dist = gl_FragCoord.z; - ivec2 closest_coord = base_coord; - float closest_z_dist = abs(texelFetch(sampler2D(depth_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), base_coord,0).r-z_dist); - - for(int i=0;i<4;i++) { - const ivec2 neighbours[4]=ivec2[](ivec2(-1,0),ivec2(1,0),ivec2(0,-1),ivec2(0,1)); - ivec2 neighbour_coord = base_coord + neighbours[i]; - float neighbour_z_dist = abs(texelFetch(sampler2D(depth_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), neighbour_coord,0).r-z_dist); - if (neighbour_z_dist < closest_z_dist) { - closest_z_dist = neighbour_z_dist; - closest_coord = neighbour_coord; - } - } + vec2 coord; -*/ - ivec2 base_coord = ivec2(gl_FragCoord.xy); - ivec2 closest_coord = base_coord; - float closest_ang = dot(normal, texelFetch(sampler2D(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), base_coord, 0).xyz * 2.0 - 1.0); + if (scene_data.gi_upscale_for_msaa) { + vec2 base_coord = screen_uv; + vec2 closest_coord = base_coord; + float closest_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), base_coord, 0.0).xyz * 2.0 - 1.0); for (int i = 0; i < 4; i++) { - const ivec2 neighbours[4] = ivec2[](ivec2(-1, 0), ivec2(1, 0), ivec2(0, -1), ivec2(0, 1)); - ivec2 neighbour_coord = base_coord + neighbours[i]; - float neighbour_ang = dot(normal, texelFetch(sampler2D(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), neighbour_coord, 0).xyz * 2.0 - 1.0); + const vec2 neighbours[4] = vec2[](vec2(-1, 0), vec2(1, 0), vec2(0, -1), vec2(0, 1)); + vec2 neighbour_coord = base_coord + neighbours[i] * scene_data.screen_pixel_size; + float neighbour_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), neighbour_coord, 0.0).xyz * 2.0 - 1.0); if (neighbour_ang > closest_ang) { closest_ang = neighbour_ang; closest_coord = neighbour_coord; @@ -2155,28 +2391,69 @@ FRAGMENT_SHADER_CODE coord = closest_coord; } else { - coord = ivec2(gl_FragCoord.xy); + coord = screen_uv; } - vec4 buffer_ambient = texelFetch(sampler2D(ambient_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), coord, 0); - vec4 buffer_reflection = texelFetch(sampler2D(reflection_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), coord, 0); + vec4 buffer_ambient = textureLod(sampler2D(ambient_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), coord, 0.0); + vec4 buffer_reflection = textureLod(sampler2D(reflection_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), coord, 0.0); ambient_light = mix(ambient_light, buffer_ambient.rgb, buffer_ambient.a); specular_light = mix(specular_light, buffer_reflection.rgb, buffer_reflection.a); } #endif +#ifndef LOW_END_MODE + if (scene_data.ssao_enabled) { + float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r; + ao = min(ao, ssao); + ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect); + } +#endif //LOW_END_MODE + { // process reflections vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0); - uint reflection_probe_count = cluster_cell.z >> CLUSTER_COUNTER_SHIFT; - uint reflection_probe_pointer = cluster_cell.z & CLUSTER_POINTER_MASK; + uint cluster_reflection_offset = cluster_offset + scene_data.cluster_type_size * 3; + + uint item_min; + uint item_max; + uint item_from; + uint item_to; - for (uint i = 0; i < reflection_probe_count; i++) { - uint ref_index = cluster_data.indices[reflection_probe_pointer + i]; - reflection_process(ref_index, vertex, normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum); + cluster_get_item_range(cluster_reflection_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif + + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_reflection_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif + + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + uint reflection_index = 32 * i + bit; + + if (!bool(reflections.data[reflection_index].mask & draw_call.layer_mask)) { + continue; //not masked + } + + reflection_process(reflection_index, vertex, normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum); + } } if (reflection_accum.a > 0.0) { @@ -2190,6 +2467,16 @@ FRAGMENT_SHADER_CODE #endif } + //finalize ambient light here + ambient_light *= albedo.rgb; + ambient_light *= ao; + + // convert ao to direct light ao + ao = mix(1.0, ao, ao_light_affect); + + //this saves some VGPRs + vec3 f0 = F0(metallic, specular, albedo); + { #if defined(DIFFUSE_TOON) //simplify for toon, as @@ -2207,24 +2494,39 @@ FRAGMENT_SHADER_CODE float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; - vec3 f0 = F0(metallic, specular, albedo); specular_light *= env.x * f0 + env.y; #endif } +#endif //GI !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + +#if !defined(MODE_RENDER_DEPTH) + //this saves some VGPRs + uint orms = packUnorm4x8(vec4(ao, roughness, metallic, specular)); +#endif + +// LIGHTING +#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) + { //directional light - for (uint i = 0; i < scene_data.directional_light_count; i++) { - if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) { + // Do shadow and lighting in two passes to reduce register pressure + uint shadow0 = 0; + uint shadow1 = 0; + + for (uint i = 0; i < 8; i++) { + if (i >= scene_data.directional_light_count) { + break; + } + + if (!bool(directional_lights.data[i].mask & draw_call.layer_mask)) { continue; //not masked } - vec3 shadow_attenuation = vec3(1.0); - -#ifdef LIGHT_TRANSMITTANCE_USED - float transmittance_z = transmittance_depth; -#endif + float shadow = 1.0; +#ifdef USE_SOFT_SHADOWS + //version with soft shadows, more expensive if (directional_lights.data[i].shadow_enabled) { float depth_z = -vertex.z; @@ -2238,8 +2540,6 @@ FRAGMENT_SHADER_CODE normal_bias -= light_dir * dot(light_dir, normal_bias); \ m_var.xyz += normal_bias; - float shadow = 0.0; - if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { vec4 v = vec4(vertex, 1.0); @@ -2260,19 +2560,6 @@ FRAGMENT_SHADER_CODE shadow_color = directional_lights.data[i].shadow_color1.rgb; -#ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_z_range.x; - float z = trans_coord.z * directional_lights.data[i].shadow_z_range.x; - - transmittance_z = z - shadow_z; - } -#endif } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { vec4 v = vec4(vertex, 1.0); @@ -2292,19 +2579,6 @@ FRAGMENT_SHADER_CODE } shadow_color = directional_lights.data[i].shadow_color2.rgb; -#ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.y, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_z_range.y; - float z = trans_coord.z * directional_lights.data[i].shadow_z_range.y; - - transmittance_z = z - shadow_z; - } -#endif } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { vec4 v = vec4(vertex, 1.0); @@ -2324,19 +2598,6 @@ FRAGMENT_SHADER_CODE } shadow_color = directional_lights.data[i].shadow_color3.rgb; -#ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.z, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_z_range.z; - float z = trans_coord.z * directional_lights.data[i].shadow_z_range.z; - - transmittance_z = z - shadow_z; - } -#endif } else { vec4 v = vec4(vertex, 1.0); @@ -2357,20 +2618,6 @@ FRAGMENT_SHADER_CODE } shadow_color = directional_lights.data[i].shadow_color4.rgb; - -#ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_z_range.w; - float z = trans_coord.z * directional_lights.data[i].shadow_z_range.w; - - transmittance_z = z - shadow_z; - } -#endif } if (directional_lights.data[i].blend_splits) { @@ -2444,130 +2691,407 @@ FRAGMENT_SHADER_CODE shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance - shadow_attenuation = mix(shadow_color, vec3(1.0), shadow); +#undef BIAS_FUNC + } +#else + // Soft shadow disabled version + + if (directional_lights.data[i].shadow_enabled) { + float depth_z = -vertex.z; + + vec4 pssm_coord; + vec3 light_dir = directional_lights.data[i].direction; + vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))); + +#define BIAS_FUNC(m_var, m_idx) \ + m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \ + vec3 normal_bias = base_normal_bias * directional_lights.data[i].shadow_normal_bias[m_idx]; \ + normal_bias -= light_dir * dot(light_dir, normal_bias); \ + m_var.xyz += normal_bias; + + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 0) + + pssm_coord = (directional_lights.data[i].shadow_matrix1 * v); +#ifdef LIGHT_TRANSMITTANCE_USED + { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x; + + transmittance_z = z - shadow_z; + } +#endif + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 1) + + pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); +#ifdef LIGHT_TRANSMITTANCE_USED + { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.y, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y; + + transmittance_z = z - shadow_z; + } +#endif + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 2) + + pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); +#ifdef LIGHT_TRANSMITTANCE_USED + { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.z, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z; + + transmittance_z = z - shadow_z; + } +#endif + + } else { + vec4 v = vec4(vertex, 1.0); + + BIAS_FUNC(v, 3) + + pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); +#ifdef LIGHT_TRANSMITTANCE_USED + { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w; + + transmittance_z = z - shadow_z; + } +#endif + } + + pssm_coord /= pssm_coord.w; + + shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + + if (directional_lights.data[i].blend_splits) { + float pssm_blend; + + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 1) + pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); + pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z); + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 2) + pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); + pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z); + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { + vec4 v = vec4(vertex, 1.0); + BIAS_FUNC(v, 3) + pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); + pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z); + } else { + pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached) + } + + pssm_coord /= pssm_coord.w; + + float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); + shadow = mix(shadow, shadow2, pssm_blend); + } + + shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance #undef BIAS_FUNC } +#endif + + if (i < 4) { + shadow0 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << (i * 8); + } else { + shadow1 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << ((i - 4) * 8); + } + } + + for (uint i = 0; i < 8; i++) { + if (i >= scene_data.directional_light_count) { + break; + } + + if (!bool(directional_lights.data[i].mask & draw_call.layer_mask)) { + continue; //not masked + } + +#ifdef LIGHT_TRANSMITTANCE_USED + float transmittance_z = transmittance_depth; + + if (directional_lights.data[i].shadow_enabled) { + float depth_z = -vertex.z; + + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x; + + transmittance_z = z - shadow_z; + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.y, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y; + + transmittance_z = z - shadow_z; + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.z, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z; + + transmittance_z = z - shadow_z; + + } else { + vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0); + vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex; + trans_coord /= trans_coord.w; + + float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; + shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w; + float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w; - light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].size, directional_lights.data[i].color * directional_lights.data[i].energy, 1.0, shadow_attenuation, albedo, roughness, metallic, specular, directional_lights.data[i].specular * specular_blob_intensity, + transmittance_z = z - shadow_z; + } +#endif + + float shadow = 1.0; + + if (i < 4) { + shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0; + } else { + shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0; + } + + blur_shadow(shadow); + + light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0, #ifdef LIGHT_BACKLIGHT_USED - backlight, + backlight, #endif #ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_curve, - transmittance_boost, - transmittance_z, + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, + transmittance_z, #endif #ifdef LIGHT_RIM_USED - rim, rim_tint, + rim, rim_tint, albedo, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_gloss, #endif #ifdef LIGHT_ANISOTROPY_USED - binormal, tangent, anisotropy, + binormal, tangent, anisotropy, +#endif +#ifdef USE_SOFT_SHADOW + directional_lights.data[i].size, #endif #ifdef USE_SHADOW_TO_OPACITY - alpha, + alpha, #endif - diffuse_light, - specular_light); + diffuse_light, + specular_light); + } } - } - { //omni lights + { //omni lights - uint omni_light_count = cluster_cell.x >> CLUSTER_COUNTER_SHIFT; - uint omni_light_pointer = cluster_cell.x & CLUSTER_POINTER_MASK; + uint cluster_omni_offset = cluster_offset; - for (uint i = 0; i < omni_light_count; i++) { - uint light_index = cluster_data.indices[omni_light_pointer + i]; + uint item_min; + uint item_max; + uint item_from; + uint item_to; - if (!bool(lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { - continue; //not masked - } + cluster_get_item_range(cluster_omni_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif - light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, albedo, roughness, metallic, specular, specular_blob_intensity, + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_omni_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif + + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + uint light_index = 32 * i + bit; + + if (!bool(omni_lights.data[light_index].mask & draw_call.layer_mask)) { + continue; //not masked + } + + float shadow = light_process_omni_shadow(light_index, vertex, view); + + shadow = blur_shadow(shadow); + + light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, #ifdef LIGHT_BACKLIGHT_USED - backlight, + backlight, #endif #ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_curve, - transmittance_boost, + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, #endif #ifdef LIGHT_RIM_USED - rim, - rim_tint, + rim, + rim_tint, + albedo, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_gloss, #endif #ifdef LIGHT_ANISOTROPY_USED - tangent, binormal, anisotropy, + tangent, binormal, anisotropy, #endif #ifdef USE_SHADOW_TO_OPACITY - alpha, + alpha, #endif - diffuse_light, specular_light); + diffuse_light, specular_light); + } + } } - } - { //spot lights - uint spot_light_count = cluster_cell.y >> CLUSTER_COUNTER_SHIFT; - uint spot_light_pointer = cluster_cell.y & CLUSTER_POINTER_MASK; + { //spot lights - for (uint i = 0; i < spot_light_count; i++) { - uint light_index = cluster_data.indices[spot_light_pointer + i]; + uint cluster_spot_offset = cluster_offset + scene_data.cluster_type_size; - if (!bool(lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { - continue; //not masked - } + uint item_min; + uint item_max; + uint item_from; + uint item_to; + + cluster_get_item_range(cluster_spot_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif + + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_spot_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif - light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, albedo, roughness, metallic, specular, specular_blob_intensity, + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + + uint light_index = 32 * i + bit; + + if (!bool(spot_lights.data[light_index].mask & draw_call.layer_mask)) { + continue; //not masked + } + + float shadow = light_process_spot_shadow(light_index, vertex, view); + + shadow = blur_shadow(shadow); + + light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, #ifdef LIGHT_BACKLIGHT_USED - backlight, + backlight, #endif #ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_curve, - transmittance_boost, + transmittance_color, + transmittance_depth, + transmittance_curve, + transmittance_boost, #endif #ifdef LIGHT_RIM_USED - rim, - rim_tint, + rim, + rim_tint, + albedo, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_gloss, #endif #ifdef LIGHT_ANISOTROPY_USED - tangent, binormal, anisotropy, + tangent, binormal, anisotropy, #endif #ifdef USE_SHADOW_TO_OPACITY - alpha, + alpha, #endif - diffuse_light, specular_light); + diffuse_light, specular_light); + } + } } - } #ifdef USE_SHADOW_TO_OPACITY - alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); + alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); #if defined(ALPHA_SCISSOR_USED) - if (alpha < alpha_scissor) { - discard; - } + if (alpha < alpha_scissor) { + discard; + } #endif // ALPHA_SCISSOR_USED #ifdef USE_OPAQUE_PREPASS - if (alpha < opaque_prepass_threshold) { - discard; - } + if (alpha < opaque_prepass_threshold) { + discard; + } #endif // USE_OPAQUE_PREPASS @@ -2579,169 +3103,149 @@ FRAGMENT_SHADER_CODE #ifdef MODE_RENDER_SDF - { - vec3 local_pos = (scene_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz; - ivec3 grid_pos = scene_data.sdf_offset + ivec3(local_pos * vec3(scene_data.sdf_size)); - - uint albedo16 = 0x1; //solid flag - albedo16 |= clamp(uint(albedo.r * 31.0), 0, 31) << 11; - albedo16 |= clamp(uint(albedo.g * 31.0), 0, 31) << 6; - albedo16 |= clamp(uint(albedo.b * 31.0), 0, 31) << 1; - - imageStore(albedo_volume_grid, grid_pos, uvec4(albedo16)); - - uint facing_bits = 0; - const vec3 aniso_dir[6] = vec3[]( - vec3(1, 0, 0), - vec3(0, 1, 0), - vec3(0, 0, 1), - vec3(-1, 0, 0), - vec3(0, -1, 0), - vec3(0, 0, -1)); - - vec3 cam_normal = mat3(scene_data.camera_matrix) * normalize(normal_interp); - - float closest_dist = -1e20; - - for (uint i = 0; i < 6; i++) { - float d = dot(cam_normal, aniso_dir[i]); - if (d > closest_dist) { - closest_dist = d; - facing_bits = (1 << i); + { + vec3 local_pos = (scene_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz; + ivec3 grid_pos = scene_data.sdf_offset + ivec3(local_pos * vec3(scene_data.sdf_size)); + + uint albedo16 = 0x1; //solid flag + albedo16 |= clamp(uint(albedo.r * 31.0), 0, 31) << 11; + albedo16 |= clamp(uint(albedo.g * 31.0), 0, 31) << 6; + albedo16 |= clamp(uint(albedo.b * 31.0), 0, 31) << 1; + + imageStore(albedo_volume_grid, grid_pos, uvec4(albedo16)); + + uint facing_bits = 0; + const vec3 aniso_dir[6] = vec3[]( + vec3(1, 0, 0), + vec3(0, 1, 0), + vec3(0, 0, 1), + vec3(-1, 0, 0), + vec3(0, -1, 0), + vec3(0, 0, -1)); + + vec3 cam_normal = mat3(scene_data.camera_matrix) * normalize(normal_interp); + + float closest_dist = -1e20; + + for (uint i = 0; i < 6; i++) { + float d = dot(cam_normal, aniso_dir[i]); + if (d > closest_dist) { + closest_dist = d; + facing_bits = (1 << i); + } } - } - imageAtomicOr(geom_facing_grid, grid_pos, facing_bits); //store facing bits + imageAtomicOr(geom_facing_grid, grid_pos, facing_bits); //store facing bits - if (length(emission) > 0.001) { - float lumas[6]; - vec3 light_total = vec3(0); + if (length(emission) > 0.001) { + float lumas[6]; + vec3 light_total = vec3(0); - for (int i = 0; i < 6; i++) { - float strength = max(0.0, dot(cam_normal, aniso_dir[i])); - vec3 light = emission * strength; - light_total += light; - lumas[i] = max(light.r, max(light.g, light.b)); - } + for (int i = 0; i < 6; i++) { + float strength = max(0.0, dot(cam_normal, aniso_dir[i])); + vec3 light = emission * strength; + light_total += light; + lumas[i] = max(light.r, max(light.g, light.b)); + } - float luma_total = max(light_total.r, max(light_total.g, light_total.b)); + float luma_total = max(light_total.r, max(light_total.g, light_total.b)); - uint light_aniso = 0; + uint light_aniso = 0; - for (int i = 0; i < 6; i++) { - light_aniso |= min(31, uint((lumas[i] / luma_total) * 31.0)) << (i * 5); - } + for (int i = 0; i < 6; i++) { + light_aniso |= min(31, uint((lumas[i] / luma_total) * 31.0)) << (i * 5); + } - //compress to RGBE9995 to save space + //compress to RGBE9995 to save space - const float pow2to9 = 512.0f; - const float B = 15.0f; - const float N = 9.0f; - const float LN2 = 0.6931471805599453094172321215; + const float pow2to9 = 512.0f; + const float B = 15.0f; + const float N = 9.0f; + const float LN2 = 0.6931471805599453094172321215; - float cRed = clamp(light_total.r, 0.0, 65408.0); - float cGreen = clamp(light_total.g, 0.0, 65408.0); - float cBlue = clamp(light_total.b, 0.0, 65408.0); + float cRed = clamp(light_total.r, 0.0, 65408.0); + float cGreen = clamp(light_total.g, 0.0, 65408.0); + float cBlue = clamp(light_total.b, 0.0, 65408.0); - float cMax = max(cRed, max(cGreen, cBlue)); + float cMax = max(cRed, max(cGreen, cBlue)); - float expp = max(-B - 1.0f, floor(log(cMax) / LN2)) + 1.0f + B; + float expp = max(-B - 1.0f, floor(log(cMax) / LN2)) + 1.0f + B; - float sMax = floor((cMax / pow(2.0f, expp - B - N)) + 0.5f); + float sMax = floor((cMax / pow(2.0f, expp - B - N)) + 0.5f); - float exps = expp + 1.0f; + float exps = expp + 1.0f; - if (0.0 <= sMax && sMax < pow2to9) { - exps = expp; - } + if (0.0 <= sMax && sMax < pow2to9) { + exps = expp; + } - float sRed = floor((cRed / pow(2.0f, exps - B - N)) + 0.5f); - float sGreen = floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f); - float sBlue = floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f); - //store as 8985 to have 2 extra neighbour bits - uint light_rgbe = ((uint(sRed) & 0x1FF) >> 1) | ((uint(sGreen) & 0x1FF) << 8) | (((uint(sBlue) & 0x1FF) >> 1) << 17) | ((uint(exps) & 0x1F) << 25); + float sRed = floor((cRed / pow(2.0f, exps - B - N)) + 0.5f); + float sGreen = floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f); + float sBlue = floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f); + //store as 8985 to have 2 extra neighbour bits + uint light_rgbe = ((uint(sRed) & 0x1FF) >> 1) | ((uint(sGreen) & 0x1FF) << 8) | (((uint(sBlue) & 0x1FF) >> 1) << 17) | ((uint(exps) & 0x1F) << 25); - imageStore(emission_grid, grid_pos, uvec4(light_rgbe)); - imageStore(emission_aniso_grid, grid_pos, uvec4(light_aniso)); + imageStore(emission_grid, grid_pos, uvec4(light_rgbe)); + imageStore(emission_aniso_grid, grid_pos, uvec4(light_aniso)); + } } - } #endif #ifdef MODE_RENDER_MATERIAL - albedo_output_buffer.rgb = albedo; - albedo_output_buffer.a = alpha; + albedo_output_buffer.rgb = albedo; + albedo_output_buffer.a = alpha; - normal_output_buffer.rgb = normal * 0.5 + 0.5; - normal_output_buffer.a = 0.0; - depth_output_buffer.r = -vertex.z; + normal_output_buffer.rgb = normal * 0.5 + 0.5; + normal_output_buffer.a = 0.0; + depth_output_buffer.r = -vertex.z; -#if defined(AO_USED) - orm_output_buffer.r = ao; -#else - orm_output_buffer.r = 0.0; -#endif - orm_output_buffer.g = roughness; - orm_output_buffer.b = metallic; - orm_output_buffer.a = sss_strength; + orm_output_buffer.r = ao; + orm_output_buffer.g = roughness; + orm_output_buffer.b = metallic; + orm_output_buffer.a = sss_strength; - emission_output_buffer.rgb = emission; - emission_output_buffer.a = 0.0; + emission_output_buffer.rgb = emission; + emission_output_buffer.a = 0.0; #endif #ifdef MODE_RENDER_NORMAL_ROUGHNESS - normal_roughness_output_buffer = vec4(normal * 0.5 + 0.5, roughness); + normal_roughness_output_buffer = vec4(normal * 0.5 + 0.5, roughness); #ifdef MODE_RENDER_GIPROBE - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes - uint index1 = instances.data[instance_index].gi_offset & 0xFFFF; - uint index2 = instances.data[instance_index].gi_offset >> 16; - giprobe_buffer.x = index1 & 0xFF; - giprobe_buffer.y = index2 & 0xFF; - } else { - giprobe_buffer.x = 0xFF; - giprobe_buffer.y = 0xFF; - } + if (bool(draw_call.flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes + uint index1 = draw_call.gi_offset & 0xFFFF; + uint index2 = draw_call.gi_offset >> 16; + giprobe_buffer.x = index1 & 0xFF; + giprobe_buffer.y = index2 & 0xFF; + } else { + giprobe_buffer.x = 0xFF; + giprobe_buffer.y = 0xFF; + } #endif -#endif //MODE_RENDER_NORMAL +#endif //MODE_RENDER_NORMAL_ROUGHNESS //nothing happens, so a tree-ssa optimizer will result in no fragment shader :) #else - specular_light *= scene_data.reflection_multiplier; - ambient_light *= albedo; //ambient must be multiplied by albedo at the end - -//ambient occlusion -#if defined(AO_USED) - - if (scene_data.ssao_enabled && scene_data.ssao_ao_affect > 0.0) { - float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r; - ao = mix(ao, min(ao, ssao), scene_data.ssao_ao_affect); - ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect); - } - - ambient_light = mix(scene_data.ao_color.rgb, ambient_light, ao); - ao_light_affect = mix(1.0, ao, ao_light_affect); - specular_light = mix(scene_data.ao_color.rgb, specular_light, ao_light_affect); - diffuse_light = mix(scene_data.ao_color.rgb, diffuse_light, ao_light_affect); -#else - - if (scene_data.ssao_enabled) { - float ao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r; - ambient_light = mix(scene_data.ao_color.rgb, ambient_light, ao); - float ao_light_affect = mix(1.0, ao, scene_data.ssao_light_affect); - specular_light = mix(scene_data.ao_color.rgb, specular_light, ao_light_affect); - diffuse_light = mix(scene_data.ao_color.rgb, diffuse_light, ao_light_affect); - } + // multiply by albedo + diffuse_light *= albedo; // ambient must be multiplied by albedo at the end -#endif // AO_USED + // apply direct light AO + ao = unpackUnorm4x8(orms).x; + specular_light *= ao; + diffuse_light *= ao; - // base color remapping - diffuse_light *= 1.0 - metallic; // TODO: avoid all diffuse and ambient light calculations when metallic == 1 up to this point + // apply metallic + metallic = unpackUnorm4x8(orms).z; + diffuse_light *= 1.0 - metallic; ambient_light *= 1.0 - metallic; + //restore fog + fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba)); + #ifdef MODE_MULTIPLE_RENDER_TARGETS #ifdef MODE_UNSHADED @@ -2757,23 +3261,8 @@ FRAGMENT_SHADER_CODE specular_buffer = vec4(specular_light, metallic); #endif - // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. - if (scene_data.fog_enabled) { - vec4 fog = fog_process(vertex); - diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a); - specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); - } - - if (scene_data.volumetric_fog_enabled) { - vec4 fog = volumetric_fog_process(screen_uv, -vertex.z); - diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a); - specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); - } - -#if defined(CUSTOM_FOG_USED) - diffuse_buffer.rgb = mix(diffuse_buffer.rgb, custom_fog.rgb, custom_fog.a); - specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), custom_fog.a); -#endif //CUSTOM_FOG_USED + diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a); + specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a); #else //MODE_MULTIPLE_RENDER_TARGETS @@ -2785,21 +3274,9 @@ FRAGMENT_SHADER_CODE #endif //USE_NO_SHADING // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. - if (scene_data.fog_enabled) { - vec4 fog = fog_process(vertex); - frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); - } - - if (scene_data.volumetric_fog_enabled) { - vec4 fog = volumetric_fog_process(screen_uv, -vertex.z); - frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); - } - -#if defined(CUSTOM_FOG_USED) - frag_color.rgb = mix(frag_color.rgb, custom_fog.rgb, custom_fog.a); -#endif //CUSTOM_FOG_USED + frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); #endif //MODE_MULTIPLE_RENDER_TARGETS #endif //MODE_RENDER_DEPTH -} + } diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl index e29a490ca1..e9b79e1560 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl @@ -3,12 +3,30 @@ #define MAX_GI_PROBES 8 +#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic) + +#extension GL_KHR_shader_subgroup_ballot : enable +#extension GL_KHR_shader_subgroup_arithmetic : enable + +#define USE_SUBGROUPS + +#endif + #include "cluster_data_inc.glsl" +#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_GIPROBE) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) +#ifndef NORMAL_USED +#define NORMAL_USED +#endif +#endif + layout(push_constant, binding = 0, std430) uniform DrawCall { - uint instance_index; - uint pad; //16 bits minimum size - vec2 bake_uv2_offset; //used for bake to uv2, ignored otherwise + mat4 transform; + uint flags; + uint instance_uniforms_ofs; //base offset in global buffer for instance variables + uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) + uint layer_mask; + vec4 lightmap_uv_scale; } draw_call; @@ -43,6 +61,11 @@ layout(set = 0, binding = 3, std140) uniform SceneData { vec2 viewport_size; vec2 screen_pixel_size; + uint cluster_shift; + uint cluster_width; + uint cluster_type_size; + uint max_cluster_element_count_div_32; + //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted vec4 directional_penumbra_shadow_kernel[32]; vec4 directional_soft_shadow_kernel[32]; @@ -128,26 +151,17 @@ scene_data; #define INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK 0x7 #define INSTANCE_FLAGS_SKELETON (1 << 19) +#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 20) -struct InstanceData { - mat4 transform; - mat4 normal_transform; - uint flags; - uint instance_uniforms_ofs; //base offset in global buffer for instance variables - uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) - uint layer_mask; - vec4 lightmap_uv_scale; -}; - -layout(set = 0, binding = 4, std430) restrict readonly buffer Instances { - InstanceData data[]; +layout(set = 0, binding = 4, std430) restrict readonly buffer OmniLights { + LightData data[]; } -instances; +omni_lights; -layout(set = 0, binding = 5, std430) restrict readonly buffer Lights { +layout(set = 0, binding = 5, std430) restrict readonly buffer SpotLights { LightData data[]; } -lights; +spot_lights; layout(set = 0, binding = 6) buffer restrict readonly ReflectionProbeData { ReflectionData data[]; @@ -166,44 +180,35 @@ struct Lightmap { mat3 normal_xform; }; -layout(set = 0, binding = 10, std140) restrict readonly buffer Lightmaps { +layout(set = 0, binding = 8, std140) restrict readonly buffer Lightmaps { Lightmap data[]; } lightmaps; -layout(set = 0, binding = 11) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES]; - struct LightmapCapture { vec4 sh[9]; }; -layout(set = 0, binding = 12, std140) restrict readonly buffer LightmapCaptures { +layout(set = 0, binding = 9, std140) restrict readonly buffer LightmapCaptures { LightmapCapture data[]; } lightmap_captures; -layout(set = 0, binding = 13) uniform texture2D decal_atlas; -layout(set = 0, binding = 14) uniform texture2D decal_atlas_srgb; +layout(set = 0, binding = 10) uniform texture2D decal_atlas; +layout(set = 0, binding = 11) uniform texture2D decal_atlas_srgb; -layout(set = 0, binding = 15, std430) restrict readonly buffer Decals { +layout(set = 0, binding = 12, std430) restrict readonly buffer Decals { DecalData data[]; } decals; -layout(set = 0, binding = 16) uniform utexture3D cluster_texture; - -layout(set = 0, binding = 17, std430) restrict readonly buffer ClusterData { - uint indices[]; -} -cluster_data; - -layout(set = 0, binding = 18) uniform texture2D directional_shadow_atlas; - -layout(set = 0, binding = 19, std430) restrict readonly buffer GlobalVariableData { +layout(set = 0, binding = 13, std430) restrict readonly buffer GlobalVariableData { vec4 data[]; } global_variables; +#ifndef LOW_END_MODE + struct SDFGIProbeCascadeData { vec3 position; float to_probe; @@ -211,7 +216,7 @@ struct SDFGIProbeCascadeData { float to_cell; // 1/bounds * grid_size }; -layout(set = 0, binding = 20, std140) uniform SDFGI { +layout(set = 0, binding = 14, std140) uniform SDFGI { vec3 grid_size; uint max_cascades; @@ -239,6 +244,8 @@ layout(set = 0, binding = 20, std140) uniform SDFGI { } sdfgi; +#endif //LOW_END_MODE + // decal atlas /* Set 1, Radiance */ @@ -255,20 +262,31 @@ layout(set = 1, binding = 0) uniform textureCube radiance_cubemap; /* Set 2, Reflection and Shadow Atlases (view dependent) */ -layout(set = 2, binding = 0) uniform textureCubeArray reflection_atlas; +layout(set = 1, binding = 1) uniform textureCubeArray reflection_atlas; + +layout(set = 1, binding = 2) uniform texture2D shadow_atlas; -layout(set = 2, binding = 1) uniform texture2D shadow_atlas; +layout(set = 1, binding = 3) uniform texture2D directional_shadow_atlas; -layout(set = 2, binding = 2) uniform texture3D gi_probe_textures[MAX_GI_PROBES]; +layout(set = 1, binding = 4) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES]; + +#ifndef LOW_END_MODE +layout(set = 1, binding = 5) uniform texture3D gi_probe_textures[MAX_GI_PROBES]; +#endif + +layout(set = 1, binding = 6, std430) buffer restrict readonly ClusterBuffer { + uint data[]; +} +cluster_buffer; /* Set 3, Render Buffers */ #ifdef MODE_RENDER_SDF -layout(r16ui, set = 3, binding = 0) uniform restrict writeonly uimage3D albedo_volume_grid; -layout(r32ui, set = 3, binding = 1) uniform restrict writeonly uimage3D emission_grid; -layout(r32ui, set = 3, binding = 2) uniform restrict writeonly uimage3D emission_aniso_grid; -layout(r32ui, set = 3, binding = 3) uniform restrict uimage3D geom_facing_grid; +layout(r16ui, set = 1, binding = 7) uniform restrict writeonly uimage3D albedo_volume_grid; +layout(r32ui, set = 1, binding = 8) uniform restrict writeonly uimage3D emission_grid; +layout(r32ui, set = 1, binding = 9) uniform restrict writeonly uimage3D emission_aniso_grid; +layout(r32ui, set = 1, binding = 10) uniform restrict uimage3D geom_facing_grid; //still need to be present for shaders that use it, so remap them to something #define depth_buffer shadow_atlas @@ -277,14 +295,17 @@ layout(r32ui, set = 3, binding = 3) uniform restrict uimage3D geom_facing_grid; #else -layout(set = 3, binding = 0) uniform texture2D depth_buffer; -layout(set = 3, binding = 1) uniform texture2D color_buffer; -layout(set = 3, binding = 2) uniform texture2D normal_roughness_buffer; -layout(set = 3, binding = 4) uniform texture2D ao_buffer; -layout(set = 3, binding = 5) uniform texture2D ambient_buffer; -layout(set = 3, binding = 6) uniform texture2D reflection_buffer; -layout(set = 3, binding = 7) uniform texture2DArray sdfgi_lightprobe_texture; -layout(set = 3, binding = 8) uniform texture3D sdfgi_occlusion_cascades; +layout(set = 1, binding = 7) uniform texture2D depth_buffer; +layout(set = 1, binding = 8) uniform texture2D color_buffer; + +#ifndef LOW_END_MODE + +layout(set = 1, binding = 9) uniform texture2D normal_roughness_buffer; +layout(set = 1, binding = 10) uniform texture2D ao_buffer; +layout(set = 1, binding = 11) uniform texture2D ambient_buffer; +layout(set = 1, binding = 12) uniform texture2D reflection_buffer; +layout(set = 1, binding = 13) uniform texture2DArray sdfgi_lightprobe_texture; +layout(set = 1, binding = 14) uniform texture3D sdfgi_occlusion_cascades; struct GIProbeData { mat4 xform; @@ -302,18 +323,20 @@ struct GIProbeData { uint mipmaps; }; -layout(set = 3, binding = 9, std140) uniform GIProbes { +layout(set = 1, binding = 15, std140) uniform GIProbes { GIProbeData data[MAX_GI_PROBES]; } gi_probes; -layout(set = 3, binding = 10) uniform texture3D volumetric_fog_texture; +layout(set = 1, binding = 16) uniform texture3D volumetric_fog_texture; + +#endif // LOW_END_MODE #endif /* Set 4 Skeleton & Instancing (Multimesh) */ -layout(set = 4, binding = 0, std430) restrict readonly buffer Transforms { +layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms { vec4 data[]; } transforms; diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl index 06dc4b13de..06dc4b13de 100644 --- a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl +++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl index a5afe74cb2..a5afe74cb2 100644 --- a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl +++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl index 218605a962..218605a962 100644 --- a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl +++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_debug.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl index 813ea29fa1..e4c3f3a84b 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_debug.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl @@ -97,6 +97,8 @@ void main() { float blend = 0.0; #if 1 + // No interpolation + vec3 inv_dir = 1.0 / ray_dir; float rough = 0.5; @@ -161,114 +163,11 @@ void main() { hit_light *= (dot(max(vec3(0.0), (hit_normal * hit_aniso0)), vec3(1.0)) + dot(max(vec3(0.0), (-hit_normal * hit_aniso1)), vec3(1.0))); - if (blend > 0.0) { - light = mix(light, hit_light, blend); - blend = 0.0; - } else { - light = hit_light; - - //process blend - float blend_from = (float(params.probe_axis_size - 1) / 2.0) - 2.5; - float blend_to = blend_from + 2.0; - - vec3 cam_pos = params.cam_transform[3].xyz - cascades.data[i].offset; - cam_pos *= cascades.data[i].to_cell; - - pos += ray_dir * min(advance, max_advance); - vec3 inner_pos = pos - cam_pos; - - inner_pos = inner_pos * float(params.probe_axis_size - 1) / params.grid_size.x; - - float len = length(inner_pos); - - inner_pos = abs(normalize(inner_pos)); - len *= max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - - if (len >= blend_from) { - blend = smoothstep(blend_from, blend_to, len); - - pos /= cascades.data[i].to_cell; - pos += cascades.data[i].offset; - ray_pos = pos; - hit = false; //continue trace for blend - - continue; - } - } + light = hit_light; break; } - light = mix(light, vec3(0.0), blend); - -#else - - vec3 inv_dir = 1.0 / ray_dir; - - bool hit = false; - vec4 light_accum = vec4(0.0); - - float blend_size = (params.grid_size.x / float(params.probe_axis_size - 1)) * 0.5; - - float radius_sizes[MAX_CASCADES]; - for (uint i = 0; i < params.max_cascades; i++) { - radius_sizes[i] = (1.0 / cascades.data[i].to_cell) * (params.grid_size.x * 0.5 - blend_size); - } - - float max_distance = radius_sizes[params.max_cascades - 1]; - float advance = 0; - while (advance < max_distance) { - for (uint i = 0; i < params.max_cascades; i++) { - if (advance < radius_sizes[i]) { - vec3 pos = (ray_pos + ray_dir * advance) - cascades.data[i].offset; - pos *= cascades.data[i].to_cell * pos_to_uvw; - - float distance = texture(sampler3D(sdf_cascades[i], linear_sampler), pos).r * 255.0 - 1.0; - - vec4 hit_light = vec4(0.0); - if (distance < 1.0) { - hit_light.a = max(0.0, 1.0 - distance); - hit_light.rgb = texture(sampler3D(light_cascades[i], linear_sampler), pos).rgb; - hit_light.rgb *= hit_light.a; - } - - distance /= cascades.data[i].to_cell; - - if (i < (params.max_cascades - 1)) { - pos = (ray_pos + ray_dir * advance) - cascades.data[i + 1].offset; - pos *= cascades.data[i + 1].to_cell * pos_to_uvw; - - float distance2 = texture(sampler3D(sdf_cascades[i + 1], linear_sampler), pos).r * 255.0 - 1.0; - - vec4 hit_light2 = vec4(0.0); - if (distance2 < 1.0) { - hit_light2.a = max(0.0, 1.0 - distance2); - hit_light2.rgb = texture(sampler3D(light_cascades[i + 1], linear_sampler), pos).rgb; - hit_light2.rgb *= hit_light2.a; - } - - float prev_radius = i == 0 ? 0.0 : radius_sizes[i - 1]; - float blend = (advance - prev_radius) / (radius_sizes[i] - prev_radius); - - distance2 /= cascades.data[i + 1].to_cell; - - hit_light = mix(hit_light, hit_light2, blend); - distance = mix(distance, distance2, blend); - } - - light_accum += hit_light; - advance += distance; - break; - } - } - - if (light_accum.a > 0.98) { - break; - } - } - - light = light_accum.rgb / light_accum.a; - #endif imageStore(screen_buffer, screen_pos, vec4(linear_to_srgb(light), 1.0)); diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_debug_probes.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl index 08da283dad..08da283dad 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_debug_probes.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl index 61e4bf5e18..bcdfe8cc85 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_direct_light.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl @@ -112,11 +112,23 @@ vec2 octahedron_encode(vec3 n) { return n.xy; } +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} + void main() { uint voxel_index = uint(gl_GlobalInvocationID.x); //used for skipping voxels every N frames - voxel_index = params.process_offset + voxel_index * params.process_increment; + if (params.process_increment > 1) { + voxel_index *= params.process_increment; + voxel_index += params.process_offset; + } if (voxel_index >= dispatch_data.total_count) { return; @@ -134,10 +146,78 @@ void main() { uint voxel_albedo = process_voxels.data[voxel_index].albedo; vec3 albedo = vec3(uvec3(voxel_albedo >> 10, voxel_albedo >> 5, voxel_albedo) & uvec3(0x1F)) / float(0x1F); - vec3 light_accum[6]; - + vec3 light_accum[6] = vec3[](vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0)); uint valid_aniso = (voxel_albedo >> 15) & 0x3F; + const vec3 aniso_dir[6] = vec3[]( + vec3(1, 0, 0), + vec3(0, 1, 0), + vec3(0, 0, 1), + vec3(-1, 0, 0), + vec3(0, -1, 0), + vec3(0, 0, -1)); + + // Add indirect light first, in order to save computation resources +#ifdef MODE_PROCESS_DYNAMIC + if (params.multibounce) { + vec3 pos = (vec3(positioni) + vec3(0.5)) * float(params.probe_axis_size - 1) / params.grid_size; + ivec3 probe_base_pos = ivec3(pos); + + float weight_accum[6] = float[](0, 0, 0, 0, 0, 0); + + ivec3 tex_pos = ivec3(probe_base_pos.xy, int(params.cascade)); + tex_pos.x += probe_base_pos.z * int(params.probe_axis_size); + + tex_pos.xy = tex_pos.xy * (OCT_SIZE + 2) + ivec2(1); + + vec3 base_tex_posf = vec3(tex_pos); + vec2 tex_pixel_size = 1.0 / vec2(ivec2((OCT_SIZE + 2) * params.probe_axis_size * params.probe_axis_size, (OCT_SIZE + 2) * params.probe_axis_size)); + vec3 probe_uv_offset = (ivec3(OCT_SIZE + 2, OCT_SIZE + 2, (OCT_SIZE + 2) * params.probe_axis_size)) * tex_pixel_size.xyx; + + for (uint j = 0; j < 8; j++) { + ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1); + ivec3 probe_posi = probe_base_pos; + probe_posi += offset; + + // Compute weight + + vec3 probe_pos = vec3(probe_posi); + vec3 probe_to_pos = pos - probe_pos; + vec3 probe_dir = normalize(-probe_to_pos); + + // Compute lightprobe texture position + + vec3 trilinear = vec3(1.0) - abs(probe_to_pos); + + for (uint k = 0; k < 6; k++) { + if (bool(valid_aniso & (1 << k))) { + vec3 n = aniso_dir[k]; + float weight = trilinear.x * trilinear.y * trilinear.z * max(0.005, dot(n, probe_dir)); + + vec3 tex_posf = base_tex_posf + vec3(octahedron_encode(n) * float(OCT_SIZE), 0.0); + tex_posf.xy *= tex_pixel_size; + + vec3 pos_uvw = tex_posf; + pos_uvw.xy += vec2(offset.xy) * probe_uv_offset.xy; + pos_uvw.x += float(offset.z) * probe_uv_offset.z; + vec3 indirect_light = textureLod(sampler2DArray(lightprobe_texture, linear_sampler), pos_uvw, 0.0).rgb; + + light_accum[k] += indirect_light * weight; + weight_accum[k] += weight; + } + } + } + + for (uint k = 0; k < 6; k++) { + if (weight_accum[k] > 0.0) { + light_accum[k] /= weight_accum[k]; + light_accum[k] *= albedo; + } + } + } + +#endif + { uint rgbe = process_voxels.data[voxel_index].light; @@ -153,18 +233,10 @@ void main() { uint aniso = process_voxels.data[voxel_index].light_aniso; for (uint i = 0; i < 6; i++) { float strength = ((aniso >> (i * 5)) & 0x1F) / float(0x1F); - light_accum[i] = l * strength; + light_accum[i] += l * strength; } } - const vec3 aniso_dir[6] = vec3[]( - vec3(1, 0, 0), - vec3(0, 1, 0), - vec3(0, 0, 1), - vec3(-1, 0, 0), - vec3(0, -1, 0), - vec3(0, 0, -1)); - // Raytrace light vec3 pos_to_uvw = 1.0 / params.grid_size; @@ -184,14 +256,15 @@ void main() { direction = normalize(rel_vec); light_distance = length(rel_vec); rel_vec.y /= params.y_mult; - attenuation = pow(clamp(1.0 - length(rel_vec) / lights.data[i].radius, 0.0, 1.0), lights.data[i].attenuation); + attenuation = get_omni_attenuation(light_distance, 1.0 / lights.data[i].radius, lights.data[i].attenuation); + } break; case LIGHT_TYPE_SPOT: { vec3 rel_vec = lights.data[i].position - position; direction = normalize(rel_vec); light_distance = length(rel_vec); rel_vec.y /= params.y_mult; - attenuation = pow(clamp(1.0 - length(rel_vec) / lights.data[i].radius, 0.0, 1.0), lights.data[i].attenuation); + attenuation = get_omni_attenuation(light_distance, 1.0 / lights.data[i].radius, lights.data[i].attenuation); float angle = acos(dot(normalize(rel_vec), -lights.data[i].direction)); if (angle > lights.data[i].spot_angle) { @@ -282,65 +355,6 @@ void main() { } } - // Add indirect light - - if (params.multibounce) { - vec3 pos = (vec3(positioni) + vec3(0.5)) * float(params.probe_axis_size - 1) / params.grid_size; - ivec3 probe_base_pos = ivec3(pos); - - vec4 probe_accum[6] = vec4[](vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); - float weight_accum[6] = float[](0, 0, 0, 0, 0, 0); - - ivec3 tex_pos = ivec3(probe_base_pos.xy, int(params.cascade)); - tex_pos.x += probe_base_pos.z * int(params.probe_axis_size); - - tex_pos.xy = tex_pos.xy * (OCT_SIZE + 2) + ivec2(1); - - vec3 base_tex_posf = vec3(tex_pos); - vec2 tex_pixel_size = 1.0 / vec2(ivec2((OCT_SIZE + 2) * params.probe_axis_size * params.probe_axis_size, (OCT_SIZE + 2) * params.probe_axis_size)); - vec3 probe_uv_offset = (ivec3(OCT_SIZE + 2, OCT_SIZE + 2, (OCT_SIZE + 2) * params.probe_axis_size)) * tex_pixel_size.xyx; - - for (uint j = 0; j < 8; j++) { - ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1); - ivec3 probe_posi = probe_base_pos; - probe_posi += offset; - - // Compute weight - - vec3 probe_pos = vec3(probe_posi); - vec3 probe_to_pos = pos - probe_pos; - vec3 probe_dir = normalize(-probe_to_pos); - - // Compute lightprobe texture position - - vec3 trilinear = vec3(1.0) - abs(probe_to_pos); - - for (uint k = 0; k < 6; k++) { - if (bool(valid_aniso & (1 << k))) { - vec3 n = aniso_dir[k]; - float weight = trilinear.x * trilinear.y * trilinear.z * max(0.005, dot(n, probe_dir)); - - vec3 tex_posf = base_tex_posf + vec3(octahedron_encode(n) * float(OCT_SIZE), 0.0); - tex_posf.xy *= tex_pixel_size; - - vec3 pos_uvw = tex_posf; - pos_uvw.xy += vec2(offset.xy) * probe_uv_offset.xy; - pos_uvw.x += float(offset.z) * probe_uv_offset.z; - vec4 indirect_light = textureLod(sampler2DArray(lightprobe_texture, linear_sampler), pos_uvw, 0.0); - - probe_accum[k] += indirect_light * weight; - weight_accum[k] += weight; - } - } - } - - for (uint k = 0; k < 6; k++) { - if (weight_accum[k] > 0.0) { - light_accum[k] += probe_accum[k].rgb * albedo / weight_accum[k]; - } - } - } - // Store the light in the light texture float lumas[6]; diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_fields.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl index eec0a90c0d..69d8824d8a 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_fields.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl @@ -14,7 +14,7 @@ layout(local_size_x = OCT_RES, local_size_y = OCT_RES, local_size_z = 1) in; layout(rgba16f, set = 0, binding = 1) uniform restrict image2DArray irradiance_texture; layout(rg16f, set = 0, binding = 2) uniform restrict image2DArray depth_texture; -ayout(rgba32ui, set = 0, binding = 3) uniform restrict uimage2DArray irradiance_history_texture; +layout(rgba32ui, set = 0, binding = 3) uniform restrict uimage2DArray irradiance_history_texture; layout(rg32ui, set = 0, binding = 4) uniform restrict uimage2DArray depth_history_texture; struct CascadeData { diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl index d516ab22c3..e4f6f4b7ea 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_integrate.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl @@ -39,8 +39,11 @@ layout(rgba32i, set = 0, binding = 13) uniform restrict iimage2D lightprobe_aver layout(rgba16f, set = 0, binding = 14) uniform restrict writeonly image2DArray lightprobe_ambient_texture; +#ifdef USE_CUBEMAP_ARRAY +layout(set = 1, binding = 0) uniform textureCubeArray sky_irradiance; +#else layout(set = 1, binding = 0) uniform textureCube sky_irradiance; - +#endif layout(set = 1, binding = 1) uniform sampler linear_sampler_mipmaps; #define HISTORY_BITS 10 @@ -136,12 +139,24 @@ uint rgbe_encode(vec3 color) { return (uint(sRed) & 0x1FF) | ((uint(sGreen) & 0x1FF) << 9) | ((uint(sBlue) & 0x1FF) << 18) | ((uint(exps) & 0x1F) << 27); } +struct SH { +#if (SH_SIZE == 16) + float c[48]; +#else + float c[28]; +#endif +}; + +shared SH sh_accum[64]; //8x8 + void main() { ivec2 pos = ivec2(gl_GlobalInvocationID.xy); if (any(greaterThanEqual(pos, params.image_size))) { //too large, do nothing return; } + uint probe_index = gl_LocalInvocationID.x + gl_LocalInvocationID.y * 8; + #ifdef MODE_PROCESS float probe_cell_size = float(params.grid_size.x / float(params.probe_axis_size - 1)) / cascades.data[params.cascade].to_cell; @@ -154,27 +169,9 @@ void main() { vec3 probe_pos = cascades.data[params.cascade].offset + vec3(probe_cell) * probe_cell_size; vec3 pos_to_uvw = 1.0 / params.grid_size; - vec4 probe_sh_accum[SH_SIZE] = vec4[]( - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0) -#if (SH_SIZE == 16) - , - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0), - vec4(0.0) -#endif - ); + for (uint i = 0; i < SH_SIZE * 3; i++) { + sh_accum[probe_index].c[i] = 0.0; + } // quickly ensure each probe has a different "offset" for the vogel function, based on integer world position uvec3 h3 = hash3(uvec3(params.world_offset + probe_cell)); @@ -195,14 +192,12 @@ void main() { vec3 inv_dir = 1.0 / ray_dir; bool hit = false; - vec3 hit_normal; - vec3 hit_light; - vec3 hit_aniso0; - vec3 hit_aniso1; + uint hit_cascade; float bias = params.ray_bias; vec3 abs_ray_dir = abs(ray_dir); ray_pos += ray_dir * 1.0 / max(abs_ray_dir.x, max(abs_ray_dir.y, abs_ray_dir.z)) * bias / cascades.data[params.cascade].to_cell; + vec3 uvw; for (uint j = params.cascade; j < params.max_cascades; j++) { //convert to local bounds @@ -221,14 +216,12 @@ void main() { float advance = 0.0; - vec3 uvw; - while (advance < max_advance) { //read how much to advance from SDF uvw = (pos + ray_dir * advance) * pos_to_uvw; float distance = texture(sampler3D(sdf_cascades[j], linear_sampler), uvw).r * 255.0 - 1.0; - if (distance < 0.001) { + if (distance < 0.05) { //consider hit hit = true; break; @@ -238,17 +231,7 @@ void main() { } if (hit) { - const float EPSILON = 0.001; - hit_normal = normalize(vec3( - texture(sampler3D(sdf_cascades[j], linear_sampler), uvw + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_cascades[j], linear_sampler), uvw - vec3(EPSILON, 0.0, 0.0)).r, - texture(sampler3D(sdf_cascades[j], linear_sampler), uvw + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_cascades[j], linear_sampler), uvw - vec3(0.0, EPSILON, 0.0)).r, - texture(sampler3D(sdf_cascades[j], linear_sampler), uvw + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_cascades[j], linear_sampler), uvw - vec3(0.0, 0.0, EPSILON)).r)); - - hit_light = texture(sampler3D(light_cascades[j], linear_sampler), uvw).rgb; - vec4 aniso0 = texture(sampler3D(aniso0_cascades[j], linear_sampler), uvw); - hit_aniso0 = aniso0.rgb; - hit_aniso1 = vec3(aniso0.a, texture(sampler3D(aniso1_cascades[j], linear_sampler), uvw).rg); - + hit_cascade = j; break; } @@ -261,11 +244,26 @@ void main() { vec4 light; if (hit) { + const float EPSILON = 0.001; + vec3 hit_normal = normalize(vec3( + texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw - vec3(EPSILON, 0.0, 0.0)).r, + texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw - vec3(0.0, EPSILON, 0.0)).r, + texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_cascades[hit_cascade], linear_sampler), uvw - vec3(0.0, 0.0, EPSILON)).r)); + + vec3 hit_light = texture(sampler3D(light_cascades[hit_cascade], linear_sampler), uvw).rgb; + vec4 aniso0 = texture(sampler3D(aniso0_cascades[hit_cascade], linear_sampler), uvw); + vec3 hit_aniso0 = aniso0.rgb; + vec3 hit_aniso1 = vec3(aniso0.a, texture(sampler3D(aniso1_cascades[hit_cascade], linear_sampler), uvw).rg); + //one liner magic light.rgb = hit_light * (dot(max(vec3(0.0), (hit_normal * hit_aniso0)), vec3(1.0)) + dot(max(vec3(0.0), (-hit_normal * hit_aniso1)), vec3(1.0))); light.a = 1.0; } else if (params.sky_mode == SKY_MODE_SKY) { +#ifdef USE_CUBEMAP_ARRAY + light.rgb = textureLod(samplerCubeArray(sky_irradiance, linear_sampler_mipmaps), vec4(ray_dir, 0.0), 2.0).rgb; //use second mipmap because we dont usually throw a lot of rays, so this compensates +#else light.rgb = textureLod(samplerCube(sky_irradiance, linear_sampler_mipmaps), ray_dir, 2.0).rgb; //use second mipmap because we dont usually throw a lot of rays, so this compensates +#endif light.rgb *= params.sky_energy; light.a = 0.0; @@ -278,33 +276,33 @@ void main() { } vec3 ray_dir2 = ray_dir * ray_dir; - float c[SH_SIZE] = float[]( - - 0.282095, //l0 - 0.488603 * ray_dir.y, //l1n1 - 0.488603 * ray_dir.z, //l1n0 - 0.488603 * ray_dir.x, //l1p1 - 1.092548 * ray_dir.x * ray_dir.y, //l2n2 - 1.092548 * ray_dir.y * ray_dir.z, //l2n1 - 0.315392 * (3.0 * ray_dir2.z - 1.0), //l20 - 1.092548 * ray_dir.x * ray_dir.z, //l2p1 - 0.546274 * (ray_dir2.x - ray_dir2.y) //l2p2 + +#define SH_ACCUM(m_idx, m_value) \ + { \ + vec3 l = light.rgb * (m_value); \ + sh_accum[probe_index].c[m_idx * 3 + 0] += l.r; \ + sh_accum[probe_index].c[m_idx * 3 + 1] += l.g; \ + sh_accum[probe_index].c[m_idx * 3 + 2] += l.b; \ + } + SH_ACCUM(0, 0.282095); //l0 + SH_ACCUM(1, 0.488603 * ray_dir.y); //l1n1 + SH_ACCUM(2, 0.488603 * ray_dir.z); //l1n0 + SH_ACCUM(3, 0.488603 * ray_dir.x); //l1p1 + SH_ACCUM(4, 1.092548 * ray_dir.x * ray_dir.y); //l2n2 + SH_ACCUM(5, 1.092548 * ray_dir.y * ray_dir.z); //l2n1 + SH_ACCUM(6, 0.315392 * (3.0 * ray_dir2.z - 1.0)); //l20 + SH_ACCUM(7, 1.092548 * ray_dir.x * ray_dir.z); //l2p1 + SH_ACCUM(8, 0.546274 * (ray_dir2.x - ray_dir2.y)); //l2p2 #if (SH_SIZE == 16) - , - 0.590043 * ray_dir.y * (3.0f * ray_dir2.x - ray_dir2.y), - 2.890611 * ray_dir.y * ray_dir.x * ray_dir.z, - 0.646360 * ray_dir.y * (-1.0f + 5.0f * ray_dir2.z), - 0.373176 * (5.0f * ray_dir2.z * ray_dir.z - 3.0f * ray_dir.z), - 0.457045 * ray_dir.x * (-1.0f + 5.0f * ray_dir2.z), - 1.445305 * (ray_dir2.x - ray_dir2.y) * ray_dir.z, - 0.590043 * ray_dir.x * (ray_dir2.x - 3.0f * ray_dir2.y) + SH_ACCUM(9, 0.590043 * ray_dir.y * (3.0f * ray_dir2.x - ray_dir2.y)); + SH_ACCUM(10, 2.890611 * ray_dir.y * ray_dir.x * ray_dir.z); + SH_ACCUM(11, 0.646360 * ray_dir.y * (-1.0f + 5.0f * ray_dir2.z)); + SH_ACCUM(12, 0.373176 * (5.0f * ray_dir2.z * ray_dir.z - 3.0f * ray_dir.z)); + SH_ACCUM(13, 0.457045 * ray_dir.x * (-1.0f + 5.0f * ray_dir2.z)); + SH_ACCUM(14, 1.445305 * (ray_dir2.x - ray_dir2.y) * ray_dir.z); + SH_ACCUM(15, 0.590043 * ray_dir.x * (ray_dir2.x - 3.0f * ray_dir2.y)); #endif - ); - - for (uint j = 0; j < SH_SIZE; j++) { - probe_sh_accum[j] += light * c[j]; - } } for (uint i = 0; i < SH_SIZE; i++) { @@ -312,7 +310,7 @@ void main() { ivec3 prev_pos = ivec3(pos.x, pos.y * SH_SIZE + i, int(params.history_index)); ivec2 average_pos = prev_pos.xy; - vec4 value = probe_sh_accum[i] * 4.0 / float(params.ray_count); + vec4 value = vec4(sh_accum[probe_index].c[i * 3 + 0], sh_accum[probe_index].c[i * 3 + 1], sh_accum[probe_index].c[i * 3 + 2], 1.0) * 4.0 / float(params.ray_count); ivec4 ivalue = clamp(ivec4(value * float(1 << HISTORY_BITS)), -32768, 32767); //clamp to 16 bits, so higher values don't break average @@ -344,37 +342,11 @@ void main() { ivec2 oct_pos = (pos / OCT_SIZE) * (OCT_SIZE + 2) + ivec2(1); ivec2 local_pos = pos % OCT_SIZE; - //fill the spherical harmonic - vec4 sh[SH_SIZE]; - - for (uint i = 0; i < SH_SIZE; i++) { - // store in history texture - ivec2 average_pos = sh_pos + ivec2(0, i); - ivec4 average = imageLoad(lightprobe_average_texture, average_pos); - - sh[i] = (vec4(average) / float(params.history_size)) / float(1 << HISTORY_BITS); - } - //compute the octahedral normal for this texel vec3 normal = octahedron_encode(vec2(local_pos) / float(OCT_SIZE)); - /* + // read the spherical harmonic - const float c1 = 0.429043; - const float c2 = 0.511664; - const float c3 = 0.743125; - const float c4 = 0.886227; - const float c5 = 0.247708; - vec4 light = (c1 * sh[8] * (normal.x * normal.x - normal.y * normal.y) + - c3 * sh[6] * normal.z * normal.z + - c4 * sh[0] - - c5 * sh[6] + - 2.0 * c1 * sh[4] * normal.x * normal.y + - 2.0 * c1 * sh[7] * normal.x * normal.z + - 2.0 * c1 * sh[5] * normal.y * normal.z + - 2.0 * c2 * sh[3] * normal.x + - 2.0 * c2 * sh[1] * normal.y + - 2.0 * c2 * sh[2] * normal.z); -*/ + vec3 normal2 = normal * normal; float c[SH_SIZE] = float[]( @@ -426,7 +398,14 @@ void main() { vec3 radiance = vec3(0.0); for (uint i = 0; i < SH_SIZE; i++) { - vec3 m = sh[i].rgb * c[i] * 4.0; + // store in history texture + ivec2 average_pos = sh_pos + ivec2(0, i); + ivec4 average = imageLoad(lightprobe_average_texture, average_pos); + + vec4 sh = (vec4(average) / float(params.history_size)) / float(1 << HISTORY_BITS); + + vec3 m = sh.rgb * c[i] * 4.0; + irradiance += m * l_mult[i]; radiance += m; } @@ -515,13 +494,15 @@ void main() { //can't scroll, must look for position in parent cascade //to global coords - float probe_cell_size = float(params.grid_size.x / float(params.probe_axis_size - 1)) / cascades.data[params.cascade].to_cell; + float cell_to_probe = float(params.grid_size.x / float(params.probe_axis_size - 1)); + + float probe_cell_size = cell_to_probe / cascades.data[params.cascade].to_cell; vec3 probe_pos = cascades.data[params.cascade].offset + vec3(probe_cell) * probe_cell_size; //to parent local coords + float probe_cell_size_next = cell_to_probe / cascades.data[params.cascade + 1].to_cell; probe_pos -= cascades.data[params.cascade + 1].offset; - probe_pos *= cascades.data[params.cascade + 1].to_cell; - probe_pos = probe_pos * float(params.probe_axis_size - 1) / float(params.grid_size.x); + probe_pos /= probe_cell_size_next; ivec3 probe_posi = ivec3(probe_pos); //add up all light, no need to use occlusion here, since occlusion will do its work afterwards @@ -574,20 +555,28 @@ void main() { } } else { - // clear and let it re-raytrace, only for the last cascade, which happens very un-often - //scroll + //scroll at the edge of the highest cascade, just copy what is there, + //since its the closest we have anyway + for (uint j = 0; j < params.history_size; j++) { + ivec2 tex_pos; + tex_pos = probe_cell.xy; + tex_pos.x += probe_cell.z * int(params.probe_axis_size); + for (int i = 0; i < SH_SIZE; i++) { // copy from history texture + ivec3 src_pos = ivec3(tex_pos.x, tex_pos.y * SH_SIZE + i, int(j)); ivec3 dst_pos = ivec3(pos.x, pos.y * SH_SIZE + i, int(j)); - imageStore(lightprobe_history_scroll_texture, dst_pos, ivec4(0)); + ivec4 value = imageLoad(lightprobe_history_texture, dst_pos); + imageStore(lightprobe_history_scroll_texture, dst_pos, value); } } for (int i = 0; i < SH_SIZE; i++) { // copy from average texture - ivec2 dst_pos = ivec2(pos.x, pos.y * SH_SIZE + i); - imageStore(lightprobe_average_scroll_texture, dst_pos, ivec4(0)); + ivec2 spos = ivec2(pos.x, pos.y * SH_SIZE + i); + ivec4 average = imageLoad(lightprobe_average_texture, spos); + imageStore(lightprobe_average_scroll_texture, spos, average); } } diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl index 916c60ac89..916c60ac89 100644 --- a/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl b/servers/rendering/renderer_rd/shaders/shadow_reduce.glsl index 29443ae7db..29443ae7db 100644 --- a/servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl +++ b/servers/rendering/renderer_rd/shaders/shadow_reduce.glsl diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl new file mode 100644 index 0000000000..b19f5a9ad3 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl @@ -0,0 +1,199 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; + +layout(set = 0, binding = 1, std430) buffer restrict writeonly DstVertexData { + uint data[]; +} +dst_vertices; + +layout(set = 0, binding = 2, std430) buffer restrict readonly BlendShapeWeights { + float data[]; +} +blend_shape_weights; + +layout(set = 1, binding = 0, std430) buffer restrict readonly SrcVertexData { + uint data[]; +} +src_vertices; + +layout(set = 1, binding = 1, std430) buffer restrict readonly BoneWeightData { + uint data[]; +} +src_bone_weights; + +layout(set = 1, binding = 2, std430) buffer restrict readonly BlendShapeData { + uint data[]; +} +src_blend_shapes; + +layout(set = 2, binding = 0, std430) buffer restrict readonly SkeletonData { + vec4 data[]; +} +bone_transforms; + +layout(push_constant, binding = 0, std430) uniform Params { + bool has_normal; + bool has_tangent; + bool has_skeleton; + bool has_blend_shape; + + uint vertex_count; + uint vertex_stride; + uint skin_stride; + uint skin_weight_offset; + + uint blend_shape_count; + bool normalized_blend_shapes; + uint pad0; + uint pad1; +} +params; + +vec4 decode_abgr_2_10_10_10(uint base) { + uvec4 abgr_2_10_10_10 = (uvec4(base) >> uvec4(0, 10, 20, 30)) & uvec4(0x3FF, 0x3FF, 0x3FF, 0x3); + return vec4(abgr_2_10_10_10) / vec4(1023.0, 1023.0, 1023.0, 3.0) * 2.0 - 1.0; +} + +uint encode_abgr_2_10_10_10(vec4 base) { + uvec4 abgr_2_10_10_10 = uvec4(clamp(ivec4((base * 0.5 + 0.5) * vec4(1023.0, 1023.0, 1023.0, 3.0)), ivec4(0), ivec4(0x3FF, 0x3FF, 0x3FF, 0x3))) << uvec4(0, 10, 20, 30); + return abgr_2_10_10_10.x | abgr_2_10_10_10.y | abgr_2_10_10_10.z | abgr_2_10_10_10.w; +} + +void main() { + uint index = gl_GlobalInvocationID.x; + if (index >= params.vertex_count) { + return; + } + + uint src_offset = index * params.vertex_stride; + +#ifdef MODE_2D + vec2 vertex = uintBitsToFloat(uvec2(src_vertices.data[src_offset + 0], src_vertices.data[src_offset + 1])); +#else + vec3 vertex; + vec3 normal; + vec4 tangent; + + vertex = uintBitsToFloat(uvec3(src_vertices.data[src_offset + 0], src_vertices.data[src_offset + 1], src_vertices.data[src_offset + 2])); + + src_offset += 3; + + if (params.has_normal) { + normal = decode_abgr_2_10_10_10(src_vertices.data[src_offset]).rgb; + src_offset++; + } + + if (params.has_tangent) { + tangent = decode_abgr_2_10_10_10(src_vertices.data[src_offset]); + } + + if (params.has_blend_shape) { + float blend_total = 0.0; + vec3 blend_vertex = vec3(0.0); + vec3 blend_normal = vec3(0.0); + vec3 blend_tangent = vec3(0.0); + + for (uint i = 0; i < params.blend_shape_count; i++) { + float w = blend_shape_weights.data[i]; + if (w > 0.0001) { + uint base_offset = (params.vertex_count * i + index) * params.vertex_stride; + + blend_vertex += uintBitsToFloat(uvec3(src_blend_shapes.data[base_offset + 0], src_blend_shapes.data[base_offset + 1], src_blend_shapes.data[base_offset + 2])) * w; + + base_offset += 3; + + if (params.has_normal) { + blend_normal += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb * w; + base_offset++; + } + + if (params.has_tangent) { + blend_tangent += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb; + } + + blend_total += w; + } + } + + if (params.normalized_blend_shapes) { + vertex = (1.0 - blend_total) * vertex; + normal = (1.0 - blend_total) * normal; + tangent.rgb = (1.0 - blend_total) * tangent.rgb; + } + + vertex += blend_vertex; + normal += normalize(normal + blend_normal); + tangent.rgb += normalize(tangent.rgb + blend_tangent); + } + + if (params.has_skeleton) { + uint skin_offset = params.skin_stride * index; + + uvec2 bones = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]); + uvec2 bones_01 = uvec2(bones.x & 0xFFFF, bones.x >> 16) * 3; //pre-add xform offset + uvec2 bones_23 = uvec2(bones.y & 0xFFFF, bones.y >> 16) * 3; + + skin_offset += params.skin_weight_offset; + + uvec2 weights = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]); + + vec2 weights_01 = unpackUnorm2x16(weights.x); + vec2 weights_23 = unpackUnorm2x16(weights.y); + + mat4 m = mat4(bone_transforms.data[bones_01.x], bone_transforms.data[bones_01.x + 1], bone_transforms.data[bones_01.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.x; + m += mat4(bone_transforms.data[bones_01.y], bone_transforms.data[bones_01.y + 1], bone_transforms.data[bones_01.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.y; + m += mat4(bone_transforms.data[bones_23.x], bone_transforms.data[bones_23.x + 1], bone_transforms.data[bones_23.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.x; + m += mat4(bone_transforms.data[bones_23.y], bone_transforms.data[bones_23.y + 1], bone_transforms.data[bones_23.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.y; + + if (params.skin_weight_offset == 4) { + //using 8 bones/weights + skin_offset = params.skin_stride * index + 2; + + bones = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]); + bones_01 = uvec2(bones.x & 0xFFFF, bones.x >> 16) * 3; //pre-add xform offset + bones_23 = uvec2(bones.y & 0xFFFF, bones.y >> 16) * 3; + + skin_offset += params.skin_weight_offset; + + weights = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]); + + weights_01 = unpackUnorm2x16(weights.x); + weights_23 = unpackUnorm2x16(weights.y); + + m += mat4(bone_transforms.data[bones_01.x], bone_transforms.data[bones_01.x + 1], bone_transforms.data[bones_01.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.x; + m += mat4(bone_transforms.data[bones_01.y], bone_transforms.data[bones_01.y + 1], bone_transforms.data[bones_01.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.y; + m += mat4(bone_transforms.data[bones_23.x], bone_transforms.data[bones_23.x + 1], bone_transforms.data[bones_23.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.x; + m += mat4(bone_transforms.data[bones_23.y], bone_transforms.data[bones_23.y + 1], bone_transforms.data[bones_23.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.y; + } + + //reverse order because its transposed + vertex = (vec4(vertex, 1.0) * m).xyz; + normal = normalize((vec4(normal, 0.0) * m).xyz); + tangent.xyz = normalize((vec4(tangent.xyz, 0.0) * m).xyz); + } + + uint dst_offset = index * params.vertex_stride; + + uvec3 uvertex = floatBitsToUint(vertex); + dst_vertices.data[dst_offset + 0] = uvertex.x; + dst_vertices.data[dst_offset + 1] = uvertex.y; + dst_vertices.data[dst_offset + 2] = uvertex.z; + + dst_offset += 3; + + if (params.has_normal) { + dst_vertices.data[dst_offset] = encode_abgr_2_10_10_10(vec4(normal, 0.0)); + dst_offset++; + } + + if (params.has_tangent) { + dst_vertices.data[dst_offset] = encode_abgr_2_10_10_10(tangent); + } + +#endif +} diff --git a/servers/rendering/rasterizer_rd/shaders/sky.glsl b/servers/rendering/renderer_rd/shaders/sky.glsl index 6c985e1f5c..6c985e1f5c 100644 --- a/servers/rendering/rasterizer_rd/shaders/sky.glsl +++ b/servers/rendering/renderer_rd/shaders/sky.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/sort.glsl b/servers/rendering/renderer_rd/shaders/sort.glsl index e5ebb9c64b..e5ebb9c64b 100644 --- a/servers/rendering/rasterizer_rd/shaders/sort.glsl +++ b/servers/rendering/renderer_rd/shaders/sort.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/specular_merge.glsl b/servers/rendering/renderer_rd/shaders/specular_merge.glsl index 0b8f406213..0b8f406213 100644 --- a/servers/rendering/rasterizer_rd/shaders/specular_merge.glsl +++ b/servers/rendering/renderer_rd/shaders/specular_merge.glsl diff --git a/servers/rendering/renderer_rd/shaders/ssao.glsl b/servers/rendering/renderer_rd/shaders/ssao.glsl new file mode 100644 index 0000000000..231f8f91ec --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssao.glsl @@ -0,0 +1,486 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2016, Intel Corporation +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of +// the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// File changes (yyyy-mm-dd) +// 2016-09-07: filip.strugar@intel.com: first commit +// 2020-12-05: clayjohn: convert to Vulkan and Godot +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#[compute] + +#version 450 + +VERSION_DEFINES + +#define SSAO_ADAPTIVE_TAP_BASE_COUNT 5 + +#define INTELSSAO_MAIN_DISK_SAMPLE_COUNT (32) +const vec4 sample_pattern[INTELSSAO_MAIN_DISK_SAMPLE_COUNT] = { + vec4(0.78488064, 0.56661671, 1.500000, -0.126083), vec4(0.26022232, -0.29575172, 1.500000, -1.064030), vec4(0.10459357, 0.08372527, 1.110000, -2.730563), vec4(-0.68286800, 0.04963045, 1.090000, -0.498827), + vec4(-0.13570161, -0.64190155, 1.250000, -0.532765), vec4(-0.26193795, -0.08205118, 0.670000, -1.783245), vec4(-0.61177456, 0.66664219, 0.710000, -0.044234), vec4(0.43675563, 0.25119025, 0.610000, -1.167283), + vec4(0.07884444, 0.86618668, 0.640000, -0.459002), vec4(-0.12790935, -0.29869005, 0.600000, -1.729424), vec4(-0.04031125, 0.02413622, 0.600000, -4.792042), vec4(0.16201244, -0.52851415, 0.790000, -1.067055), + vec4(-0.70991218, 0.47301072, 0.640000, -0.335236), vec4(0.03277707, -0.22349690, 0.600000, -1.982384), vec4(0.68921727, 0.36800742, 0.630000, -0.266718), vec4(0.29251814, 0.37775412, 0.610000, -1.422520), + vec4(-0.12224089, 0.96582592, 0.600000, -0.426142), vec4(0.11071457, -0.16131058, 0.600000, -2.165947), vec4(0.46562141, -0.59747696, 0.600000, -0.189760), vec4(-0.51548797, 0.11804193, 0.600000, -1.246800), + vec4(0.89141309, -0.42090443, 0.600000, 0.028192), vec4(-0.32402530, -0.01591529, 0.600000, -1.543018), vec4(0.60771245, 0.41635221, 0.600000, -0.605411), vec4(0.02379565, -0.08239821, 0.600000, -3.809046), + vec4(0.48951152, -0.23657045, 0.600000, -1.189011), vec4(-0.17611565, -0.81696892, 0.600000, -0.513724), vec4(-0.33930185, -0.20732205, 0.600000, -1.698047), vec4(-0.91974425, 0.05403209, 0.600000, 0.062246), + vec4(-0.15064627, -0.14949332, 0.600000, -1.896062), vec4(0.53180975, -0.35210401, 0.600000, -0.758838), vec4(0.41487166, 0.81442589, 0.600000, -0.505648), vec4(-0.24106961, -0.32721516, 0.600000, -1.665244) +}; + +// these values can be changed (up to SSAO_MAX_TAPS) with no changes required elsewhere; values for 4th and 5th preset are ignored but array needed to avoid compilation errors +// the actual number of texture samples is two times this value (each "tap" has two symmetrical depth texture samples) +const int num_taps[5] = { 3, 5, 12, 0, 0 }; + +#define SSAO_TILT_SAMPLES_ENABLE_AT_QUALITY_PRESET (99) // to disable simply set to 99 or similar +#define SSAO_TILT_SAMPLES_AMOUNT (0.4) +// +#define SSAO_HALOING_REDUCTION_ENABLE_AT_QUALITY_PRESET (1) // to disable simply set to 99 or similar +#define SSAO_HALOING_REDUCTION_AMOUNT (0.6) // values from 0.0 - 1.0, 1.0 means max weighting (will cause artifacts, 0.8 is more reasonable) +// +#define SSAO_NORMAL_BASED_EDGES_ENABLE_AT_QUALITY_PRESET (2) // to disable simply set to 99 or similar +#define SSAO_NORMAL_BASED_EDGES_DOT_THRESHOLD (0.5) // use 0-0.1 for super-sharp normal-based edges +// +#define SSAO_DETAIL_AO_ENABLE_AT_QUALITY_PRESET (1) // whether to use detail; to disable simply set to 99 or similar +// +#define SSAO_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET (2) // !!warning!! the MIP generation on the C++ side will be enabled on quality preset 2 regardless of this value, so if changing here, change the C++ side too +#define SSAO_DEPTH_MIPS_GLOBAL_OFFSET (-4.3) // best noise/quality/performance tradeoff, found empirically +// +// !!warning!! the edge handling is hard-coded to 'disabled' on quality level 0, and enabled above, on the C++ side; while toggling it here will work for +// testing purposes, it will not yield performance gains (or correct results) +#define SSAO_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET (1) +// +#define SSAO_REDUCE_RADIUS_NEAR_SCREEN_BORDER_ENABLE_AT_QUALITY_PRESET (1) + +#define SSAO_MAX_TAPS 32 +#define SSAO_MAX_REF_TAPS 512 +#define SSAO_ADAPTIVE_TAP_BASE_COUNT 5 +#define SSAO_ADAPTIVE_TAP_FLEXIBLE_COUNT (SSAO_MAX_TAPS - SSAO_ADAPTIVE_TAP_BASE_COUNT) +#define SSAO_DEPTH_MIP_LEVELS 4 + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(set = 0, binding = 0) uniform sampler2DArray source_depth_mipmaps; +layout(rgba8, set = 0, binding = 1) uniform restrict readonly image2D source_normal; +layout(set = 0, binding = 2) uniform Constants { //get into a lower set + vec4 rotation_matrices[20]; +} +constants; + +#ifdef ADAPTIVE +layout(rg8, set = 1, binding = 0) uniform restrict readonly image2DArray source_ssao; +layout(set = 1, binding = 1) uniform sampler2D source_importance; +layout(set = 1, binding = 2, std430) buffer Counter { + uint sum; +} +counter; +#endif + +layout(rg8, set = 2, binding = 0) uniform restrict writeonly image2D dest_image; + +// This push_constant is full - 128 bytes - if you need to add more data, consider adding to the uniform buffer instead +layout(push_constant, binding = 3, std430) uniform Params { + ivec2 screen_size; + int pass; + int quality; + + vec2 half_screen_pixel_size; + int size_multiplier; + float detail_intensity; + + vec2 NDC_to_view_mul; + vec2 NDC_to_view_add; + + vec2 pad2; + vec2 half_screen_pixel_size_x025; + + float radius; + float intensity; + float shadow_power; + float shadow_clamp; + + float fade_out_mul; + float fade_out_add; + float horizon_angle_threshold; + float inv_radius_near_limit; + + bool is_orthogonal; + float neg_inv_radius; + float load_counter_avg_div; + float adaptive_sample_limit; + + ivec2 pass_coord_offset; + vec2 pass_uv_offset; +} +params; + +// packing/unpacking for edges; 2 bits per edge mean 4 gradient values (0, 0.33, 0.66, 1) for smoother transitions! +float pack_edges(vec4 p_edgesLRTB) { + p_edgesLRTB = round(clamp(p_edgesLRTB, 0.0, 1.0) * 3.05); + return dot(p_edgesLRTB, vec4(64.0 / 255.0, 16.0 / 255.0, 4.0 / 255.0, 1.0 / 255.0)); +} + +vec3 NDC_to_view_space(vec2 p_pos, float p_viewspace_depth) { + if (params.is_orthogonal) { + return vec3((params.NDC_to_view_mul * p_pos.xy + params.NDC_to_view_add), p_viewspace_depth); + } else { + return vec3((params.NDC_to_view_mul * p_pos.xy + params.NDC_to_view_add) * p_viewspace_depth, p_viewspace_depth); + } +} + +// calculate effect radius and fit our screen sampling pattern inside it +void calculate_radius_parameters(const float p_pix_center_length, const vec2 p_pixel_size_at_center, out float r_lookup_radius, out float r_radius, out float r_fallof_sq) { + r_radius = params.radius; + + // when too close, on-screen sampling disk will grow beyond screen size; limit this to avoid closeup temporal artifacts + const float too_close_limit = clamp(p_pix_center_length * params.inv_radius_near_limit, 0.0, 1.0) * 0.8 + 0.2; + + r_radius *= too_close_limit; + + // 0.85 is to reduce the radius to allow for more samples on a slope to still stay within influence + r_lookup_radius = (0.85 * r_radius) / p_pixel_size_at_center.x; + + // used to calculate falloff (both for AO samples and per-sample weights) + r_fallof_sq = -1.0 / (r_radius * r_radius); +} + +vec4 calculate_edges(const float p_center_z, const float p_left_z, const float p_right_z, const float p_top_z, const float p_bottom_z) { + // slope-sensitive depth-based edge detection + vec4 edgesLRTB = vec4(p_left_z, p_right_z, p_top_z, p_bottom_z) - p_center_z; + vec4 edgesLRTB_slope_adjusted = edgesLRTB + edgesLRTB.yxwz; + edgesLRTB = min(abs(edgesLRTB), abs(edgesLRTB_slope_adjusted)); + return clamp((1.3 - edgesLRTB / (p_center_z * 0.040)), 0.0, 1.0); +} + +vec3 decode_normal(vec3 p_encoded_normal) { + vec3 normal = p_encoded_normal * 2.0 - 1.0; + return normal; +} + +vec3 load_normal(ivec2 p_pos) { + vec3 encoded_normal = imageLoad(source_normal, p_pos).xyz; + encoded_normal.z = 1.0 - encoded_normal.z; + return decode_normal(encoded_normal); +} + +vec3 load_normal(ivec2 p_pos, ivec2 p_offset) { + vec3 encoded_normal = imageLoad(source_normal, p_pos + p_offset).xyz; + encoded_normal.z = 1.0 - encoded_normal.z; + return decode_normal(encoded_normal); +} + +// all vectors in viewspace +float calculate_pixel_obscurance(vec3 p_pixel_normal, vec3 p_hit_delta, float p_fallof_sq) { + float length_sq = dot(p_hit_delta, p_hit_delta); + float NdotD = dot(p_pixel_normal, p_hit_delta) / sqrt(length_sq); + + float falloff_mult = max(0.0, length_sq * p_fallof_sq + 1.0); + + return max(0, NdotD - params.horizon_angle_threshold) * falloff_mult; +} + +void SSAO_tap_inner(const int p_quality_level, inout float r_obscurance_sum, inout float r_weight_sum, const vec2 p_sampling_uv, const float p_mip_level, const vec3 p_pix_center_pos, vec3 p_pixel_normal, const float p_fallof_sq, const float p_weight_mod) { + // get depth at sample + float viewspace_sample_z = textureLod(source_depth_mipmaps, vec3(p_sampling_uv, params.pass), p_mip_level).x; + + // convert to viewspace + vec3 hit_pos = NDC_to_view_space(p_sampling_uv.xy, viewspace_sample_z).xyz; + vec3 hit_delta = hit_pos - p_pix_center_pos; + + float obscurance = calculate_pixel_obscurance(p_pixel_normal, hit_delta, p_fallof_sq); + float weight = 1.0; + + if (p_quality_level >= SSAO_HALOING_REDUCTION_ENABLE_AT_QUALITY_PRESET) { + float reduct = max(0, -hit_delta.z); + reduct = clamp(reduct * params.neg_inv_radius + 2.0, 0.0, 1.0); + weight = SSAO_HALOING_REDUCTION_AMOUNT * reduct + (1.0 - SSAO_HALOING_REDUCTION_AMOUNT); + } + weight *= p_weight_mod; + r_obscurance_sum += obscurance * weight; + r_weight_sum += weight; +} + +void SSAOTap(const int p_quality_level, inout float r_obscurance_sum, inout float r_weight_sum, const int p_tap_index, const mat2 p_rot_scale, const vec3 p_pix_center_pos, vec3 p_pixel_normal, const vec2 p_normalized_screen_pos, const float p_mip_offset, const float p_fallof_sq, float p_weight_mod, vec2 p_norm_xy, float p_norm_xy_length) { + vec2 sample_offset; + float sample_pow_2_len; + + // patterns + { + vec4 new_sample = sample_pattern[p_tap_index]; + sample_offset = new_sample.xy * p_rot_scale; + sample_pow_2_len = new_sample.w; // precalculated, same as: sample_pow_2_len = log2( length( new_sample.xy ) ); + p_weight_mod *= new_sample.z; + } + + // snap to pixel center (more correct obscurance math, avoids artifacts) + sample_offset = round(sample_offset); + + // calculate MIP based on the sample distance from the centre, similar to as described + // in http://graphics.cs.williams.edu/papers/SAOHPG12/. + float mip_level = (p_quality_level < SSAO_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET) ? (0) : (sample_pow_2_len + p_mip_offset); + + vec2 sampling_uv = sample_offset * params.half_screen_pixel_size + p_normalized_screen_pos; + + SSAO_tap_inner(p_quality_level, r_obscurance_sum, r_weight_sum, sampling_uv, mip_level, p_pix_center_pos, p_pixel_normal, p_fallof_sq, p_weight_mod); + + // for the second tap, just use the mirrored offset + vec2 sample_offset_mirrored_uv = -sample_offset; + + // tilt the second set of samples so that the disk is effectively rotated by the normal + // effective at removing one set of artifacts, but too expensive for lower quality settings + if (p_quality_level >= SSAO_TILT_SAMPLES_ENABLE_AT_QUALITY_PRESET) { + float dot_norm = dot(sample_offset_mirrored_uv, p_norm_xy); + sample_offset_mirrored_uv -= dot_norm * p_norm_xy_length * p_norm_xy; + sample_offset_mirrored_uv = round(sample_offset_mirrored_uv); + } + + // snap to pixel center (more correct obscurance math, avoids artifacts) + vec2 sampling_mirrored_uv = sample_offset_mirrored_uv * params.half_screen_pixel_size + p_normalized_screen_pos; + + SSAO_tap_inner(p_quality_level, r_obscurance_sum, r_weight_sum, sampling_mirrored_uv, mip_level, p_pix_center_pos, p_pixel_normal, p_fallof_sq, p_weight_mod); +} + +void generate_SSAO_shadows_internal(out float r_shadow_term, out vec4 r_edges, out float r_weight, const vec2 p_pos, int p_quality_level, bool p_adaptive_base) { + vec2 pos_rounded = trunc(p_pos); + uvec2 upos = uvec2(pos_rounded); + + const int number_of_taps = (p_adaptive_base) ? (SSAO_ADAPTIVE_TAP_BASE_COUNT) : (num_taps[p_quality_level]); + float pix_z, pix_left_z, pix_top_z, pix_right_z, pix_bottom_z; + + vec4 valuesUL = textureGather(source_depth_mipmaps, vec3(pos_rounded * params.half_screen_pixel_size, params.pass)); + vec4 valuesBR = textureGather(source_depth_mipmaps, vec3((pos_rounded + vec2(1.0)) * params.half_screen_pixel_size, params.pass)); + + // get this pixel's viewspace depth + pix_z = valuesUL.y; + + // get left right top bottom neighbouring pixels for edge detection (gets compiled out on quality_level == 0) + pix_left_z = valuesUL.x; + pix_top_z = valuesUL.z; + pix_right_z = valuesBR.z; + pix_bottom_z = valuesBR.x; + + vec2 normalized_screen_pos = pos_rounded * params.half_screen_pixel_size + params.half_screen_pixel_size_x025; + vec3 pix_center_pos = NDC_to_view_space(normalized_screen_pos, pix_z); + + // Load this pixel's viewspace normal + uvec2 full_res_coord = upos * 2 * params.size_multiplier + params.pass_coord_offset.xy; + vec3 pixel_normal = load_normal(ivec2(full_res_coord)); + + const vec2 pixel_size_at_center = NDC_to_view_space(normalized_screen_pos.xy + params.half_screen_pixel_size, pix_center_pos.z).xy - pix_center_pos.xy; + + float pixel_lookup_radius; + float fallof_sq; + + // calculate effect radius and fit our screen sampling pattern inside it + float viewspace_radius; + calculate_radius_parameters(length(pix_center_pos), pixel_size_at_center, pixel_lookup_radius, viewspace_radius, fallof_sq); + + // calculate samples rotation/scaling + mat2 rot_scale_matrix; + uint pseudo_random_index; + + { + vec4 rotation_scale; + // reduce effect radius near the screen edges slightly; ideally, one would render a larger depth buffer (5% on each side) instead + if (!p_adaptive_base && (p_quality_level >= SSAO_REDUCE_RADIUS_NEAR_SCREEN_BORDER_ENABLE_AT_QUALITY_PRESET)) { + float near_screen_border = min(min(normalized_screen_pos.x, 1.0 - normalized_screen_pos.x), min(normalized_screen_pos.y, 1.0 - normalized_screen_pos.y)); + near_screen_border = clamp(10.0 * near_screen_border + 0.6, 0.0, 1.0); + pixel_lookup_radius *= near_screen_border; + } + + // load & update pseudo-random rotation matrix + pseudo_random_index = uint(pos_rounded.y * 2 + pos_rounded.x) % 5; + rotation_scale = constants.rotation_matrices[params.pass * 5 + pseudo_random_index]; + rot_scale_matrix = mat2(rotation_scale.x * pixel_lookup_radius, rotation_scale.y * pixel_lookup_radius, rotation_scale.z * pixel_lookup_radius, rotation_scale.w * pixel_lookup_radius); + } + + // the main obscurance & sample weight storage + float obscurance_sum = 0.0; + float weight_sum = 0.0; + + // edge mask for between this and left/right/top/bottom neighbour pixels - not used in quality level 0 so initialize to "no edge" (1 is no edge, 0 is edge) + vec4 edgesLRTB = vec4(1.0, 1.0, 1.0, 1.0); + + // Move center pixel slightly towards camera to avoid imprecision artifacts due to using of 16bit depth buffer; a lot smaller offsets needed when using 32bit floats + pix_center_pos *= 0.9992; + + if (!p_adaptive_base && (p_quality_level >= SSAO_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) { + edgesLRTB = calculate_edges(pix_z, pix_left_z, pix_right_z, pix_top_z, pix_bottom_z); + } + + // adds a more high definition sharp effect, which gets blurred out (reuses left/right/top/bottom samples that we used for edge detection) + if (!p_adaptive_base && (p_quality_level >= SSAO_DETAIL_AO_ENABLE_AT_QUALITY_PRESET)) { + // disable in case of quality level 4 (reference) + if (p_quality_level != 4) { + //approximate neighbouring pixels positions (actually just deltas or "positions - pix_center_pos" ) + vec3 normalized_viewspace_dir = vec3(pix_center_pos.xy / pix_center_pos.zz, 1.0); + vec3 pixel_left_delta = vec3(-pixel_size_at_center.x, 0.0, 0.0) + normalized_viewspace_dir * (pix_left_z - pix_center_pos.z); + vec3 pixel_right_delta = vec3(+pixel_size_at_center.x, 0.0, 0.0) + normalized_viewspace_dir * (pix_right_z - pix_center_pos.z); + vec3 pixel_top_delta = vec3(0.0, -pixel_size_at_center.y, 0.0) + normalized_viewspace_dir * (pix_top_z - pix_center_pos.z); + vec3 pixel_bottom_delta = vec3(0.0, +pixel_size_at_center.y, 0.0) + normalized_viewspace_dir * (pix_bottom_z - pix_center_pos.z); + + const float range_reduction = 4.0f; // this is to avoid various artifacts + const float modified_fallof_sq = range_reduction * fallof_sq; + + vec4 additional_obscurance; + additional_obscurance.x = calculate_pixel_obscurance(pixel_normal, pixel_left_delta, modified_fallof_sq); + additional_obscurance.y = calculate_pixel_obscurance(pixel_normal, pixel_right_delta, modified_fallof_sq); + additional_obscurance.z = calculate_pixel_obscurance(pixel_normal, pixel_top_delta, modified_fallof_sq); + additional_obscurance.w = calculate_pixel_obscurance(pixel_normal, pixel_bottom_delta, modified_fallof_sq); + + obscurance_sum += params.detail_intensity * dot(additional_obscurance, edgesLRTB); + } + } + + // Sharp normals also create edges - but this adds to the cost as well + if (!p_adaptive_base && (p_quality_level >= SSAO_NORMAL_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) { + vec3 neighbour_normal_left = load_normal(ivec2(full_res_coord), ivec2(-2, 0)); + vec3 neighbour_normal_right = load_normal(ivec2(full_res_coord), ivec2(2, 0)); + vec3 neighbour_normal_top = load_normal(ivec2(full_res_coord), ivec2(0, -2)); + vec3 neighbour_normal_bottom = load_normal(ivec2(full_res_coord), ivec2(0, 2)); + + const float dot_threshold = SSAO_NORMAL_BASED_EDGES_DOT_THRESHOLD; + + vec4 normal_edgesLRTB; + normal_edgesLRTB.x = clamp((dot(pixel_normal, neighbour_normal_left) + dot_threshold), 0.0, 1.0); + normal_edgesLRTB.y = clamp((dot(pixel_normal, neighbour_normal_right) + dot_threshold), 0.0, 1.0); + normal_edgesLRTB.z = clamp((dot(pixel_normal, neighbour_normal_top) + dot_threshold), 0.0, 1.0); + normal_edgesLRTB.w = clamp((dot(pixel_normal, neighbour_normal_bottom) + dot_threshold), 0.0, 1.0); + + edgesLRTB *= normal_edgesLRTB; + } + + const float global_mip_offset = SSAO_DEPTH_MIPS_GLOBAL_OFFSET; + float mip_offset = (p_quality_level < SSAO_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET) ? (0) : (log2(pixel_lookup_radius) + global_mip_offset); + + // Used to tilt the second set of samples so that the disk is effectively rotated by the normal + // effective at removing one set of artifacts, but too expensive for lower quality settings + vec2 norm_xy = vec2(pixel_normal.x, pixel_normal.y); + float norm_xy_length = length(norm_xy); + norm_xy /= vec2(norm_xy_length, -norm_xy_length); + norm_xy_length *= SSAO_TILT_SAMPLES_AMOUNT; + + // standard, non-adaptive approach + if ((p_quality_level != 3) || p_adaptive_base) { + for (int i = 0; i < number_of_taps; i++) { + SSAOTap(p_quality_level, obscurance_sum, weight_sum, i, rot_scale_matrix, pix_center_pos, pixel_normal, normalized_screen_pos, mip_offset, fallof_sq, 1.0, norm_xy, norm_xy_length); + } + } +#ifdef ADAPTIVE + else { + // add new ones if needed + vec2 full_res_uv = normalized_screen_pos + params.pass_uv_offset.xy; + float importance = textureLod(source_importance, full_res_uv, 0.0).x; + + // this is to normalize SSAO_DETAIL_AO_AMOUNT across all pixel regardless of importance + obscurance_sum *= (SSAO_ADAPTIVE_TAP_BASE_COUNT / float(SSAO_MAX_TAPS)) + (importance * SSAO_ADAPTIVE_TAP_FLEXIBLE_COUNT / float(SSAO_MAX_TAPS)); + + // load existing base values + vec2 base_values = imageLoad(source_ssao, ivec3(upos, params.pass)).xy; + weight_sum += base_values.y * float(SSAO_ADAPTIVE_TAP_BASE_COUNT * 4.0); + obscurance_sum += (base_values.x) * weight_sum; + + // increase importance around edges + float edge_count = dot(1.0 - edgesLRTB, vec4(1.0, 1.0, 1.0, 1.0)); + + float avg_total_importance = float(counter.sum) * params.load_counter_avg_div; + + float importance_limiter = clamp(params.adaptive_sample_limit / avg_total_importance, 0.0, 1.0); + importance *= importance_limiter; + + float additional_sample_count = SSAO_ADAPTIVE_TAP_FLEXIBLE_COUNT * importance; + + const float blend_range = 3.0; + const float blend_range_inv = 1.0 / blend_range; + + additional_sample_count += 0.5; + uint additional_samples = uint(additional_sample_count); + uint additional_samples_to = min(SSAO_MAX_TAPS, additional_samples + SSAO_ADAPTIVE_TAP_BASE_COUNT); + + for (uint i = SSAO_ADAPTIVE_TAP_BASE_COUNT; i < additional_samples_to; i++) { + additional_sample_count -= 1.0f; + float weight_mod = clamp(additional_sample_count * blend_range_inv, 0.0, 1.0); + SSAOTap(p_quality_level, obscurance_sum, weight_sum, int(i), rot_scale_matrix, pix_center_pos, pixel_normal, normalized_screen_pos, mip_offset, fallof_sq, weight_mod, norm_xy, norm_xy_length); + } + } +#endif + + // early out for adaptive base - just output weight (used for the next pass) + if (p_adaptive_base) { + float obscurance = obscurance_sum / weight_sum; + + r_shadow_term = obscurance; + r_edges = vec4(0.0); + r_weight = weight_sum; + return; + } + + // calculate weighted average + float obscurance = obscurance_sum / weight_sum; + + // calculate fadeout (1 close, gradient, 0 far) + float fade_out = clamp(pix_center_pos.z * params.fade_out_mul + params.fade_out_add, 0.0, 1.0); + + // Reduce the SSAO shadowing if we're on the edge to remove artifacts on edges (we don't care for the lower quality one) + if (!p_adaptive_base && (p_quality_level >= SSAO_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) { + // when there's more than 2 opposite edges, start fading out the occlusion to reduce aliasing artifacts + float edge_fadeout_factor = clamp((1.0 - edgesLRTB.x - edgesLRTB.y) * 0.35, 0.0, 1.0) + clamp((1.0 - edgesLRTB.z - edgesLRTB.w) * 0.35, 0.0, 1.0); + + fade_out *= clamp(1.0 - edge_fadeout_factor, 0.0, 1.0); + } + + // strength + obscurance = params.intensity * obscurance; + + // clamp + obscurance = min(obscurance, params.shadow_clamp); + + // fadeout + obscurance *= fade_out; + + // conceptually switch to occlusion with the meaning being visibility (grows with visibility, occlusion == 1 implies full visibility), + // to be in line with what is more commonly used. + float occlusion = 1.0 - obscurance; + + // modify the gradient + // note: this cannot be moved to a later pass because of loss of precision after storing in the render target + occlusion = pow(clamp(occlusion, 0.0, 1.0), params.shadow_power); + + // outputs! + r_shadow_term = occlusion; // Our final 'occlusion' term (0 means fully occluded, 1 means fully lit) + r_edges = edgesLRTB; // These are used to prevent blurring across edges, 1 means no edge, 0 means edge, 0.5 means half way there, etc. + r_weight = weight_sum; +} + +void main() { + float out_shadow_term; + float out_weight; + vec4 out_edges; + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(ssC, params.screen_size))) { //too large, do nothing + return; + } + + vec2 uv = vec2(gl_GlobalInvocationID) + vec2(0.5); +#ifdef SSAO_BASE + generate_SSAO_shadows_internal(out_shadow_term, out_edges, out_weight, uv, params.quality, true); + + imageStore(dest_image, ivec2(gl_GlobalInvocationID.xy), vec4(out_shadow_term, out_weight / (float(SSAO_ADAPTIVE_TAP_BASE_COUNT) * 4.0), 0.0, 0.0)); +#else + generate_SSAO_shadows_internal(out_shadow_term, out_edges, out_weight, uv, params.quality, false); // pass in quality levels + if (params.quality == 0) { + out_edges = vec4(1.0); + } + + imageStore(dest_image, ivec2(gl_GlobalInvocationID.xy), vec4(out_shadow_term, pack_edges(out_edges), 0.0, 0.0)); +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/ssao_blur.glsl b/servers/rendering/renderer_rd/shaders/ssao_blur.glsl new file mode 100644 index 0000000000..510a777048 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssao_blur.glsl @@ -0,0 +1,154 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2016, Intel Corporation +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of +// the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// File changes (yyyy-mm-dd) +// 2016-09-07: filip.strugar@intel.com: first commit +// 2020-12-05: clayjohn: convert to Vulkan and Godot +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(set = 0, binding = 0) uniform sampler2D source_ssao; + +layout(rg8, set = 1, binding = 0) uniform restrict writeonly image2D dest_image; + +layout(push_constant, binding = 1, std430) uniform Params { + float edge_sharpness; + float pad; + vec2 half_screen_pixel_size; +} +params; + +vec4 unpack_edges(float p_packed_val) { + uint packed_val = uint(p_packed_val * 255.5); + vec4 edgesLRTB; + edgesLRTB.x = float((packed_val >> 6) & 0x03) / 3.0; + edgesLRTB.y = float((packed_val >> 4) & 0x03) / 3.0; + edgesLRTB.z = float((packed_val >> 2) & 0x03) / 3.0; + edgesLRTB.w = float((packed_val >> 0) & 0x03) / 3.0; + + return clamp(edgesLRTB + params.edge_sharpness, 0.0, 1.0); +} + +void add_sample(float p_ssao_value, float p_edge_value, inout float r_sum, inout float r_sum_weight) { + float weight = p_edge_value; + + r_sum += (weight * p_ssao_value); + r_sum_weight += weight; +} + +#ifdef MODE_WIDE +vec2 sample_blurred_wide(vec2 p_coord) { + vec2 vC = textureLodOffset(source_ssao, vec2(p_coord), 0.0, ivec2(0, 0)).xy; + vec2 vL = textureLodOffset(source_ssao, vec2(p_coord), 0.0, ivec2(-2, 0)).xy; + vec2 vT = textureLodOffset(source_ssao, vec2(p_coord), 0.0, ivec2(0, -2)).xy; + vec2 vR = textureLodOffset(source_ssao, vec2(p_coord), 0.0, ivec2(2, 0)).xy; + vec2 vB = textureLodOffset(source_ssao, vec2(p_coord), 0.0, ivec2(0, 2)).xy; + + float packed_edges = vC.y; + vec4 edgesLRTB = unpack_edges(packed_edges); + edgesLRTB.x *= unpack_edges(vL.y).y; + edgesLRTB.z *= unpack_edges(vT.y).w; + edgesLRTB.y *= unpack_edges(vR.y).x; + edgesLRTB.w *= unpack_edges(vB.y).z; + + float ssao_value = vC.x; + float ssao_valueL = vL.x; + float ssao_valueT = vT.x; + float ssao_valueR = vR.x; + float ssao_valueB = vB.x; + + float sum_weight = 0.8f; + float sum = ssao_value * sum_weight; + + add_sample(ssao_valueL, edgesLRTB.x, sum, sum_weight); + add_sample(ssao_valueR, edgesLRTB.y, sum, sum_weight); + add_sample(ssao_valueT, edgesLRTB.z, sum, sum_weight); + add_sample(ssao_valueB, edgesLRTB.w, sum, sum_weight); + + float ssao_avg = sum / sum_weight; + + ssao_value = ssao_avg; + + return vec2(ssao_value, packed_edges); +} +#endif + +#ifdef MODE_SMART +vec2 sample_blurred(vec3 p_pos, vec2 p_coord) { + float packed_edges = texelFetch(source_ssao, ivec2(p_pos.xy), 0).y; + vec4 edgesLRTB = unpack_edges(packed_edges); + + vec4 valuesUL = textureGather(source_ssao, vec2(p_coord - params.half_screen_pixel_size * 0.5)); + vec4 valuesBR = textureGather(source_ssao, vec2(p_coord + params.half_screen_pixel_size * 0.5)); + + float ssao_value = valuesUL.y; + float ssao_valueL = valuesUL.x; + float ssao_valueT = valuesUL.z; + float ssao_valueR = valuesBR.z; + float ssao_valueB = valuesBR.x; + + float sum_weight = 0.5; + float sum = ssao_value * sum_weight; + + add_sample(ssao_valueL, edgesLRTB.x, sum, sum_weight); + add_sample(ssao_valueR, edgesLRTB.y, sum, sum_weight); + + add_sample(ssao_valueT, edgesLRTB.z, sum, sum_weight); + add_sample(ssao_valueB, edgesLRTB.w, sum, sum_weight); + + float ssao_avg = sum / sum_weight; + + ssao_value = ssao_avg; + + return vec2(ssao_value, packed_edges); +} +#endif + +void main() { + // Pixel being shaded + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + +#ifdef MODE_NON_SMART + + vec2 halfPixel = params.half_screen_pixel_size * 0.5f; + + vec2 uv = (vec2(gl_GlobalInvocationID.xy) + vec2(0.5, 0.5)) * params.half_screen_pixel_size; + + vec2 centre = textureLod(source_ssao, vec2(uv), 0.0).xy; + + vec4 vals; + vals.x = textureLod(source_ssao, vec2(uv + vec2(-halfPixel.x * 3, -halfPixel.y)), 0.0).x; + vals.y = textureLod(source_ssao, vec2(uv + vec2(+halfPixel.x, -halfPixel.y * 3)), 0.0).x; + vals.z = textureLod(source_ssao, vec2(uv + vec2(-halfPixel.x, +halfPixel.y * 3)), 0.0).x; + vals.w = textureLod(source_ssao, vec2(uv + vec2(+halfPixel.x * 3, +halfPixel.y)), 0.0).x; + + vec2 sampled = vec2(dot(vals, vec4(0.2)) + centre.x * 0.2, centre.y); + +#else +#ifdef MODE_SMART + vec2 sampled = sample_blurred(vec3(gl_GlobalInvocationID), (vec2(gl_GlobalInvocationID.xy) + vec2(0.5, 0.5)) * params.half_screen_pixel_size); +#else // MODE_WIDE + vec2 sampled = sample_blurred_wide((vec2(gl_GlobalInvocationID.xy) + vec2(0.5, 0.5)) * params.half_screen_pixel_size); +#endif + +#endif + imageStore(dest_image, ivec2(ssC), vec4(sampled, 0.0, 0.0)); +} diff --git a/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl b/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl new file mode 100644 index 0000000000..cb2d31f70d --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl @@ -0,0 +1,206 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2016, Intel Corporation +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of +// the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// File changes (yyyy-mm-dd) +// 2016-09-07: filip.strugar@intel.com: first commit +// 2020-12-05: clayjohn: convert to Vulkan and Godot +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(push_constant, binding = 1, std430) uniform Params { + vec2 pixel_size; + float z_far; + float z_near; + bool orthogonal; + float radius_sq; + uvec2 pad; +} +params; + +layout(set = 0, binding = 0) uniform sampler2D source_depth; + +layout(r16f, set = 1, binding = 0) uniform restrict writeonly image2DArray dest_image0; //rename +#ifdef GENERATE_MIPS +layout(r16f, set = 2, binding = 0) uniform restrict writeonly image2DArray dest_image1; +layout(r16f, set = 2, binding = 1) uniform restrict writeonly image2DArray dest_image2; +layout(r16f, set = 2, binding = 2) uniform restrict writeonly image2DArray dest_image3; +#endif + +vec4 screen_space_to_view_space_depth(vec4 p_depth) { + if (params.orthogonal) { + vec4 depth = p_depth * 2.0 - 1.0; + return ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + } + + float depth_linearize_mul = params.z_near; + float depth_linearize_add = params.z_far; + + // Optimised version of "-cameraClipNear / (cameraClipFar - projDepth * (cameraClipFar - cameraClipNear)) * cameraClipFar" + + // Set your depth_linearize_mul and depth_linearize_add to: + // depth_linearize_mul = ( cameraClipFar * cameraClipNear) / ( cameraClipFar - cameraClipNear ); + // depth_linearize_add = cameraClipFar / ( cameraClipFar - cameraClipNear ); + + return depth_linearize_mul / (depth_linearize_add - p_depth); +} + +float screen_space_to_view_space_depth(float p_depth) { + if (params.orthogonal) { + float depth = p_depth * 2.0 - 1.0; + return ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / (2.0 * params.z_far); + } + + float depth_linearize_mul = params.z_near; + float depth_linearize_add = params.z_far; + + return depth_linearize_mul / (depth_linearize_add - p_depth); +} + +#ifdef GENERATE_MIPS + +shared float depth_buffer[4][8][8]; + +float mip_smart_average(vec4 p_depths) { + float closest = min(min(p_depths.x, p_depths.y), min(p_depths.z, p_depths.w)); + float fallof_sq = -1.0f / params.radius_sq; + vec4 dists = p_depths - closest.xxxx; + vec4 weights = clamp(dists * dists * fallof_sq + 1.0, 0.0, 1.0); + return dot(weights, p_depths) / dot(weights, vec4(1.0, 1.0, 1.0, 1.0)); +} + +void prepare_depths_and_mips(vec4 p_samples, uvec2 p_output_coord, uvec2 p_gtid) { + p_samples = screen_space_to_view_space_depth(p_samples); + + depth_buffer[0][p_gtid.x][p_gtid.y] = p_samples.w; + depth_buffer[1][p_gtid.x][p_gtid.y] = p_samples.z; + depth_buffer[2][p_gtid.x][p_gtid.y] = p_samples.x; + depth_buffer[3][p_gtid.x][p_gtid.y] = p_samples.y; + + imageStore(dest_image0, ivec3(p_output_coord.x, p_output_coord.y, 0), vec4(p_samples.w)); + imageStore(dest_image0, ivec3(p_output_coord.x, p_output_coord.y, 1), vec4(p_samples.z)); + imageStore(dest_image0, ivec3(p_output_coord.x, p_output_coord.y, 2), vec4(p_samples.x)); + imageStore(dest_image0, ivec3(p_output_coord.x, p_output_coord.y, 3), vec4(p_samples.y)); + + uint depth_array_index = 2 * (p_gtid.y % 2) + (p_gtid.x % 2); + uvec2 depth_array_offset = ivec2(p_gtid.x % 2, p_gtid.y % 2); + ivec2 buffer_coord = ivec2(p_gtid) - ivec2(depth_array_offset); + + p_output_coord /= 2; + groupMemoryBarrier(); + barrier(); + + // if (still_alive) <-- all threads alive here + { + float sample_00 = depth_buffer[depth_array_index][buffer_coord.x + 0][buffer_coord.y + 0]; + float sample_01 = depth_buffer[depth_array_index][buffer_coord.x + 0][buffer_coord.y + 1]; + float sample_10 = depth_buffer[depth_array_index][buffer_coord.x + 1][buffer_coord.y + 0]; + float sample_11 = depth_buffer[depth_array_index][buffer_coord.x + 1][buffer_coord.y + 1]; + + float avg = mip_smart_average(vec4(sample_00, sample_01, sample_10, sample_11)); + imageStore(dest_image1, ivec3(p_output_coord.x, p_output_coord.y, depth_array_index), vec4(avg)); + depth_buffer[depth_array_index][buffer_coord.x][buffer_coord.y] = avg; + } + + bool still_alive = p_gtid.x % 4 == depth_array_offset.x && p_gtid.y % 4 == depth_array_offset.y; + + p_output_coord /= 2; + groupMemoryBarrier(); + barrier(); + + if (still_alive) { + float sample_00 = depth_buffer[depth_array_index][buffer_coord.x + 0][buffer_coord.y + 0]; + float sample_01 = depth_buffer[depth_array_index][buffer_coord.x + 0][buffer_coord.y + 2]; + float sample_10 = depth_buffer[depth_array_index][buffer_coord.x + 2][buffer_coord.y + 0]; + float sample_11 = depth_buffer[depth_array_index][buffer_coord.x + 2][buffer_coord.y + 2]; + + float avg = mip_smart_average(vec4(sample_00, sample_01, sample_10, sample_11)); + imageStore(dest_image2, ivec3(p_output_coord.x, p_output_coord.y, depth_array_index), vec4(avg)); + depth_buffer[depth_array_index][buffer_coord.x][buffer_coord.y] = avg; + } + + still_alive = p_gtid.x % 8 == depth_array_offset.x && depth_array_offset.y % 8 == depth_array_offset.y; + + p_output_coord /= 2; + groupMemoryBarrier(); + barrier(); + + if (still_alive) { + float sample_00 = depth_buffer[depth_array_index][buffer_coord.x + 0][buffer_coord.y + 0]; + float sample_01 = depth_buffer[depth_array_index][buffer_coord.x + 0][buffer_coord.y + 4]; + float sample_10 = depth_buffer[depth_array_index][buffer_coord.x + 4][buffer_coord.y + 0]; + float sample_11 = depth_buffer[depth_array_index][buffer_coord.x + 4][buffer_coord.y + 4]; + + float avg = mip_smart_average(vec4(sample_00, sample_01, sample_10, sample_11)); + imageStore(dest_image3, ivec3(p_output_coord.x, p_output_coord.y, depth_array_index), vec4(avg)); + } +} +#else +#ifndef USE_HALF_BUFFERS +void prepare_depths(vec4 p_samples, uvec2 p_tid) { + p_samples = screen_space_to_view_space_depth(p_samples); + + imageStore(dest_image0, ivec3(p_tid, 0), vec4(p_samples.w)); + imageStore(dest_image0, ivec3(p_tid, 1), vec4(p_samples.z)); + imageStore(dest_image0, ivec3(p_tid, 2), vec4(p_samples.x)); + imageStore(dest_image0, ivec3(p_tid, 3), vec4(p_samples.y)); +} +#endif +#endif + +void main() { +#ifdef USE_HALF_BUFFERS +#ifdef USE_HALF_SIZE + float sample_00 = texelFetch(source_depth, ivec2(4 * gl_GlobalInvocationID.x + 0, 4 * gl_GlobalInvocationID.y + 0), 0).x; + float sample_11 = texelFetch(source_depth, ivec2(4 * gl_GlobalInvocationID.x + 2, 4 * gl_GlobalInvocationID.y + 2), 0).x; +#else + float sample_00 = texelFetch(source_depth, ivec2(2 * gl_GlobalInvocationID.x + 0, 2 * gl_GlobalInvocationID.y + 0), 0).x; + float sample_11 = texelFetch(source_depth, ivec2(2 * gl_GlobalInvocationID.x + 1, 2 * gl_GlobalInvocationID.y + 1), 0).x; +#endif + sample_00 = screen_space_to_view_space_depth(sample_00); + sample_11 = screen_space_to_view_space_depth(sample_11); + + imageStore(dest_image0, ivec3(gl_GlobalInvocationID.xy, 0), vec4(sample_00)); + imageStore(dest_image0, ivec3(gl_GlobalInvocationID.xy, 3), vec4(sample_11)); +#else //!USE_HALF_BUFFERS +#ifdef USE_HALF_SIZE + ivec2 depth_buffer_coord = 4 * ivec2(gl_GlobalInvocationID.xy); + ivec2 output_coord = ivec2(gl_GlobalInvocationID); + + vec2 uv = (vec2(depth_buffer_coord) + 0.5f) * params.pixel_size; + vec4 samples; + samples.x = textureLodOffset(source_depth, uv, 0, ivec2(0, 2)).x; + samples.y = textureLodOffset(source_depth, uv, 0, ivec2(2, 2)).x; + samples.z = textureLodOffset(source_depth, uv, 0, ivec2(2, 0)).x; + samples.w = textureLodOffset(source_depth, uv, 0, ivec2(0, 0)).x; +#else + ivec2 depth_buffer_coord = 2 * ivec2(gl_GlobalInvocationID.xy); + ivec2 output_coord = ivec2(gl_GlobalInvocationID); + + vec2 uv = (vec2(depth_buffer_coord) + 0.5f) * params.pixel_size; + vec4 samples = textureGather(source_depth, uv); +#endif +#ifdef GENERATE_MIPS + prepare_depths_and_mips(samples, output_coord, gl_LocalInvocationID.xy); +#else + prepare_depths(samples, gl_GlobalInvocationID.xy); +#endif +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl b/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl new file mode 100644 index 0000000000..6aa7624261 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl @@ -0,0 +1,126 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2016, Intel Corporation +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of +// the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// File changes (yyyy-mm-dd) +// 2016-09-07: filip.strugar@intel.com: first commit +// 2020-12-05: clayjohn: convert to Vulkan and Godot +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +#ifdef GENERATE_MAP +layout(set = 0, binding = 0) uniform sampler2DArray source_ssao; +#else +layout(set = 0, binding = 0) uniform sampler2D source_importance; +#endif +layout(r8, set = 1, binding = 0) uniform restrict writeonly image2D dest_image; + +#ifdef PROCESS_MAPB +layout(set = 2, binding = 0, std430) buffer Counter { + uint sum; +} +counter; +#endif + +layout(push_constant, binding = 1, std430) uniform Params { + vec2 half_screen_pixel_size; + float intensity; + float power; +} +params; + +void main() { + // Pixel being shaded + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + +#ifdef GENERATE_MAP + // importance map stuff + uvec2 base_position = ssC * 2; + + vec2 base_uv = (vec2(base_position) + vec2(0.5f, 0.5f)) * params.half_screen_pixel_size; + + float avg = 0.0; + float minV = 1.0; + float maxV = 0.0; + for (int i = 0; i < 4; i++) { + vec4 vals = textureGather(source_ssao, vec3(base_uv, i)); + + // apply the same modifications that would have been applied in the main shader + vals = params.intensity * vals; + + vals = 1 - vals; + + vals = pow(clamp(vals, 0.0, 1.0), vec4(params.power)); + + avg += dot(vec4(vals.x, vals.y, vals.z, vals.w), vec4(1.0 / 16.0, 1.0 / 16.0, 1.0 / 16.0, 1.0 / 16.0)); + + maxV = max(maxV, max(max(vals.x, vals.y), max(vals.z, vals.w))); + minV = min(minV, min(min(vals.x, vals.y), min(vals.z, vals.w))); + } + + float min_max_diff = maxV - minV; + + imageStore(dest_image, ssC, vec4(pow(clamp(min_max_diff * 2.0, 0.0, 1.0), 0.8))); +#endif + +#ifdef PROCESS_MAPA + vec2 uv = (vec2(ssC) + 0.5f) * params.half_screen_pixel_size * 2.0; + + float centre = textureLod(source_importance, uv, 0.0).x; + + vec2 half_pixel = params.half_screen_pixel_size; + + vec4 vals; + vals.x = textureLod(source_importance, uv + vec2(-half_pixel.x * 3, -half_pixel.y), 0.0).x; + vals.y = textureLod(source_importance, uv + vec2(+half_pixel.x, -half_pixel.y * 3), 0.0).x; + vals.z = textureLod(source_importance, uv + vec2(+half_pixel.x * 3, +half_pixel.y), 0.0).x; + vals.w = textureLod(source_importance, uv + vec2(-half_pixel.x, +half_pixel.y * 3), 0.0).x; + + float avg = dot(vals, vec4(0.25, 0.25, 0.25, 0.25)); + + imageStore(dest_image, ssC, vec4(avg)); +#endif + +#ifdef PROCESS_MAPB + vec2 uv = (vec2(ssC) + 0.5f) * params.half_screen_pixel_size * 2.0; + + float centre = textureLod(source_importance, uv, 0.0).x; + + vec2 half_pixel = params.half_screen_pixel_size; + + vec4 vals; + vals.x = textureLod(source_importance, uv + vec2(-half_pixel.x, -half_pixel.y * 3), 0.0).x; + vals.y = textureLod(source_importance, uv + vec2(+half_pixel.x * 3, -half_pixel.y), 0.0).x; + vals.z = textureLod(source_importance, uv + vec2(+half_pixel.x, +half_pixel.y * 3), 0.0).x; + vals.w = textureLod(source_importance, uv + vec2(-half_pixel.x * 3, +half_pixel.y), 0.0).x; + + float avg = dot(vals, vec4(0.25, 0.25, 0.25, 0.25)); + + imageStore(dest_image, ssC, vec4(avg)); + + // sum the average; to avoid overflowing we assume max AO resolution is not bigger than 16384x16384; so quarter res (used here) will be 4096x4096, which leaves us with 8 bits per pixel + uint sum = uint(clamp(avg, 0.0, 1.0) * 255.0 + 0.5); + + // save every 9th to avoid InterlockedAdd congestion - since we're blurring, this is good enough; compensated by multiplying load_counter_avg_div by 9 + if (((ssC.x % 3) + (ssC.y % 3)) == 0) { + atomicAdd(counter.sum, sum); + } +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl b/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl new file mode 100644 index 0000000000..4fdf334aa5 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl @@ -0,0 +1,119 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2016, Intel Corporation +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of +// the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// File changes (yyyy-mm-dd) +// 2016-09-07: filip.strugar@intel.com: first commit +// 2020-12-05: clayjohn: convert to Vulkan and Godot +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(rgba8, set = 0, binding = 0) uniform restrict writeonly image2D dest_image; +layout(set = 1, binding = 0) uniform sampler2DArray source_texture; + +layout(push_constant, binding = 1, std430) uniform Params { + float inv_sharpness; + uint size_modifier; + vec2 pixel_size; +} +params; + +vec4 unpack_edges(float p_packed_val) { + uint packed_val = uint(p_packed_val * 255.5); + vec4 edgesLRTB; + edgesLRTB.x = float((packed_val >> 6) & 0x03) / 3.0; + edgesLRTB.y = float((packed_val >> 4) & 0x03) / 3.0; + edgesLRTB.z = float((packed_val >> 2) & 0x03) / 3.0; + edgesLRTB.w = float((packed_val >> 0) & 0x03) / 3.0; + + return clamp(edgesLRTB + params.inv_sharpness, 0.0, 1.0); +} + +void main() { + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(ssC, ivec2(1.0 / params.pixel_size)))) { //too large, do nothing + return; + } + +#ifdef MODE_SMART + float ao; + uvec2 pix_pos = uvec2(gl_GlobalInvocationID.xy); + vec2 uv = (gl_GlobalInvocationID.xy + vec2(0.5)) * params.pixel_size; + + // calculate index in the four deinterleaved source array texture + int mx = int(pix_pos.x % 2); + int my = int(pix_pos.y % 2); + int index_center = mx + my * 2; // center index + int index_horizontal = (1 - mx) + my * 2; // neighbouring, horizontal + int index_vertical = mx + (1 - my) * 2; // neighbouring, vertical + int index_diagonal = (1 - mx) + (1 - my) * 2; // diagonal + + vec2 center_val = texelFetch(source_texture, ivec3(pix_pos / uvec2(params.size_modifier), index_center), 0).xy; + + ao = center_val.x; + + vec4 edgesLRTB = unpack_edges(center_val.y); + + // convert index shifts to sampling offsets + float fmx = float(mx); + float fmy = float(my); + + // in case of an edge, push sampling offsets away from the edge (towards pixel center) + float fmxe = (edgesLRTB.y - edgesLRTB.x); + float fmye = (edgesLRTB.w - edgesLRTB.z); + + // calculate final sampling offsets and sample using bilinear filter + vec2 uv_horizontal = (gl_GlobalInvocationID.xy + vec2(0.5) + vec2(fmx + fmxe - 0.5, 0.5 - fmy)) * params.pixel_size; + float ao_horizontal = textureLod(source_texture, vec3(uv_horizontal, index_horizontal), 0.0).x; + vec2 uv_vertical = (gl_GlobalInvocationID.xy + vec2(0.5) + vec2(0.5 - fmx, fmy - 0.5 + fmye)) * params.pixel_size; + float ao_vertical = textureLod(source_texture, vec3(uv_vertical, index_vertical), 0.0).x; + vec2 uv_diagonal = (gl_GlobalInvocationID.xy + vec2(0.5) + vec2(fmx - 0.5 + fmxe, fmy - 0.5 + fmye)) * params.pixel_size; + float ao_diagonal = textureLod(source_texture, vec3(uv_diagonal, index_diagonal), 0.0).x; + + // reduce weight for samples near edge - if the edge is on both sides, weight goes to 0 + vec4 blendWeights; + blendWeights.x = 1.0; + blendWeights.y = (edgesLRTB.x + edgesLRTB.y) * 0.5; + blendWeights.z = (edgesLRTB.z + edgesLRTB.w) * 0.5; + blendWeights.w = (blendWeights.y + blendWeights.z) * 0.5; + + // calculate weighted average + float blendWeightsSum = dot(blendWeights, vec4(1.0, 1.0, 1.0, 1.0)); + ao = dot(vec4(ao, ao_horizontal, ao_vertical, ao_diagonal), blendWeights) / blendWeightsSum; + + imageStore(dest_image, ivec2(gl_GlobalInvocationID.xy), vec4(ao)); +#else // !MODE_SMART + + vec2 uv = (gl_GlobalInvocationID.xy + vec2(0.5)) * params.pixel_size; +#ifdef MODE_HALF + float a = textureLod(source_texture, vec3(uv, 0), 0.0).x; + float d = textureLod(source_texture, vec3(uv, 3), 0.0).x; + float avg = (a + d) * 0.5; + +#else + float a = textureLod(source_texture, vec3(uv, 0), 0.0).x; + float b = textureLod(source_texture, vec3(uv, 1), 0.0).x; + float c = textureLod(source_texture, vec3(uv, 2), 0.0).x; + float d = textureLod(source_texture, vec3(uv, 3), 0.0).x; + float avg = (a + b + c + d) * 0.25; + +#endif + imageStore(dest_image, ivec2(gl_GlobalInvocationID.xy), vec4(avg)); +#endif +} diff --git a/servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl b/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl index 88a953562f..88a953562f 100644 --- a/servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl +++ b/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl diff --git a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl index 4cc4fd3f64..7de91fd541 100644 --- a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl +++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl @@ -23,7 +23,11 @@ layout(location = 0) in vec2 uv_interp; layout(set = 0, binding = 0) uniform sampler2D source_color; layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; layout(set = 2, binding = 0) uniform sampler2D source_glow; -layout(set = 3, binding = 0) uniform sampler3D color_correction; +#ifdef USE_1D_LUT +layout(set = 3, binding = 0) uniform sampler2D source_color_correction; +#else +layout(set = 3, binding = 0) uniform sampler3D source_color_correction; +#endif layout(push_constant, binding = 1, std430) uniform Params { vec3 bcs; @@ -35,9 +39,9 @@ layout(push_constant, binding = 1, std430) uniform Params { uint tonemapper; uvec2 glow_texture_size; - float glow_intensity; uint pad3; + uint glow_mode; float glow_levels[7]; @@ -255,10 +259,18 @@ vec3 apply_bcs(vec3 color, vec3 bcs) { return color; } - -vec3 apply_color_correction(vec3 color, sampler3D correction_tex) { - return texture(correction_tex, color).rgb; +#ifdef USE_1D_LUT +vec3 apply_color_correction(vec3 color) { + color.r = texture(source_color_correction, vec2(color.r, 0.0f)).r; + color.g = texture(source_color_correction, vec2(color.g, 0.0f)).g; + color.b = texture(source_color_correction, vec2(color.b, 0.0f)).b; + return color; +} +#else +vec3 apply_color_correction(vec3 color) { + return textureLod(source_color_correction, color, 0.0).rgb; } +#endif vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { const float FXAA_REDUCE_MIN = (1.0 / 128.0); @@ -367,7 +379,7 @@ void main() { } if (params.use_color_correction) { - color = apply_color_correction(color, color_correction); + color = apply_color_correction(color); } frag_color = vec4(color, 1.0f); diff --git a/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl index 13b162f0c9..aa32809a06 100644 --- a/servers/rendering/rasterizer_rd/shaders/volumetric_fog.glsl +++ b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl @@ -4,6 +4,15 @@ VERSION_DEFINES +/* Do not use subgroups here, seems there is not much advantage and causes glitches +#extension GL_KHR_shader_subgroup_ballot: enable +#extension GL_KHR_shader_subgroup_arithmetic: enable + +#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic) +#define USE_SUBGROUPS +#endif +*/ + #if defined(MODE_FOG) || defined(MODE_FILTER) layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; @@ -23,22 +32,25 @@ layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; layout(set = 0, binding = 1) uniform texture2D shadow_atlas; layout(set = 0, binding = 2) uniform texture2D directional_shadow_atlas; -layout(set = 0, binding = 3, std430) restrict readonly buffer Lights { +layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights { LightData data[]; } -lights; +omni_lights; -layout(set = 0, binding = 4, std140) uniform DirectionalLights { +layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights { + LightData data[]; +} +spot_lights; + +layout(set = 0, binding = 5, std140) uniform DirectionalLights { DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; } directional_lights; -layout(set = 0, binding = 5) uniform utexture3D cluster_texture; - -layout(set = 0, binding = 6, std430) restrict readonly buffer ClusterData { - uint indices[]; +layout(set = 0, binding = 6, std430) buffer restrict readonly ClusterBuffer { + uint data[]; } -cluster_data; +cluster_buffer; layout(set = 0, binding = 7) uniform sampler linear_sampler; @@ -132,7 +144,7 @@ layout(set = 1, binding = 2) uniform texture3D sdfgi_occlusion_texture; #endif //SDFGI -layout(push_constant, binding = 0, std430) uniform Params { +layout(set = 0, binding = 14, std140) uniform Params { vec2 fog_frustum_size_begin; vec2 fog_frustum_size_end; @@ -150,7 +162,14 @@ layout(push_constant, binding = 0, std430) uniform Params { float detail_spread; float gi_inject; uint max_gi_probes; - uint pad; + uint cluster_type_size; + + vec2 screen_size; + uint cluster_shift; + uint cluster_width; + + uvec3 cluster_pad; + uint max_cluster_element_count_div_32; mat3x4 cam_rotation; } @@ -169,6 +188,31 @@ vec3 hash3f(uvec3 x) { return vec3(x & 0xFFFFF) / vec3(float(0xFFFFF)); } +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} + +void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) { + uint item_min_max = cluster_buffer.data[p_offset]; + item_min = item_min_max & 0xFFFF; + item_max = item_min_max >> 16; + ; + + item_from = item_min >> 5; + item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements +} + +uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) { + int local_min = clamp(int(z_min) - int(i) * 32, 0, 31); + int mask_width = min(int(z_max) - int(z_min), 32 - local_min); + return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width); +} + void main() { vec3 fog_cell_size = 1.0 / vec3(params.fog_volume_size); @@ -184,6 +228,12 @@ void main() { //posf += mix(vec3(0.0),vec3(1.0),0.3) * hash3f(uvec3(pos)) * 2.0 - 1.0; vec3 fog_unit_pos = posf * fog_cell_size + fog_cell_size * 0.5; //center of voxels + + uvec2 screen_pos = uvec2(fog_unit_pos.xy * params.screen_size); + uvec2 cluster_pos = screen_pos >> params.cluster_shift; + uint cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32); + //positions in screen are too spread apart, no hopes for optimizing with subgroups + fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread); vec3 view_pos; @@ -191,6 +241,8 @@ void main() { view_pos.z = -params.fog_frustum_end * fog_unit_pos.z; view_pos.y = -view_pos.y; + uint cluster_z = uint(clamp((abs(view_pos.z) / params.z_far) * 32.0, 0.0, 31.0)); + vec3 total_light = params.light_color; float total_density = params.base_density; @@ -257,108 +309,160 @@ void main() { //compute lights from cluster - vec3 cluster_pos; - cluster_pos.xy = fog_unit_pos.xy; - cluster_pos.z = clamp((abs(view_pos.z) - params.z_near) / (params.z_far - params.z_near), 0.0, 1.0); + { //omni lights - uvec4 cluster_cell = texture(usampler3D(cluster_texture, linear_sampler), cluster_pos); + uint cluster_omni_offset = cluster_offset; - uint omni_light_count = cluster_cell.x >> CLUSTER_COUNTER_SHIFT; - uint omni_light_pointer = cluster_cell.x & CLUSTER_POINTER_MASK; + uint item_min; + uint item_max; + uint item_from; + uint item_to; - for (uint i = 0; i < omni_light_count; i++) { - uint light_index = cluster_data.indices[omni_light_pointer + i]; + cluster_get_item_range(cluster_omni_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); - vec3 light_pos = lights.data[i].position; - float d = distance(lights.data[i].position, view_pos) * lights.data[i].inv_radius; - vec3 shadow_attenuation = vec3(1.0); +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif - if (d < 1.0) { - vec2 attenuation_energy = unpackHalf2x16(lights.data[i].attenuation_energy); - vec4 color_specular = unpackUnorm4x8(lights.data[i].color_specular); + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_omni_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif + + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + uint light_index = 32 * i + bit; - float attenuation = pow(max(1.0 - d, 0.0), attenuation_energy.x); + //if (!bool(omni_omni_lights.data[light_index].mask & draw_call.layer_mask)) { + // continue; //not masked + //} - vec3 light = attenuation_energy.y * color_specular.rgb / M_PI; + vec3 light_pos = omni_lights.data[light_index].position; + float d = distance(omni_lights.data[light_index].position, view_pos); + float shadow_attenuation = 1.0; - vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[i].shadow_color_enabled); + if (d * omni_lights.data[light_index].inv_radius < 1.0) { + float attenuation = get_omni_attenuation(d, omni_lights.data[light_index].inv_radius, omni_lights.data[light_index].attenuation); - if (shadow_color_enabled.a > 0.5) { - //has shadow - vec4 v = vec4(view_pos, 1.0); + vec3 light = omni_lights.data[light_index].color / M_PI; - vec4 splane = (lights.data[i].shadow_matrix * v); - float shadow_len = length(splane.xyz); //need to remember shadow len from here + if (omni_lights.data[light_index].shadow_enabled) { + //has shadow + vec4 v = vec4(view_pos, 1.0); - splane.xyz = normalize(splane.xyz); - vec4 clamp_rect = lights.data[i].atlas_rect; + vec4 splane = (omni_lights.data[light_index].shadow_matrix * v); + float shadow_len = length(splane.xyz); //need to remember shadow len from here - if (splane.z >= 0.0) { - splane.z += 1.0; + splane.xyz = normalize(splane.xyz); + vec4 clamp_rect = omni_lights.data[light_index].atlas_rect; - clamp_rect.y += clamp_rect.w; + if (splane.z >= 0.0) { + splane.z += 1.0; - } else { - splane.z = 1.0 - splane.z; - } + clamp_rect.y += clamp_rect.w; + + } else { + splane.z = 1.0 - splane.z; + } - splane.xy /= splane.z; + splane.xy /= splane.z; - splane.xy = splane.xy * 0.5 + 0.5; - splane.z = shadow_len * lights.data[i].inv_radius; - splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; - splane.w = 1.0; //needed? i think it should be 1 already + splane.xy = splane.xy * 0.5 + 0.5; + splane.z = shadow_len * omni_lights.data[light_index].inv_radius; + splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + splane.w = 1.0; //needed? i think it should be 1 already - float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r; - float shadow = exp(min(0.0, (depth - splane.z)) / lights.data[i].inv_radius * lights.data[i].shadow_volumetric_fog_fade); + float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r; - shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow); + shadow_attenuation = exp(min(0.0, (depth - splane.z)) / omni_lights.data[light_index].inv_radius * omni_lights.data[light_index].shadow_volumetric_fog_fade); + } + total_light += light * attenuation * shadow_attenuation; + } } - total_light += light * attenuation * shadow_attenuation; } } - uint spot_light_count = cluster_cell.y >> CLUSTER_COUNTER_SHIFT; - uint spot_light_pointer = cluster_cell.y & CLUSTER_POINTER_MASK; + { //spot lights - for (uint i = 0; i < spot_light_count; i++) { - uint light_index = cluster_data.indices[spot_light_pointer + i]; + uint cluster_spot_offset = cluster_offset + params.cluster_type_size; - vec3 light_pos = lights.data[i].position; - vec3 light_rel_vec = lights.data[i].position - view_pos; - float d = length(light_rel_vec) * lights.data[i].inv_radius; - vec3 shadow_attenuation = vec3(1.0); + uint item_min; + uint item_max; + uint item_from; + uint item_to; + + cluster_get_item_range(cluster_spot_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif + + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_spot_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif - if (d < 1.0) { - vec2 attenuation_energy = unpackHalf2x16(lights.data[i].attenuation_energy); - vec4 color_specular = unpackUnorm4x8(lights.data[i].color_specular); + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif - float attenuation = pow(max(1.0 - d, 0.0), attenuation_energy.x); + //if (!bool(omni_lights.data[light_index].mask & draw_call.layer_mask)) { + // continue; //not masked + //} - vec3 spot_dir = lights.data[i].direction; - vec2 spot_att_angle = unpackHalf2x16(lights.data[i].cone_attenuation_angle); - float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_att_angle.y); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_att_angle.y)); - attenuation *= 1.0 - pow(spot_rim, spot_att_angle.x); + uint light_index = 32 * i + bit; - vec3 light = attenuation_energy.y * color_specular.rgb / M_PI; + vec3 light_pos = omni_lights.data[light_index].position; + vec3 light_rel_vec = omni_lights.data[light_index].position - view_pos; + float d = length(light_rel_vec); + float shadow_attenuation = 1.0; - vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[i].shadow_color_enabled); + if (d * omni_lights.data[light_index].inv_radius < 1.0) { + float attenuation = get_omni_attenuation(d, omni_lights.data[light_index].inv_radius, omni_lights.data[light_index].attenuation); - if (shadow_color_enabled.a > 0.5) { - //has shadow - vec4 v = vec4(view_pos, 1.0); + vec3 spot_dir = omni_lights.data[light_index].direction; + float scos = max(dot(-normalize(light_rel_vec), spot_dir), omni_lights.data[light_index].cone_angle); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - omni_lights.data[light_index].cone_angle)); + attenuation *= 1.0 - pow(spot_rim, omni_lights.data[light_index].cone_attenuation); - vec4 splane = (lights.data[i].shadow_matrix * v); - splane /= splane.w; + vec3 light = omni_lights.data[light_index].color / M_PI; - float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r; - float shadow = exp(min(0.0, (depth - splane.z)) / lights.data[i].inv_radius * lights.data[i].shadow_volumetric_fog_fade); + if (omni_lights.data[light_index].shadow_enabled) { + //has shadow + vec4 v = vec4(view_pos, 1.0); - shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow); - } + vec4 splane = (omni_lights.data[light_index].shadow_matrix * v); + splane /= splane.w; - total_light += light * attenuation * shadow_attenuation; + float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r; + + shadow_attenuation = exp(min(0.0, (depth - splane.z)) / omni_lights.data[light_index].inv_radius * omni_lights.data[light_index].shadow_volumetric_fog_fade); + } + + total_light += light * attenuation * shadow_attenuation; + } + } } } diff --git a/servers/rendering/renderer_scene.cpp b/servers/rendering/renderer_scene.cpp new file mode 100644 index 0000000000..dd544d4f3f --- /dev/null +++ b/servers/rendering/renderer_scene.cpp @@ -0,0 +1,37 @@ +/*************************************************************************/ +/* renderer_scene.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "renderer_scene.h" + +RendererScene::RendererScene() { +} + +RendererScene::~RendererScene() { +} diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h new file mode 100644 index 0000000000..d92642886c --- /dev/null +++ b/servers/rendering/renderer_scene.h @@ -0,0 +1,206 @@ +/*************************************************************************/ +/* renderer_scene.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERINGSERVERSCENE_H +#define RENDERINGSERVERSCENE_H + +#include "servers/rendering/renderer_compositor.h" +#include "servers/xr/xr_interface.h" + +class RendererScene { +public: + virtual RID camera_create() = 0; + + virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) = 0; + virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) = 0; + virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) = 0; + virtual void camera_set_transform(RID p_camera, const Transform &p_transform) = 0; + virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers) = 0; + virtual void camera_set_environment(RID p_camera, RID p_env) = 0; + virtual void camera_set_camera_effects(RID p_camera, RID p_fx) = 0; + virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable) = 0; + virtual bool is_camera(RID p_camera) const = 0; + + virtual RID scenario_create() = 0; + + virtual void scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode) = 0; + virtual void scenario_set_environment(RID p_scenario, RID p_environment) = 0; + virtual void scenario_set_camera_effects(RID p_scenario, RID p_fx) = 0; + virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment) = 0; + virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) = 0; + virtual bool is_scenario(RID p_scenario) const = 0; + virtual RID scenario_get_environment(RID p_scenario) = 0; + + virtual RID instance_create() = 0; + + virtual void instance_set_base(RID p_instance, RID p_base) = 0; + virtual void instance_set_scenario(RID p_instance, RID p_scenario) = 0; + virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask) = 0; + virtual void instance_set_transform(RID p_instance, const Transform &p_transform) = 0; + virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0; + virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0; + virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material) = 0; + virtual void instance_set_visible(RID p_instance, bool p_visible) = 0; + + virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb) = 0; + + virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton) = 0; + virtual void instance_set_exterior(RID p_instance, bool p_enabled) = 0; + + virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) = 0; + + // don't use these in a game! + virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const = 0; + virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const = 0; + virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario = RID()) const = 0; + + virtual void instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled) = 0; + virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting) = 0; + virtual void instance_geometry_set_material_override(RID p_instance, RID p_material) = 0; + + virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0; + virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) = 0; + virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) = 0; + virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) = 0; + + virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) = 0; + virtual void instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const = 0; + virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const = 0; + virtual Variant instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const = 0; + + virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) = 0; + + /* SKY API */ + + virtual RID sky_create() = 0; + virtual void sky_set_radiance_size(RID p_sky, int p_radiance_size) = 0; + virtual void sky_set_mode(RID p_sky, RS::SkyMode p_samples) = 0; + virtual void sky_set_material(RID p_sky, RID p_material) = 0; + virtual Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) = 0; + + /* ENVIRONMENT API */ + + virtual RID environment_create() = 0; + + virtual void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) = 0; + virtual void environment_set_sky(RID p_env, RID p_sky) = 0; + virtual void environment_set_sky_custom_fov(RID p_env, float p_scale) = 0; + virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) = 0; + virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0; + virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0; + virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0; + virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) = 0; + + virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0; + virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0; + virtual void environment_glow_set_use_high_quality(bool p_enable) = 0; + + virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter) = 0; + + virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0; + virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0; + virtual void environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size) = 0; + virtual void environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size) = 0; + + virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) = 0; + virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) = 0; + + virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) = 0; + + virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; + + virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; + + virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) = 0; + virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) = 0; + virtual void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) = 0; + + virtual void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) = 0; + + virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) = 0; + + virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) = 0; + + virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) = 0; + + virtual RS::EnvironmentBG environment_get_background(RID p_Env) const = 0; + virtual int environment_get_canvas_max_layer(RID p_env) const = 0; + + virtual bool is_environment(RID p_environment) const = 0; + + virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) = 0; + virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) = 0; + virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) = 0; + + /* Camera Effects */ + + virtual RID camera_effects_create() = 0; + + virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) = 0; + virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) = 0; + + virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0; + virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0; + + virtual void shadows_quality_set(RS::ShadowQuality p_quality) = 0; + virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) = 0; + + virtual RID shadow_atlas_create() = 0; + virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_use_16_bits = false) = 0; + virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0; + + /* Render Buffers */ + + virtual RID render_buffers_create() = 0; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) = 0; + + virtual void gi_set_use_half_resolution(bool p_enable) = 0; + + virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0; + + virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) = 0; + virtual void gi_probe_set_quality(RS::GIProbeQuality) = 0; + + virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0; + + virtual void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) = 0; + virtual void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0; + virtual void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0; + + virtual void update() = 0; + virtual void render_probes() = 0; + + virtual bool free(RID p_rid) = 0; + + RendererScene(); + virtual ~RendererScene(); +}; + +#endif // RENDERINGSERVERSCENE_H diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp new file mode 100644 index 0000000000..db601ba49c --- /dev/null +++ b/servers/rendering/renderer_scene_cull.cpp @@ -0,0 +1,3520 @@ +/*************************************************************************/ +/* renderer_scene_cull.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "renderer_scene_cull.h" + +#include "core/config/project_settings.h" +#include "core/os/os.h" +#include "rendering_server_default.h" +#include "rendering_server_globals.h" + +#include <new> + +/* CAMERA API */ + +RID RendererSceneCull::camera_create() { + Camera *camera = memnew(Camera); + return camera_owner.make_rid(camera); +} + +void RendererSceneCull::camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) { + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + camera->type = Camera::PERSPECTIVE; + camera->fov = p_fovy_degrees; + camera->znear = p_z_near; + camera->zfar = p_z_far; +} + +void RendererSceneCull::camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) { + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + camera->type = Camera::ORTHOGONAL; + camera->size = p_size; + camera->znear = p_z_near; + camera->zfar = p_z_far; +} + +void RendererSceneCull::camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) { + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + camera->type = Camera::FRUSTUM; + camera->size = p_size; + camera->offset = p_offset; + camera->znear = p_z_near; + camera->zfar = p_z_far; +} + +void RendererSceneCull::camera_set_transform(RID p_camera, const Transform &p_transform) { + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + camera->transform = p_transform.orthonormalized(); +} + +void RendererSceneCull::camera_set_cull_mask(RID p_camera, uint32_t p_layers) { + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + + camera->visible_layers = p_layers; +} + +void RendererSceneCull::camera_set_environment(RID p_camera, RID p_env) { + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + camera->env = p_env; +} + +void RendererSceneCull::camera_set_camera_effects(RID p_camera, RID p_fx) { + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + camera->effects = p_fx; +} + +void RendererSceneCull::camera_set_use_vertical_aspect(RID p_camera, bool p_enable) { + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + camera->vaspect = p_enable; +} + +bool RendererSceneCull::is_camera(RID p_camera) const { + return camera_owner.owns(p_camera); +} + +/* SCENARIO API */ + +void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) { + RendererSceneCull *self = (RendererSceneCull *)singleton; + Instance *A = p_A; + Instance *B = p_B; + + //instance indices are designed so greater always contains lesser + if (A->base_type > B->base_type) { + SWAP(A, B); //lesser always first + } + + if (B->base_type == RS::INSTANCE_LIGHT && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + geom->lights.insert(B); + light->geometries.insert(A); + + if (geom->can_cast_shadows) { + light->shadow_dirty = true; + } + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_LIGHTING_DIRTY; + } + + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + geom->reflection_probes.insert(B); + reflection_probe->geometries.insert(A); + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_REFLECTION_DIRTY; + } + + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + geom->decals.insert(B); + decal->geometries.insert(A); + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_DECAL_DIRTY; + } + + } else if (B->base_type == RS::INSTANCE_LIGHTMAP && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + if (A->dynamic_gi) { + geom->lightmap_captures.insert(A); + lightmap_data->geometries.insert(B); + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_LIGHTMAP_CAPTURE; + } + ((RendererSceneCull *)self)->_instance_queue_update(A, false, false); //need to update capture + } + + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_GI_PROBE) && B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + geom->gi_probes.insert(B); + + if (A->dynamic_gi) { + gi_probe->dynamic_geometries.insert(A); + } else { + gi_probe->geometries.insert(A); + } + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_GI_PROBE_DIRTY; + } + + } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); + gi_probe->lights.insert(A); + } else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) { + InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(B->base_data); + RSG::storage->particles_add_collision(A->base, collision->instance); + } +} + +void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) { + RendererSceneCull *self = (RendererSceneCull *)singleton; + Instance *A = p_A; + Instance *B = p_B; + + //instance indices are designed so greater always contains lesser + if (A->base_type > B->base_type) { + SWAP(A, B); //lesser always first + } + + if (B->base_type == RS::INSTANCE_LIGHT && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + geom->lights.erase(B); + light->geometries.erase(A); + + if (geom->can_cast_shadows) { + light->shadow_dirty = true; + } + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_LIGHTING_DIRTY; + } + + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + geom->reflection_probes.erase(B); + reflection_probe->geometries.erase(A); + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_REFLECTION_DIRTY; + } + + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + geom->decals.erase(B); + decal->geometries.erase(A); + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_DECAL_DIRTY; + } + + } else if (B->base_type == RS::INSTANCE_LIGHTMAP && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + if (A->dynamic_gi) { + geom->lightmap_captures.erase(B); + + if (geom->lightmap_captures.is_empty() && A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags &= ~uint32_t(InstanceData::FLAG_LIGHTMAP_CAPTURE); + } + + lightmap_data->geometries.erase(A); + ((RendererSceneCull *)self)->_instance_queue_update(A, false, false); //need to update capture + } + + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_GI_PROBE) && B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); + + geom->gi_probes.erase(B); + if (A->dynamic_gi) { + gi_probe->dynamic_geometries.erase(A); + } else { + gi_probe->geometries.erase(A); + } + + if (A->scenario && A->array_index >= 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_GI_PROBE_DIRTY; + } + + } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); + gi_probe->lights.erase(A); + } else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) { + InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(B->base_data); + RSG::storage->particles_remove_collision(A->base, collision->instance); + } +} + +RID RendererSceneCull::scenario_create() { + Scenario *scenario = memnew(Scenario); + ERR_FAIL_COND_V(!scenario, RID()); + RID scenario_rid = scenario_owner.make_rid(scenario); + scenario->self = scenario_rid; + + scenario->reflection_probe_shadow_atlas = scene_render->shadow_atlas_create(); + scene_render->shadow_atlas_set_size(scenario->reflection_probe_shadow_atlas, 1024); //make enough shadows for close distance, don't bother with rest + scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 0, 4); + scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 1, 4); + scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 2, 4); + scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 3, 8); + scenario->reflection_atlas = scene_render->reflection_atlas_create(); + + scenario->instance_aabbs.set_page_pool(&instance_aabb_page_pool); + scenario->instance_data.set_page_pool(&instance_data_page_pool); + + return scenario_rid; +} + +void RendererSceneCull::scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND(!scenario); + scenario->debug = p_debug_mode; +} + +void RendererSceneCull::scenario_set_environment(RID p_scenario, RID p_environment) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND(!scenario); + scenario->environment = p_environment; +} + +void RendererSceneCull::scenario_set_camera_effects(RID p_scenario, RID p_camera_effects) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND(!scenario); + scenario->camera_effects = p_camera_effects; +} + +void RendererSceneCull::scenario_set_fallback_environment(RID p_scenario, RID p_environment) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND(!scenario); + scenario->fallback_environment = p_environment; +} + +void RendererSceneCull::scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND(!scenario); + scene_render->reflection_atlas_set_size(scenario->reflection_atlas, p_reflection_size, p_reflection_count); +} + +bool RendererSceneCull::is_scenario(RID p_scenario) const { + return scenario_owner.owns(p_scenario); +} + +RID RendererSceneCull::scenario_get_environment(RID p_scenario) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND_V(!scenario, RID()); + return scenario->environment; +} + +/* INSTANCING API */ + +void RendererSceneCull::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies) { + if (p_update_aabb) { + p_instance->update_aabb = true; + } + if (p_update_dependencies) { + p_instance->update_dependencies = true; + } + + if (p_instance->update_item.in_list()) { + return; + } + + _instance_update_list.add(&p_instance->update_item); +} + +RID RendererSceneCull::instance_create() { + Instance *instance = memnew(Instance); + ERR_FAIL_COND_V(!instance, RID()); + + RID instance_rid = instance_owner.make_rid(instance); + instance->self = instance_rid; + + return instance_rid; +} + +void RendererSceneCull::_instance_update_mesh_instance(Instance *p_instance) { + bool needs_instance = RSG::storage->mesh_needs_instance(p_instance->base, p_instance->skeleton.is_valid()); + if (needs_instance != p_instance->mesh_instance.is_valid()) { + if (needs_instance) { + p_instance->mesh_instance = RSG::storage->mesh_instance_create(p_instance->base); + + } else { + RSG::storage->free(p_instance->mesh_instance); + p_instance->mesh_instance = RID(); + } + + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + scene_render->geometry_instance_set_mesh_instance(geom->geometry_instance, p_instance->mesh_instance); + + if (p_instance->scenario && p_instance->array_index >= 0) { + InstanceData &idata = p_instance->scenario->instance_data[p_instance->array_index]; + if (p_instance->mesh_instance.is_valid()) { + idata.flags |= InstanceData::FLAG_USES_MESH_INSTANCE; + } else { + idata.flags &= ~uint32_t(InstanceData::FLAG_USES_MESH_INSTANCE); + } + } + } + + if (p_instance->mesh_instance.is_valid()) { + RSG::storage->mesh_instance_set_skeleton(p_instance->mesh_instance, p_instance->skeleton); + } +} + +void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + Scenario *scenario = instance->scenario; + + if (instance->base_type != RS::INSTANCE_NONE) { + //free anything related to that base + + if (scenario && instance->indexer_id.is_valid()) { + _unpair_instance(instance); + } + + if (instance->mesh_instance.is_valid()) { + RSG::storage->free(instance->mesh_instance); + instance->mesh_instance = RID(); + // no need to set instance data flag here, as it was freed above + } + + switch (instance->base_type) { + case RS::INSTANCE_MESH: + case RS::INSTANCE_MULTIMESH: + case RS::INSTANCE_IMMEDIATE: + case RS::INSTANCE_PARTICLES: { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_free(geom->geometry_instance); + } break; + case RS::INSTANCE_LIGHT: { + InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); + + if (scenario && instance->visible && RSG::storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { + scenario->dynamic_lights.erase(light->instance); + } + +#ifdef DEBUG_ENABLED + if (light->geometries.size()) { + ERR_PRINT("BUG, indexing did not unpair geometries from light."); + } +#endif + if (scenario && light->D) { + scenario->directional_lights.erase(light->D); + light->D = nullptr; + } + scene_render->free(light->instance); + } break; + case RS::INSTANCE_PARTICLES_COLLISION: { + InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(instance->base_data); + RSG::storage->free(collision->instance); + } break; + case RS::INSTANCE_REFLECTION_PROBE: { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data); + scene_render->free(reflection_probe->instance); + if (reflection_probe->update_list.in_list()) { + reflection_probe_render_list.remove(&reflection_probe->update_list); + } + } break; + case RS::INSTANCE_DECAL: { + InstanceDecalData *decal = static_cast<InstanceDecalData *>(instance->base_data); + scene_render->free(decal->instance); + + } break; + case RS::INSTANCE_LIGHTMAP: { + InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(instance->base_data); + //erase dependencies, since no longer a lightmap + while (lightmap_data->users.front()) { + instance_geometry_set_lightmap(lightmap_data->users.front()->get()->self, RID(), Rect2(), 0); + } + scene_render->free(lightmap_data->instance); + } break; + case RS::INSTANCE_GI_PROBE: { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); +#ifdef DEBUG_ENABLED + if (gi_probe->geometries.size()) { + ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe."); + } +#endif +#ifdef DEBUG_ENABLED + if (gi_probe->lights.size()) { + ERR_PRINT("BUG, indexing did not unpair lights from GIProbe."); + } +#endif + if (gi_probe->update_element.in_list()) { + gi_probe_update_list.remove(&gi_probe->update_element); + } + + scene_render->free(gi_probe->probe_instance); + + } break; + default: { + } + } + + if (instance->base_data) { + memdelete(instance->base_data); + instance->base_data = nullptr; + } + + instance->materials.clear(); + } + + instance->base_type = RS::INSTANCE_NONE; + instance->base = RID(); + + if (p_base.is_valid()) { + instance->base_type = RSG::storage->get_base_type(p_base); + ERR_FAIL_COND(instance->base_type == RS::INSTANCE_NONE); + + switch (instance->base_type) { + case RS::INSTANCE_LIGHT: { + InstanceLightData *light = memnew(InstanceLightData); + + if (scenario && RSG::storage->light_get_type(p_base) == RS::LIGHT_DIRECTIONAL) { + light->D = scenario->directional_lights.push_back(instance); + } + + light->instance = scene_render->light_instance_create(p_base); + + instance->base_data = light; + } break; + case RS::INSTANCE_MESH: + case RS::INSTANCE_MULTIMESH: + case RS::INSTANCE_IMMEDIATE: + case RS::INSTANCE_PARTICLES: { + InstanceGeometryData *geom = memnew(InstanceGeometryData); + instance->base_data = geom; + geom->geometry_instance = scene_render->geometry_instance_create(p_base); + + scene_render->geometry_instance_set_skeleton(geom->geometry_instance, instance->skeleton); + scene_render->geometry_instance_set_material_override(geom->geometry_instance, instance->material_override); + scene_render->geometry_instance_set_surface_materials(geom->geometry_instance, instance->materials); + scene_render->geometry_instance_set_transform(geom->geometry_instance, instance->transform, instance->aabb, instance->transformed_aabb); + scene_render->geometry_instance_set_layer_mask(geom->geometry_instance, instance->layer_mask); + scene_render->geometry_instance_set_lod_bias(geom->geometry_instance, instance->lod_bias); + scene_render->geometry_instance_set_use_baked_light(geom->geometry_instance, instance->baked_light); + scene_render->geometry_instance_set_use_dynamic_gi(geom->geometry_instance, instance->dynamic_gi); + scene_render->geometry_instance_set_cast_double_sided_shadows(geom->geometry_instance, instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED); + scene_render->geometry_instance_set_use_lightmap(geom->geometry_instance, RID(), instance->lightmap_uv_scale, instance->lightmap_slice_index); + if (instance->lightmap_sh.size() == 9) { + scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, instance->lightmap_sh.ptr()); + } + + } break; + case RS::INSTANCE_PARTICLES_COLLISION: { + InstanceParticlesCollisionData *collision = memnew(InstanceParticlesCollisionData); + collision->instance = RSG::storage->particles_collision_instance_create(p_base); + RSG::storage->particles_collision_instance_set_active(collision->instance, instance->visible); + instance->base_data = collision; + } break; + case RS::INSTANCE_REFLECTION_PROBE: { + InstanceReflectionProbeData *reflection_probe = memnew(InstanceReflectionProbeData); + reflection_probe->owner = instance; + instance->base_data = reflection_probe; + + reflection_probe->instance = scene_render->reflection_probe_instance_create(p_base); + } break; + case RS::INSTANCE_DECAL: { + InstanceDecalData *decal = memnew(InstanceDecalData); + decal->owner = instance; + instance->base_data = decal; + + decal->instance = scene_render->decal_instance_create(p_base); + } break; + case RS::INSTANCE_LIGHTMAP: { + InstanceLightmapData *lightmap_data = memnew(InstanceLightmapData); + instance->base_data = lightmap_data; + lightmap_data->instance = scene_render->lightmap_instance_create(p_base); + } break; + case RS::INSTANCE_GI_PROBE: { + InstanceGIProbeData *gi_probe = memnew(InstanceGIProbeData); + instance->base_data = gi_probe; + gi_probe->owner = instance; + + if (scenario && !gi_probe->update_element.in_list()) { + gi_probe_update_list.add(&gi_probe->update_element); + } + + gi_probe->probe_instance = scene_render->gi_probe_instance_create(p_base); + + } break; + default: { + } + } + + instance->base = p_base; + + if (instance->base_type == RS::INSTANCE_MESH) { + _instance_update_mesh_instance(instance); + } + + //forcefully update the dependency now, so if for some reason it gets removed, we can immediately clear it + RSG::storage->base_update_dependency(p_base, &instance->dependency_tracker); + } + + _instance_queue_update(instance, true, true); +} + +void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + if (instance->scenario) { + instance->scenario->instances.remove(&instance->scenario_item); + + if (instance->indexer_id.is_valid()) { + _unpair_instance(instance); + } + + switch (instance->base_type) { + case RS::INSTANCE_LIGHT: { + InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); +#ifdef DEBUG_ENABLED + if (light->geometries.size()) { + ERR_PRINT("BUG, indexing did not unpair geometries from light."); + } +#endif + if (light->D) { + instance->scenario->directional_lights.erase(light->D); + light->D = nullptr; + } + } break; + case RS::INSTANCE_REFLECTION_PROBE: { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data); + scene_render->reflection_probe_release_atlas_index(reflection_probe->instance); + + } break; + case RS::INSTANCE_PARTICLES_COLLISION: { + heightfield_particle_colliders_update_list.erase(instance); + } break; + case RS::INSTANCE_GI_PROBE: { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); + +#ifdef DEBUG_ENABLED + if (gi_probe->geometries.size()) { + ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe."); + } +#endif +#ifdef DEBUG_ENABLED + if (gi_probe->lights.size()) { + ERR_PRINT("BUG, indexing did not unpair lights from GIProbe."); + } +#endif + + if (gi_probe->update_element.in_list()) { + gi_probe_update_list.remove(&gi_probe->update_element); + } + } break; + default: { + } + } + + instance->scenario = nullptr; + } + + if (p_scenario.is_valid()) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND(!scenario); + + instance->scenario = scenario; + + scenario->instances.add(&instance->scenario_item); + + switch (instance->base_type) { + case RS::INSTANCE_LIGHT: { + InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); + + if (RSG::storage->light_get_type(instance->base) == RS::LIGHT_DIRECTIONAL) { + light->D = scenario->directional_lights.push_back(instance); + } + } break; + case RS::INSTANCE_GI_PROBE: { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); + if (!gi_probe->update_element.in_list()) { + gi_probe_update_list.add(&gi_probe->update_element); + } + } break; + default: { + } + } + + _instance_queue_update(instance, true, true); + } +} + +void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + instance->layer_mask = p_mask; + if (instance->scenario && instance->array_index >= 0) { + instance->scenario->instance_data[instance->array_index].layer_mask = p_mask; + } + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_layer_mask(geom->geometry_instance, p_mask); + } +} + +void RendererSceneCull::instance_set_transform(RID p_instance, const Transform &p_transform) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + if (instance->transform == p_transform) { + return; //must be checked to avoid worst evil + } + +#ifdef DEBUG_ENABLED + + for (int i = 0; i < 4; i++) { + const Vector3 &v = i < 3 ? p_transform.basis.elements[i] : p_transform.origin; + ERR_FAIL_COND(Math::is_inf(v.x)); + ERR_FAIL_COND(Math::is_nan(v.x)); + ERR_FAIL_COND(Math::is_inf(v.y)); + ERR_FAIL_COND(Math::is_nan(v.y)); + ERR_FAIL_COND(Math::is_inf(v.z)); + ERR_FAIL_COND(Math::is_nan(v.z)); + } + +#endif + instance->transform = p_transform; + _instance_queue_update(instance, true); +} + +void RendererSceneCull::instance_attach_object_instance_id(RID p_instance, ObjectID p_id) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + instance->object_id = p_id; +} + +void RendererSceneCull::instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + if (instance->update_item.in_list()) { + _update_dirty_instance(instance); + } + + if (instance->mesh_instance.is_valid()) { + RSG::storage->mesh_instance_set_blend_shape_weight(instance->mesh_instance, p_shape, p_weight); + } +} + +void RendererSceneCull::instance_set_surface_material(RID p_instance, int p_surface, RID p_material) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + if (instance->base_type == RS::INSTANCE_MESH) { + //may not have been updated yet, may also have not been set yet. When updated will be correcte, worst case + instance->materials.resize(MAX(p_surface + 1, RSG::storage->mesh_get_surface_count(instance->base))); + } + + ERR_FAIL_INDEX(p_surface, instance->materials.size()); + + instance->materials.write[p_surface] = p_material; + + _instance_queue_update(instance, false, true); +} + +void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + if (instance->visible == p_visible) { + return; + } + + instance->visible = p_visible; + + if (p_visible) { + if (instance->scenario != nullptr) { + _instance_queue_update(instance, true, false); + } + } else if (instance->indexer_id.is_valid()) { + _unpair_instance(instance); + } + + if (instance->base_type == RS::INSTANCE_LIGHT) { + InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); + if (instance->scenario && RSG::storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { + if (p_visible) { + instance->scenario->dynamic_lights.push_back(light->instance); + } else { + instance->scenario->dynamic_lights.erase(light->instance); + } + } + } + + if (instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { + InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(instance->base_data); + RSG::storage->particles_collision_instance_set_active(collision->instance, p_visible); + } +} + +inline bool is_geometry_instance(RenderingServer::InstanceType p_type) { + return p_type == RS::INSTANCE_MESH || p_type == RS::INSTANCE_MULTIMESH || p_type == RS::INSTANCE_PARTICLES || p_type == RS::INSTANCE_IMMEDIATE; +} + +void RendererSceneCull::instance_set_custom_aabb(RID p_instance, AABB p_aabb) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + ERR_FAIL_COND(!is_geometry_instance(instance->base_type)); + + if (p_aabb != AABB()) { + // Set custom AABB + if (instance->custom_aabb == nullptr) { + instance->custom_aabb = memnew(AABB); + } + *instance->custom_aabb = p_aabb; + + } else { + // Clear custom AABB + if (instance->custom_aabb != nullptr) { + memdelete(instance->custom_aabb); + instance->custom_aabb = nullptr; + } + } + + if (instance->scenario) { + _instance_queue_update(instance, true, false); + } +} + +void RendererSceneCull::instance_attach_skeleton(RID p_instance, RID p_skeleton) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + if (instance->skeleton == p_skeleton) { + return; + } + + instance->skeleton = p_skeleton; + + if (p_skeleton.is_valid()) { + //update the dependency now, so if cleared, we remove it + RSG::storage->skeleton_update_dependency(p_skeleton, &instance->dependency_tracker); + } + + _instance_queue_update(instance, true, true); + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + _instance_update_mesh_instance(instance); + + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_skeleton(geom->geometry_instance, p_skeleton); + } +} + +void RendererSceneCull::instance_set_exterior(RID p_instance, bool p_enabled) { +} + +void RendererSceneCull::instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + instance->extra_margin = p_margin; + _instance_queue_update(instance, true, false); +} + +Vector<ObjectID> RendererSceneCull::instances_cull_aabb(const AABB &p_aabb, RID p_scenario) const { + Vector<ObjectID> instances; + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND_V(!scenario, instances); + + const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling + + struct CullAABB { + Vector<ObjectID> instances; + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + if (!p_instance->object_id.is_null()) { + instances.push_back(p_instance->object_id); + } + return false; + } + }; + + CullAABB cull_aabb; + scenario->indexers[Scenario::INDEXER_GEOMETRY].aabb_query(p_aabb, cull_aabb); + scenario->indexers[Scenario::INDEXER_VOLUMES].aabb_query(p_aabb, cull_aabb); + return cull_aabb.instances; +} + +Vector<ObjectID> RendererSceneCull::instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const { + Vector<ObjectID> instances; + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND_V(!scenario, instances); + const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling + + struct CullRay { + Vector<ObjectID> instances; + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + if (!p_instance->object_id.is_null()) { + instances.push_back(p_instance->object_id); + } + return false; + } + }; + + CullRay cull_ray; + scenario->indexers[Scenario::INDEXER_GEOMETRY].ray_query(p_from, p_to, cull_ray); + scenario->indexers[Scenario::INDEXER_VOLUMES].ray_query(p_from, p_to, cull_ray); + return cull_ray.instances; +} + +Vector<ObjectID> RendererSceneCull::instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario) const { + Vector<ObjectID> instances; + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND_V(!scenario, instances); + const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling + + Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&p_convex[0], p_convex.size()); + + struct CullConvex { + Vector<ObjectID> instances; + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + if (!p_instance->object_id.is_null()) { + instances.push_back(p_instance->object_id); + } + return false; + } + }; + + CullConvex cull_convex; + scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(p_convex.ptr(), p_convex.size(), points.ptr(), points.size(), cull_convex); + scenario->indexers[Scenario::INDEXER_VOLUMES].convex_query(p_convex.ptr(), p_convex.size(), points.ptr(), points.size(), cull_convex); + return cull_convex.instances; +} + +void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + //ERR_FAIL_COND(((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK)); + + switch (p_flags) { + case RS::INSTANCE_FLAG_USE_BAKED_LIGHT: { + instance->baked_light = p_enabled; + + if (instance->scenario && instance->array_index >= 0) { + InstanceData &idata = instance->scenario->instance_data[instance->array_index]; + if (instance->baked_light) { + idata.flags |= InstanceData::FLAG_USES_BAKED_LIGHT; + } else { + idata.flags &= ~uint32_t(InstanceData::FLAG_USES_BAKED_LIGHT); + } + } + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_use_baked_light(geom->geometry_instance, p_enabled); + } + + } break; + case RS::INSTANCE_FLAG_USE_DYNAMIC_GI: { + if (p_enabled == instance->dynamic_gi) { + //bye, redundant + return; + } + + if (instance->indexer_id.is_valid()) { + _unpair_instance(instance); + _instance_queue_update(instance, true, true); + } + + //once out of octree, can be changed + instance->dynamic_gi = p_enabled; + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_use_dynamic_gi(geom->geometry_instance, p_enabled); + } + + } break; + case RS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE: { + instance->redraw_if_visible = p_enabled; + + if (instance->scenario && instance->array_index >= 0) { + InstanceData &idata = instance->scenario->instance_data[instance->array_index]; + if (instance->redraw_if_visible) { + idata.flags |= InstanceData::FLAG_REDRAW_IF_VISIBLE; + } else { + idata.flags &= ~uint32_t(InstanceData::FLAG_REDRAW_IF_VISIBLE); + } + } + + } break; + default: { + } + } +} + +void RendererSceneCull::instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + instance->cast_shadows = p_shadow_casting_setting; + + if (instance->scenario && instance->array_index >= 0) { + InstanceData &idata = instance->scenario->instance_data[instance->array_index]; + + if (instance->cast_shadows != RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { + idata.flags |= InstanceData::FLAG_CAST_SHADOWS; + } else { + idata.flags &= ~uint32_t(InstanceData::FLAG_CAST_SHADOWS); + } + + if (instance->cast_shadows == RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { + idata.flags |= InstanceData::FLAG_CAST_SHADOWS_ONLY; + } else { + idata.flags &= ~uint32_t(InstanceData::FLAG_CAST_SHADOWS_ONLY); + } + } + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_cast_double_sided_shadows(geom->geometry_instance, instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED); + } + + _instance_queue_update(instance, false, true); +} + +void RendererSceneCull::instance_geometry_set_material_override(RID p_instance, RID p_material) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + instance->material_override = p_material; + _instance_queue_update(instance, false, true); + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_material_override(geom->geometry_instance, p_material); + } +} + +void RendererSceneCull::instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) { +} + +void RendererSceneCull::instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) { +} + +void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + if (instance->lightmap) { + InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(((Instance *)instance->lightmap)->base_data); + lightmap_data->users.erase(instance); + instance->lightmap = nullptr; + } + + Instance *lightmap_instance = instance_owner.getornull(p_lightmap); + + instance->lightmap = lightmap_instance; + instance->lightmap_uv_scale = p_lightmap_uv_scale; + instance->lightmap_slice_index = p_slice_index; + + RID lightmap_instance_rid; + + if (lightmap_instance) { + InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(lightmap_instance->base_data); + lightmap_data->users.insert(instance); + lightmap_instance_rid = lightmap_data->instance; + } + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_use_lightmap(geom->geometry_instance, lightmap_instance_rid, p_lightmap_uv_scale, p_slice_index); + } +} + +void RendererSceneCull::instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + instance->lod_bias = p_lod_bias; + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_lod_bias(geom->geometry_instance, p_lod_bias); + } +} + +void RendererSceneCull::instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + Map<StringName, Instance::InstanceShaderParameter>::Element *E = instance->instance_shader_parameters.find(p_parameter); + + if (!E) { + Instance::InstanceShaderParameter isp; + isp.index = -1; + isp.info = PropertyInfo(); + isp.value = p_value; + instance->instance_shader_parameters[p_parameter] = isp; + } else { + E->get().value = p_value; + if (E->get().index >= 0 && instance->instance_allocated_shader_parameters) { + //update directly + RSG::storage->global_variables_instance_update(p_instance, E->get().index, p_value); + } + } +} + +Variant RendererSceneCull::instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const { + const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!instance, Variant()); + + if (instance->instance_shader_parameters.has(p_parameter)) { + return instance->instance_shader_parameters[p_parameter].value; + } + return Variant(); +} + +Variant RendererSceneCull::instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const { + const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!instance, Variant()); + + if (instance->instance_shader_parameters.has(p_parameter)) { + return instance->instance_shader_parameters[p_parameter].default_value; + } + return Variant(); +} + +void RendererSceneCull::instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const { + const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + const_cast<RendererSceneCull *>(this)->update_dirty_instances(); + + Vector<StringName> names; + for (Map<StringName, Instance::InstanceShaderParameter>::Element *E = instance->instance_shader_parameters.front(); E; E = E->next()) { + names.push_back(E->key()); + } + names.sort_custom<StringName::AlphCompare>(); + for (int i = 0; i < names.size(); i++) { + PropertyInfo pinfo = instance->instance_shader_parameters[names[i]].info; + p_parameters->push_back(pinfo); + } +} + +void RendererSceneCull::_update_instance(Instance *p_instance) { + p_instance->version++; + + if (p_instance->base_type == RS::INSTANCE_LIGHT) { + InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); + + scene_render->light_instance_set_transform(light->instance, p_instance->transform); + scene_render->light_instance_set_aabb(light->instance, p_instance->transform.xform(p_instance->aabb)); + light->shadow_dirty = true; + + RS::LightBakeMode bake_mode = RSG::storage->light_get_bake_mode(p_instance->base); + if (RSG::storage->light_get_type(p_instance->base) != RS::LIGHT_DIRECTIONAL && bake_mode != light->bake_mode) { + if (p_instance->visible && p_instance->scenario && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { + p_instance->scenario->dynamic_lights.erase(light->instance); + } + + light->bake_mode = bake_mode; + + if (p_instance->visible && p_instance->scenario && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { + p_instance->scenario->dynamic_lights.push_back(light->instance); + } + } + + uint32_t max_sdfgi_cascade = RSG::storage->light_get_max_sdfgi_cascade(p_instance->base); + if (light->max_sdfgi_cascade != max_sdfgi_cascade) { + light->max_sdfgi_cascade = max_sdfgi_cascade; //should most likely make sdfgi dirty in scenario + } + } else if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data); + + scene_render->reflection_probe_instance_set_transform(reflection_probe->instance, p_instance->transform); + + if (p_instance->scenario && p_instance->array_index >= 0) { + InstanceData &idata = p_instance->scenario->instance_data[p_instance->array_index]; + idata.flags |= InstanceData::FLAG_REFLECTION_PROBE_DIRTY; + } + } else if (p_instance->base_type == RS::INSTANCE_DECAL) { + InstanceDecalData *decal = static_cast<InstanceDecalData *>(p_instance->base_data); + + scene_render->decal_instance_set_transform(decal->instance, p_instance->transform); + } else if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) { + InstanceLightmapData *lightmap = static_cast<InstanceLightmapData *>(p_instance->base_data); + + scene_render->lightmap_instance_set_transform(lightmap->instance, p_instance->transform); + } else if (p_instance->base_type == RS::INSTANCE_GI_PROBE) { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(p_instance->base_data); + + scene_render->gi_probe_instance_set_transform_to_data(gi_probe->probe_instance, p_instance->transform); + } else if (p_instance->base_type == RS::INSTANCE_PARTICLES) { + RSG::storage->particles_set_emission_transform(p_instance->base, p_instance->transform); + } else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { + InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(p_instance->base_data); + + //remove materials no longer used and un-own them + if (RSG::storage->particles_collision_is_heightfield(p_instance->base)) { + heightfield_particle_colliders_update_list.insert(p_instance); + } + RSG::storage->particles_collision_instance_set_transform(collision->instance, p_instance->transform); + } + + if (p_instance->aabb.has_no_surface()) { + return; + } + + if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) { + //if this moved, update the captured objects + InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(p_instance->base_data); + //erase dependencies, since no longer a lightmap + + for (Set<Instance *>::Element *E = lightmap_data->geometries.front(); E; E = E->next()) { + Instance *geom = E->get(); + _instance_queue_update(geom, true, false); + } + } + + AABB new_aabb; + new_aabb = p_instance->transform.xform(p_instance->aabb); + p_instance->transformed_aabb = new_aabb; + + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + //make sure lights are updated if it casts shadow + + if (geom->can_cast_shadows) { + for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) { + InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); + light->shadow_dirty = true; + } + } + + if (!p_instance->lightmap && geom->lightmap_captures.size()) { + //affected by lightmap captures, must update capture info! + _update_instance_lightmap_captures(p_instance); + } else { + if (!p_instance->lightmap_sh.is_empty()) { + p_instance->lightmap_sh.clear(); //don't need SH + p_instance->lightmap_target_sh.clear(); //don't need SH + scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, nullptr); + } + } + + scene_render->geometry_instance_set_transform(geom->geometry_instance, p_instance->transform, p_instance->aabb, p_instance->transformed_aabb); + } + + // note: we had to remove is equal approx check here, it meant that det == 0.000004 won't work, which is the case for some of our scenes. + if (p_instance->scenario == nullptr || !p_instance->visible || p_instance->transform.basis.determinant() == 0) { + p_instance->prev_transformed_aabb = p_instance->transformed_aabb; + return; + } + + //quantize to improve moving object performance + AABB bvh_aabb = p_instance->transformed_aabb; + + if (p_instance->indexer_id.is_valid() && bvh_aabb != p_instance->prev_transformed_aabb) { + //assume motion, see if bounds need to be quantized + AABB motion_aabb = bvh_aabb.merge(p_instance->prev_transformed_aabb); + float motion_longest_axis = motion_aabb.get_longest_axis_size(); + float longest_axis = p_instance->transformed_aabb.get_longest_axis_size(); + + if (motion_longest_axis < longest_axis * 2) { + //moved but not a lot, use motion aabb quantizing + float quantize_size = Math::pow(2.0, Math::ceil(Math::log(motion_longest_axis) / Math::log(2.0))) * 0.5; //one fifth + bvh_aabb.quantize(quantize_size); + } + } + + if (!p_instance->indexer_id.is_valid()) { + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + p_instance->indexer_id = p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY].insert(bvh_aabb, p_instance); + } else { + p_instance->indexer_id = p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES].insert(bvh_aabb, p_instance); + } + + p_instance->array_index = p_instance->scenario->instance_data.size(); + InstanceData idata; + idata.instance = p_instance; + idata.layer_mask = p_instance->layer_mask; + idata.flags = p_instance->base_type; //changing it means de-indexing, so this never needs to be changed later + idata.base_rid = p_instance->base; + switch (p_instance->base_type) { + case RS::INSTANCE_MESH: + case RS::INSTANCE_MULTIMESH: + case RS::INSTANCE_IMMEDIATE: + case RS::INSTANCE_PARTICLES: { + idata.instance_geometry = static_cast<InstanceGeometryData *>(p_instance->base_data)->geometry_instance; + } break; + case RS::INSTANCE_LIGHT: { + idata.instance_data_rid = static_cast<InstanceLightData *>(p_instance->base_data)->instance.get_id(); + } break; + case RS::INSTANCE_REFLECTION_PROBE: { + idata.instance_data_rid = static_cast<InstanceReflectionProbeData *>(p_instance->base_data)->instance.get_id(); + } break; + case RS::INSTANCE_DECAL: { + idata.instance_data_rid = static_cast<InstanceDecalData *>(p_instance->base_data)->instance.get_id(); + } break; + case RS::INSTANCE_LIGHTMAP: { + idata.instance_data_rid = static_cast<InstanceLightmapData *>(p_instance->base_data)->instance.get_id(); + } break; + case RS::INSTANCE_GI_PROBE: { + idata.instance_data_rid = static_cast<InstanceGIProbeData *>(p_instance->base_data)->probe_instance.get_id(); + } break; + default: { + } + } + + if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) { + //always dirty when added + idata.flags |= InstanceData::FLAG_REFLECTION_PROBE_DIRTY; + } + if (p_instance->cast_shadows != RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { + idata.flags |= InstanceData::FLAG_CAST_SHADOWS; + } + if (p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { + idata.flags |= InstanceData::FLAG_CAST_SHADOWS_ONLY; + } + if (p_instance->redraw_if_visible) { + idata.flags |= InstanceData::FLAG_REDRAW_IF_VISIBLE; + } + // dirty flags should not be set here, since no pairing has happened + if (p_instance->baked_light) { + idata.flags |= InstanceData::FLAG_USES_BAKED_LIGHT; + } + if (p_instance->mesh_instance.is_valid()) { + idata.flags |= InstanceData::FLAG_USES_MESH_INSTANCE; + } + + p_instance->scenario->instance_data.push_back(idata); + p_instance->scenario->instance_aabbs.push_back(InstanceBounds(p_instance->transformed_aabb)); + } else { + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY].update(p_instance->indexer_id, bvh_aabb); + } else { + p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES].update(p_instance->indexer_id, bvh_aabb); + } + p_instance->scenario->instance_aabbs[p_instance->array_index] = InstanceBounds(p_instance->transformed_aabb); + } + + //move instance and repair + pair_pass++; + + PairInstances pair; + + pair.instance = p_instance; + pair.pair_allocator = &pair_allocator; + pair.pair_pass = pair_pass; + pair.pair_mask = 0; + + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + pair.pair_mask |= 1 << RS::INSTANCE_LIGHT; + pair.pair_mask |= 1 << RS::INSTANCE_GI_PROBE; + pair.pair_mask |= 1 << RS::INSTANCE_LIGHTMAP; + + pair.pair_mask |= geometry_instance_pair_mask; + + pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES]; + } else if (p_instance->base_type == RS::INSTANCE_LIGHT) { + pair.pair_mask |= RS::INSTANCE_GEOMETRY_MASK; + pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; + + if (RSG::storage->light_get_bake_mode(p_instance->base) == RS::LIGHT_BAKE_DYNAMIC) { + pair.pair_mask |= (1 << RS::INSTANCE_GI_PROBE); + pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES]; + } + } else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE)) { + pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK; + pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; + } else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (p_instance->base_type == RS::INSTANCE_DECAL)) { + pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK; + pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; + } else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { + pair.pair_mask = (1 << RS::INSTANCE_PARTICLES); + pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; + } else if (p_instance->base_type == RS::INSTANCE_GI_PROBE) { + //lights and geometries + pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK | (1 << RS::INSTANCE_LIGHT); + pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; + pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES]; + } + + pair.pair(); + + p_instance->prev_transformed_aabb = p_instance->transformed_aabb; +} + +void RendererSceneCull::_unpair_instance(Instance *p_instance) { + if (!p_instance->indexer_id.is_valid()) { + return; //nothing to do + } + + while (p_instance->pairs.first()) { + InstancePair *pair = p_instance->pairs.first()->self(); + Instance *other_instance = p_instance == pair->a ? pair->b : pair->a; + _instance_unpair(p_instance, other_instance); + pair_allocator.free(pair); + } + + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY].remove(p_instance->indexer_id); + } else { + p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES].remove(p_instance->indexer_id); + } + + p_instance->indexer_id = DynamicBVH::ID(); + + //replace this by last + int32_t swap_with_index = p_instance->scenario->instance_data.size() - 1; + if (swap_with_index != p_instance->array_index) { + p_instance->scenario->instance_data[swap_with_index].instance->array_index = p_instance->array_index; //swap + p_instance->scenario->instance_data[p_instance->array_index] = p_instance->scenario->instance_data[swap_with_index]; + p_instance->scenario->instance_aabbs[p_instance->array_index] = p_instance->scenario->instance_aabbs[swap_with_index]; + } + + // pop last + p_instance->scenario->instance_data.pop_back(); + p_instance->scenario->instance_aabbs.pop_back(); + + //uninitialize + p_instance->array_index = -1; + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + // Clear these now because the InstanceData containing the dirty flags is gone + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + + scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, nullptr, 0); + scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, nullptr, 0); + scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, nullptr, 0); + scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, nullptr, 0); + } +} + +void RendererSceneCull::_update_instance_aabb(Instance *p_instance) { + AABB new_aabb; + + ERR_FAIL_COND(p_instance->base_type != RS::INSTANCE_NONE && !p_instance->base.is_valid()); + + switch (p_instance->base_type) { + case RenderingServer::INSTANCE_NONE: { + // do nothing + } break; + case RenderingServer::INSTANCE_MESH: { + if (p_instance->custom_aabb) { + new_aabb = *p_instance->custom_aabb; + } else { + new_aabb = RSG::storage->mesh_get_aabb(p_instance->base, p_instance->skeleton); + } + + } break; + + case RenderingServer::INSTANCE_MULTIMESH: { + if (p_instance->custom_aabb) { + new_aabb = *p_instance->custom_aabb; + } else { + new_aabb = RSG::storage->multimesh_get_aabb(p_instance->base); + } + + } break; + case RenderingServer::INSTANCE_IMMEDIATE: { + if (p_instance->custom_aabb) { + new_aabb = *p_instance->custom_aabb; + } else { + new_aabb = RSG::storage->immediate_get_aabb(p_instance->base); + } + + } break; + case RenderingServer::INSTANCE_PARTICLES: { + if (p_instance->custom_aabb) { + new_aabb = *p_instance->custom_aabb; + } else { + new_aabb = RSG::storage->particles_get_aabb(p_instance->base); + } + + } break; + case RenderingServer::INSTANCE_PARTICLES_COLLISION: { + new_aabb = RSG::storage->particles_collision_get_aabb(p_instance->base); + + } break; + case RenderingServer::INSTANCE_LIGHT: { + new_aabb = RSG::storage->light_get_aabb(p_instance->base); + + } break; + case RenderingServer::INSTANCE_REFLECTION_PROBE: { + new_aabb = RSG::storage->reflection_probe_get_aabb(p_instance->base); + + } break; + case RenderingServer::INSTANCE_DECAL: { + new_aabb = RSG::storage->decal_get_aabb(p_instance->base); + + } break; + case RenderingServer::INSTANCE_GI_PROBE: { + new_aabb = RSG::storage->gi_probe_get_bounds(p_instance->base); + + } break; + case RenderingServer::INSTANCE_LIGHTMAP: { + new_aabb = RSG::storage->lightmap_get_aabb(p_instance->base); + + } break; + default: { + } + } + + // <Zylann> This is why I didn't re-use Instance::aabb to implement custom AABBs + if (p_instance->extra_margin) { + new_aabb.grow_by(p_instance->extra_margin); + } + + p_instance->aabb = new_aabb; +} + +void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance) { + bool first_set = p_instance->lightmap_sh.size() == 0; + p_instance->lightmap_sh.resize(9); //using SH + p_instance->lightmap_target_sh.resize(9); //using SH + Color *instance_sh = p_instance->lightmap_target_sh.ptrw(); + bool inside = false; + Color accum_sh[9]; + float accum_blend = 0.0; + + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + for (Set<Instance *>::Element *E = geom->lightmap_captures.front(); E; E = E->next()) { + Instance *lightmap = E->get(); + + bool interior = RSG::storage->lightmap_is_interior(lightmap->base); + + if (inside && !interior) { + continue; //we are inside, ignore exteriors + } + + Transform to_bounds = lightmap->transform.affine_inverse(); + Vector3 center = p_instance->transform.xform(p_instance->aabb.position + p_instance->aabb.size * 0.5); //use aabb center + + Vector3 lm_pos = to_bounds.xform(center); + + AABB bounds = RSG::storage->lightmap_get_aabb(lightmap->base); + if (!bounds.has_point(lm_pos)) { + continue; //not in this lightmap + } + + Color sh[9]; + RSG::storage->lightmap_tap_sh_light(lightmap->base, lm_pos, sh); + + //rotate it + Basis rot = lightmap->transform.basis.orthonormalized(); + for (int i = 0; i < 3; i++) { + float csh[9]; + for (int j = 0; j < 9; j++) { + csh[j] = sh[j][i]; + } + rot.rotate_sh(csh); + for (int j = 0; j < 9; j++) { + sh[j][i] = csh[j]; + } + } + + Vector3 inner_pos = ((lm_pos - bounds.position) / bounds.size) * 2.0 - Vector3(1.0, 1.0, 1.0); + + float blend = MAX(inner_pos.x, MAX(inner_pos.y, inner_pos.z)); + //make blend more rounded + blend = Math::lerp(inner_pos.length(), blend, blend); + blend *= blend; + blend = MAX(0.0, 1.0 - blend); + + if (interior && !inside) { + //do not blend, just replace + for (int j = 0; j < 9; j++) { + accum_sh[j] = sh[j] * blend; + } + accum_blend = blend; + inside = true; + } else { + for (int j = 0; j < 9; j++) { + accum_sh[j] += sh[j] * blend; + } + accum_blend += blend; + } + } + + if (accum_blend > 0.0) { + for (int j = 0; j < 9; j++) { + instance_sh[j] = accum_sh[j] / accum_blend; + if (first_set) { + p_instance->lightmap_sh.write[j] = instance_sh[j]; + } + } + } + + scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, p_instance->lightmap_sh.ptr()); +} + +void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect) { + InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); + + Transform light_transform = p_instance->transform; + light_transform.orthonormalize(); //scale does not count on lights + + real_t max_distance = p_cam_projection.get_z_far(); + real_t shadow_max = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE); + if (shadow_max > 0 && !p_cam_orthogonal) { //its impractical (and leads to unwanted behaviors) to set max distance in orthogonal camera + max_distance = MIN(shadow_max, max_distance); + } + max_distance = MAX(max_distance, p_cam_projection.get_z_near() + 0.001); + real_t min_distance = MIN(p_cam_projection.get_z_near(), max_distance); + + RS::LightDirectionalShadowDepthRangeMode depth_range_mode = RSG::storage->light_directional_get_shadow_depth_range_mode(p_instance->base); + + real_t pancake_size = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE); + + real_t range = max_distance - min_distance; + + int splits = 0; + switch (RSG::storage->light_directional_get_shadow_mode(p_instance->base)) { + case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: + splits = 1; + break; + case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: + splits = 2; + break; + case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: + splits = 4; + break; + } + + real_t distances[5]; + + distances[0] = min_distance; + for (int i = 0; i < splits; i++) { + distances[i + 1] = min_distance + RSG::storage->light_get_param(p_instance->base, RS::LightParam(RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET + i)) * range; + }; + + distances[splits] = max_distance; + + real_t texture_size = scene_render->get_directional_light_shadow_size(light->instance); + + bool overlap = RSG::storage->light_directional_get_blend_splits(p_instance->base); + + real_t first_radius = 0.0; + + real_t min_distance_bias_scale = distances[1]; + + cull.shadow_count = p_shadow_index + 1; + cull.shadows[p_shadow_index].cascade_count = splits; + cull.shadows[p_shadow_index].light_instance = light->instance; + + for (int i = 0; i < splits; i++) { + RENDER_TIMESTAMP("Culling Directional Light split" + itos(i)); + + // setup a camera matrix for that range! + CameraMatrix camera_matrix; + + real_t aspect = p_cam_projection.get_aspect(); + + if (p_cam_orthogonal) { + Vector2 vp_he = p_cam_projection.get_viewport_half_extents(); + + camera_matrix.set_orthogonal(vp_he.y * 2.0, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); + } else { + real_t fov = p_cam_projection.get_fov(); //this is actually yfov, because set aspect tries to keep it + camera_matrix.set_perspective(fov, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); + } + + //obtain the frustum endpoints + + Vector3 endpoints[8]; // frustum plane endpoints + bool res = camera_matrix.get_endpoints(p_cam_transform, endpoints); + ERR_CONTINUE(!res); + + // obtain the light frustum ranges (given endpoints) + + Transform transform = light_transform; //discard scale and stabilize light + + Vector3 x_vec = transform.basis.get_axis(Vector3::AXIS_X).normalized(); + Vector3 y_vec = transform.basis.get_axis(Vector3::AXIS_Y).normalized(); + Vector3 z_vec = transform.basis.get_axis(Vector3::AXIS_Z).normalized(); + //z_vec points against the camera, like in default opengl + + real_t x_min = 0.f, x_max = 0.f; + real_t y_min = 0.f, y_max = 0.f; + real_t z_min = 0.f, z_max = 0.f; + + // FIXME: z_max_cam is defined, computed, but not used below when setting up + // ortho_camera. Commented out for now to fix warnings but should be investigated. + real_t x_min_cam = 0.f, x_max_cam = 0.f; + real_t y_min_cam = 0.f, y_max_cam = 0.f; + real_t z_min_cam = 0.f; + //real_t z_max_cam = 0.f; + + real_t bias_scale = 1.0; + real_t aspect_bias_scale = 1.0; + + //used for culling + + for (int j = 0; j < 8; j++) { + real_t d_x = x_vec.dot(endpoints[j]); + real_t d_y = y_vec.dot(endpoints[j]); + real_t d_z = z_vec.dot(endpoints[j]); + + if (j == 0 || d_x < x_min) { + x_min = d_x; + } + if (j == 0 || d_x > x_max) { + x_max = d_x; + } + + if (j == 0 || d_y < y_min) { + y_min = d_y; + } + if (j == 0 || d_y > y_max) { + y_max = d_y; + } + + if (j == 0 || d_z < z_min) { + z_min = d_z; + } + if (j == 0 || d_z > z_max) { + z_max = d_z; + } + } + + real_t radius = 0; + real_t soft_shadow_expand = 0; + Vector3 center; + + { + //camera viewport stuff + + for (int j = 0; j < 8; j++) { + center += endpoints[j]; + } + center /= 8.0; + + //center=x_vec*(x_max-x_min)*0.5 + y_vec*(y_max-y_min)*0.5 + z_vec*(z_max-z_min)*0.5; + + for (int j = 0; j < 8; j++) { + real_t d = center.distance_to(endpoints[j]); + if (d > radius) { + radius = d; + } + } + + radius *= texture_size / (texture_size - 2.0); //add a texel by each side + + if (i == 0) { + first_radius = radius; + } else { + bias_scale = radius / first_radius; + } + + z_min_cam = z_vec.dot(center) - radius; + + { + float soft_shadow_angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SIZE); + + if (soft_shadow_angle > 0.0) { + float z_range = (z_vec.dot(center) + radius + pancake_size) - z_min_cam; + soft_shadow_expand = Math::tan(Math::deg2rad(soft_shadow_angle)) * z_range; + + x_max += soft_shadow_expand; + y_max += soft_shadow_expand; + + x_min -= soft_shadow_expand; + y_min -= soft_shadow_expand; + } + } + + x_max_cam = x_vec.dot(center) + radius + soft_shadow_expand; + x_min_cam = x_vec.dot(center) - radius - soft_shadow_expand; + y_max_cam = y_vec.dot(center) + radius + soft_shadow_expand; + y_min_cam = y_vec.dot(center) - radius - soft_shadow_expand; + + if (depth_range_mode == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE) { + //this trick here is what stabilizes the shadow (make potential jaggies to not move) + //at the cost of some wasted resolution. Still the quality increase is very well worth it + + real_t unit = radius * 2.0 / texture_size; + + x_max_cam = Math::snapped(x_max_cam, unit); + x_min_cam = Math::snapped(x_min_cam, unit); + y_max_cam = Math::snapped(y_max_cam, unit); + y_min_cam = Math::snapped(y_min_cam, unit); + } + } + + //now that we know all ranges, we can proceed to make the light frustum planes, for culling octree + + Vector<Plane> light_frustum_planes; + light_frustum_planes.resize(6); + + //right/left + light_frustum_planes.write[0] = Plane(x_vec, x_max); + light_frustum_planes.write[1] = Plane(-x_vec, -x_min); + //top/bottom + light_frustum_planes.write[2] = Plane(y_vec, y_max); + light_frustum_planes.write[3] = Plane(-y_vec, -y_min); + //near/far + light_frustum_planes.write[4] = Plane(z_vec, z_max + 1e6); + light_frustum_planes.write[5] = Plane(-z_vec, -z_min); // z_min is ok, since casters further than far-light plane are not needed + + // a pre pass will need to be needed to determine the actual z-near to be used + + if (pancake_size > 0) { + z_max = z_vec.dot(center) + radius + pancake_size; + } + + if (aspect != 1.0) { + // if the aspect is different, then the radius will become larger. + // if this happens, then bias needs to be adjusted too, as depth will increase + // to do this, compare the depth of one that would have resulted from a square frustum + + CameraMatrix camera_matrix_square; + if (p_cam_orthogonal) { + Vector2 vp_he = camera_matrix.get_viewport_half_extents(); + if (p_cam_vaspect) { + camera_matrix_square.set_orthogonal(vp_he.x * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); + } else { + camera_matrix_square.set_orthogonal(vp_he.y * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); + } + } else { + Vector2 vp_he = camera_matrix.get_viewport_half_extents(); + if (p_cam_vaspect) { + camera_matrix_square.set_frustum(vp_he.x * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); + } else { + camera_matrix_square.set_frustum(vp_he.y * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); + } + } + + Vector3 endpoints_square[8]; // frustum plane endpoints + res = camera_matrix_square.get_endpoints(p_cam_transform, endpoints_square); + ERR_CONTINUE(!res); + Vector3 center_square; + + for (int j = 0; j < 8; j++) { + center_square += endpoints_square[j]; + } + + center_square /= 8.0; + + real_t radius_square = 0; + + for (int j = 0; j < 8; j++) { + real_t d = center_square.distance_to(endpoints_square[j]); + if (d > radius_square) { + radius_square = d; + } + } + + radius_square *= texture_size / (texture_size - 2.0); //add a texel by each side + + float z_max_square = z_vec.dot(center_square) + radius_square + pancake_size; + + real_t z_min_cam_square = z_vec.dot(center_square) - radius_square; + + aspect_bias_scale = (z_max - z_min_cam) / (z_max_square - z_min_cam_square); + + // this is not entirely perfect, because the cull-adjusted z-max may be different + // but at least it's warranted that it results in a greater bias, so no acne should be present either way. + // pancaking also helps with this. + } + + { + CameraMatrix ortho_camera; + real_t half_x = (x_max_cam - x_min_cam) * 0.5; + real_t half_y = (y_max_cam - y_min_cam) * 0.5; + + ortho_camera.set_orthogonal(-half_x, half_x, -half_y, half_y, 0, (z_max - z_min_cam)); + + Vector2 uv_scale(1.0 / (x_max_cam - x_min_cam), 1.0 / (y_max_cam - y_min_cam)); + + Transform ortho_transform; + ortho_transform.basis = transform.basis; + ortho_transform.origin = x_vec * (x_min_cam + half_x) + y_vec * (y_min_cam + half_y) + z_vec * z_max; + + cull.shadows[p_shadow_index].cascades[i].frustum = Frustum(light_frustum_planes); + cull.shadows[p_shadow_index].cascades[i].projection = ortho_camera; + cull.shadows[p_shadow_index].cascades[i].transform = ortho_transform; + cull.shadows[p_shadow_index].cascades[i].zfar = z_max - z_min_cam; + cull.shadows[p_shadow_index].cascades[i].split = distances[i + 1]; + cull.shadows[p_shadow_index].cascades[i].shadow_texel_size = radius * 2.0 / texture_size; + cull.shadows[p_shadow_index].cascades[i].bias_scale = bias_scale * aspect_bias_scale * min_distance_bias_scale; + cull.shadows[p_shadow_index].cascades[i].range_begin = z_max; + cull.shadows[p_shadow_index].cascades[i].uv_scale = uv_scale; + } + } +} + +bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_screen_lod_threshold) { + InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); + + Transform light_transform = p_instance->transform; + light_transform.orthonormalize(); //scale does not count on lights + + bool animated_material_found = false; + + switch (RSG::storage->light_get_type(p_instance->base)) { + case RS::LIGHT_DIRECTIONAL: { + } break; + case RS::LIGHT_OMNI: { + RS::LightOmniShadowMode shadow_mode = RSG::storage->light_omni_get_shadow_mode(p_instance->base); + + if (shadow_mode == RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID || !scene_render->light_instances_can_render_shadow_cube()) { + for (int i = 0; i < 2; i++) { + //using this one ensures that raster deferred will have it + RENDER_TIMESTAMP("Culling Shadow Paraboloid" + itos(i)); + + real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); + + real_t z = i == 0 ? -1 : 1; + Vector<Plane> planes; + planes.resize(6); + planes.write[0] = light_transform.xform(Plane(Vector3(0, 0, z), radius)); + planes.write[1] = light_transform.xform(Plane(Vector3(1, 0, z).normalized(), radius)); + planes.write[2] = light_transform.xform(Plane(Vector3(-1, 0, z).normalized(), radius)); + planes.write[3] = light_transform.xform(Plane(Vector3(0, 1, z).normalized(), radius)); + planes.write[4] = light_transform.xform(Plane(Vector3(0, -1, z).normalized(), radius)); + planes.write[5] = light_transform.xform(Plane(Vector3(0, 0, -z), 0)); + + geometry_instances_to_shadow_render.clear(); + instance_shadow_cull_result.clear(); + + Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); + + struct CullConvex { + PagedArray<Instance *> *result; + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + result->push_back(p_instance); + return false; + } + }; + + CullConvex cull_convex; + cull_convex.result = &instance_shadow_cull_result; + + p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_convex); + + Plane near_plane(light_transform.origin, light_transform.basis.get_axis(2) * z); + + for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { + Instance *instance = instance_shadow_cull_result[j]; + if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { + continue; + } else { + if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { + animated_material_found = true; + } + + if (instance->mesh_instance.is_valid()) { + RSG::storage->mesh_instance_check_for_update(instance->mesh_instance); + } + } + + geometry_instances_to_shadow_render.push_back(static_cast<InstanceGeometryData *>(instance->base_data)->geometry_instance); + } + + RSG::storage->update_mesh_instances(); + + scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i, 0); + scene_render->render_shadow(light->instance, p_shadow_atlas, i, geometry_instances_to_shadow_render); + } + } else { //shadow cube + + real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); + CameraMatrix cm; + cm.set_perspective(90, 1, 0.01, radius); + + for (int i = 0; i < 6; i++) { + RENDER_TIMESTAMP("Culling Shadow Cube side" + itos(i)); + //using this one ensures that raster deferred will have it + + static const Vector3 view_normals[6] = { + Vector3(+1, 0, 0), + Vector3(-1, 0, 0), + Vector3(0, -1, 0), + Vector3(0, +1, 0), + Vector3(0, 0, +1), + Vector3(0, 0, -1) + }; + static const Vector3 view_up[6] = { + Vector3(0, -1, 0), + Vector3(0, -1, 0), + Vector3(0, 0, -1), + Vector3(0, 0, +1), + Vector3(0, -1, 0), + Vector3(0, -1, 0) + }; + + Transform xform = light_transform * Transform().looking_at(view_normals[i], view_up[i]); + + Vector<Plane> planes = cm.get_projection_planes(xform); + + geometry_instances_to_shadow_render.clear(); + instance_shadow_cull_result.clear(); + + Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); + + struct CullConvex { + PagedArray<Instance *> *result; + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + result->push_back(p_instance); + return false; + } + }; + + CullConvex cull_convex; + cull_convex.result = &instance_shadow_cull_result; + + p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_convex); + + Plane near_plane(xform.origin, -xform.basis.get_axis(2)); + + for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { + Instance *instance = instance_shadow_cull_result[j]; + if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { + continue; + } else { + if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { + animated_material_found = true; + } + if (instance->mesh_instance.is_valid()) { + RSG::storage->mesh_instance_check_for_update(instance->mesh_instance); + } + } + + geometry_instances_to_shadow_render.push_back(static_cast<InstanceGeometryData *>(instance->base_data)->geometry_instance); + } + + RSG::storage->update_mesh_instances(); + scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0); + scene_render->render_shadow(light->instance, p_shadow_atlas, i, geometry_instances_to_shadow_render); + } + + //restore the regular DP matrix + scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, 0, 0); + } + + } break; + case RS::LIGHT_SPOT: { + RENDER_TIMESTAMP("Culling Spot Light"); + + real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); + real_t angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); + + CameraMatrix cm; + cm.set_perspective(angle * 2.0, 1.0, 0.01, radius); + + Vector<Plane> planes = cm.get_projection_planes(light_transform); + + geometry_instances_to_shadow_render.clear(); + instance_shadow_cull_result.clear(); + + Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); + + struct CullConvex { + PagedArray<Instance *> *result; + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + result->push_back(p_instance); + return false; + } + }; + + CullConvex cull_convex; + cull_convex.result = &instance_shadow_cull_result; + + p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_convex); + + Plane near_plane(light_transform.origin, -light_transform.basis.get_axis(2)); + + for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { + Instance *instance = instance_shadow_cull_result[j]; + if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { + continue; + } else { + if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { + animated_material_found = true; + } + + if (instance->mesh_instance.is_valid()) { + RSG::storage->mesh_instance_check_for_update(instance->mesh_instance); + } + } + geometry_instances_to_shadow_render.push_back(static_cast<InstanceGeometryData *>(instance->base_data)->geometry_instance); + } + + RSG::storage->update_mesh_instances(); + + scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0); + scene_render->render_shadow(light->instance, p_shadow_atlas, 0, geometry_instances_to_shadow_render); + + } break; + } + + return animated_material_found; +} + +void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) { +// render to mono camera +#ifndef _3D_DISABLED + + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + + /* STEP 1 - SETUP CAMERA */ + CameraMatrix camera_matrix; + bool ortho = false; + + switch (camera->type) { + case Camera::ORTHOGONAL: { + camera_matrix.set_orthogonal( + camera->size, + p_viewport_size.width / (float)p_viewport_size.height, + camera->znear, + camera->zfar, + camera->vaspect); + ortho = true; + } break; + case Camera::PERSPECTIVE: { + camera_matrix.set_perspective( + camera->fov, + p_viewport_size.width / (float)p_viewport_size.height, + camera->znear, + camera->zfar, + camera->vaspect); + ortho = false; + + } break; + case Camera::FRUSTUM: { + camera_matrix.set_frustum( + camera->size, + p_viewport_size.width / (float)p_viewport_size.height, + camera->offset, + camera->znear, + camera->zfar, + camera->vaspect); + ortho = false; + } break; + } + + RID environment = _render_get_environment(p_camera, p_scenario); + + _prepare_scene(camera->transform, camera_matrix, ortho, camera->vaspect, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), p_screen_lod_threshold); + _render_scene(p_render_buffers, camera->transform, camera_matrix, ortho, environment, camera->effects, p_scenario, p_shadow_atlas, RID(), -1, p_screen_lod_threshold); +#endif +} + +void RendererSceneCull::render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) { + // render for AR/VR interface + + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + + /* SETUP CAMERA, we are ignoring type and FOV here */ + float aspect = p_viewport_size.width / (float)p_viewport_size.height; + CameraMatrix camera_matrix = p_interface->get_projection_for_eye(p_eye, aspect, camera->znear, camera->zfar); + + // We also ignore our camera position, it will have been positioned with a slightly old tracking position. + // Instead we take our origin point and have our ar/vr interface add fresh tracking data! Whoohoo! + Transform world_origin = XRServer::get_singleton()->get_world_origin(); + Transform cam_transform = p_interface->get_transform_for_eye(p_eye, world_origin); + + RID environment = _render_get_environment(p_camera, p_scenario); + + // For stereo render we only prepare for our left eye and then reuse the outcome for our right eye + if (p_eye == XRInterface::EYE_LEFT) { + // Center our transform, we assume basis is equal. + Transform mono_transform = cam_transform; + Transform right_transform = p_interface->get_transform_for_eye(XRInterface::EYE_RIGHT, world_origin); + mono_transform.origin += right_transform.origin; + mono_transform.origin *= 0.5; + + // We need to combine our projection frustums for culling. + // Ideally we should use our clipping planes for this and combine them, + // however our shadow map logic uses our projection matrix. + // Note: as our left and right frustums should be mirrored, we don't need our right projection matrix. + + // - get some base values we need + float eye_dist = (mono_transform.origin - cam_transform.origin).length(); + float z_near = camera_matrix.get_z_near(); // get our near plane + float z_far = camera_matrix.get_z_far(); // get our far plane + float width = (2.0 * z_near) / camera_matrix.matrix[0][0]; + float x_shift = width * camera_matrix.matrix[2][0]; + float height = (2.0 * z_near) / camera_matrix.matrix[1][1]; + float y_shift = height * camera_matrix.matrix[2][1]; + + // printf("Eye_dist = %f, Near = %f, Far = %f, Width = %f, Shift = %f\n", eye_dist, z_near, z_far, width, x_shift); + + // - calculate our near plane size (horizontal only, right_near is mirrored) + float left_near = -eye_dist - ((width - x_shift) * 0.5); + + // - calculate our far plane size (horizontal only, right_far is mirrored) + float left_far = -eye_dist - (z_far * (width - x_shift) * 0.5 / z_near); + float left_far_right_eye = eye_dist - (z_far * (width + x_shift) * 0.5 / z_near); + if (left_far > left_far_right_eye) { + // on displays smaller then double our iod, the right eye far frustrum can overtake the left eyes. + left_far = left_far_right_eye; + } + + // - figure out required z-shift + float slope = (left_far - left_near) / (z_far - z_near); + float z_shift = (left_near / slope) - z_near; + + // - figure out new vertical near plane size (this will be slightly oversized thanks to our z-shift) + float top_near = (height - y_shift) * 0.5; + top_near += (top_near / z_near) * z_shift; + float bottom_near = -(height + y_shift) * 0.5; + bottom_near += (bottom_near / z_near) * z_shift; + + // printf("Left_near = %f, Left_far = %f, Top_near = %f, Bottom_near = %f, Z_shift = %f\n", left_near, left_far, top_near, bottom_near, z_shift); + + // - generate our frustum + CameraMatrix combined_matrix; + combined_matrix.set_frustum(left_near, -left_near, bottom_near, top_near, z_near + z_shift, z_far + z_shift); + + // and finally move our camera back + Transform apply_z_shift; + apply_z_shift.origin = Vector3(0.0, 0.0, z_shift); // z negative is forward so this moves it backwards + mono_transform *= apply_z_shift; + + // now prepare our scene with our adjusted transform projection matrix + _prepare_scene(mono_transform, combined_matrix, false, false, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), p_screen_lod_threshold); + } else if (p_eye == XRInterface::EYE_MONO) { + // For mono render, prepare as per usual + _prepare_scene(cam_transform, camera_matrix, false, false, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), p_screen_lod_threshold); + } + + // And render our scene... + _render_scene(p_render_buffers, cam_transform, camera_matrix, false, environment, camera->effects, p_scenario, p_shadow_atlas, RID(), -1, p_screen_lod_threshold); +}; + +void RendererSceneCull::_frustum_cull_threaded(uint32_t p_thread, FrustumCullData *cull_data) { + uint32_t cull_total = cull_data->scenario->instance_data.size(); + uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count(); + uint32_t cull_from = p_thread * cull_total / total_threads; + uint32_t cull_to = (p_thread + 1 == total_threads) ? cull_total : ((p_thread + 1) * cull_total / total_threads); + + _frustum_cull(*cull_data, frustum_cull_result_threads[p_thread], cull_from, cull_to); +} + +void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to) { + uint64_t frame_number = RSG::rasterizer->get_frame_number(); + float lightmap_probe_update_speed = RSG::storage->lightmap_get_probe_capture_update_speed() * RSG::rasterizer->get_frame_delta_time(); + + uint32_t sdfgi_last_light_index = 0xFFFFFFFF; + uint32_t sdfgi_last_light_cascade = 0xFFFFFFFF; + + RID instance_pair_buffer[MAX_INSTANCE_PAIRS]; + + for (uint64_t i = p_from; i < p_to; i++) { + bool mesh_visible = false; + + if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->frustum)) { + InstanceData &idata = cull_data.scenario->instance_data[i]; + uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; + + if ((cull_data.visible_layers & idata.layer_mask) == 0) { + //failure + } else if (base_type == RS::INSTANCE_LIGHT) { + cull_result.lights.push_back(idata.instance); + cull_result.light_instances.push_back(RID::from_uint64(idata.instance_data_rid)); + if (cull_data.shadow_atlas.is_valid() && RSG::storage->light_has_shadow(idata.base_rid)) { + scene_render->light_instance_mark_visible(RID::from_uint64(idata.instance_data_rid)); //mark it visible for shadow allocation later + } + + } else if (base_type == RS::INSTANCE_REFLECTION_PROBE) { + if (cull_data.render_reflection_probe != idata.instance) { + //avoid entering The Matrix + + if ((idata.flags & InstanceData::FLAG_REFLECTION_PROBE_DIRTY) || scene_render->reflection_probe_instance_needs_redraw(RID::from_uint64(idata.instance_data_rid))) { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(idata.instance->base_data); + cull_data.cull->lock.lock(); + if (!reflection_probe->update_list.in_list()) { + reflection_probe->render_step = 0; + reflection_probe_render_list.add_last(&reflection_probe->update_list); + } + cull_data.cull->lock.unlock(); + + idata.flags &= ~uint32_t(InstanceData::FLAG_REFLECTION_PROBE_DIRTY); + } + + if (scene_render->reflection_probe_instance_has_reflection(RID::from_uint64(idata.instance_data_rid))) { + cull_result.reflections.push_back(RID::from_uint64(idata.instance_data_rid)); + } + } + } else if (base_type == RS::INSTANCE_DECAL) { + cull_result.decals.push_back(RID::from_uint64(idata.instance_data_rid)); + + } else if (base_type == RS::INSTANCE_GI_PROBE) { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(idata.instance->base_data); + cull_data.cull->lock.lock(); + if (!gi_probe->update_element.in_list()) { + gi_probe_update_list.add(&gi_probe->update_element); + } + cull_data.cull->lock.unlock(); + cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid)); + + } else if (base_type == RS::INSTANCE_LIGHTMAP) { + cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid)); + } else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) { + bool keep = true; + + if (idata.flags & InstanceData::FLAG_REDRAW_IF_VISIBLE) { + RenderingServerDefault::redraw_request(); + } + + if (base_type == RS::INSTANCE_MESH) { + mesh_visible = true; + } else if (base_type == RS::INSTANCE_PARTICLES) { + //particles visible? process them + if (RSG::storage->particles_is_inactive(idata.base_rid)) { + //but if nothing is going on, don't do it. + keep = false; + } else { + cull_data.cull->lock.lock(); + RSG::storage->particles_request_process(idata.base_rid); + cull_data.cull->lock.unlock(); + RSG::storage->particles_set_view_axis(idata.base_rid, -cull_data.cam_transform.basis.get_axis(2).normalized()); + //particles visible? request redraw + RenderingServerDefault::redraw_request(); + } + } + + if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + uint32_t idx = 0; + + for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) { + InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); + instance_pair_buffer[idx++] = light->instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } + } + + scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, instance_pair_buffer, idx); + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_LIGHTING_DIRTY); + } + + if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (idata.flags & InstanceData::FLAG_GEOM_REFLECTION_DIRTY)) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + uint32_t idx = 0; + + for (Set<Instance *>::Element *E = geom->reflection_probes.front(); E; E = E->next()) { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data); + + instance_pair_buffer[idx++] = reflection_probe->instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } + } + + scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, instance_pair_buffer, idx); + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_REFLECTION_DIRTY); + } + + if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (idata.flags & InstanceData::FLAG_GEOM_DECAL_DIRTY)) { + //InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + //todo for GLES3 + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY); + /*for (Set<Instance *>::Element *E = geom->dec.front(); E; E = E->next()) { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data); + + instance_pair_buffer[idx++] = reflection_probe->instance; + if (idx==MAX_INSTANCE_PAIRS) { + break; + } + }*/ + //scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, light_instances, idx); + } + + if (idata.flags & InstanceData::FLAG_GEOM_GI_PROBE_DIRTY) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + uint32_t idx = 0; + for (Set<Instance *>::Element *E = geom->gi_probes.front(); E; E = E->next()) { + InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(E->get()->base_data); + + instance_pair_buffer[idx++] = gi_probe->probe_instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } + } + + scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, instance_pair_buffer, idx); + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_GI_PROBE_DIRTY); + } + + if ((idata.flags & InstanceData::FLAG_LIGHTMAP_CAPTURE) && idata.instance->last_frame_pass != frame_number && !idata.instance->lightmap_target_sh.is_empty() && !idata.instance->lightmap_sh.is_empty()) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + Color *sh = idata.instance->lightmap_sh.ptrw(); + const Color *target_sh = idata.instance->lightmap_target_sh.ptr(); + for (uint32_t j = 0; j < 9; j++) { + sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed)); + } + scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, sh); + idata.instance->last_frame_pass = frame_number; + } + + if (keep) { + cull_result.geometry_instances.push_back(idata.instance_geometry); + } + } + } + + for (uint32_t j = 0; j < cull_data.cull->shadow_count; j++) { + for (uint32_t k = 0; k < cull_data.cull->shadows[j].cascade_count; k++) { + if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->shadows[j].cascades[k].frustum)) { + InstanceData &idata = cull_data.scenario->instance_data[i]; + uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; + + if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS) { + cull_result.directional_shadows[j].cascade_geometry_instances[k].push_back(idata.instance_geometry); + mesh_visible = true; + } + } + } + } + + for (uint32_t j = 0; j < cull_data.cull->sdfgi.region_count; j++) { + if (cull_data.scenario->instance_aabbs[i].in_aabb(cull_data.cull->sdfgi.region_aabb[j])) { + InstanceData &idata = cull_data.scenario->instance_data[i]; + uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; + + if (base_type == RS::INSTANCE_LIGHT) { + InstanceLightData *instance_light = (InstanceLightData *)idata.instance->base_data; + if (instance_light->bake_mode == RS::LIGHT_BAKE_STATIC && cull_data.cull->sdfgi.region_cascade[j] <= instance_light->max_sdfgi_cascade) { + if (sdfgi_last_light_index != i || sdfgi_last_light_cascade != cull_data.cull->sdfgi.region_cascade[j]) { + sdfgi_last_light_index = i; + sdfgi_last_light_cascade = cull_data.cull->sdfgi.region_cascade[j]; + cull_result.sdfgi_cascade_lights[sdfgi_last_light_cascade].push_back(instance_light->instance); + } + } + } else if ((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) { + if (idata.flags & InstanceData::FLAG_USES_BAKED_LIGHT) { + cull_result.sdfgi_region_geometry_instances[j].push_back(idata.instance_geometry); + mesh_visible = true; + } + } + } + } + + if (mesh_visible && cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_USES_MESH_INSTANCE) { + cull_result.mesh_instances.push_back(cull_data.scenario->instance_data[i].instance->mesh_instance); + } + } +} + +void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, float p_screen_lod_threshold, bool p_using_shadows) { + // Note, in stereo rendering: + // - p_cam_transform will be a transform in the middle of our two eyes + // - p_cam_projection is a wider frustrum that encompasses both eyes + + Instance *render_reflection_probe = instance_owner.getornull(p_reflection_probe); //if null, not rendering to it + + Scenario *scenario = scenario_owner.getornull(p_scenario); + + render_pass++; + + scene_render->set_scene_pass(render_pass); + + if (p_render_buffers.is_valid()) { + scene_render->sdfgi_update(p_render_buffers, p_environment, p_cam_transform.origin); //update conditions for SDFGI (whether its used or not) + } + + RENDER_TIMESTAMP("Frustum Culling"); + + //rasterizer->set_camera(camera->transform, camera_matrix,ortho); + + Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform); + + Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(2).normalized()); + + /* STEP 2 - CULL */ + + cull.frustum = Frustum(planes); + + Vector<RID> directional_lights; + // directional lights + { + cull.shadow_count = 0; + + Vector<Instance *> lights_with_shadow; + + for (List<Instance *>::Element *E = scenario->directional_lights.front(); E; E = E->next()) { + if (!E->get()->visible) { + continue; + } + + if (directional_lights.size() > RendererSceneRender::MAX_DIRECTIONAL_LIGHTS) { + break; + } + + InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); + + //check shadow.. + + if (light) { + if (p_using_shadows && p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(E->get()->base) && !(RSG::storage->light_get_type(E->get()->base) == RS::LIGHT_DIRECTIONAL && RSG::storage->light_directional_is_sky_only(E->get()->base))) { + lights_with_shadow.push_back(E->get()); + } + //add to list + directional_lights.push_back(light->instance); + } + } + + scene_render->set_directional_shadow_count(lights_with_shadow.size()); + + for (int i = 0; i < lights_with_shadow.size(); i++) { + _light_instance_setup_directional_shadow(i, lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect); + } + } + + { //sdfgi + cull.sdfgi.region_count = 0; + + if (p_render_buffers.is_valid()) { + cull.sdfgi.cascade_light_count = 0; + + uint32_t prev_cascade = 0xFFFFFFFF; + uint32_t pending_region_count = scene_render->sdfgi_get_pending_region_count(p_render_buffers); + + for (uint32_t i = 0; i < pending_region_count; i++) { + cull.sdfgi.region_aabb[i] = scene_render->sdfgi_get_pending_region_bounds(p_render_buffers, i); + uint32_t region_cascade = scene_render->sdfgi_get_pending_region_cascade(p_render_buffers, i); + cull.sdfgi.region_cascade[i] = region_cascade; + + if (region_cascade != prev_cascade) { + cull.sdfgi.cascade_light_index[cull.sdfgi.cascade_light_count] = region_cascade; + cull.sdfgi.cascade_light_count++; + prev_cascade = region_cascade; + } + } + + cull.sdfgi.region_count = pending_region_count; + } + } + + frustum_cull_result.clear(); + + { + uint64_t cull_from = 0; + uint64_t cull_to = scenario->instance_data.size(); + + FrustumCullData cull_data; + + //prepare for eventual thread usage + cull_data.cull = &cull; + cull_data.scenario = scenario; + cull_data.shadow_atlas = p_shadow_atlas; + cull_data.cam_transform = p_cam_transform; + cull_data.visible_layers = p_visible_layers; + cull_data.render_reflection_probe = render_reflection_probe; +//#define DEBUG_CULL_TIME +#ifdef DEBUG_CULL_TIME + uint64_t time_from = OS::get_singleton()->get_ticks_usec(); +#endif + if (cull_to > thread_cull_threshold) { + //multiple threads + for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) { + frustum_cull_result_threads[i].clear(); + } + + RendererThreadPool::singleton->thread_work_pool.do_work(frustum_cull_result_threads.size(), this, &RendererSceneCull::_frustum_cull_threaded, &cull_data); + + for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) { + frustum_cull_result.append_from(frustum_cull_result_threads[i]); + } + + } else { + //single threaded + _frustum_cull(cull_data, frustum_cull_result, cull_from, cull_to); + } + +#ifdef DEBUG_CULL_TIME + static float time_avg = 0; + static uint32_t time_count = 0; + time_avg += double(OS::get_singleton()->get_ticks_usec() - time_from) / 1000.0; + time_count++; + print_line("time taken: " + rtos(time_avg / time_count)); +#endif + + if (frustum_cull_result.mesh_instances.size()) { + for (uint64_t i = 0; i < frustum_cull_result.mesh_instances.size(); i++) { + RSG::storage->mesh_instance_check_for_update(frustum_cull_result.mesh_instances[i]); + } + RSG::storage->update_mesh_instances(); + } + } + + //render shadows + + for (uint32_t i = 0; i < cull.shadow_count; i++) { + for (uint32_t j = 0; j < cull.shadows[i].cascade_count; j++) { + const Cull::Shadow::Cascade &c = cull.shadows[i].cascades[j]; + // print_line("shadow " + itos(i) + " cascade " + itos(j) + " elements: " + itos(c.cull_result.size())); + scene_render->light_instance_set_shadow_transform(cull.shadows[i].light_instance, c.projection, c.transform, c.zfar, c.split, j, c.shadow_texel_size, c.bias_scale, c.range_begin, c.uv_scale); + scene_render->render_shadow(cull.shadows[i].light_instance, p_shadow_atlas, j, frustum_cull_result.directional_shadows[i].cascade_geometry_instances[j], near_plane, p_cam_projection.get_lod_multiplier(), p_screen_lod_threshold); + } + } + + //render SDFGI + + { + if (cull.sdfgi.region_count > 0) { + //update regions + for (uint32_t i = 0; i < cull.sdfgi.region_count; i++) { + scene_render->render_sdfgi(p_render_buffers, i, frustum_cull_result.sdfgi_region_geometry_instances[i]); + } + //check if static lights were culled + bool static_lights_culled = false; + for (uint32_t i = 0; i < cull.sdfgi.cascade_light_count; i++) { + if (frustum_cull_result.sdfgi_cascade_lights[i].size()) { + static_lights_culled = true; + break; + } + } + + if (static_lights_culled) { + scene_render->render_sdfgi_static_lights(p_render_buffers, cull.sdfgi.cascade_light_count, cull.sdfgi.cascade_light_index, frustum_cull_result.sdfgi_cascade_lights); + } + } + + if (p_render_buffers.is_valid()) { + scene_render->sdfgi_update_probes(p_render_buffers, p_environment, directional_lights, scenario->dynamic_lights.ptr(), scenario->dynamic_lights.size()); + } + } + + //light_samplers_culled=0; + + /* + print_line("OT: "+rtos( (OS::get_singleton()->get_ticks_usec()-t)/1000.0)); + print_line("OTO: "+itos(p_scenario->octree.get_octant_count())); + print_line("OTE: "+itos(p_scenario->octree.get_elem_count())); + print_line("OTP: "+itos(p_scenario->octree.get_pair_count())); + */ + + /* STEP 3 - PROCESS PORTALS, VALIDATE ROOMS */ + //removed, will replace with culling + + /* STEP 4 - REMOVE FURTHER CULLED OBJECTS, ADD LIGHTS */ + + /* STEP 5 - PROCESS POSITIONAL LIGHTS */ + + if (p_using_shadows) { //setup shadow maps + + //SortArray<Instance*,_InstanceLightsort> sorter; + //sorter.sort(light_cull_result,light_cull_count); + for (uint32_t i = 0; i < (uint32_t)frustum_cull_result.lights.size(); i++) { + Instance *ins = frustum_cull_result.lights[i]; + + if (!p_shadow_atlas.is_valid() || !RSG::storage->light_has_shadow(ins->base)) { + continue; + } + + InstanceLightData *light = static_cast<InstanceLightData *>(ins->base_data); + + float coverage = 0.f; + + { //compute coverage + + Transform cam_xf = p_cam_transform; + float zn = p_cam_projection.get_z_near(); + Plane p(cam_xf.origin + cam_xf.basis.get_axis(2) * -zn, -cam_xf.basis.get_axis(2)); //camera near plane + + // near plane half width and height + Vector2 vp_half_extents = p_cam_projection.get_viewport_half_extents(); + + switch (RSG::storage->light_get_type(ins->base)) { + case RS::LIGHT_OMNI: { + float radius = RSG::storage->light_get_param(ins->base, RS::LIGHT_PARAM_RANGE); + + //get two points parallel to near plane + Vector3 points[2] = { + ins->transform.origin, + ins->transform.origin + cam_xf.basis.get_axis(0) * radius + }; + + if (!p_cam_orthogonal) { + //if using perspetive, map them to near plane + for (int j = 0; j < 2; j++) { + if (p.distance_to(points[j]) < 0) { + points[j].z = -zn; //small hack to keep size constant when hitting the screen + } + + p.intersects_segment(cam_xf.origin, points[j], &points[j]); //map to plane + } + } + + float screen_diameter = points[0].distance_to(points[1]) * 2; + coverage = screen_diameter / (vp_half_extents.x + vp_half_extents.y); + } break; + case RS::LIGHT_SPOT: { + float radius = RSG::storage->light_get_param(ins->base, RS::LIGHT_PARAM_RANGE); + float angle = RSG::storage->light_get_param(ins->base, RS::LIGHT_PARAM_SPOT_ANGLE); + + float w = radius * Math::sin(Math::deg2rad(angle)); + float d = radius * Math::cos(Math::deg2rad(angle)); + + Vector3 base = ins->transform.origin - ins->transform.basis.get_axis(2).normalized() * d; + + Vector3 points[2] = { + base, + base + cam_xf.basis.get_axis(0) * w + }; + + if (!p_cam_orthogonal) { + //if using perspetive, map them to near plane + for (int j = 0; j < 2; j++) { + if (p.distance_to(points[j]) < 0) { + points[j].z = -zn; //small hack to keep size constant when hitting the screen + } + + p.intersects_segment(cam_xf.origin, points[j], &points[j]); //map to plane + } + } + + float screen_diameter = points[0].distance_to(points[1]) * 2; + coverage = screen_diameter / (vp_half_extents.x + vp_half_extents.y); + + } break; + default: { + ERR_PRINT("Invalid Light Type"); + } + } + } + + if (light->shadow_dirty) { + light->last_version++; + light->shadow_dirty = false; + } + + bool redraw = scene_render->shadow_atlas_update_light(p_shadow_atlas, light->instance, coverage, light->last_version); + + if (redraw) { + //must redraw! + RENDER_TIMESTAMP(">Rendering Light " + itos(i)); + light->shadow_dirty = _light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario, p_screen_lod_threshold); + RENDER_TIMESTAMP("<Rendering Light " + itos(i)); + } + } + } + + //append the directional lights to the lights culled + for (int i = 0; i < directional_lights.size(); i++) { + frustum_cull_result.light_instances.push_back(directional_lights[i]); + } +} + +RID RendererSceneCull::_render_get_environment(RID p_camera, RID p_scenario) { + Camera *camera = camera_owner.getornull(p_camera); + if (camera && scene_render->is_environment(camera->env)) { + return camera->env; + } + + Scenario *scenario = scenario_owner.getornull(p_scenario); + if (!scenario) { + return RID(); + } + if (scene_render->is_environment(scenario->environment)) { + return scenario->environment; + } + + if (scene_render->is_environment(scenario->fallback_environment)) { + return scenario->fallback_environment; + } + + return RID(); +} + +void RendererSceneCull::_render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + + RID camera_effects; + if (p_force_camera_effects.is_valid()) { + camera_effects = p_force_camera_effects; + } else { + camera_effects = scenario->camera_effects; + } + /* PROCESS GEOMETRY AND DRAW SCENE */ + + RENDER_TIMESTAMP("Render Scene "); + scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, frustum_cull_result.geometry_instances, frustum_cull_result.light_instances, frustum_cull_result.reflections, frustum_cull_result.gi_probes, frustum_cull_result.decals, frustum_cull_result.lightmaps, p_environment, camera_effects, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold); +} + +void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) { +#ifndef _3D_DISABLED + + Scenario *scenario = scenario_owner.getornull(p_scenario); + + RID environment; + if (scenario->environment.is_valid()) { + environment = scenario->environment; + } else { + environment = scenario->fallback_environment; + } + RENDER_TIMESTAMP("Render Empty Scene "); + scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, scenario->reflection_atlas, RID(), 0, 0); +#endif +} + +bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int p_step) { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data); + Scenario *scenario = p_instance->scenario; + ERR_FAIL_COND_V(!scenario, true); + + RenderingServerDefault::redraw_request(); //update, so it updates in editor + + if (p_step == 0) { + if (!scene_render->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) { + return true; //all full + } + } + + if (p_step >= 0 && p_step < 6) { + static const Vector3 view_normals[6] = { + Vector3(+1, 0, 0), + Vector3(-1, 0, 0), + Vector3(0, +1, 0), + Vector3(0, -1, 0), + Vector3(0, 0, +1), + Vector3(0, 0, -1) + }; + static const Vector3 view_up[6] = { + Vector3(0, -1, 0), + Vector3(0, -1, 0), + Vector3(0, 0, +1), + Vector3(0, 0, -1), + Vector3(0, -1, 0), + Vector3(0, -1, 0) + }; + + Vector3 extents = RSG::storage->reflection_probe_get_extents(p_instance->base); + Vector3 origin_offset = RSG::storage->reflection_probe_get_origin_offset(p_instance->base); + float max_distance = RSG::storage->reflection_probe_get_origin_max_distance(p_instance->base); + float size = scene_render->reflection_atlas_get_size(scenario->reflection_atlas); + float lod_threshold = RSG::storage->reflection_probe_get_lod_threshold(p_instance->base) / size; + + Vector3 edge = view_normals[p_step] * extents; + float distance = ABS(view_normals[p_step].dot(edge) - view_normals[p_step].dot(origin_offset)); //distance from origin offset to actual view distance limit + + max_distance = MAX(max_distance, distance); + + //render cubemap side + CameraMatrix cm; + cm.set_perspective(90, 1, 0.01, max_distance); + + Transform local_view; + local_view.set_look_at(origin_offset, origin_offset + view_normals[p_step], view_up[p_step]); + + Transform xform = p_instance->transform * local_view; + + RID shadow_atlas; + + bool use_shadows = RSG::storage->reflection_probe_renders_shadows(p_instance->base); + if (use_shadows) { + shadow_atlas = scenario->reflection_probe_shadow_atlas; + } + + RENDER_TIMESTAMP("Render Reflection Probe, Step " + itos(p_step)); + _prepare_scene(xform, cm, false, false, RID(), RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, lod_threshold, use_shadows); + _render_scene(RID(), xform, cm, false, RID(), RID(), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step, lod_threshold); + + } else { + //do roughness postprocess step until it believes it's done + RENDER_TIMESTAMP("Post-Process Reflection Probe, Step " + itos(p_step)); + return scene_render->reflection_probe_instance_postprocess_step(reflection_probe->instance); + } + + return false; +} + +void RendererSceneCull::render_probes() { + /* REFLECTION PROBES */ + + SelfList<InstanceReflectionProbeData> *ref_probe = reflection_probe_render_list.first(); + + bool busy = false; + + while (ref_probe) { + SelfList<InstanceReflectionProbeData> *next = ref_probe->next(); + RID base = ref_probe->self()->owner->base; + + switch (RSG::storage->reflection_probe_get_update_mode(base)) { + case RS::REFLECTION_PROBE_UPDATE_ONCE: { + if (busy) { //already rendering something + break; + } + + bool done = _render_reflection_probe_step(ref_probe->self()->owner, ref_probe->self()->render_step); + if (done) { + reflection_probe_render_list.remove(ref_probe); + } else { + ref_probe->self()->render_step++; + } + + busy = true; //do not render another one of this kind + } break; + case RS::REFLECTION_PROBE_UPDATE_ALWAYS: { + int step = 0; + bool done = false; + while (!done) { + done = _render_reflection_probe_step(ref_probe->self()->owner, step); + step++; + } + + reflection_probe_render_list.remove(ref_probe); + } break; + } + + ref_probe = next; + } + + /* GI PROBES */ + + SelfList<InstanceGIProbeData> *gi_probe = gi_probe_update_list.first(); + + if (gi_probe) { + RENDER_TIMESTAMP("Render GI Probes"); + } + + while (gi_probe) { + SelfList<InstanceGIProbeData> *next = gi_probe->next(); + + InstanceGIProbeData *probe = gi_probe->self(); + //Instance *instance_probe = probe->owner; + + //check if probe must be setup, but don't do if on the lighting thread + + bool cache_dirty = false; + int cache_count = 0; + { + int light_cache_size = probe->light_cache.size(); + const InstanceGIProbeData::LightCache *caches = probe->light_cache.ptr(); + const RID *instance_caches = probe->light_instances.ptr(); + + int idx = 0; //must count visible lights + for (Set<Instance *>::Element *E = probe->lights.front(); E; E = E->next()) { + Instance *instance = E->get(); + InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; + if (!instance->visible) { + continue; + } + if (cache_dirty) { + //do nothing, since idx must count all visible lights anyway + } else if (idx >= light_cache_size) { + cache_dirty = true; + } else { + const InstanceGIProbeData::LightCache *cache = &caches[idx]; + + if ( + instance_caches[idx] != instance_light->instance || + cache->has_shadow != RSG::storage->light_has_shadow(instance->base) || + cache->type != RSG::storage->light_get_type(instance->base) || + cache->transform != instance->transform || + cache->color != RSG::storage->light_get_color(instance->base) || + cache->energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY) || + cache->bake_energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY) || + cache->radius != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE) || + cache->attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION) || + cache->spot_angle != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE) || + cache->spot_attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION)) { + cache_dirty = true; + } + } + + idx++; + } + + for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) { + Instance *instance = E->get(); + InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; + if (!instance->visible) { + continue; + } + if (cache_dirty) { + //do nothing, since idx must count all visible lights anyway + } else if (idx >= light_cache_size) { + cache_dirty = true; + } else { + const InstanceGIProbeData::LightCache *cache = &caches[idx]; + + if ( + instance_caches[idx] != instance_light->instance || + cache->has_shadow != RSG::storage->light_has_shadow(instance->base) || + cache->type != RSG::storage->light_get_type(instance->base) || + cache->transform != instance->transform || + cache->color != RSG::storage->light_get_color(instance->base) || + cache->energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY) || + cache->bake_energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY) || + cache->radius != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE) || + cache->attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION) || + cache->spot_angle != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE) || + cache->spot_attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION) || + cache->sky_only != RSG::storage->light_directional_is_sky_only(instance->base)) { + cache_dirty = true; + } + } + + idx++; + } + + if (idx != light_cache_size) { + cache_dirty = true; + } + + cache_count = idx; + } + + bool update_lights = scene_render->gi_probe_needs_update(probe->probe_instance); + + if (cache_dirty) { + probe->light_cache.resize(cache_count); + probe->light_instances.resize(cache_count); + + if (cache_count) { + InstanceGIProbeData::LightCache *caches = probe->light_cache.ptrw(); + RID *instance_caches = probe->light_instances.ptrw(); + + int idx = 0; //must count visible lights + for (Set<Instance *>::Element *E = probe->lights.front(); E; E = E->next()) { + Instance *instance = E->get(); + InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; + if (!instance->visible) { + continue; + } + + InstanceGIProbeData::LightCache *cache = &caches[idx]; + + instance_caches[idx] = instance_light->instance; + cache->has_shadow = RSG::storage->light_has_shadow(instance->base); + cache->type = RSG::storage->light_get_type(instance->base); + cache->transform = instance->transform; + cache->color = RSG::storage->light_get_color(instance->base); + cache->energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY); + cache->bake_energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY); + cache->radius = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE); + cache->attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION); + cache->spot_angle = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); + cache->spot_attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION); + + idx++; + } + for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) { + Instance *instance = E->get(); + InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; + if (!instance->visible) { + continue; + } + + InstanceGIProbeData::LightCache *cache = &caches[idx]; + + instance_caches[idx] = instance_light->instance; + cache->has_shadow = RSG::storage->light_has_shadow(instance->base); + cache->type = RSG::storage->light_get_type(instance->base); + cache->transform = instance->transform; + cache->color = RSG::storage->light_get_color(instance->base); + cache->energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY); + cache->bake_energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY); + cache->radius = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE); + cache->attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION); + cache->spot_angle = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); + cache->spot_attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION); + cache->sky_only = RSG::storage->light_directional_is_sky_only(instance->base); + + idx++; + } + } + + update_lights = true; + } + + frustum_cull_result.geometry_instances.clear(); + + RID instance_pair_buffer[MAX_INSTANCE_PAIRS]; + + for (Set<Instance *>::Element *E = probe->dynamic_geometries.front(); E; E = E->next()) { + Instance *ins = E->get(); + if (!ins->visible) { + continue; + } + InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data; + + if (ins->scenario && ins->array_index >= 0 && (ins->scenario->instance_data[ins->array_index].flags & InstanceData::FLAG_GEOM_GI_PROBE_DIRTY)) { + uint32_t idx = 0; + for (Set<Instance *>::Element *F = geom->gi_probes.front(); F; F = F->next()) { + InstanceGIProbeData *gi_probe2 = static_cast<InstanceGIProbeData *>(F->get()->base_data); + + instance_pair_buffer[idx++] = gi_probe2->probe_instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } + } + + scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, instance_pair_buffer, idx); + + ins->scenario->instance_data[ins->array_index].flags &= ~uint32_t(InstanceData::FLAG_GEOM_GI_PROBE_DIRTY); + } + + frustum_cull_result.geometry_instances.push_back(geom->geometry_instance); + } + + scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, frustum_cull_result.geometry_instances); + + gi_probe_update_list.remove(gi_probe); + + gi_probe = next; + } +} + +void RendererSceneCull::render_particle_colliders() { + while (heightfield_particle_colliders_update_list.front()) { + Instance *hfpc = heightfield_particle_colliders_update_list.front()->get(); + + if (hfpc->scenario && hfpc->base_type == RS::INSTANCE_PARTICLES_COLLISION && RSG::storage->particles_collision_is_heightfield(hfpc->base)) { + //update heightfield + instance_cull_result.clear(); + frustum_cull_result.geometry_instances.clear(); + + struct CullAABB { + PagedArray<Instance *> *result; + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + result->push_back(p_instance); + return false; + } + }; + + CullAABB cull_aabb; + cull_aabb.result = &instance_cull_result; + hfpc->scenario->indexers[Scenario::INDEXER_GEOMETRY].aabb_query(hfpc->transformed_aabb, cull_aabb); + hfpc->scenario->indexers[Scenario::INDEXER_VOLUMES].aabb_query(hfpc->transformed_aabb, cull_aabb); + + for (int i = 0; i < (int)instance_cull_result.size(); i++) { + Instance *instance = instance_cull_result[i]; + if (!instance || !((1 << instance->base_type) & (RS::INSTANCE_GEOMETRY_MASK & (~(1 << RS::INSTANCE_PARTICLES))))) { //all but particles to avoid self collision + continue; + } + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + frustum_cull_result.geometry_instances.push_back(geom->geometry_instance); + } + + scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, frustum_cull_result.geometry_instances); + } + heightfield_particle_colliders_update_list.erase(heightfield_particle_colliders_update_list.front()); + } +} + +void RendererSceneCull::_update_instance_shader_parameters_from_material(Map<StringName, Instance::InstanceShaderParameter> &isparams, const Map<StringName, Instance::InstanceShaderParameter> &existing_isparams, RID p_material) { + List<RendererStorage::InstanceShaderParam> plist; + RSG::storage->material_get_instance_shader_parameters(p_material, &plist); + for (List<RendererStorage::InstanceShaderParam>::Element *E = plist.front(); E; E = E->next()) { + StringName name = E->get().info.name; + if (isparams.has(name)) { + if (isparams[name].info.type != E->get().info.type) { + WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E->get().info.name + "', but they do it with different data types. Only the first one (in order) will display correctly."); + } + if (isparams[name].index != E->get().index) { + WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E->get().info.name + "', but they do it with different indices. Only the first one (in order) will display correctly."); + } + continue; //first one found always has priority + } + + Instance::InstanceShaderParameter isp; + isp.index = E->get().index; + isp.info = E->get().info; + isp.default_value = E->get().default_value; + if (existing_isparams.has(name)) { + isp.value = existing_isparams[name].value; + } else { + isp.value = E->get().default_value; + } + isparams[name] = isp; + } +} + +void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { + if (p_instance->update_aabb) { + _update_instance_aabb(p_instance); + } + + if (p_instance->update_dependencies) { + p_instance->dependency_tracker.update_begin(); + + if (p_instance->base.is_valid()) { + RSG::storage->base_update_dependency(p_instance->base, &p_instance->dependency_tracker); + } + + if (p_instance->material_override.is_valid()) { + RSG::storage->material_update_dependency(p_instance->material_override, &p_instance->dependency_tracker); + } + + if (p_instance->base_type == RS::INSTANCE_MESH) { + //remove materials no longer used and un-own them + + int new_mat_count = RSG::storage->mesh_get_surface_count(p_instance->base); + p_instance->materials.resize(new_mat_count); + + _instance_update_mesh_instance(p_instance); + } + + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + + bool can_cast_shadows = true; + bool is_animated = false; + Map<StringName, Instance::InstanceShaderParameter> isparams; + + if (p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_OFF) { + can_cast_shadows = false; + } + + if (p_instance->material_override.is_valid()) { + if (!RSG::storage->material_casts_shadows(p_instance->material_override)) { + can_cast_shadows = false; + } + is_animated = RSG::storage->material_is_animated(p_instance->material_override); + _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, p_instance->material_override); + } else { + if (p_instance->base_type == RS::INSTANCE_MESH) { + RID mesh = p_instance->base; + + if (mesh.is_valid()) { + bool cast_shadows = false; + + for (int i = 0; i < p_instance->materials.size(); i++) { + RID mat = p_instance->materials[i].is_valid() ? p_instance->materials[i] : RSG::storage->mesh_surface_get_material(mesh, i); + + if (!mat.is_valid()) { + cast_shadows = true; + } else { + if (RSG::storage->material_casts_shadows(mat)) { + cast_shadows = true; + } + + if (RSG::storage->material_is_animated(mat)) { + is_animated = true; + } + + _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); + + RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker); + } + } + + if (!cast_shadows) { + can_cast_shadows = false; + } + } + + } else if (p_instance->base_type == RS::INSTANCE_MULTIMESH) { + RID mesh = RSG::storage->multimesh_get_mesh(p_instance->base); + if (mesh.is_valid()) { + bool cast_shadows = false; + + int sc = RSG::storage->mesh_get_surface_count(mesh); + for (int i = 0; i < sc; i++) { + RID mat = RSG::storage->mesh_surface_get_material(mesh, i); + + if (!mat.is_valid()) { + cast_shadows = true; + + } else { + if (RSG::storage->material_casts_shadows(mat)) { + cast_shadows = true; + } + if (RSG::storage->material_is_animated(mat)) { + is_animated = true; + } + + _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); + + RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker); + } + } + + if (!cast_shadows) { + can_cast_shadows = false; + } + + RSG::storage->base_update_dependency(mesh, &p_instance->dependency_tracker); + } + } else if (p_instance->base_type == RS::INSTANCE_IMMEDIATE) { + RID mat = RSG::storage->immediate_get_material(p_instance->base); + + if (!(!mat.is_valid() || RSG::storage->material_casts_shadows(mat))) { + can_cast_shadows = false; + } + + if (mat.is_valid() && RSG::storage->material_is_animated(mat)) { + is_animated = true; + } + + if (mat.is_valid()) { + _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); + } + + if (mat.is_valid()) { + RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker); + } + + } else if (p_instance->base_type == RS::INSTANCE_PARTICLES) { + bool cast_shadows = false; + + int dp = RSG::storage->particles_get_draw_passes(p_instance->base); + + for (int i = 0; i < dp; i++) { + RID mesh = RSG::storage->particles_get_draw_pass_mesh(p_instance->base, i); + if (!mesh.is_valid()) { + continue; + } + + int sc = RSG::storage->mesh_get_surface_count(mesh); + for (int j = 0; j < sc; j++) { + RID mat = RSG::storage->mesh_surface_get_material(mesh, j); + + if (!mat.is_valid()) { + cast_shadows = true; + } else { + if (RSG::storage->material_casts_shadows(mat)) { + cast_shadows = true; + } + + if (RSG::storage->material_is_animated(mat)) { + is_animated = true; + } + + _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); + + RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker); + } + } + } + + if (!cast_shadows) { + can_cast_shadows = false; + } + } + } + + if (can_cast_shadows != geom->can_cast_shadows) { + //ability to cast shadows change, let lights now + for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) { + InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); + light->shadow_dirty = true; + } + + geom->can_cast_shadows = can_cast_shadows; + } + + geom->material_is_animated = is_animated; + p_instance->instance_shader_parameters = isparams; + + if (p_instance->instance_allocated_shader_parameters != (p_instance->instance_shader_parameters.size() > 0)) { + p_instance->instance_allocated_shader_parameters = (p_instance->instance_shader_parameters.size() > 0); + if (p_instance->instance_allocated_shader_parameters) { + p_instance->instance_allocated_shader_parameters_offset = RSG::storage->global_variables_instance_allocate(p_instance->self); + scene_render->geometry_instance_set_instance_shader_parameters_offset(geom->geometry_instance, p_instance->instance_allocated_shader_parameters_offset); + + for (Map<StringName, Instance::InstanceShaderParameter>::Element *E = p_instance->instance_shader_parameters.front(); E; E = E->next()) { + if (E->get().value.get_type() != Variant::NIL) { + RSG::storage->global_variables_instance_update(p_instance->self, E->get().index, E->get().value); + } + } + } else { + RSG::storage->global_variables_instance_free(p_instance->self); + p_instance->instance_allocated_shader_parameters_offset = -1; + scene_render->geometry_instance_set_instance_shader_parameters_offset(geom->geometry_instance, -1); + } + } + } + + if (p_instance->skeleton.is_valid()) { + RSG::storage->skeleton_update_dependency(p_instance->skeleton, &p_instance->dependency_tracker); + } + + p_instance->dependency_tracker.update_end(); + + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + scene_render->geometry_instance_set_surface_materials(geom->geometry_instance, p_instance->materials); + } + } + + _instance_update_list.remove(&p_instance->update_item); + + _update_instance(p_instance); + + p_instance->update_aabb = false; + p_instance->update_dependencies = false; +} + +void RendererSceneCull::update_dirty_instances() { + RSG::storage->update_dirty_resources(); + + while (_instance_update_list.first()) { + _update_dirty_instance(_instance_update_list.first()->self()); + } +} + +void RendererSceneCull::update() { + //optimize bvhs + for (uint32_t i = 0; i < scenario_owner.get_rid_count(); i++) { + Scenario *s = scenario_owner.get_ptr_by_index(i); + s->indexers[Scenario::INDEXER_GEOMETRY].optimize_incremental(indexer_update_iterations); + s->indexers[Scenario::INDEXER_VOLUMES].optimize_incremental(indexer_update_iterations); + } + scene_render->update(); + update_dirty_instances(); + render_particle_colliders(); +} + +bool RendererSceneCull::free(RID p_rid) { + if (scene_render->free(p_rid)) { + return true; + } + + if (camera_owner.owns(p_rid)) { + Camera *camera = camera_owner.getornull(p_rid); + + camera_owner.free(p_rid); + memdelete(camera); + + } else if (scenario_owner.owns(p_rid)) { + Scenario *scenario = scenario_owner.getornull(p_rid); + + while (scenario->instances.first()) { + instance_set_scenario(scenario->instances.first()->self()->self, RID()); + } + scenario->instance_aabbs.reset(); + scenario->instance_data.reset(); + + scene_render->free(scenario->reflection_probe_shadow_atlas); + scene_render->free(scenario->reflection_atlas); + scenario_owner.free(p_rid); + memdelete(scenario); + + } else if (instance_owner.owns(p_rid)) { + // delete the instance + + update_dirty_instances(); + + Instance *instance = instance_owner.getornull(p_rid); + + instance_geometry_set_lightmap(p_rid, RID(), Rect2(), 0); + instance_set_scenario(p_rid, RID()); + instance_set_base(p_rid, RID()); + instance_geometry_set_material_override(p_rid, RID()); + instance_attach_skeleton(p_rid, RID()); + + if (instance->instance_allocated_shader_parameters) { + //free the used shader parameters + RSG::storage->global_variables_instance_free(instance->self); + } + update_dirty_instances(); //in case something changed this + + instance_owner.free(p_rid); + memdelete(instance); + } else { + return false; + } + + return true; +} + +TypedArray<Image> RendererSceneCull::bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) { + return scene_render->bake_render_uv2(p_base, p_material_overrides, p_image_size); +} + +/*******************************/ +/* Passthrough to Scene Render */ +/*******************************/ + +/* ENVIRONMENT API */ + +RendererSceneCull *RendererSceneCull::singleton = nullptr; + +void RendererSceneCull::set_scene_render(RendererSceneRender *p_scene_render) { + scene_render = p_scene_render; + geometry_instance_pair_mask = scene_render->geometry_instance_get_pair_mask(); +} + +RendererSceneCull::RendererSceneCull() { + render_pass = 1; + singleton = this; + + instance_cull_result.set_page_pool(&instance_cull_page_pool); + instance_shadow_cull_result.set_page_pool(&instance_cull_page_pool); + + geometry_instances_to_shadow_render.set_page_pool(&geometry_instance_cull_page_pool); + + frustum_cull_result.init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool); + frustum_cull_result_threads.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count()); + for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) { + frustum_cull_result_threads[i].init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool); + } + + indexer_update_iterations = GLOBAL_GET("rendering/spatial_indexer/update_iterations_per_frame"); + thread_cull_threshold = GLOBAL_GET("rendering/spatial_indexer/threaded_cull_minimum_instances"); + thread_cull_threshold = MAX(thread_cull_threshold, (uint32_t)RendererThreadPool::singleton->thread_work_pool.get_thread_count()); //make sure there is at least one thread per CPU +} + +RendererSceneCull::~RendererSceneCull() { + instance_cull_result.reset(); + instance_shadow_cull_result.reset(); + + geometry_instances_to_shadow_render.reset(); + + frustum_cull_result.reset(); + for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) { + frustum_cull_result_threads[i].reset(); + } + frustum_cull_result_threads.clear(); +} diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h new file mode 100644 index 0000000000..2ffaf48675 --- /dev/null +++ b/servers/rendering/renderer_scene_cull.h @@ -0,0 +1,1048 @@ +/*************************************************************************/ +/* renderer_scene_cull.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERING_SERVER_SCENE_CULL_H +#define RENDERING_SERVER_SCENE_CULL_H + +#include "core/templates/pass_func.h" +#include "servers/rendering/renderer_compositor.h" + +#include "core/math/dynamic_bvh.h" +#include "core/math/geometry_3d.h" +#include "core/math/octree.h" +#include "core/os/semaphore.h" +#include "core/os/thread.h" +#include "core/templates/local_vector.h" +#include "core/templates/paged_allocator.h" +#include "core/templates/paged_array.h" +#include "core/templates/rid_owner.h" +#include "core/templates/self_list.h" +#include "servers/rendering/renderer_scene.h" +#include "servers/rendering/renderer_scene_render.h" +#include "servers/xr/xr_interface.h" +class RendererSceneCull : public RendererScene { +public: + RendererSceneRender *scene_render; + + enum { + SDFGI_MAX_CASCADES = 8, + SDFGI_MAX_REGIONS_PER_CASCADE = 3, + MAX_INSTANCE_PAIRS = 32 + }; + + uint64_t render_pass; + + static RendererSceneCull *singleton; + + /* CAMERA API */ + + struct Camera { + enum Type { + PERSPECTIVE, + ORTHOGONAL, + FRUSTUM + }; + Type type; + float fov; + float znear, zfar; + float size; + Vector2 offset; + uint32_t visible_layers; + bool vaspect; + RID env; + RID effects; + + Transform transform; + + Camera() { + visible_layers = 0xFFFFFFFF; + fov = 75; + type = PERSPECTIVE; + znear = 0.05; + zfar = 4000; + size = 1.0; + offset = Vector2(); + vaspect = false; + } + }; + + mutable RID_PtrOwner<Camera> camera_owner; + + virtual RID camera_create(); + virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far); + virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far); + virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far); + virtual void camera_set_transform(RID p_camera, const Transform &p_transform); + virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers); + virtual void camera_set_environment(RID p_camera, RID p_env); + virtual void camera_set_camera_effects(RID p_camera, RID p_fx); + virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable); + virtual bool is_camera(RID p_camera) const; + + /* SCENARIO API */ + + struct Instance; + + struct PlaneSign { + _ALWAYS_INLINE_ PlaneSign() {} + _ALWAYS_INLINE_ PlaneSign(const Plane &p_plane) { + if (p_plane.normal.x > 0) { + signs[0] = 0; + } else { + signs[0] = 3; + } + if (p_plane.normal.y > 0) { + signs[1] = 1; + } else { + signs[1] = 4; + } + if (p_plane.normal.z > 0) { + signs[2] = 2; + } else { + signs[2] = 5; + } + } + + uint32_t signs[3]; + }; + + struct Frustum { + Vector<Plane> planes; + Vector<PlaneSign> plane_signs; + const Plane *planes_ptr; + const PlaneSign *plane_signs_ptr; + uint32_t plane_count; + + _ALWAYS_INLINE_ Frustum() {} + _ALWAYS_INLINE_ Frustum(const Frustum &p_frustum) { + planes = p_frustum.planes; + plane_signs = p_frustum.plane_signs; + + planes_ptr = planes.ptr(); + plane_signs_ptr = plane_signs.ptr(); + plane_count = p_frustum.plane_count; + } + _ALWAYS_INLINE_ void operator=(const Frustum &p_frustum) { + planes = p_frustum.planes; + plane_signs = p_frustum.plane_signs; + + planes_ptr = planes.ptr(); + plane_signs_ptr = plane_signs.ptr(); + plane_count = p_frustum.plane_count; + } + _ALWAYS_INLINE_ Frustum(const Vector<Plane> &p_planes) { + planes = p_planes; + planes_ptr = planes.ptrw(); + plane_count = planes.size(); + for (int i = 0; i < planes.size(); i++) { + PlaneSign ps(p_planes[i]); + plane_signs.push_back(ps); + } + + plane_signs_ptr = plane_signs.ptr(); + } + }; + + struct InstanceBounds { + // Efficiently store instance bounds. + // Because bounds checking is performed first, + // keep it separated from data. + + real_t bounds[6]; + _ALWAYS_INLINE_ InstanceBounds() {} + + _ALWAYS_INLINE_ InstanceBounds(const AABB &p_aabb) { + bounds[0] = p_aabb.position.x; + bounds[1] = p_aabb.position.y; + bounds[2] = p_aabb.position.z; + bounds[3] = p_aabb.position.x + p_aabb.size.x; + bounds[4] = p_aabb.position.y + p_aabb.size.y; + bounds[5] = p_aabb.position.z + p_aabb.size.z; + } + _ALWAYS_INLINE_ bool in_frustum(const Frustum &p_frustum) const { + // This is not a full SAT check and the possibility of false positives exist, + // but the tradeoff vs performance is still very good. + + for (uint32_t i = 0; i < p_frustum.plane_count; i++) { + Vector3 min( + bounds[p_frustum.plane_signs_ptr[i].signs[0]], + bounds[p_frustum.plane_signs_ptr[i].signs[1]], + bounds[p_frustum.plane_signs_ptr[i].signs[2]]); + + if (p_frustum.planes_ptr[i].distance_to(min) >= 0.0) { + return false; + } + } + + return true; + } + _ALWAYS_INLINE_ bool in_aabb(const AABB &p_aabb) const { + Vector3 end = p_aabb.position + p_aabb.size; + + if (bounds[0] >= end.x) { + return false; + } + if (bounds[3] <= p_aabb.position.x) { + return false; + } + if (bounds[1] >= end.y) { + return false; + } + if (bounds[4] <= p_aabb.position.y) { + return false; + } + if (bounds[2] >= end.z) { + return false; + } + if (bounds[5] <= p_aabb.position.z) { + return false; + } + + return true; + } + }; + + struct InstanceData { + // Store instance pointer as well as common instance processing information, + // to make processing more cache friendly. + enum Flags { + FLAG_BASE_TYPE_MASK = 0xFF, + FLAG_CAST_SHADOWS = (1 << 8), + FLAG_CAST_SHADOWS_ONLY = (1 << 9), + FLAG_REDRAW_IF_VISIBLE = (1 << 10), + FLAG_GEOM_LIGHTING_DIRTY = (1 << 11), + FLAG_GEOM_REFLECTION_DIRTY = (1 << 12), + FLAG_GEOM_DECAL_DIRTY = (1 << 13), + FLAG_GEOM_GI_PROBE_DIRTY = (1 << 14), + FLAG_LIGHTMAP_CAPTURE = (1 << 15), + FLAG_USES_BAKED_LIGHT = (1 << 16), + FLAG_USES_MESH_INSTANCE = (1 << 17), + FLAG_REFLECTION_PROBE_DIRTY = (1 << 18), + }; + + uint32_t flags = 0; + uint32_t layer_mask = 0; //for fast layer-mask discard + RID base_rid; + union { + uint64_t instance_data_rid; + RendererSceneRender::GeometryInstance *instance_geometry; + }; + Instance *instance = nullptr; + }; + + PagedArrayPool<InstanceBounds> instance_aabb_page_pool; + PagedArrayPool<InstanceData> instance_data_page_pool; + + struct Scenario { + enum IndexerType { + INDEXER_GEOMETRY, //for geometry + INDEXER_VOLUMES, //for everything else + INDEXER_MAX + }; + + DynamicBVH indexers[INDEXER_MAX]; + + RS::ScenarioDebugMode debug; + RID self; + + List<Instance *> directional_lights; + RID environment; + RID fallback_environment; + RID camera_effects; + RID reflection_probe_shadow_atlas; + RID reflection_atlas; + + SelfList<Instance>::List instances; + + LocalVector<RID> dynamic_lights; + + PagedArray<InstanceBounds> instance_aabbs; + PagedArray<InstanceData> instance_data; + + Scenario() { + indexers[INDEXER_GEOMETRY].set_index(INDEXER_GEOMETRY); + indexers[INDEXER_VOLUMES].set_index(INDEXER_VOLUMES); + debug = RS::SCENARIO_DEBUG_DISABLED; + } + }; + + int indexer_update_iterations = 0; + + mutable RID_PtrOwner<Scenario> scenario_owner; + + static void _instance_pair(Instance *p_A, Instance *p_B); + static void _instance_unpair(Instance *p_A, Instance *p_B); + + void _instance_update_mesh_instance(Instance *p_instance); + + virtual RID scenario_create(); + + virtual void scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode); + virtual void scenario_set_environment(RID p_scenario, RID p_environment); + virtual void scenario_set_camera_effects(RID p_scenario, RID p_fx); + virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment); + virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count); + virtual bool is_scenario(RID p_scenario) const; + virtual RID scenario_get_environment(RID p_scenario); + + /* INSTANCING API */ + + struct InstancePair { + Instance *a; + Instance *b; + SelfList<InstancePair> list_a; + SelfList<InstancePair> list_b; + InstancePair() : + list_a(this), list_b(this) {} + }; + + PagedAllocator<InstancePair> pair_allocator; + + struct InstanceBaseData { + virtual ~InstanceBaseData() {} + }; + + struct Instance { + RS::InstanceType base_type; + RID base; + + RID skeleton; + RID material_override; + + RID mesh_instance; //only used for meshes and when skeleton/blendshapes exist + + Transform transform; + + float lod_bias; + + Vector<RID> materials; + + RS::ShadowCastingSetting cast_shadows; + + uint32_t layer_mask; + //fit in 32 bits + bool mirror : 8; + bool receive_shadows : 8; + bool visible : 8; + bool baked_light : 2; //this flag is only to know if it actually did use baked light + bool dynamic_gi : 2; //same above for dynamic objects + bool redraw_if_visible : 4; + + Instance *lightmap; + Rect2 lightmap_uv_scale; + int lightmap_slice_index; + uint32_t lightmap_cull_index; + Vector<Color> lightmap_sh; //spherical harmonic + + AABB aabb; + AABB transformed_aabb; + AABB prev_transformed_aabb; + + struct InstanceShaderParameter { + int32_t index = -1; + Variant value; + Variant default_value; + PropertyInfo info; + }; + + Map<StringName, InstanceShaderParameter> instance_shader_parameters; + bool instance_allocated_shader_parameters = false; + int32_t instance_allocated_shader_parameters_offset = -1; + + // + + RID self; + //scenario stuff + DynamicBVH::ID indexer_id; + int32_t array_index; + Scenario *scenario; + SelfList<Instance> scenario_item; + + //aabb stuff + bool update_aabb; + bool update_dependencies; + + SelfList<Instance> update_item; + + AABB *custom_aabb; // <Zylann> would using aabb directly with a bool be better? + float extra_margin; + ObjectID object_id; + + float lod_begin; + float lod_end; + float lod_begin_hysteresis; + float lod_end_hysteresis; + RID lod_instance; + + Vector<Color> lightmap_target_sh; //target is used for incrementally changing the SH over time, this avoids pops in some corner cases and when going interior <-> exterior + + uint64_t last_frame_pass; + + uint64_t version; // changes to this, and changes to base increase version + + InstanceBaseData *base_data; + + SelfList<InstancePair>::List pairs; + uint64_t pair_check; + + RendererStorage::DependencyTracker dependency_tracker; + + static void dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *tracker) { + Instance *instance = (Instance *)tracker->userdata; + switch (p_notification) { + case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: + case RendererStorage::DEPENDENCY_CHANGED_AABB: { + singleton->_instance_queue_update(instance, true, false); + + } break; + case RendererStorage::DEPENDENCY_CHANGED_MATERIAL: { + singleton->_instance_queue_update(instance, false, true); + } break; + case RendererStorage::DEPENDENCY_CHANGED_MESH: + case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH: + case RendererStorage::DEPENDENCY_CHANGED_DECAL: + case RendererStorage::DEPENDENCY_CHANGED_LIGHT: + case RendererStorage::DEPENDENCY_CHANGED_REFLECTION_PROBE: { + singleton->_instance_queue_update(instance, true, true); + } break; + case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: + case RendererStorage::DEPENDENCY_CHANGED_SKELETON_BONES: { + //ignored + } break; + } + } + + static void dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *tracker) { + Instance *instance = (Instance *)tracker->userdata; + + if (p_dependency == instance->base) { + singleton->instance_set_base(instance->self, RID()); + } else if (p_dependency == instance->skeleton) { + singleton->instance_attach_skeleton(instance->self, RID()); + } else { + singleton->_instance_queue_update(instance, false, true); + } + } + + Instance() : + scenario_item(this), + update_item(this) { + base_type = RS::INSTANCE_NONE; + cast_shadows = RS::SHADOW_CASTING_SETTING_ON; + receive_shadows = true; + visible = true; + layer_mask = 1; + baked_light = false; + dynamic_gi = false; + redraw_if_visible = false; + lightmap_slice_index = 0; + lightmap = nullptr; + lightmap_cull_index = 0; + lod_bias = 1.0; + + scenario = nullptr; + + update_aabb = false; + update_dependencies = false; + + extra_margin = 0; + + visible = true; + + lod_begin = 0; + lod_end = 0; + lod_begin_hysteresis = 0; + lod_end_hysteresis = 0; + + last_frame_pass = 0; + version = 1; + base_data = nullptr; + + custom_aabb = nullptr; + + pair_check = 0; + array_index = -1; + + dependency_tracker.userdata = this; + dependency_tracker.changed_callback = dependency_changed; + dependency_tracker.deleted_callback = dependency_deleted; + } + + ~Instance() { + if (base_data) { + memdelete(base_data); + } + if (custom_aabb) { + memdelete(custom_aabb); + } + } + }; + + SelfList<Instance>::List _instance_update_list; + void _instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies = false); + + struct InstanceGeometryData : public InstanceBaseData { + RendererSceneRender::GeometryInstance *geometry_instance = nullptr; + Set<Instance *> lights; + bool can_cast_shadows; + bool material_is_animated; + + Set<Instance *> decals; + Set<Instance *> reflection_probes; + Set<Instance *> gi_probes; + Set<Instance *> lightmap_captures; + + InstanceGeometryData() { + can_cast_shadows = true; + material_is_animated = true; + } + }; + + struct InstanceReflectionProbeData : public InstanceBaseData { + Instance *owner; + + Set<Instance *> geometries; + + RID instance; + SelfList<InstanceReflectionProbeData> update_list; + + int render_step; + + InstanceReflectionProbeData() : + update_list(this) { + render_step = -1; + } + }; + + struct InstanceDecalData : public InstanceBaseData { + Instance *owner; + RID instance; + + Set<Instance *> geometries; + + InstanceDecalData() { + } + }; + + SelfList<InstanceReflectionProbeData>::List reflection_probe_render_list; + + struct InstanceParticlesCollisionData : public InstanceBaseData { + RID instance; + }; + + struct InstanceLightData : public InstanceBaseData { + RID instance; + uint64_t last_version; + List<Instance *>::Element *D; // directional light in scenario + + bool shadow_dirty; + + Set<Instance *> geometries; + + Instance *baked_light; + + RS::LightBakeMode bake_mode; + uint32_t max_sdfgi_cascade = 2; + + InstanceLightData() { + bake_mode = RS::LIGHT_BAKE_DISABLED; + shadow_dirty = true; + D = nullptr; + last_version = 0; + baked_light = nullptr; + } + }; + + struct InstanceGIProbeData : public InstanceBaseData { + Instance *owner; + + Set<Instance *> geometries; + Set<Instance *> dynamic_geometries; + + Set<Instance *> lights; + + struct LightCache { + RS::LightType type; + Transform transform; + Color color; + float energy; + float bake_energy; + float radius; + float attenuation; + float spot_angle; + float spot_attenuation; + bool has_shadow; + bool sky_only; + }; + + Vector<LightCache> light_cache; + Vector<RID> light_instances; + + RID probe_instance; + + bool invalid; + uint32_t base_version; + + SelfList<InstanceGIProbeData> update_element; + + InstanceGIProbeData() : + update_element(this) { + invalid = true; + base_version = 0; + } + }; + + SelfList<InstanceGIProbeData>::List gi_probe_update_list; + + struct InstanceLightmapData : public InstanceBaseData { + RID instance; + Set<Instance *> geometries; + Set<Instance *> users; + + InstanceLightmapData() { + } + }; + + uint64_t pair_pass = 1; + + struct PairInstances { + Instance *instance = nullptr; + PagedAllocator<InstancePair> *pair_allocator = nullptr; + SelfList<InstancePair>::List pairs_found; + DynamicBVH *bvh = nullptr; + DynamicBVH *bvh2 = nullptr; //some may need to cull in two + uint32_t pair_mask; + uint64_t pair_pass; + + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + if (instance != p_instance && instance->transformed_aabb.intersects(p_instance->transformed_aabb) && (pair_mask & (1 << p_instance->base_type))) { + //test is more coarse in indexer + p_instance->pair_check = pair_pass; + InstancePair *pair = pair_allocator->alloc(); + pair->a = instance; + pair->b = p_instance; + pairs_found.add(&pair->list_a); + } + return false; + } + + void pair() { + if (bvh) { + bvh->aabb_query(instance->transformed_aabb, *this); + } + if (bvh2) { + bvh2->aabb_query(instance->transformed_aabb, *this); + } + while (instance->pairs.first()) { + InstancePair *pair = instance->pairs.first()->self(); + Instance *other_instance = instance == pair->a ? pair->b : pair->a; + if (other_instance->pair_check != pair_pass) { + //unpaired + _instance_unpair(instance, other_instance); + } else { + //kept + other_instance->pair_check = 0; // if kept, then put pair check to zero, so we can distinguish with the newly added ones + } + + pair_allocator->free(pair); + } + while (pairs_found.first()) { + InstancePair *pair = pairs_found.first()->self(); + pairs_found.remove(pairs_found.first()); + + if (pair->b->pair_check == pair_pass) { + //paired + _instance_pair(instance, pair->b); + } + pair->a->pairs.add(&pair->list_a); + pair->b->pairs.add(&pair->list_b); + } + } + }; + + Set<Instance *> heightfield_particle_colliders_update_list; + + PagedArrayPool<Instance *> instance_cull_page_pool; + PagedArrayPool<RendererSceneRender::GeometryInstance *> geometry_instance_cull_page_pool; + PagedArrayPool<RID> rid_cull_page_pool; + + PagedArray<Instance *> instance_cull_result; + PagedArray<Instance *> instance_shadow_cull_result; + PagedArray<RendererSceneRender::GeometryInstance *> geometry_instances_to_shadow_render; + + struct FrustumCullResult { + PagedArray<RendererSceneRender::GeometryInstance *> geometry_instances; + PagedArray<Instance *> lights; + PagedArray<RID> light_instances; + PagedArray<RID> lightmaps; + PagedArray<RID> reflections; + PagedArray<RID> decals; + PagedArray<RID> gi_probes; + PagedArray<RID> mesh_instances; + + struct DirectionalShadow { + PagedArray<RendererSceneRender::GeometryInstance *> cascade_geometry_instances[RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES]; + } directional_shadows[RendererSceneRender::MAX_DIRECTIONAL_LIGHTS]; + + PagedArray<RendererSceneRender::GeometryInstance *> sdfgi_region_geometry_instances[SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE]; + PagedArray<RID> sdfgi_cascade_lights[SDFGI_MAX_CASCADES]; + + void clear() { + geometry_instances.clear(); + lights.clear(); + light_instances.clear(); + lightmaps.clear(); + reflections.clear(); + decals.clear(); + gi_probes.clear(); + mesh_instances.clear(); + for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { + for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { + directional_shadows[i].cascade_geometry_instances[j].clear(); + } + } + + for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { + sdfgi_region_geometry_instances[i].clear(); + } + + for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { + sdfgi_cascade_lights[i].clear(); + } + } + + void reset() { + geometry_instances.reset(); + lights.reset(); + light_instances.reset(); + lightmaps.reset(); + reflections.reset(); + decals.reset(); + gi_probes.reset(); + mesh_instances.reset(); + for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { + for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { + directional_shadows[i].cascade_geometry_instances[j].reset(); + } + } + + for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { + sdfgi_region_geometry_instances[i].reset(); + } + + for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { + sdfgi_cascade_lights[i].reset(); + } + } + + void append_from(FrustumCullResult &p_cull_result) { + geometry_instances.merge_unordered(p_cull_result.geometry_instances); + lights.merge_unordered(p_cull_result.lights); + light_instances.merge_unordered(p_cull_result.light_instances); + lightmaps.merge_unordered(p_cull_result.lightmaps); + reflections.merge_unordered(p_cull_result.reflections); + decals.merge_unordered(p_cull_result.decals); + gi_probes.merge_unordered(p_cull_result.gi_probes); + mesh_instances.merge_unordered(p_cull_result.mesh_instances); + + for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { + for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { + directional_shadows[i].cascade_geometry_instances[j].merge_unordered(p_cull_result.directional_shadows[i].cascade_geometry_instances[j]); + } + } + + for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { + sdfgi_region_geometry_instances[i].merge_unordered(p_cull_result.sdfgi_region_geometry_instances[i]); + } + + for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { + sdfgi_cascade_lights[i].merge_unordered(p_cull_result.sdfgi_cascade_lights[i]); + } + } + + void init(PagedArrayPool<RID> *p_rid_pool, PagedArrayPool<RendererSceneRender::GeometryInstance *> *p_geometry_instance_pool, PagedArrayPool<Instance *> *p_instance_pool) { + geometry_instances.set_page_pool(p_geometry_instance_pool); + light_instances.set_page_pool(p_rid_pool); + lights.set_page_pool(p_instance_pool); + lightmaps.set_page_pool(p_rid_pool); + reflections.set_page_pool(p_rid_pool); + decals.set_page_pool(p_rid_pool); + gi_probes.set_page_pool(p_rid_pool); + mesh_instances.set_page_pool(p_rid_pool); + for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { + for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { + directional_shadows[i].cascade_geometry_instances[j].set_page_pool(p_geometry_instance_pool); + } + } + + for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { + sdfgi_region_geometry_instances[i].set_page_pool(p_geometry_instance_pool); + } + + for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { + sdfgi_cascade_lights[i].set_page_pool(p_rid_pool); + } + } + }; + + FrustumCullResult frustum_cull_result; + LocalVector<FrustumCullResult> frustum_cull_result_threads; + + uint32_t thread_cull_threshold = 200; + + RID_PtrOwner<Instance> instance_owner; + + uint32_t geometry_instance_pair_mask; // used in traditional forward, unnecesary on clustered + + virtual RID instance_create(); + + virtual void instance_set_base(RID p_instance, RID p_base); + virtual void instance_set_scenario(RID p_instance, RID p_scenario); + virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask); + virtual void instance_set_transform(RID p_instance, const Transform &p_transform); + virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id); + virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight); + virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material); + virtual void instance_set_visible(RID p_instance, bool p_visible); + + virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb); + + virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton); + virtual void instance_set_exterior(RID p_instance, bool p_enabled); + + virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin); + + // don't use these in a game! + virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const; + virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const; + virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario = RID()) const; + + virtual void instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled); + virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting); + virtual void instance_geometry_set_material_override(RID p_instance, RID p_material); + + virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin); + virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance); + virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index); + virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias); + + void _update_instance_shader_parameters_from_material(Map<StringName, Instance::InstanceShaderParameter> &isparams, const Map<StringName, Instance::InstanceShaderParameter> &existing_isparams, RID p_material); + + virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value); + virtual void instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const; + virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const; + virtual Variant instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const; + + _FORCE_INLINE_ void _update_instance(Instance *p_instance); + _FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance); + _FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance); + _FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance); + void _unpair_instance(Instance *p_instance); + + void _light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect); + + _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_scren_lod_threshold); + + RID _render_get_environment(RID p_camera, RID p_scenario); + + struct Cull { + struct Shadow { + RID light_instance; + struct Cascade { + Frustum frustum; + + CameraMatrix projection; + Transform transform; + real_t zfar; + real_t split; + real_t shadow_texel_size; + real_t bias_scale; + real_t range_begin; + Vector2 uv_scale; + + } cascades[RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES]; //max 4 cascades + uint32_t cascade_count; + + } shadows[RendererSceneRender::MAX_DIRECTIONAL_LIGHTS]; + + uint32_t shadow_count; + + struct SDFGI { + //have arrays here because SDFGI functions expects this, plus regions can have areas + AABB region_aabb[SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE]; //max 3 regions per cascade + uint32_t region_cascade[SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE]; //max 3 regions per cascade + uint32_t region_count = 0; + + uint32_t cascade_light_index[SDFGI_MAX_CASCADES]; + uint32_t cascade_light_count = 0; + + } sdfgi; + + SpinLock lock; + + Frustum frustum; + } cull; + + struct FrustumCullData { + Cull *cull; + Scenario *scenario; + RID shadow_atlas; + Transform cam_transform; + uint32_t visible_layers; + Instance *render_reflection_probe; + }; + + void _frustum_cull_threaded(uint32_t p_thread, FrustumCullData *cull_data); + void _frustum_cull(FrustumCullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to); + + bool _render_reflection_probe_step(Instance *p_instance, int p_step); + void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, float p_screen_lod_threshold, bool p_using_shadows = true); + void _render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold); + void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas); + + void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas); + void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas); + void update_dirty_instances(); + + void render_particle_colliders(); + virtual void render_probes(); + + TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size); + + //pass to scene render + + /* ENVIRONMENT API */ + +#ifdef PASSBASE +#undef PASSBASE +#endif + +#define PASSBASE scene_render + + PASS2(directional_shadow_atlas_set_size, int, bool) + PASS1(gi_probe_set_quality, RS::GIProbeQuality) + + /* SKY API */ + + PASS0R(RID, sky_create) + PASS2(sky_set_radiance_size, RID, int) + PASS2(sky_set_mode, RID, RS::SkyMode) + PASS2(sky_set_material, RID, RID) + PASS4R(Ref<Image>, sky_bake_panorama, RID, float, bool, const Size2i &) + + PASS0R(RID, environment_create) + + PASS1RC(bool, is_environment, RID) + + PASS2(environment_set_background, RID, RS::EnvironmentBG) + PASS2(environment_set_sky, RID, RID) + PASS2(environment_set_sky_custom_fov, RID, float) + PASS2(environment_set_sky_orientation, RID, const Basis &) + PASS2(environment_set_bg_color, RID, const Color &) + PASS2(environment_set_bg_energy, RID, float) + PASS2(environment_set_canvas_max_layer, RID, int) + PASS7(environment_set_ambient_light, RID, const Color &, RS::EnvironmentAmbientSource, float, float, RS::EnvironmentReflectionSource, const Color &) + + PASS6(environment_set_ssr, RID, bool, int, float, float, float) + PASS1(environment_set_ssr_roughness_quality, RS::EnvironmentSSRRoughnessQuality) + + PASS10(environment_set_ssao, RID, bool, float, float, float, float, float, float, float, float) + PASS6(environment_set_ssao_quality, RS::EnvironmentSSAOQuality, bool, float, int, float, float) + + PASS11(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, RS::EnvironmentGlowBlendMode, float, float, float) + PASS1(environment_glow_set_use_bicubic_upscale, bool) + PASS1(environment_glow_set_use_high_quality, bool) + + PASS9(environment_set_tonemap, RID, RS::EnvironmentToneMapper, float, float, bool, float, float, float, float) + + PASS7(environment_set_adjustment, RID, bool, float, float, float, bool, RID) + + PASS9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float) + PASS9(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, RS::EnvVolumetricFogShadowFilter) + + PASS2(environment_set_volumetric_fog_volume_size, int, int) + PASS1(environment_set_volumetric_fog_filter_active, bool) + PASS1(environment_set_volumetric_fog_directional_shadow_shrink_size, int) + PASS1(environment_set_volumetric_fog_positional_shadow_shrink_size, int) + + PASS11(environment_set_sdfgi, RID, bool, RS::EnvironmentSDFGICascades, float, RS::EnvironmentSDFGIYScale, bool, bool, bool, float, float, float) + PASS1(environment_set_sdfgi_ray_count, RS::EnvironmentSDFGIRayCount) + PASS1(environment_set_sdfgi_frames_to_converge, RS::EnvironmentSDFGIFramesToConverge) + PASS1(environment_set_sdfgi_frames_to_update_light, RS::EnvironmentSDFGIFramesToUpdateLight) + + PASS1RC(RS::EnvironmentBG, environment_get_background, RID) + PASS1RC(int, environment_get_canvas_max_layer, RID) + + PASS3R(Ref<Image>, environment_bake_panorama, RID, bool, const Size2i &) + + PASS3(screen_space_roughness_limiter_set_active, bool, float, float) + PASS1(sub_surface_scattering_set_quality, RS::SubSurfaceScatteringQuality) + PASS2(sub_surface_scattering_set_scale, float, float) + + /* CAMERA EFFECTS */ + + PASS0R(RID, camera_effects_create) + + PASS2(camera_effects_set_dof_blur_quality, RS::DOFBlurQuality, bool) + PASS1(camera_effects_set_dof_blur_bokeh_shape, RS::DOFBokehShape) + + PASS8(camera_effects_set_dof_blur, RID, bool, float, float, bool, float, float, float) + PASS3(camera_effects_set_custom_exposure, RID, bool, float) + + PASS1(shadows_quality_set, RS::ShadowQuality) + PASS1(directional_shadow_quality_set, RS::ShadowQuality) + + PASS2(sdfgi_set_debug_probe_select, const Vector3 &, const Vector3 &) + + /* Render Buffers */ + + PASS0R(RID, render_buffers_create) + PASS7(render_buffers_configure, RID, RID, int, int, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool) + PASS1(gi_set_use_half_resolution, bool) + + /* Shadow Atlas */ + PASS0R(RID, shadow_atlas_create) + PASS3(shadow_atlas_set_size, RID, int, bool) + PASS3(shadow_atlas_set_quadrant_subdivision, RID, int, int) + + PASS1(set_debug_draw_mode, RS::ViewportDebugDraw) + + virtual void update(); + + bool free(RID p_rid); + + void set_scene_render(RendererSceneRender *p_scene_render); + + RendererSceneCull(); + virtual ~RendererSceneCull(); +}; + +#endif // VISUALSERVERSCENE_H diff --git a/servers/rendering/renderer_scene_render.cpp b/servers/rendering/renderer_scene_render.cpp new file mode 100644 index 0000000000..f27bdc6798 --- /dev/null +++ b/servers/rendering/renderer_scene_render.cpp @@ -0,0 +1,31 @@ +/*************************************************************************/ +/* renderer_scene_render.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "renderer_scene_render.h" diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h new file mode 100644 index 0000000000..ecec03db94 --- /dev/null +++ b/servers/rendering/renderer_scene_render.h @@ -0,0 +1,232 @@ +/*************************************************************************/ +/* renderer_scene_render.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERINGSERVERSCENERENDER_H +#define RENDERINGSERVERSCENERENDER_H + +#include "core/math/camera_matrix.h" +#include "core/templates/paged_array.h" +#include "servers/rendering/renderer_storage.h" + +class RendererSceneRender { +public: + enum { + MAX_DIRECTIONAL_LIGHTS = 8, + MAX_DIRECTIONAL_LIGHT_CASCADES = 4 + }; + + struct GeometryInstance { + virtual ~GeometryInstance() {} + }; + + virtual GeometryInstance *geometry_instance_create(RID p_base) = 0; + virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) = 0; + virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) = 0; + virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_material) = 0; + virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) = 0; + virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) = 0; + virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) = 0; + virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) = 0; + virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) = 0; + virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) = 0; + virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) = 0; + virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) = 0; + virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) = 0; + virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) = 0; + + virtual uint32_t geometry_instance_get_pair_mask() = 0; + virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) = 0; + virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) = 0; + virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) = 0; + virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) = 0; + + virtual void geometry_instance_free(GeometryInstance *p_geometry_instance) = 0; + + /* SHADOW ATLAS API */ + + virtual RID + shadow_atlas_create() = 0; + virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = false) = 0; + virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0; + virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) = 0; + + virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) = 0; + virtual int get_directional_light_shadow_size(RID p_light_intance) = 0; + virtual void set_directional_shadow_count(int p_count) = 0; + + /* SDFGI UPDATE */ + + virtual void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) = 0; + virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const = 0; + virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const = 0; + virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const = 0; + virtual void sdfgi_update_probes(RID p_render_buffers, RID p_environment, const Vector<RID> &p_directional_lights, const RID *p_positional_light_instances, uint32_t p_positional_light_count) = 0; + + /* SKY API */ + + virtual RID sky_create() = 0; + virtual void sky_set_radiance_size(RID p_sky, int p_radiance_size) = 0; + virtual void sky_set_mode(RID p_sky, RS::SkyMode p_samples) = 0; + virtual void sky_set_material(RID p_sky, RID p_material) = 0; + virtual Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) = 0; + + /* ENVIRONMENT API */ + + virtual RID environment_create() = 0; + + virtual void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) = 0; + virtual void environment_set_sky(RID p_env, RID p_sky) = 0; + virtual void environment_set_sky_custom_fov(RID p_env, float p_scale) = 0; + virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) = 0; + virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0; + virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0; + virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0; + virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) = 0; +// FIXME: Disabled during Vulkan refactoring, should be ported. +#if 0 + virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) = 0; +#endif + + virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0; + virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0; + virtual void environment_glow_set_use_high_quality(bool p_enable) = 0; + + virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter) = 0; + + virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0; + virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0; + virtual void environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size) = 0; + virtual void environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size) = 0; + + virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) = 0; + virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) = 0; + + virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) = 0; + + virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; + + virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; + + virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) = 0; + virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) = 0; + virtual void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) = 0; + + virtual void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) = 0; + + virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) = 0; + + virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) = 0; + + virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) = 0; + + virtual bool is_environment(RID p_env) const = 0; + virtual RS::EnvironmentBG environment_get_background(RID p_env) const = 0; + virtual int environment_get_canvas_max_layer(RID p_env) const = 0; + + virtual RID camera_effects_create() = 0; + + virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) = 0; + virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) = 0; + + virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0; + virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0; + + virtual void shadows_quality_set(RS::ShadowQuality p_quality) = 0; + virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) = 0; + + virtual RID light_instance_create(RID p_light) = 0; + virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) = 0; + virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) = 0; + virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) = 0; + virtual void light_instance_mark_visible(RID p_light_instance) = 0; + virtual bool light_instances_can_render_shadow_cube() const { + return true; + } + + virtual RID reflection_atlas_create() = 0; + virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) = 0; + virtual int reflection_atlas_get_size(RID p_ref_atlas) const = 0; + + virtual RID reflection_probe_instance_create(RID p_probe) = 0; + virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) = 0; + virtual void reflection_probe_release_atlas_index(RID p_instance) = 0; + virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0; + virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0; + virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0; + virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0; + + virtual RID decal_instance_create(RID p_decal) = 0; + virtual void decal_instance_set_transform(RID p_decal, const Transform &p_transform) = 0; + + virtual RID lightmap_instance_create(RID p_lightmap) = 0; + virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform) = 0; + + virtual RID gi_probe_instance_create(RID p_gi_probe) = 0; + virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) = 0; + virtual bool gi_probe_needs_update(RID p_probe) const = 0; + virtual void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) = 0; + + virtual void gi_probe_set_quality(RS::GIProbeQuality) = 0; + + virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold) = 0; + + virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0) = 0; + virtual void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; + virtual void render_sdfgi(RID p_render_buffers, int p_region, const PagedArray<GeometryInstance *> &p_instances) = 0; + virtual void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_lights) = 0; + virtual void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) = 0; + + virtual void set_scene_pass(uint64_t p_pass) = 0; + virtual void set_time(double p_time, double p_step) = 0; + virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0; + + virtual RID render_buffers_create() = 0; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) = 0; + virtual void gi_set_use_half_resolution(bool p_enable) = 0; + + virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) = 0; + virtual bool screen_space_roughness_limiter_is_active() const = 0; + + virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) = 0; + virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) = 0; + + virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) = 0; + + virtual bool free(RID p_rid) = 0; + + virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0; + + virtual bool is_low_end() const = 0; + + virtual void update() = 0; + virtual ~RendererSceneRender() {} +}; + +#endif // RENDERINGSERVERSCENERENDER_H diff --git a/servers/rendering/rasterizer.cpp b/servers/rendering/renderer_storage.cpp index 566a14b655..a402ecc668 100644 --- a/servers/rendering/rasterizer.cpp +++ b/servers/rendering/renderer_storage.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rasterizer.cpp */ +/* renderer_storage.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,49 +28,41 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rasterizer.h" +#include "renderer_storage.h" -#include "core/os/os.h" -#include "core/print_string.h" +RendererStorage *RendererStorage::base_singleton = nullptr; -Rasterizer *(*Rasterizer::_create_func)() = nullptr; - -void RasterizerScene::InstanceDependency::instance_notify_changed(bool p_aabb, bool p_dependencies) { - for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { - E->key()->dependency_changed(p_aabb, p_dependencies); +void RendererStorage::Dependency::changed_notify(DependencyChangedNotification p_notification) { + for (Map<DependencyTracker *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { + if (E->key()->changed_callback) { + E->key()->changed_callback(p_notification, E->key()); + } } } -void RasterizerScene::InstanceDependency::instance_notify_deleted(RID p_deleted) { - for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { - E->key()->dependency_deleted(p_deleted); +void RendererStorage::Dependency::deleted_notify(const RID &p_rid) { + for (Map<DependencyTracker *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { + if (E->key()->deleted_callback) { + E->key()->deleted_callback(p_rid, E->key()); + } } - for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { + for (Map<DependencyTracker *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { E->key()->dependencies.erase(this); } - instances.clear(); } -RasterizerScene::InstanceDependency::~InstanceDependency() { +RendererStorage::Dependency::~Dependency() { #ifdef DEBUG_ENABLED if (instances.size()) { WARN_PRINT("Leaked instance dependency: Bug - did not call instance_notify_deleted when freeing."); - for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { + for (Map<DependencyTracker *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { E->key()->dependencies.erase(this); } } #endif } -Rasterizer *Rasterizer::create() { - return _create_func(); -} - -RasterizerCanvas *RasterizerCanvas::singleton = nullptr; - -RasterizerStorage *RasterizerStorage::base_singleton = nullptr; - -RasterizerStorage::RasterizerStorage() { +RendererStorage::RendererStorage() { base_singleton = this; } diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h new file mode 100644 index 0000000000..7a80c2b0bf --- /dev/null +++ b/servers/rendering/renderer_storage.h @@ -0,0 +1,625 @@ +/*************************************************************************/ +/* renderer_storage.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERINGSERVERSTORAGE_H +#define RENDERINGSERVERSTORAGE_H + +#include "servers/rendering_server.h" + +class RendererStorage { + Color default_clear_color; + +public: + enum DependencyChangedNotification { + DEPENDENCY_CHANGED_AABB, + DEPENDENCY_CHANGED_MATERIAL, + DEPENDENCY_CHANGED_MESH, + DEPENDENCY_CHANGED_MULTIMESH, + DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES, + DEPENDENCY_CHANGED_DECAL, + DEPENDENCY_CHANGED_SKELETON_DATA, + DEPENDENCY_CHANGED_SKELETON_BONES, + DEPENDENCY_CHANGED_LIGHT, + DEPENDENCY_CHANGED_REFLECTION_PROBE, + }; + + struct DependencyTracker; + +protected: + struct Dependency { + void changed_notify(DependencyChangedNotification p_notification); + void deleted_notify(const RID &p_rid); + + ~Dependency(); + + private: + friend struct DependencyTracker; + Map<DependencyTracker *, uint32_t> instances; + }; + +public: + struct DependencyTracker { + void *userdata = nullptr; + typedef void (*ChangedCallback)(DependencyChangedNotification, DependencyTracker *); + typedef void (*DeletedCallback)(const RID &, DependencyTracker *); + + ChangedCallback changed_callback = nullptr; + DeletedCallback deleted_callback = nullptr; + + void update_begin() { // call before updating dependencies + instance_version++; + } + + void update_dependency(Dependency *p_dependency) { //called internally, can't be used directly, use update functions in Storage + dependencies.insert(p_dependency); + p_dependency->instances[this] = instance_version; + } + + void update_end() { //call after updating dependencies + List<Pair<Dependency *, Map<DependencyTracker *, uint32_t>::Element *>> to_clean_up; + for (Set<Dependency *>::Element *E = dependencies.front(); E; E = E->next()) { + Dependency *dep = E->get(); + Map<DependencyTracker *, uint32_t>::Element *F = dep->instances.find(this); + ERR_CONTINUE(!F); + if (F->get() != instance_version) { + Pair<Dependency *, Map<DependencyTracker *, uint32_t>::Element *> p; + p.first = dep; + p.second = F; + to_clean_up.push_back(p); + } + } + + while (to_clean_up.size()) { + to_clean_up.front()->get().first->instances.erase(to_clean_up.front()->get().second); + to_clean_up.pop_front(); + } + } + + void clear() { // clear all dependencies + for (Set<Dependency *>::Element *E = dependencies.front(); E; E = E->next()) { + Dependency *dep = E->get(); + dep->instances.erase(this); + } + dependencies.clear(); + } + + ~DependencyTracker() { clear(); } + + private: + friend struct Dependency; + uint32_t instance_version = 0; + Set<Dependency *> dependencies; + }; + + /* TEXTURE API */ + + virtual RID texture_2d_create(const Ref<Image> &p_image) = 0; + virtual RID texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) = 0; + virtual RID texture_3d_create(Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) = 0; + virtual RID texture_proxy_create(RID p_base) = 0; //all slices, then all the mipmaps, must be coherent + + virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; //mostly used for video and streaming + virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; + virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) = 0; + virtual void texture_proxy_update(RID p_proxy, RID p_base) = 0; + + //these two APIs can be used together or in combination with the others. + virtual RID texture_2d_placeholder_create() = 0; + virtual RID texture_2d_layered_placeholder_create(RenderingServer::TextureLayeredType p_layered_type) = 0; + virtual RID texture_3d_placeholder_create() = 0; + + virtual Ref<Image> texture_2d_get(RID p_texture) const = 0; + virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const = 0; + virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const = 0; + + virtual void texture_replace(RID p_texture, RID p_by_texture) = 0; + virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) = 0; + + virtual void texture_set_path(RID p_texture, const String &p_path) = 0; + virtual String texture_get_path(RID p_texture) const = 0; + + virtual void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) = 0; + virtual void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) = 0; + virtual void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) = 0; + + virtual void texture_debug_usage(List<RS::TextureInfo> *r_info) = 0; + + virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) = 0; + + virtual Size2 texture_size_with_proxy(RID p_proxy) = 0; + + virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0; + virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0; + + /* CANVAS TEXTURE API */ + + virtual RID canvas_texture_create() = 0; + virtual void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) = 0; + virtual void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) = 0; + + virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) = 0; + virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) = 0; + + /* SHADER API */ + + virtual RID shader_create() = 0; + + virtual void shader_set_code(RID p_shader, const String &p_code) = 0; + virtual String shader_get_code(RID p_shader) const = 0; + virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0; + + virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) = 0; + virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const = 0; + virtual Variant shader_get_param_default(RID p_material, const StringName &p_param) const = 0; + + virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const = 0; + + /* COMMON MATERIAL API */ + + virtual RID material_create() = 0; + + virtual void material_set_render_priority(RID p_material, int priority) = 0; + virtual void material_set_shader(RID p_shader_material, RID p_shader) = 0; + + virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) = 0; + virtual Variant material_get_param(RID p_material, const StringName &p_param) const = 0; + + virtual void material_set_next_pass(RID p_material, RID p_next_material) = 0; + + virtual bool material_is_animated(RID p_material) = 0; + virtual bool material_casts_shadows(RID p_material) = 0; + + struct InstanceShaderParam { + PropertyInfo info; + int index; + Variant default_value; + }; + + virtual void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) = 0; + + virtual void material_update_dependency(RID p_material, DependencyTracker *p_instance) = 0; + + /* MESH API */ + + virtual RID mesh_create() = 0; + + virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) = 0; + + /// Returns stride + virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) = 0; + + virtual int mesh_get_blend_shape_count(RID p_mesh) const = 0; + + virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) = 0; + virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const = 0; + + virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0; + + virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) = 0; + virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const = 0; + + virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const = 0; + + virtual int mesh_get_surface_count(RID p_mesh) const = 0; + + virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0; + virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0; + + virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) = 0; + + virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) = 0; + + virtual void mesh_clear(RID p_mesh) = 0; + + virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) = 0; + + /* MESH INSTANCE */ + + virtual RID mesh_instance_create(RID p_base) = 0; + virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) = 0; + virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) = 0; + virtual void mesh_instance_check_for_update(RID p_mesh_instance) = 0; + virtual void update_mesh_instances() = 0; + + /* MULTIMESH API */ + + virtual RID multimesh_create() = 0; + + virtual void multimesh_allocate(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0; + + virtual int multimesh_get_instance_count(RID p_multimesh) const = 0; + + virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0; + virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) = 0; + virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) = 0; + virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0; + virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0; + + virtual RID multimesh_get_mesh(RID p_multimesh) const = 0; + + virtual Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0; + virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0; + virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0; + virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0; + + virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0; + virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const = 0; + + virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0; + virtual int multimesh_get_visible_instances(RID p_multimesh) const = 0; + + virtual AABB multimesh_get_aabb(RID p_multimesh) const = 0; + + /* IMMEDIATE API */ + + virtual RID immediate_create() = 0; + virtual void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) = 0; + virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) = 0; + virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal) = 0; + virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent) = 0; + virtual void immediate_color(RID p_immediate, const Color &p_color) = 0; + virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv) = 0; + virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) = 0; + virtual void immediate_end(RID p_immediate) = 0; + virtual void immediate_clear(RID p_immediate) = 0; + virtual void immediate_set_material(RID p_immediate, RID p_material) = 0; + virtual RID immediate_get_material(RID p_immediate) const = 0; + virtual AABB immediate_get_aabb(RID p_immediate) const = 0; + + /* SKELETON API */ + + virtual RID skeleton_create() = 0; + virtual void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0; + virtual int skeleton_get_bone_count(RID p_skeleton) const = 0; + virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) = 0; + virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0; + virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0; + virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0; + virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0; + + /* Light API */ + + virtual RID light_create(RS::LightType p_type) = 0; + + RID directional_light_create() { return light_create(RS::LIGHT_DIRECTIONAL); } + RID omni_light_create() { return light_create(RS::LIGHT_OMNI); } + RID spot_light_create() { return light_create(RS::LIGHT_SPOT); } + + virtual void light_set_color(RID p_light, const Color &p_color) = 0; + virtual void light_set_param(RID p_light, RS::LightParam p_param, float p_value) = 0; + virtual void light_set_shadow(RID p_light, bool p_enabled) = 0; + virtual void light_set_shadow_color(RID p_light, const Color &p_color) = 0; + virtual void light_set_projector(RID p_light, RID p_texture) = 0; + virtual void light_set_negative(RID p_light, bool p_enable) = 0; + virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0; + virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0; + virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) = 0; + virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) = 0; + + virtual void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) = 0; + + virtual void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) = 0; + virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0; + virtual bool light_directional_get_blend_splits(RID p_light) const = 0; + virtual void light_directional_set_sky_only(RID p_light, bool p_sky_only) = 0; + virtual bool light_directional_is_sky_only(RID p_light) const = 0; + virtual void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) = 0; + virtual RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const = 0; + + virtual RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) = 0; + virtual RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) = 0; + + virtual bool light_has_shadow(RID p_light) const = 0; + + virtual RS::LightType light_get_type(RID p_light) const = 0; + virtual AABB light_get_aabb(RID p_light) const = 0; + virtual float light_get_param(RID p_light, RS::LightParam p_param) = 0; + virtual Color light_get_color(RID p_light) = 0; + virtual RS::LightBakeMode light_get_bake_mode(RID p_light) = 0; + virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) = 0; + virtual uint64_t light_get_version(RID p_light) const = 0; + + /* PROBE API */ + + virtual RID reflection_probe_create() = 0; + + virtual void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) = 0; + virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0; + virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity) = 0; + virtual void reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) = 0; + virtual void reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) = 0; + virtual void reflection_probe_set_ambient_energy(RID p_probe, float p_energy) = 0; + virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance) = 0; + virtual void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) = 0; + virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) = 0; + virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable) = 0; + virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) = 0; + virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) = 0; + virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0; + virtual void reflection_probe_set_lod_threshold(RID p_probe, float p_ratio) = 0; + + virtual AABB reflection_probe_get_aabb(RID p_probe) const = 0; + virtual RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const = 0; + virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const = 0; + virtual Vector3 reflection_probe_get_extents(RID p_probe) const = 0; + virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const = 0; + virtual float reflection_probe_get_origin_max_distance(RID p_probe) const = 0; + virtual bool reflection_probe_renders_shadows(RID p_probe) const = 0; + virtual float reflection_probe_get_lod_threshold(RID p_probe) const = 0; + + virtual void base_update_dependency(RID p_base, DependencyTracker *p_instance) = 0; + virtual void skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) = 0; + + /* DECAL API */ + + virtual RID decal_create() = 0; + virtual void decal_set_extents(RID p_decal, const Vector3 &p_extents) = 0; + virtual void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) = 0; + virtual void decal_set_emission_energy(RID p_decal, float p_energy) = 0; + virtual void decal_set_albedo_mix(RID p_decal, float p_mix) = 0; + virtual void decal_set_modulate(RID p_decal, const Color &p_modulate) = 0; + virtual void decal_set_cull_mask(RID p_decal, uint32_t p_layers) = 0; + virtual void decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) = 0; + virtual void decal_set_fade(RID p_decal, float p_above, float p_below) = 0; + virtual void decal_set_normal_fade(RID p_decal, float p_fade) = 0; + + virtual AABB decal_get_aabb(RID p_decal) const = 0; + + /* GI PROBE API */ + + virtual RID gi_probe_create() = 0; + + virtual void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0; + + virtual AABB gi_probe_get_bounds(RID p_gi_probe) const = 0; + virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0; + virtual Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const = 0; + virtual Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const = 0; + virtual Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const = 0; + + virtual Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const = 0; + virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) = 0; + virtual float gi_probe_get_dynamic_range(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_propagation(RID p_gi_probe, float p_range) = 0; + virtual float gi_probe_get_propagation(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_energy(RID p_gi_probe, float p_energy) = 0; + virtual float gi_probe_get_energy(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_ao(RID p_gi_probe, float p_ao) = 0; + virtual float gi_probe_get_ao(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_ao_size(RID p_gi_probe, float p_strength) = 0; + virtual float gi_probe_get_ao_size(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_bias(RID p_gi_probe, float p_bias) = 0; + virtual float gi_probe_get_bias(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) = 0; + virtual float gi_probe_get_normal_bias(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_interior(RID p_gi_probe, bool p_enable) = 0; + virtual bool gi_probe_is_interior(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) = 0; + virtual bool gi_probe_is_using_two_bounces(RID p_gi_probe) const = 0; + + virtual void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) = 0; + virtual float gi_probe_get_anisotropy_strength(RID p_gi_probe) const = 0; + + virtual uint32_t gi_probe_get_version(RID p_probe) = 0; + + /* LIGHTMAP CAPTURE */ + + virtual RID lightmap_create() = 0; + + virtual void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) = 0; + virtual void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) = 0; + virtual void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) = 0; + virtual void lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) = 0; + virtual PackedVector3Array lightmap_get_probe_capture_points(RID p_lightmap) const = 0; + virtual PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const = 0; + virtual PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const = 0; + virtual PackedInt32Array lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const = 0; + virtual AABB lightmap_get_aabb(RID p_lightmap) const = 0; + virtual void lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) = 0; + virtual bool lightmap_is_interior(RID p_lightmap) const = 0; + virtual void lightmap_set_probe_capture_update_speed(float p_speed) = 0; + virtual float lightmap_get_probe_capture_update_speed() const = 0; + + /* PARTICLES */ + + virtual RID particles_create() = 0; + + virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0; + virtual bool particles_get_emitting(RID p_particles) = 0; + + virtual void particles_set_amount(RID p_particles, int p_amount) = 0; + virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0; + virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0; + virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0; + virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0; + virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0; + virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) = 0; + virtual void particles_set_speed_scale(RID p_particles, float p_scale) = 0; + virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0; + virtual void particles_set_process_material(RID p_particles, RID p_material) = 0; + virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0; + virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0; + virtual void particles_set_collision_base_size(RID p_particles, float p_size) = 0; + virtual void particles_restart(RID p_particles) = 0; + virtual void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0; + virtual void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) = 0; + + virtual bool particles_is_inactive(RID p_particles) const = 0; + + virtual void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) = 0; + + virtual void particles_set_draw_passes(RID p_particles, int p_count) = 0; + virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) = 0; + + virtual void particles_request_process(RID p_particles) = 0; + virtual AABB particles_get_current_aabb(RID p_particles) = 0; + virtual AABB particles_get_aabb(RID p_particles) const = 0; + + virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform) = 0; + + virtual int particles_get_draw_passes(RID p_particles) const = 0; + virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const = 0; + + virtual void particles_set_view_axis(RID p_particles, const Vector3 &p_axis) = 0; + + virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance) = 0; + virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance) = 0; + + virtual void update_particles() = 0; + + /* PARTICLES COLLISION */ + + virtual RID particles_collision_create() = 0; + virtual void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) = 0; + virtual void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) = 0; + virtual void particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius) = 0; //for spheres + virtual void particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) = 0; //for non-spheres + virtual void particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength) = 0; + virtual void particles_collision_set_attractor_directionality(RID p_particles_collision, float p_directionality) = 0; + virtual void particles_collision_set_attractor_attenuation(RID p_particles_collision, float p_curve) = 0; + virtual void particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) = 0; //for SDF and vector field, heightfield is dynamic + virtual void particles_collision_height_field_update(RID p_particles_collision) = 0; //for SDF and vector field + virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) = 0; //for SDF and vector field + virtual AABB particles_collision_get_aabb(RID p_particles_collision) const = 0; + virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 0; + virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const = 0; + + //used from 2D and 3D + virtual RID particles_collision_instance_create(RID p_collision) = 0; + virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform) = 0; + virtual void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) = 0; + + /* GLOBAL VARIABLES */ + + virtual void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) = 0; + virtual void global_variable_remove(const StringName &p_name) = 0; + virtual Vector<StringName> global_variable_get_list() const = 0; + + virtual void global_variable_set(const StringName &p_name, const Variant &p_value) = 0; + virtual void global_variable_set_override(const StringName &p_name, const Variant &p_value) = 0; + virtual Variant global_variable_get(const StringName &p_name) const = 0; + virtual RS::GlobalVariableType global_variable_get_type(const StringName &p_name) const = 0; + + virtual void global_variables_load_settings(bool p_load_textures = true) = 0; + virtual void global_variables_clear() = 0; + + virtual int32_t global_variables_instance_allocate(RID p_instance) = 0; + virtual void global_variables_instance_free(RID p_instance) = 0; + virtual void global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) = 0; + + /* RENDER TARGET */ + + enum RenderTargetFlags { + RENDER_TARGET_TRANSPARENT, + RENDER_TARGET_DIRECT_TO_SCREEN, + RENDER_TARGET_FLAG_MAX + }; + + virtual RID render_target_create() = 0; + virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) = 0; + virtual void render_target_set_size(RID p_render_target, int p_width, int p_height) = 0; + virtual RID render_target_get_texture(RID p_render_target) = 0; + virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0; + virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0; + virtual bool render_target_was_used(RID p_render_target) = 0; + virtual void render_target_set_as_unused(RID p_render_target) = 0; + + virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) = 0; + virtual bool render_target_is_clear_requested(RID p_render_target) = 0; + virtual Color render_target_get_clear_request_color(RID p_render_target) = 0; + virtual void render_target_disable_clear_request(RID p_render_target) = 0; + virtual void render_target_do_clear_request(RID p_render_target) = 0; + + virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) = 0; + virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const = 0; + + virtual RS::InstanceType get_base_type(RID p_rid) const = 0; + virtual bool free(RID p_rid) = 0; + + virtual bool has_os_feature(const String &p_feature) const = 0; + + virtual void update_dirty_resources() = 0; + + virtual void set_debug_generate_wireframes(bool p_generate) = 0; + + virtual void render_info_begin_capture() = 0; + virtual void render_info_end_capture() = 0; + virtual int get_captured_render_info(RS::RenderInfo p_info) = 0; + + virtual int get_render_info(RS::RenderInfo p_info) = 0; + virtual String get_video_adapter_name() const = 0; + virtual String get_video_adapter_vendor() const = 0; + + static RendererStorage *base_singleton; + + void set_default_clear_color(const Color &p_color) { + default_clear_color = p_color; + } + + Color get_default_clear_color() const { + return default_clear_color; + } +#define TIMESTAMP_BEGIN() \ + { \ + if (RSG::storage->capturing_timestamps) \ + RSG::storage->capture_timestamps_begin(); \ + } + +#define RENDER_TIMESTAMP(m_text) \ + { \ + if (RSG::storage->capturing_timestamps) \ + RSG::storage->capture_timestamp(m_text); \ + } + + bool capturing_timestamps = false; + + virtual void capture_timestamps_begin() = 0; + virtual void capture_timestamp(const String &p_name) = 0; + virtual uint32_t get_captured_timestamps_count() const = 0; + virtual uint64_t get_captured_timestamps_frame() const = 0; + virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const = 0; + virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const = 0; + virtual String get_captured_timestamp_name(uint32_t p_index) const = 0; + + RendererStorage(); + virtual ~RendererStorage() {} +}; + +#endif // RENDERINGSERVERSTORAGE_H diff --git a/servers/rendering/renderer_thread_pool.cpp b/servers/rendering/renderer_thread_pool.cpp new file mode 100644 index 0000000000..98050dd508 --- /dev/null +++ b/servers/rendering/renderer_thread_pool.cpp @@ -0,0 +1,42 @@ +/*************************************************************************/ +/* renderer_thread_pool.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "renderer_thread_pool.h" + +RendererThreadPool *RendererThreadPool::singleton = nullptr; + +RendererThreadPool::RendererThreadPool() { + singleton = this; + thread_work_pool.init(); +} + +RendererThreadPool::~RendererThreadPool() { + thread_work_pool.finish(); +} diff --git a/servers/rendering/renderer_thread_pool.h b/servers/rendering/renderer_thread_pool.h new file mode 100644 index 0000000000..ae25415a0d --- /dev/null +++ b/servers/rendering/renderer_thread_pool.h @@ -0,0 +1,45 @@ +/*************************************************************************/ +/* renderer_thread_pool.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RENDERERTHREADPOOL_H +#define RENDERERTHREADPOOL_H + +#include "core/templates/thread_work_pool.h" + +class RendererThreadPool { +public: + ThreadWorkPool thread_work_pool; + + static RendererThreadPool *singleton; + RendererThreadPool(); + ~RendererThreadPool(); +}; + +#endif // RENDERERTHREADPOOL_H diff --git a/servers/rendering/rendering_server_viewport.cpp b/servers/rendering/renderer_viewport.cpp index b5d8f0da40..d52da5b331 100644 --- a/servers/rendering/rendering_server_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rendering_server_viewport.cpp */ +/* renderer_viewport.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,14 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rendering_server_viewport.h" +#include "renderer_viewport.h" -#include "core/project_settings.h" -#include "rendering_server_canvas.h" +#include "core/config/project_settings.h" +#include "renderer_canvas_cull.h" +#include "renderer_scene_cull.h" #include "rendering_server_globals.h" -#include "rendering_server_scene.h" -static Transform2D _canvas_get_transform(RenderingServerViewport::Viewport *p_viewport, RenderingServerCanvas::Canvas *p_canvas, RenderingServerViewport::Viewport::CanvasData *p_canvas_data, const Vector2 &p_vp_size) { +static Transform2D _canvas_get_transform(RendererViewport::Viewport *p_viewport, RendererCanvasCull::Canvas *p_canvas, RendererViewport::Viewport::CanvasData *p_canvas_data, const Vector2 &p_vp_size) { Transform2D xf = p_viewport->global_transform; float scale = 1.0; @@ -71,7 +71,7 @@ static Transform2D _canvas_get_transform(RenderingServerViewport::Viewport *p_vi return xf; } -void RenderingServerViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye) { +void RendererViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye) { RENDER_TIMESTAMP(">Begin Rendering 3D Scene"); Ref<XRInterface> xr_interface; @@ -79,15 +79,16 @@ void RenderingServerViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p xr_interface = XRServer::get_singleton()->get_primary_interface(); } + float screen_lod_threshold = p_viewport->lod_threshold / float(p_viewport->size.width); if (p_viewport->use_xr && xr_interface.is_valid()) { - RSG::scene->render_camera(p_viewport->render_buffers, xr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); + RSG::scene->render_camera(p_viewport->render_buffers, xr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas); } else { - RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); + RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas); } RENDER_TIMESTAMP("<End Rendering 3D Scene"); } -void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye) { +void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye) { if (p_viewport->measure_render_time) { String rt_id = "vp_begin_" + itos(p_viewport->self.get_id()); RSG::storage->capture_timestamp(rt_id); @@ -101,17 +102,15 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: Color bgcolor = RSG::storage->get_default_clear_color(); - if (!p_viewport->hide_canvas && !p_viewport->disable_environment && RSG::scene->scenario_owner.owns(p_viewport->scenario)) { - RenderingServerScene::Scenario *scenario = RSG::scene->scenario_owner.getornull(p_viewport->scenario); - ERR_FAIL_COND(!scenario); - if (RSG::scene_render->is_environment(scenario->environment)) { - scenario_draw_canvas_bg = RSG::scene_render->environment_get_background(scenario->environment) == RS::ENV_BG_CANVAS; - - scenario_canvas_max_layer = RSG::scene_render->environment_get_canvas_max_layer(scenario->environment); + if (!p_viewport->hide_canvas && !p_viewport->disable_environment && RSG::scene->is_scenario(p_viewport->scenario)) { + RID environment = RSG::scene->scenario_get_environment(p_viewport->scenario); + if (RSG::scene->is_environment(environment)) { + scenario_draw_canvas_bg = RSG::scene->environment_get_background(environment) == RS::ENV_BG_CANVAS; + scenario_canvas_max_layer = RSG::scene->environment_get_canvas_max_layer(environment); } } - bool can_draw_3d = RSG::scene->camera_owner.owns(p_viewport->camera); + bool can_draw_3d = RSG::scene->is_camera(p_viewport->camera); if (p_viewport->clear_mode != RS::VIEWPORT_CLEAR_NEVER) { if (p_viewport->transparent_bg) { @@ -124,8 +123,8 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: if ((scenario_draw_canvas_bg || can_draw_3d) && !p_viewport->render_buffers.is_valid()) { //wants to draw 3D but there is no render buffer, create - p_viewport->render_buffers = RSG::scene_render->render_buffers_create(); - RSG::scene_render->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, p_viewport->size.width, p_viewport->size.height, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_debanding); + p_viewport->render_buffers = RSG::scene->render_buffers_create(); + RSG::scene->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, p_viewport->size.width, p_viewport->size.height, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_debanding); } RSG::storage->render_target_request_clear(p_viewport->render_target, bgcolor); @@ -140,24 +139,58 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: Map<Viewport::CanvasKey, Viewport::CanvasData *> canvas_map; Rect2 clip_rect(0, 0, p_viewport->size.x, p_viewport->size.y); - RasterizerCanvas::Light *lights = nullptr; - RasterizerCanvas::Light *lights_with_shadow = nullptr; - RasterizerCanvas::Light *lights_with_mask = nullptr; + RendererCanvasRender::Light *lights = nullptr; + RendererCanvasRender::Light *lights_with_shadow = nullptr; + + RendererCanvasRender::Light *directional_lights = nullptr; + RendererCanvasRender::Light *directional_lights_with_shadow = nullptr; + + if (p_viewport->sdf_active) { + //process SDF + + Rect2 sdf_rect = RSG::storage->render_target_get_sdf_rect(p_viewport->render_target); + + RendererCanvasRender::LightOccluderInstance *occluders = nullptr; + + //make list of occluders + for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) { + RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get().canvas); + Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size); + + for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) { + if (!F->get()->enabled) { + continue; + } + F->get()->xform_cache = xf * F->get()->xform; + + if (sdf_rect.intersects_transformed(F->get()->xform_cache, F->get()->aabb_cache)) { + F->get()->next = occluders; + occluders = F->get(); + } + } + } + + RSG::canvas_render->render_sdf(p_viewport->render_target, occluders); + + p_viewport->sdf_active = false; // if used, gets set active again + } + Rect2 shadow_rect; int light_count = 0; int shadow_count = 0; + int directional_light_count = 0; RENDER_TIMESTAMP("Cull Canvas Lights"); for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) { - RenderingServerCanvas::Canvas *canvas = static_cast<RenderingServerCanvas::Canvas *>(E->get().canvas); + RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get().canvas); Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size); //find lights in canvas - for (Set<RasterizerCanvas::Light *>::Element *F = canvas->lights.front(); F; F = F->next()) { - RasterizerCanvas::Light *cl = F->get(); + for (Set<RendererCanvasRender::Light *>::Element *F = canvas->lights.front(); F; F = F->next()) { + RendererCanvasRender::Light *cl = F->get(); if (cl->enabled && cl->texture.is_valid()) { //not super efficient.. Size2 tsize = RSG::storage->texture_size_with_proxy(cl->texture); @@ -186,16 +219,31 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: lights_with_shadow = cl; cl->radius_cache = cl->rect_cache.size.length(); } - if (cl->mode == RS::CANVAS_LIGHT_MODE_MASK) { - cl->mask_next_ptr = lights_with_mask; - lights_with_mask = cl; - } light_count++; } //guess this is not needed, but keeping because it may be - //RSG::canvas_render->light_internal_update(cl->light_internal, cl); + } + } + + for (Set<RendererCanvasRender::Light *>::Element *F = canvas->directional_lights.front(); F; F = F->next()) { + RendererCanvasRender::Light *cl = F->get(); + if (cl->enabled) { + cl->filter_next_ptr = directional_lights; + directional_lights = cl; + cl->xform_cache = xf * cl->xform; + cl->xform_cache.elements[2] = Vector2(); //translation is pointless + if (cl->use_shadow) { + cl->shadows_next_ptr = directional_lights_with_shadow; + directional_lights_with_shadow = cl; + } + + directional_light_count++; + + if (directional_light_count == RS::MAX_2D_DIRECTIONAL_LIGHTS) { + break; + } } } @@ -205,17 +253,17 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: if (lights_with_shadow) { //update shadows if any - RasterizerCanvas::LightOccluderInstance *occluders = nullptr; + RendererCanvasRender::LightOccluderInstance *occluders = nullptr; RENDER_TIMESTAMP(">Render 2D Shadows"); RENDER_TIMESTAMP("Cull Occluders"); //make list of occluders for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) { - RenderingServerCanvas::Canvas *canvas = static_cast<RenderingServerCanvas::Canvas *>(E->get().canvas); + RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get().canvas); Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size); - for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) { + for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) { if (!F->get()->enabled) { continue; } @@ -228,7 +276,7 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: } //update the light shadowmaps with them - RasterizerCanvas::Light *light = lights_with_shadow; + RendererCanvasRender::Light *light = lights_with_shadow; while (light) { RENDER_TIMESTAMP("Render Shadow"); @@ -236,10 +284,92 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: light = light->shadows_next_ptr; } - //RSG::canvas_render->reset_canvas(); RENDER_TIMESTAMP("<End rendering 2D Shadows"); } + if (directional_lights_with_shadow) { + //update shadows if any + RendererCanvasRender::Light *light = directional_lights_with_shadow; + while (light) { + Vector2 light_dir = -light->xform_cache.elements[1].normalized(); // Y is light direction + float cull_distance = light->directional_distance; + + Vector2 light_dir_sign; + light_dir_sign.x = (ABS(light_dir.x) < CMP_EPSILON) ? 0.0 : ((light_dir.x > 0.0) ? 1.0 : -1.0); + light_dir_sign.y = (ABS(light_dir.y) < CMP_EPSILON) ? 0.0 : ((light_dir.y > 0.0) ? 1.0 : -1.0); + + Vector2 points[6]; + int point_count = 0; + + for (int j = 0; j < 4; j++) { + static const Vector2 signs[4] = { Vector2(1, 1), Vector2(1, 0), Vector2(0, 0), Vector2(0, 1) }; + Vector2 sign_cmp = signs[j] * 2.0 - Vector2(1.0, 1.0); + Vector2 point = clip_rect.position + clip_rect.size * signs[j]; + + if (sign_cmp == light_dir_sign) { + //both point in same direction, plot offseted + points[point_count++] = point + light_dir * cull_distance; + } else if (sign_cmp.x == light_dir_sign.x || sign_cmp.y == light_dir_sign.y) { + int next_j = (j + 1) % 4; + Vector2 next_sign_cmp = signs[next_j] * 2.0 - Vector2(1.0, 1.0); + + //one point in the same direction, plot segment + + if (next_sign_cmp.x == light_dir_sign.x || next_sign_cmp.y == light_dir_sign.y) { + if (light_dir_sign.x != 0.0 || light_dir_sign.y != 0.0) { + points[point_count++] = point; + } + points[point_count++] = point + light_dir * cull_distance; + } else { + points[point_count++] = point + light_dir * cull_distance; + if (light_dir_sign.x != 0.0 || light_dir_sign.y != 0.0) { + points[point_count++] = point; + } + } + } else { + //plot normally + points[point_count++] = point; + } + } + + Vector2 xf_points[6]; + + RendererCanvasRender::LightOccluderInstance *occluders = nullptr; + + RENDER_TIMESTAMP(">Render Directional 2D Shadows"); + + //make list of occluders + int occ_cullded = 0; + for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) { + RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get().canvas); + Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size); + + for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) { + if (!F->get()->enabled) { + continue; + } + F->get()->xform_cache = xf * F->get()->xform; + Transform2D localizer = F->get()->xform_cache.affine_inverse(); + + for (int j = 0; j < point_count; j++) { + xf_points[j] = localizer.xform(points[j]); + } + if (F->get()->aabb_cache.intersects_filled_polygon(xf_points, point_count)) { + F->get()->next = occluders; + occluders = F->get(); + occ_cullded++; + } + } + } + + RSG::canvas_render->light_update_directional_shadow(light->light_internal, shadow_count++, light->xform_cache, light->item_shadow_mask, cull_distance, clip_rect, occluders); + + light = light->shadows_next_ptr; + } + + RENDER_TIMESTAMP("<Render Directional 2D Shadows"); + } + if (scenario_draw_canvas_bg && canvas_map.front() && canvas_map.front()->key().get_layer() > scenario_canvas_max_layer) { if (!can_draw_3d) { RSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas); @@ -250,13 +380,14 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: } for (Map<Viewport::CanvasKey, Viewport::CanvasData *>::Element *E = canvas_map.front(); E; E = E->next()) { - RenderingServerCanvas::Canvas *canvas = static_cast<RenderingServerCanvas::Canvas *>(E->get()->canvas); + RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get()->canvas); Transform2D xform = _canvas_get_transform(p_viewport, canvas, E->get(), clip_rect.size); - RasterizerCanvas::Light *canvas_lights = nullptr; + RendererCanvasRender::Light *canvas_lights = nullptr; + RendererCanvasRender::Light *canvas_directional_lights = nullptr; - RasterizerCanvas::Light *ptr = lights; + RendererCanvasRender::Light *ptr = lights; while (ptr) { if (E->get()->layer >= ptr->layer_min && E->get()->layer <= ptr->layer_max) { ptr->next_ptr = canvas_lights; @@ -265,7 +396,19 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: ptr = ptr->filter_next_ptr; } - RSG::canvas->render_canvas(p_viewport->render_target, canvas, xform, canvas_lights, lights_with_mask, clip_rect, p_viewport->texture_filter, p_viewport->texture_repeat, p_viewport->snap_2d_transforms_to_pixel, p_viewport->snap_2d_vertices_to_pixel); + ptr = directional_lights; + while (ptr) { + if (E->get()->layer >= ptr->layer_min && E->get()->layer <= ptr->layer_max) { + ptr->next_ptr = canvas_directional_lights; + canvas_directional_lights = ptr; + } + ptr = ptr->filter_next_ptr; + } + + RSG::canvas->render_canvas(p_viewport->render_target, canvas, xform, canvas_lights, canvas_directional_lights, clip_rect, p_viewport->texture_filter, p_viewport->texture_repeat, p_viewport->snap_2d_transforms_to_pixel, p_viewport->snap_2d_vertices_to_pixel); + if (RSG::canvas->was_sdf_used()) { + p_viewport->sdf_active = true; + } i++; if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) { @@ -286,8 +429,6 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: _draw_3d(p_viewport, p_eye); } } - - //RSG::canvas_render->canvas_debug_viewport_shadows(lights_with_shadow); } if (RSG::storage->render_target_is_clear_requested(p_viewport->render_target)) { @@ -302,7 +443,7 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface:: } } -void RenderingServerViewport::draw_viewports() { +void RendererViewport::draw_viewports() { timestamp_vp_map.clear(); // get our xr interface in case we need it @@ -322,7 +463,7 @@ void RenderingServerViewport::draw_viewports() { //sort viewports active_viewports.sort_custom<ViewportSort>(); - Map<DisplayServer::WindowID, Vector<Rasterizer::BlitToScreen>> blit_to_screen_list; + Map<DisplayServer::WindowID, Vector<RendererCompositor::BlitToScreen>> blit_to_screen_list; //draw viewports RENDER_TIMESTAMP(">Render Viewports"); @@ -417,7 +558,7 @@ void RenderingServerViewport::draw_viewports() { { RSG::storage->render_target_set_external_texture(vp->render_target, 0); - RSG::scene_render->set_debug_draw_mode(vp->debug_draw); + RSG::scene->set_debug_draw_mode(vp->debug_draw); RSG::storage->render_info_begin_capture(); // render standard mono camera @@ -433,7 +574,7 @@ void RenderingServerViewport::draw_viewports() { if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID && (!vp->viewport_render_direct_to_screen || !RSG::rasterizer->is_low_end())) { //copy to screen if set as such - Rasterizer::BlitToScreen blit; + RendererCompositor::BlitToScreen blit; blit.render_target = vp->render_target; if (vp->viewport_to_screen_rect != Rect2()) { blit.rect = vp->viewport_to_screen_rect; @@ -443,7 +584,7 @@ void RenderingServerViewport::draw_viewports() { } if (!blit_to_screen_list.has(vp->viewport_to_screen)) { - blit_to_screen_list[vp->viewport_to_screen] = Vector<Rasterizer::BlitToScreen>(); + blit_to_screen_list[vp->viewport_to_screen] = Vector<RendererCompositor::BlitToScreen>(); } blit_to_screen_list[vp->viewport_to_screen].push_back(blit); @@ -456,18 +597,18 @@ void RenderingServerViewport::draw_viewports() { RENDER_TIMESTAMP("<Rendering Viewport " + itos(i)); } - RSG::scene_render->set_debug_draw_mode(RS::VIEWPORT_DEBUG_DRAW_DISABLED); + RSG::scene->set_debug_draw_mode(RS::VIEWPORT_DEBUG_DRAW_DISABLED); RENDER_TIMESTAMP("<Render Viewports"); //this needs to be called to make screen swapping more efficient RSG::rasterizer->prepare_for_blitting_render_targets(); - for (Map<int, Vector<Rasterizer::BlitToScreen>>::Element *E = blit_to_screen_list.front(); E; E = E->next()) { + for (Map<int, Vector<RendererCompositor::BlitToScreen>>::Element *E = blit_to_screen_list.front(); E; E = E->next()) { RSG::rasterizer->blit_render_targets_to_screen(E->key(), E->get().ptr(), E->get().size()); } } -RID RenderingServerViewport::viewport_create() { +RID RendererViewport::viewport_create() { Viewport *viewport = memnew(Viewport); RID rid = viewport_owner.make_rid(viewport); @@ -476,20 +617,20 @@ RID RenderingServerViewport::viewport_create() { viewport->hide_scenario = false; viewport->hide_canvas = false; viewport->render_target = RSG::storage->render_target_create(); - viewport->shadow_atlas = RSG::scene_render->shadow_atlas_create(); + viewport->shadow_atlas = RSG::scene->shadow_atlas_create(); viewport->viewport_render_direct_to_screen = false; return rid; } -void RenderingServerViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) { +void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->use_xr = p_use_xr; } -void RenderingServerViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) { +void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) { ERR_FAIL_COND(p_width < 0 && p_height < 0); Viewport *viewport = viewport_owner.getornull(p_viewport); @@ -499,15 +640,15 @@ void RenderingServerViewport::viewport_set_size(RID p_viewport, int p_width, int RSG::storage->render_target_set_size(viewport->render_target, p_width, p_height); if (viewport->render_buffers.is_valid()) { if (p_width == 0 || p_height == 0) { - RSG::scene_render->free(viewport->render_buffers); + RSG::scene->free(viewport->render_buffers); viewport->render_buffers = RID(); } else { - RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, viewport->use_debanding); + RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, viewport->use_debanding); } } } -void RenderingServerViewport::viewport_set_active(RID p_viewport, bool p_active) { +void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -519,21 +660,21 @@ void RenderingServerViewport::viewport_set_active(RID p_viewport, bool p_active) } } -void RenderingServerViewport::viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) { +void RendererViewport::viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->parent = p_parent_viewport; } -void RenderingServerViewport::viewport_set_clear_mode(RID p_viewport, RS::ViewportClearMode p_clear_mode) { +void RendererViewport::viewport_set_clear_mode(RID p_viewport, RS::ViewportClearMode p_clear_mode) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->clear_mode = p_clear_mode; } -void RenderingServerViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect, DisplayServer::WindowID p_screen) { +void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect, DisplayServer::WindowID p_screen) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -559,7 +700,7 @@ void RenderingServerViewport::viewport_attach_to_screen(RID p_viewport, const Re } } -void RenderingServerViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable) { +void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -573,7 +714,7 @@ void RenderingServerViewport::viewport_set_render_direct_to_screen(RID p_viewpor RSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y); } - RSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN, p_enable); + RSG::storage->render_target_set_flag(viewport->render_target, RendererStorage::RENDER_TARGET_DIRECT_TO_SCREEN, p_enable); viewport->viewport_render_direct_to_screen = p_enable; // if attached to screen already, setup screen size and position, this needs to happen after setting flag to avoid an unnecessary buffer allocation @@ -583,61 +724,61 @@ void RenderingServerViewport::viewport_set_render_direct_to_screen(RID p_viewpor } } -void RenderingServerViewport::viewport_set_update_mode(RID p_viewport, RS::ViewportUpdateMode p_mode) { +void RendererViewport::viewport_set_update_mode(RID p_viewport, RS::ViewportUpdateMode p_mode) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->update_mode = p_mode; } -RID RenderingServerViewport::viewport_get_texture(RID p_viewport) const { +RID RendererViewport::viewport_get_texture(RID p_viewport) const { const Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND_V(!viewport, RID()); return RSG::storage->render_target_get_texture(viewport->render_target); } -void RenderingServerViewport::viewport_set_hide_scenario(RID p_viewport, bool p_hide) { +void RendererViewport::viewport_set_hide_scenario(RID p_viewport, bool p_hide) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->hide_scenario = p_hide; } -void RenderingServerViewport::viewport_set_hide_canvas(RID p_viewport, bool p_hide) { +void RendererViewport::viewport_set_hide_canvas(RID p_viewport, bool p_hide) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->hide_canvas = p_hide; } -void RenderingServerViewport::viewport_set_disable_environment(RID p_viewport, bool p_disable) { +void RendererViewport::viewport_set_disable_environment(RID p_viewport, bool p_disable) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->disable_environment = p_disable; } -void RenderingServerViewport::viewport_attach_camera(RID p_viewport, RID p_camera) { +void RendererViewport::viewport_attach_camera(RID p_viewport, RID p_camera) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->camera = p_camera; } -void RenderingServerViewport::viewport_set_scenario(RID p_viewport, RID p_scenario) { +void RendererViewport::viewport_set_scenario(RID p_viewport, RID p_scenario) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->scenario = p_scenario; } -void RenderingServerViewport::viewport_attach_canvas(RID p_viewport, RID p_canvas) { +void RendererViewport::viewport_attach_canvas(RID p_viewport, RID p_canvas) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); ERR_FAIL_COND(viewport->canvas_map.has(p_canvas)); - RenderingServerCanvas::Canvas *canvas = RSG::canvas->canvas_owner.getornull(p_canvas); + RendererCanvasCull::Canvas *canvas = RSG::canvas->canvas_owner.getornull(p_canvas); ERR_FAIL_COND(!canvas); canvas->viewports.insert(p_viewport); @@ -647,18 +788,18 @@ void RenderingServerViewport::viewport_attach_canvas(RID p_viewport, RID p_canva viewport->canvas_map[p_canvas].canvas = canvas; } -void RenderingServerViewport::viewport_remove_canvas(RID p_viewport, RID p_canvas) { +void RendererViewport::viewport_remove_canvas(RID p_viewport, RID p_canvas) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); - RenderingServerCanvas::Canvas *canvas = RSG::canvas->canvas_owner.getornull(p_canvas); + RendererCanvasCull::Canvas *canvas = RSG::canvas->canvas_owner.getornull(p_canvas); ERR_FAIL_COND(!canvas); viewport->canvas_map.erase(p_canvas); canvas->viewports.erase(p_viewport); } -void RenderingServerViewport::viewport_set_canvas_transform(RID p_viewport, RID p_canvas, const Transform2D &p_offset) { +void RendererViewport::viewport_set_canvas_transform(RID p_viewport, RID p_canvas, const Transform2D &p_offset) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -666,22 +807,22 @@ void RenderingServerViewport::viewport_set_canvas_transform(RID p_viewport, RID viewport->canvas_map[p_canvas].transform = p_offset; } -void RenderingServerViewport::viewport_set_transparent_background(RID p_viewport, bool p_enabled) { +void RendererViewport::viewport_set_transparent_background(RID p_viewport, bool p_enabled) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); - RSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_TRANSPARENT, p_enabled); + RSG::storage->render_target_set_flag(viewport->render_target, RendererStorage::RENDER_TARGET_TRANSPARENT, p_enabled); viewport->transparent_bg = p_enabled; } -void RenderingServerViewport::viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform) { +void RendererViewport::viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->global_transform = p_transform; } -void RenderingServerViewport::viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) { +void RendererViewport::viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -690,23 +831,24 @@ void RenderingServerViewport::viewport_set_canvas_stacking(RID p_viewport, RID p viewport->canvas_map[p_canvas].sublayer = p_sublayer; } -void RenderingServerViewport::viewport_set_shadow_atlas_size(RID p_viewport, int p_size) { +void RendererViewport::viewport_set_shadow_atlas_size(RID p_viewport, int p_size, bool p_16_bits) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->shadow_atlas_size = p_size; + viewport->shadow_atlas_16_bits = p_16_bits; - RSG::scene_render->shadow_atlas_set_size(viewport->shadow_atlas, viewport->shadow_atlas_size); + RSG::scene->shadow_atlas_set_size(viewport->shadow_atlas, viewport->shadow_atlas_size, viewport->shadow_atlas_16_bits); } -void RenderingServerViewport::viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) { +void RendererViewport::viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); - RSG::scene_render->shadow_atlas_set_quadrant_subdivision(viewport->shadow_atlas, p_quadrant, p_subdiv); + RSG::scene->shadow_atlas_set_quadrant_subdivision(viewport->shadow_atlas, p_quadrant, p_subdiv); } -void RenderingServerViewport::viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa) { +void RendererViewport::viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -715,11 +857,11 @@ void RenderingServerViewport::viewport_set_msaa(RID p_viewport, RS::ViewportMSAA } viewport->msaa = p_msaa; if (viewport->render_buffers.is_valid()) { - RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, p_msaa, viewport->screen_space_aa, viewport->use_debanding); + RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, p_msaa, viewport->screen_space_aa, viewport->use_debanding); } } -void RenderingServerViewport::viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode) { +void RendererViewport::viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -728,11 +870,11 @@ void RenderingServerViewport::viewport_set_screen_space_aa(RID p_viewport, RS::V } viewport->screen_space_aa = p_mode; if (viewport->render_buffers.is_valid()) { - RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, p_mode, viewport->use_debanding); + RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, p_mode, viewport->use_debanding); } } -void RenderingServerViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_debanding) { +void RendererViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_debanding) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -741,11 +883,18 @@ void RenderingServerViewport::viewport_set_use_debanding(RID p_viewport, bool p_ } viewport->use_debanding = p_use_debanding; if (viewport->render_buffers.is_valid()) { - RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, p_use_debanding); + RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, p_use_debanding); } } -int RenderingServerViewport::viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info) { +void RendererViewport::viewport_set_lod_threshold(RID p_viewport, float p_pixels) { + Viewport *viewport = viewport_owner.getornull(p_viewport); + ERR_FAIL_COND(!viewport); + + viewport->lod_threshold = p_pixels; +} + +int RendererViewport::viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info) { ERR_FAIL_INDEX_V(p_info, RS::VIEWPORT_RENDER_INFO_MAX, -1); Viewport *viewport = viewport_owner.getornull(p_viewport); @@ -756,54 +905,54 @@ int RenderingServerViewport::viewport_get_render_info(RID p_viewport, RS::Viewpo return viewport->render_info[p_info]; } -void RenderingServerViewport::viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw) { +void RendererViewport::viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->debug_draw = p_draw; } -void RenderingServerViewport::viewport_set_measure_render_time(RID p_viewport, bool p_enable) { +void RendererViewport::viewport_set_measure_render_time(RID p_viewport, bool p_enable) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->measure_render_time = p_enable; } -float RenderingServerViewport::viewport_get_measured_render_time_cpu(RID p_viewport) const { +float RendererViewport::viewport_get_measured_render_time_cpu(RID p_viewport) const { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND_V(!viewport, 0); return double(viewport->time_cpu_end - viewport->time_cpu_begin) / 1000.0; } -float RenderingServerViewport::viewport_get_measured_render_time_gpu(RID p_viewport) const { +float RendererViewport::viewport_get_measured_render_time_gpu(RID p_viewport) const { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND_V(!viewport, 0); return double((viewport->time_gpu_end - viewport->time_gpu_begin) / 1000) / 1000.0; } -void RenderingServerViewport::viewport_set_snap_2d_transforms_to_pixel(RID p_viewport, bool p_enabled) { +void RendererViewport::viewport_set_snap_2d_transforms_to_pixel(RID p_viewport, bool p_enabled) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->snap_2d_transforms_to_pixel = p_enabled; } -void RenderingServerViewport::viewport_set_snap_2d_vertices_to_pixel(RID p_viewport, bool p_enabled) { +void RendererViewport::viewport_set_snap_2d_vertices_to_pixel(RID p_viewport, bool p_enabled) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->snap_2d_vertices_to_pixel = p_enabled; } -void RenderingServerViewport::viewport_set_default_canvas_item_texture_filter(RID p_viewport, RS::CanvasItemTextureFilter p_filter) { +void RendererViewport::viewport_set_default_canvas_item_texture_filter(RID p_viewport, RS::CanvasItemTextureFilter p_filter) { ERR_FAIL_COND_MSG(p_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, "Viewport does not accept DEFAULT as texture filter (it's the topmost choice already).)"); Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); viewport->texture_filter = p_filter; } -void RenderingServerViewport::viewport_set_default_canvas_item_texture_repeat(RID p_viewport, RS::CanvasItemTextureRepeat p_repeat) { +void RendererViewport::viewport_set_default_canvas_item_texture_repeat(RID p_viewport, RS::CanvasItemTextureRepeat p_repeat) { ERR_FAIL_COND_MSG(p_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, "Viewport does not accept DEFAULT as texture repeat (it's the topmost choice already).)"); Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); @@ -811,14 +960,21 @@ void RenderingServerViewport::viewport_set_default_canvas_item_texture_repeat(RI viewport->texture_repeat = p_repeat; } -bool RenderingServerViewport::free(RID p_rid) { +void RendererViewport::viewport_set_sdf_oversize_and_scale(RID p_viewport, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) { + Viewport *viewport = viewport_owner.getornull(p_viewport); + ERR_FAIL_COND(!viewport); + + RSG::storage->render_target_set_sdf_size_and_scale(viewport->render_target, p_size, p_scale); +} + +bool RendererViewport::free(RID p_rid) { if (viewport_owner.owns(p_rid)) { Viewport *viewport = viewport_owner.getornull(p_rid); RSG::storage->free(viewport->render_target); - RSG::scene_render->free(viewport->shadow_atlas); + RSG::scene->free(viewport->shadow_atlas); if (viewport->render_buffers.is_valid()) { - RSG::scene_render->free(viewport->render_buffers); + RSG::scene->free(viewport->render_buffers); } while (viewport->canvas_map.front()) { @@ -837,7 +993,7 @@ bool RenderingServerViewport::free(RID p_rid) { return false; } -void RenderingServerViewport::handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time) { +void RendererViewport::handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time) { RID *vp = timestamp_vp_map.getptr(p_timestamp); if (!vp) { return; @@ -859,9 +1015,9 @@ void RenderingServerViewport::handle_timestamp(String p_timestamp, uint64_t p_cp } } -void RenderingServerViewport::set_default_clear_color(const Color &p_color) { +void RendererViewport::set_default_clear_color(const Color &p_color) { RSG::storage->set_default_clear_color(p_color); } -RenderingServerViewport::RenderingServerViewport() { +RendererViewport::RendererViewport() { } diff --git a/servers/rendering/rendering_server_viewport.h b/servers/rendering/renderer_viewport.h index d00a06c5ee..979cbb095b 100644 --- a/servers/rendering/rendering_server_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rendering_server_viewport.h */ +/* renderer_viewport.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,13 +31,13 @@ #ifndef VISUALSERVERVIEWPORT_H #define VISUALSERVERVIEWPORT_H -#include "core/rid_owner.h" -#include "core/self_list.h" -#include "rasterizer.h" +#include "core/templates/rid_owner.h" +#include "core/templates/self_list.h" +#include "renderer_compositor.h" #include "servers/rendering_server.h" #include "servers/xr/xr_interface.h" -class RenderingServerViewport { +class RendererViewport { public: struct CanvasBase { }; @@ -81,6 +81,11 @@ public: RID shadow_atlas; int shadow_atlas_size; + bool shadow_atlas_16_bits = false; + + bool sdf_active; + + float lod_threshold = 1.0; uint64_t last_pass = 0; @@ -146,6 +151,7 @@ public: render_info[i] = 0; } use_xr = false; + sdf_active = false; time_cpu_begin = 0; time_cpu_end = 0; @@ -212,13 +218,15 @@ public: void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform); void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer); - void viewport_set_shadow_atlas_size(RID p_viewport, int p_size); + void viewport_set_shadow_atlas_size(RID p_viewport, int p_size, bool p_16_bits = false); void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv); void viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa); void viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode); void viewport_set_use_debanding(RID p_viewport, bool p_use_debanding); + void viewport_set_lod_threshold(RID p_viewport, float p_pixels); + virtual int viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info); virtual void viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw); @@ -232,6 +240,8 @@ public: void viewport_set_default_canvas_item_texture_filter(RID p_viewport, RS::CanvasItemTextureFilter p_filter); void viewport_set_default_canvas_item_texture_repeat(RID p_viewport, RS::CanvasItemTextureRepeat p_repeat); + void viewport_set_sdf_oversize_and_scale(RID p_viewport, RS::ViewportSDFOversize p_over_size, RS::ViewportSDFScale p_scale); + void handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time); void set_default_clear_color(const Color &p_color); @@ -239,8 +249,8 @@ public: bool free(RID p_rid); - RenderingServerViewport(); - virtual ~RenderingServerViewport() {} + RendererViewport(); + virtual ~RendererViewport() {} }; #endif // VISUALSERVERVIEWPORT_H diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 1259b161bd..70497bcdb3 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -68,7 +68,7 @@ RID RenderingDevice::_texture_create(const Ref<RDTextureFormat> &p_format, const Vector<Vector<uint8_t>> data; for (int i = 0; i < p_data.size(); i++) { Vector<uint8_t> byte_slice = p_data[i]; - ERR_FAIL_COND_V(byte_slice.empty(), RID()); + ERR_FAIL_COND_V(byte_slice.is_empty(), RID()); data.push_back(byte_slice); } return texture_create(p_format->base, p_view->base, data); @@ -154,7 +154,7 @@ RID RenderingDevice::shader_create_from_bytecode(const Ref<RDShaderBytecode> &p_ String error = p_bytecode->get_stage_compile_error(stage); ERR_FAIL_COND_V_MSG(error != String(), RID(), "Can't create a shader from an errored bytecode. Check errors in source bytecode."); sd.spir_v = p_bytecode->get_stage_bytecode(stage); - if (sd.spir_v.empty()) { + if (sd.spir_v.is_empty()) { continue; } stage_data.push_back(sd); @@ -174,8 +174,8 @@ RID RenderingDevice::_uniform_set_create(const Array &p_uniforms, RID p_shader, return uniform_set_create(uniforms, p_shader, p_shader_set); } -Error RenderingDevice::_buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, bool p_sync_with_draw) { - return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_sync_with_draw); +Error RenderingDevice::_buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, uint32_t p_post_barrier) { + return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_post_barrier); } RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags) { @@ -249,7 +249,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("texture_create_shared", "view", "with_texture"), &RenderingDevice::_texture_create_shared); ClassDB::bind_method(D_METHOD("texture_create_shared_from_slice", "view", "with_texture", "layer", "mipmap", "slice_type"), &RenderingDevice::_texture_create_shared_from_slice, DEFVAL(TEXTURE_SLICE_2D)); - ClassDB::bind_method(D_METHOD("texture_update", "texture", "layer", "data", "sync_with_draw"), &RenderingDevice::texture_update, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("texture_update", "texture", "layer", "data", "post_barrier"), &RenderingDevice::texture_update, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("texture_get_data", "texture", "layer"), &RenderingDevice::texture_get_data); ClassDB::bind_method(D_METHOD("texture_is_format_supported_for_usage", "format", "usage_flags"), &RenderingDevice::texture_is_format_supported_for_usage); @@ -257,20 +257,20 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("texture_is_shared", "texture"), &RenderingDevice::texture_is_shared); ClassDB::bind_method(D_METHOD("texture_is_valid", "texture"), &RenderingDevice::texture_is_valid); - ClassDB::bind_method(D_METHOD("texture_copy", "from_texture", "to_texture", "from_pos", "to_pos", "size", "src_mipmap", "dst_mipmap", "src_layer", "dst_layer", "sync_with_draw"), &RenderingDevice::texture_copy, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "sync_with_draw"), &RenderingDevice::texture_clear, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "sync_with_draw"), &RenderingDevice::texture_resolve_multisample, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("texture_copy", "from_texture", "to_texture", "from_pos", "to_pos", "size", "src_mipmap", "dst_mipmap", "src_layer", "dst_layer", "post_barrier"), &RenderingDevice::texture_copy, DEFVAL(BARRIER_MASK_ALL)); + ClassDB::bind_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "post_barrier"), &RenderingDevice::texture_clear, DEFVAL(BARRIER_MASK_ALL)); + ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "post_barrier"), &RenderingDevice::texture_resolve_multisample, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("framebuffer_format_create", "attachments"), &RenderingDevice::_framebuffer_format_create); - ClassDB::bind_method(D_METHOD("framebuffer_format_create_empty", "size"), &RenderingDevice::framebuffer_format_create_empty); + ClassDB::bind_method(D_METHOD("framebuffer_format_create_empty", "samples"), &RenderingDevice::framebuffer_format_create_empty, DEFVAL(TEXTURE_SAMPLES_1)); ClassDB::bind_method(D_METHOD("framebuffer_format_get_texture_samples", "format"), &RenderingDevice::framebuffer_format_get_texture_samples); ClassDB::bind_method(D_METHOD("framebuffer_create", "textures", "validate_with_format"), &RenderingDevice::_framebuffer_create, DEFVAL(INVALID_FORMAT_ID)); - ClassDB::bind_method(D_METHOD("framebuffer_create_empty", "size", "validate_with_format"), &RenderingDevice::framebuffer_create_empty, DEFVAL(INVALID_FORMAT_ID)); + ClassDB::bind_method(D_METHOD("framebuffer_create_empty", "size", "samples", "validate_with_format"), &RenderingDevice::framebuffer_create_empty, DEFVAL(TEXTURE_SAMPLES_1), DEFVAL(INVALID_FORMAT_ID)); ClassDB::bind_method(D_METHOD("framebuffer_get_format", "framebuffer"), &RenderingDevice::framebuffer_get_format); ClassDB::bind_method(D_METHOD("sampler_create", "state"), &RenderingDevice::_sampler_create); - ClassDB::bind_method(D_METHOD("vertex_buffer_create", "size_bytes", "data"), &RenderingDevice::vertex_buffer_create, DEFVAL(Vector<uint8_t>())); + ClassDB::bind_method(D_METHOD("vertex_buffer_create", "size_bytes", "data", "use_as_storage"), &RenderingDevice::vertex_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("vertex_format_create", "vertex_descriptions"), &RenderingDevice::_vertex_format_create); ClassDB::bind_method(D_METHOD("index_buffer_create", "size_indices", "format", "data"), &RenderingDevice::index_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false)); @@ -287,7 +287,8 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("uniform_set_create", "uniforms", "shader", "shader_set"), &RenderingDevice::_uniform_set_create); ClassDB::bind_method(D_METHOD("uniform_set_is_valid", "uniform_set"), &RenderingDevice::uniform_set_is_valid); - ClassDB::bind_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data", "sync_with_draw"), &RenderingDevice::_buffer_update, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("buffer_update", "buffer", "offset", "size_bytes", "data", "post_barrier"), &RenderingDevice::_buffer_update, DEFVAL(BARRIER_MASK_ALL)); + ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes", "post_barrier"), &RenderingDevice::buffer_clear, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("buffer_get_data", "buffer"), &RenderingDevice::buffer_get_data); ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags"), &RenderingDevice::_render_pipeline_create, DEFVAL(0)); @@ -316,7 +317,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_list_enable_scissor", "draw_list", "rect"), &RenderingDevice::draw_list_enable_scissor, DEFVAL(Rect2i())); ClassDB::bind_method(D_METHOD("draw_list_disable_scissor", "draw_list"), &RenderingDevice::draw_list_disable_scissor); - ClassDB::bind_method(D_METHOD("draw_list_end"), &RenderingDevice::draw_list_end); + ClassDB::bind_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::draw_list_end, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("compute_list_begin"), &RenderingDevice::compute_list_begin); ClassDB::bind_method(D_METHOD("compute_list_bind_compute_pipeline", "compute_list", "compute_pipeline"), &RenderingDevice::compute_list_bind_compute_pipeline); @@ -324,11 +325,11 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("compute_list_bind_uniform_set", "compute_list", "uniform_set", "set_index"), &RenderingDevice::compute_list_bind_uniform_set); ClassDB::bind_method(D_METHOD("compute_list_dispatch", "compute_list", "x_groups", "y_groups", "z_groups"), &RenderingDevice::compute_list_dispatch); ClassDB::bind_method(D_METHOD("compute_list_add_barrier", "compute_list"), &RenderingDevice::compute_list_add_barrier); - ClassDB::bind_method(D_METHOD("compute_list_end"), &RenderingDevice::compute_list_end); + ClassDB::bind_method(D_METHOD("compute_list_end", "post_barrier"), &RenderingDevice::compute_list_end, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("free", "rid"), &RenderingDevice::free); - ClassDB::bind_method(D_METHOD("capture_timestamp", "name", "sync_to_draw"), &RenderingDevice::capture_timestamp); + ClassDB::bind_method(D_METHOD("capture_timestamp", "name"), &RenderingDevice::capture_timestamp); ClassDB::bind_method(D_METHOD("get_captured_timestamps_count"), &RenderingDevice::get_captured_timestamps_count); ClassDB::bind_method(D_METHOD("get_captured_timestamps_frame"), &RenderingDevice::get_captured_timestamps_frame); ClassDB::bind_method(D_METHOD("get_captured_timestamp_gpu_time", "index"), &RenderingDevice::get_captured_timestamp_gpu_time); @@ -340,8 +341,22 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("submit"), &RenderingDevice::submit); ClassDB::bind_method(D_METHOD("sync"), &RenderingDevice::sync); + ClassDB::bind_method(D_METHOD("barrier", "from", "to"), &RenderingDevice::barrier, DEFVAL(BARRIER_MASK_ALL), DEFVAL(BARRIER_MASK_ALL)); + ClassDB::bind_method(D_METHOD("full_barrier"), &RenderingDevice::full_barrier); + ClassDB::bind_method(D_METHOD("create_local_device"), &RenderingDevice::create_local_device); + ClassDB::bind_method(D_METHOD("set_resource_name", "id", "name"), &RenderingDevice::set_resource_name); + + ClassDB::bind_method(D_METHOD("draw_command_begin_label", "name", "color"), &RenderingDevice::draw_command_begin_label); + ClassDB::bind_method(D_METHOD("draw_command_insert_label", "name", "color"), &RenderingDevice::draw_command_insert_label); + ClassDB::bind_method(D_METHOD("draw_command_end_label"), &RenderingDevice::draw_command_end_label); + + BIND_CONSTANT(BARRIER_MASK_RASTER); + BIND_CONSTANT(BARRIER_MASK_COMPUTE); + BIND_CONSTANT(BARRIER_MASK_TRANSFER); + BIND_CONSTANT(BARRIER_MASK_ALL); + BIND_ENUM_CONSTANT(DATA_FORMAT_R4G4_UNORM_PACK8); BIND_ENUM_CONSTANT(DATA_FORMAT_R4G4B4A4_UNORM_PACK16); BIND_ENUM_CONSTANT(DATA_FORMAT_B4G4R4A4_UNORM_PACK16); @@ -744,6 +759,7 @@ void RenderingDevice::_bind_methods() { BIND_ENUM_CONSTANT(DYNAMIC_STATE_STENCIL_REFERENCE); BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR); //start rendering and clear the framebuffer (supply params) + BIND_ENUM_CONSTANT(INITIAL_ACTION_CLEAR_REGION); //start rendering and clear the framebuffer (supply params) BIND_ENUM_CONSTANT(INITIAL_ACTION_KEEP); //start rendering); but keep attached color texture contents (depth will be cleared) BIND_ENUM_CONSTANT(INITIAL_ACTION_DROP); //start rendering); ignore what is there); just write above it BIND_ENUM_CONSTANT(INITIAL_ACTION_CONTINUE); //continue rendering (framebuffer must have been left in "continue" state as final action previously) diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 6df66e7b20..47ef54cef7 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,8 +31,8 @@ #ifndef RENDERING_DEVICE_H #define RENDERING_DEVICE_H -#include "core/class_db.h" -#include "core/typed_array.h" +#include "core/object/class_db.h" +#include "core/variant/typed_array.h" #include "servers/display_server.h" class RDTextureFormat; @@ -336,6 +336,17 @@ public: }; /*****************/ + /**** BARRIER ****/ + /*****************/ + + enum BarrierMask { + BARRIER_MASK_RASTER = 1, + BARRIER_MASK_COMPUTE = 2, + BARRIER_MASK_TRANSFER = 4, + BARRIER_MASK_ALL = BARRIER_MASK_RASTER | BARRIER_MASK_COMPUTE | BARRIER_MASK_TRANSFER + }; + + /*****************/ /**** TEXTURE ****/ /*****************/ @@ -392,7 +403,7 @@ public: uint32_t depth; uint32_t array_layers; uint32_t mipmaps; - TextureType type; + TextureType texture_type; TextureSamples samples; uint32_t usage_bits; Vector<DataFormat> shareable_formats; @@ -404,7 +415,7 @@ public: depth = 1; array_layers = 1; mipmaps = 1; - type = TEXTURE_TYPE_2D; + texture_type = TEXTURE_TYPE_2D; samples = TEXTURE_SAMPLES_1; usage_bits = 0; } @@ -433,20 +444,21 @@ public: TEXTURE_SLICE_2D, TEXTURE_SLICE_CUBEMAP, TEXTURE_SLICE_3D, + TEXTURE_SLICE_2D_ARRAY, }; virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type = TEXTURE_SLICE_2D) = 0; - virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the beginning of the frame, unless sync with draw is used, which is used to mix updates with draw calls + virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; virtual Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer) = 0; // CPU textures will return immediately, while GPU textures will most likely force a flush virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const = 0; virtual bool texture_is_shared(RID p_texture) = 0; virtual bool texture_is_valid(RID p_texture) = 0; - virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, bool p_sync_with_draw = false) = 0; - virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, bool p_sync_with_draw = false) = 0; - virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, bool p_sync_with_draw = false) = 0; + virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; + virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; + virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; /*********************/ /**** FRAMEBUFFER ****/ @@ -467,11 +479,11 @@ public: // This ID is warranted to be unique for the same formats, does not need to be freed virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format) = 0; - virtual FramebufferFormatID framebuffer_format_create_empty(const Size2i &p_size) = 0; + virtual FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1) = 0; virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format) = 0; virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID) = 0; - virtual RID framebuffer_create_empty(const Size2i &p_size, FramebufferFormatID p_format_check = INVALID_ID) = 0; + virtual RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID) = 0; virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer) = 0; @@ -564,7 +576,7 @@ public: frequency = VERTEX_FREQUENCY_VERTEX; } }; - virtual RID vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0; + virtual RID vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), bool p_use_as_storage = false) = 0; typedef int64_t VertexFormatID; @@ -629,7 +641,7 @@ public: virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0; struct Uniform { - UniformType type; + UniformType uniform_type; int binding; //binding index as specified in shader //for single items, provide one ID, for @@ -640,7 +652,7 @@ public: Vector<RID> ids; Uniform() { - type = UNIFORM_TYPE_IMAGE; + uniform_type = UNIFORM_TYPE_IMAGE; binding = 0; } }; @@ -648,7 +660,8 @@ public: virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) = 0; virtual bool uniform_set_is_valid(RID p_uniform_set) = 0; - virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the beginning of the frame, unless sync with draw is used, which is used to mix updates with draw calls + virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; + virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; virtual Vector<uint8_t> buffer_get_data(RID p_buffer) = 0; //this causes stall, only use to retrieve large buffers for saving /*************************/ @@ -929,7 +942,8 @@ public: /********************/ enum InitialAction { - INITIAL_ACTION_CLEAR, //start rendering and clear the framebuffer (supply params) + INITIAL_ACTION_CLEAR, //start rendering and clear the whole framebuffer (region or not) (supply params) + INITIAL_ACTION_CLEAR_REGION, //start rendering and clear the framebuffer in the specified region (supply params) INITIAL_ACTION_KEEP, //start rendering, but keep attached color texture contents (depth will be cleared) INITIAL_ACTION_DROP, //start rendering, ignore what is there, just write above it INITIAL_ACTION_CONTINUE, //continue rendering (framebuffer must have been left in "continue" state as final action previously) @@ -961,7 +975,7 @@ public: virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) = 0; virtual void draw_list_disable_scissor(DrawListID p_list) = 0; - virtual void draw_list_end() = 0; + virtual void draw_list_end(uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; /***********************/ /**** COMPUTE LISTS ****/ @@ -978,8 +992,9 @@ public: virtual void compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset) = 0; virtual void compute_list_add_barrier(ComputeListID p_list) = 0; - virtual void compute_list_end() = 0; + virtual void compute_list_end(uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; + virtual void barrier(uint32_t p_from = BARRIER_MASK_ALL, uint32_t p_to = BARRIER_MASK_ALL) = 0; virtual void full_barrier() = 0; /***************/ @@ -992,7 +1007,7 @@ public: /**** Timing ****/ /****************/ - virtual void capture_timestamp(const String &p_name, bool p_sync_to_draw) = 0; + virtual void capture_timestamp(const String &p_name) = 0; virtual uint32_t get_captured_timestamps_count() const = 0; virtual uint64_t get_captured_timestamps_frame() const = 0; virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const = 0; @@ -1057,6 +1072,12 @@ public: virtual RenderingDevice *create_local_device() = 0; + virtual void set_resource_name(RID p_id, const String p_name) = 0; + + virtual void draw_command_begin_label(String p_label_name, const Color p_color = Color(1, 1, 1, 1)) = 0; + virtual void draw_command_insert_label(String p_label_name, const Color p_color = Color(1, 1, 1, 1)) = 0; + virtual void draw_command_end_label() = 0; + static RenderingDevice *get_singleton(); RenderingDevice(); @@ -1076,7 +1097,7 @@ protected: RID _uniform_set_create(const Array &p_uniforms, RID p_shader, uint32_t p_shader_set); - Error _buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, bool p_sync_with_draw = false); + Error _buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags = 0); diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp index af9ecef0dd..2f11360364 100644 --- a/servers/rendering/rendering_device_binds.cpp +++ b/servers/rendering/rendering_device_binds.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -163,7 +163,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "When writing compute shaders, [compute] mustbe the only stage present."); } - if (version_texts.empty()) { + if (version_texts.is_empty()) { version_texts[""] = ""; //make sure a default version exists } diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h index 66c6a1c3a9..e43c3669b5 100644 --- a/servers/rendering/rendering_device_binds.h +++ b/servers/rendering/rendering_device_binds.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -64,7 +64,7 @@ public: RD_SETGET(uint32_t, depth) RD_SETGET(uint32_t, array_layers) RD_SETGET(uint32_t, mipmaps) - RD_SETGET(RD::TextureType, type) + RD_SETGET(RD::TextureType, texture_type) RD_SETGET(RD::TextureSamples, samples) RD_SETGET(uint32_t, usage_bits) @@ -79,7 +79,7 @@ protected: RD_BIND(Variant::INT, RDTextureFormat, depth); RD_BIND(Variant::INT, RDTextureFormat, array_layers); RD_BIND(Variant::INT, RDTextureFormat, mipmaps); - RD_BIND(Variant::INT, RDTextureFormat, type); + RD_BIND(Variant::INT, RDTextureFormat, texture_type); RD_BIND(Variant::INT, RDTextureFormat, samples); RD_BIND(Variant::INT, RDTextureFormat, usage_bits); ClassDB::bind_method(D_METHOD("add_shareable_format", "format"), &RDTextureFormat::add_shareable_format); @@ -392,7 +392,7 @@ class RDUniform : public Reference { RD::Uniform base; public: - RD_SETGET(RD::UniformType, type) + RD_SETGET(RD::UniformType, uniform_type) RD_SETGET(int32_t, binding) void add_id(const RID &p_id) { base.ids.push_back(p_id); } @@ -415,7 +415,7 @@ protected: } } static void _bind_methods() { - RD_BIND(Variant::INT, RDUniform, type); + RD_BIND(Variant::INT, RDUniform, uniform_type); RD_BIND(Variant::INT, RDUniform, binding); ClassDB::bind_method(D_METHOD("add_id", "id"), &RDUniform::add_id); ClassDB::bind_method(D_METHOD("clear_ids"), &RDUniform::clear_ids); diff --git a/servers/rendering/rendering_server_raster.cpp b/servers/rendering/rendering_server_default.cpp index cbc91497ba..360b333454 100644 --- a/servers/rendering/rendering_server_raster.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rendering_server_raster.cpp */ +/* rendering_server_default.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,43 +28,43 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "rendering_server_raster.h" +#include "rendering_server_default.h" +#include "core/config/project_settings.h" #include "core/io/marshalls.h" #include "core/os/os.h" -#include "core/project_settings.h" -#include "core/sort_array.h" -#include "rendering_server_canvas.h" +#include "core/templates/sort_array.h" +#include "renderer_canvas_cull.h" +#include "renderer_scene_cull.h" #include "rendering_server_globals.h" -#include "rendering_server_scene.h" // careful, these may run in different threads than the visual server -int RenderingServerRaster::changes = 0; +int RenderingServerDefault::changes = 0; /* BLACK BARS */ -void RenderingServerRaster::black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) { - black_margin[MARGIN_LEFT] = p_left; - black_margin[MARGIN_TOP] = p_top; - black_margin[MARGIN_RIGHT] = p_right; - black_margin[MARGIN_BOTTOM] = p_bottom; +void RenderingServerDefault::black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) { + black_margin[SIDE_LEFT] = p_left; + black_margin[SIDE_TOP] = p_top; + black_margin[SIDE_RIGHT] = p_right; + black_margin[SIDE_BOTTOM] = p_bottom; } -void RenderingServerRaster::black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) { - black_image[MARGIN_LEFT] = p_left; - black_image[MARGIN_TOP] = p_top; - black_image[MARGIN_RIGHT] = p_right; - black_image[MARGIN_BOTTOM] = p_bottom; +void RenderingServerDefault::black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) { + black_image[SIDE_LEFT] = p_left; + black_image[SIDE_TOP] = p_top; + black_image[SIDE_RIGHT] = p_right; + black_image[SIDE_BOTTOM] = p_bottom; } -void RenderingServerRaster::_draw_margins() { +void RenderingServerDefault::_draw_margins() { RSG::canvas_render->draw_window_margins(black_margin, black_image); }; /* FREE */ -void RenderingServerRaster::free(RID p_rid) { +void RenderingServerDefault::free(RID p_rid) { if (RSG::storage->free(p_rid)) { return; } @@ -77,14 +77,11 @@ void RenderingServerRaster::free(RID p_rid) { if (RSG::scene->free(p_rid)) { return; } - if (RSG::scene_render->free(p_rid)) { - return; - } } /* EVENT QUEUING */ -void RenderingServerRaster::request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata) { +void RenderingServerDefault::request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata) { ERR_FAIL_NULL(p_where); FrameDrawnCallbacks fdc; fdc.object = p_where->get_instance_id(); @@ -94,7 +91,7 @@ void RenderingServerRaster::request_frame_drawn_callback(Object *p_where, const frame_drawn_callbacks.push_back(fdc); } -void RenderingServerRaster::draw(bool p_swap_buffers, double frame_step) { +void RenderingServerDefault::draw(bool p_swap_buffers, double frame_step) { //needs to be done before changes is reset to 0, to not force the editor to redraw RS::get_singleton()->emit_signal("frame_pre_draw"); @@ -104,14 +101,16 @@ void RenderingServerRaster::draw(bool p_swap_buffers, double frame_step) { TIMESTAMP_BEGIN() - RSG::scene_render->update(); //update scenes stuff before updating instances + uint64_t time_usec = OS::get_singleton()->get_ticks_usec(); + + RSG::scene->update(); //update scenes stuff before updating instances - RSG::scene->update_dirty_instances(); //update scene stuff + frame_setup_time = double(OS::get_singleton()->get_ticks_usec() - time_usec) / 1000.0; - RSG::scene->render_particle_colliders(); RSG::storage->update_particles(); //need to be done after instances are updated (colliders and particle transforms), and colliders are rendered RSG::scene->render_probes(); + RSG::viewport->draw_viewports(); RSG::canvas_render->update(); @@ -163,20 +162,69 @@ void RenderingServerRaster::draw(bool p_swap_buffers, double frame_step) { } frame_profile_frame = RSG::storage->get_captured_timestamps_frame(); + + if (print_gpu_profile) { + if (print_frame_profile_ticks_from == 0) { + print_frame_profile_ticks_from = OS::get_singleton()->get_ticks_usec(); + } + float total_time = 0.0; + + for (int i = 0; i < frame_profile.size() - 1; i++) { + String name = frame_profile[i].name; + if (name[0] == '<' || name[0] == '>') { + continue; + } + + float time = frame_profile[i + 1].gpu_msec - frame_profile[i].gpu_msec; + + if (name[0] != '<' && name[0] != '>') { + if (print_gpu_profile_task_time.has(name)) { + print_gpu_profile_task_time[name] += time; + } else { + print_gpu_profile_task_time[name] = time; + } + } + } + + if (frame_profile.size()) { + total_time = frame_profile[frame_profile.size() - 1].gpu_msec; + } + + uint64_t ticks_elapsed = OS::get_singleton()->get_ticks_usec() - print_frame_profile_ticks_from; + print_frame_profile_frame_count++; + if (ticks_elapsed > 1000000) { + print_line("GPU PROFILE (total " + rtos(total_time) + "ms): "); + + float print_threshold = 0.01; + for (OrderedHashMap<String, float>::Element E = print_gpu_profile_task_time.front(); E; E = E.next()) { + float time = E.value() / float(print_frame_profile_frame_count); + if (time > print_threshold) { + print_line("\t-" + E.key() + ": " + rtos(time) + "ms"); + } + } + print_gpu_profile_task_time.clear(); + print_frame_profile_ticks_from = OS::get_singleton()->get_ticks_usec(); + print_frame_profile_frame_count = 0; + } + } } -void RenderingServerRaster::sync() { +float RenderingServerDefault::get_frame_setup_time_cpu() const { + return frame_setup_time; } -bool RenderingServerRaster::has_changed() const { +void RenderingServerDefault::sync() { +} + +bool RenderingServerDefault::has_changed() const { return changes > 0; } -void RenderingServerRaster::init() { +void RenderingServerDefault::init() { RSG::rasterizer->initialize(); } -void RenderingServerRaster::finish() { +void RenderingServerDefault::finish() { if (test_cube.is_valid()) { free(test_cube); } @@ -186,69 +234,74 @@ void RenderingServerRaster::finish() { /* STATUS INFORMATION */ -int RenderingServerRaster::get_render_info(RenderInfo p_info) { +int RenderingServerDefault::get_render_info(RenderInfo p_info) { return RSG::storage->get_render_info(p_info); } -String RenderingServerRaster::get_video_adapter_name() const { +String RenderingServerDefault::get_video_adapter_name() const { return RSG::storage->get_video_adapter_name(); } -String RenderingServerRaster::get_video_adapter_vendor() const { +String RenderingServerDefault::get_video_adapter_vendor() const { return RSG::storage->get_video_adapter_vendor(); } -void RenderingServerRaster::set_frame_profiling_enabled(bool p_enable) { +void RenderingServerDefault::set_frame_profiling_enabled(bool p_enable) { RSG::storage->capturing_timestamps = p_enable; } -uint64_t RenderingServerRaster::get_frame_profile_frame() { +uint64_t RenderingServerDefault::get_frame_profile_frame() { return frame_profile_frame; } -Vector<RenderingServer::FrameProfileArea> RenderingServerRaster::get_frame_profile() { +Vector<RenderingServer::FrameProfileArea> RenderingServerDefault::get_frame_profile() { return frame_profile; } /* TESTING */ -void RenderingServerRaster::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) { +void RenderingServerDefault::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) { redraw_request(); RSG::rasterizer->set_boot_image(p_image, p_color, p_scale, p_use_filter); } -void RenderingServerRaster::set_default_clear_color(const Color &p_color) { +void RenderingServerDefault::set_default_clear_color(const Color &p_color) { RSG::viewport->set_default_clear_color(p_color); } -bool RenderingServerRaster::has_feature(Features p_feature) const { +bool RenderingServerDefault::has_feature(Features p_feature) const { return false; } -void RenderingServerRaster::sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) { - RSG::scene_render->sdfgi_set_debug_probe_select(p_position, p_dir); +void RenderingServerDefault::sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) { + RSG::scene->sdfgi_set_debug_probe_select(p_position, p_dir); +} + +void RenderingServerDefault::set_print_gpu_profile(bool p_enable) { + RSG::storage->capturing_timestamps = p_enable; + print_gpu_profile = p_enable; } -RID RenderingServerRaster::get_test_cube() { +RID RenderingServerDefault::get_test_cube() { if (!test_cube.is_valid()) { test_cube = _make_test_cube(); } return test_cube; } -bool RenderingServerRaster::has_os_feature(const String &p_feature) const { +bool RenderingServerDefault::has_os_feature(const String &p_feature) const { return RSG::storage->has_os_feature(p_feature); } -void RenderingServerRaster::set_debug_generate_wireframes(bool p_generate) { +void RenderingServerDefault::set_debug_generate_wireframes(bool p_generate) { RSG::storage->set_debug_generate_wireframes(p_generate); } -void RenderingServerRaster::call_set_use_vsync(bool p_enable) { +void RenderingServerDefault::call_set_use_vsync(bool p_enable) { DisplayServer::get_singleton()->_set_use_vsync(p_enable); } -bool RenderingServerRaster::is_low_end() const { +bool RenderingServerDefault::is_low_end() const { // FIXME: Commented out when rebasing vulkan branch on master, // causes a crash, it seems rasterizer is not initialized yet the // first time it's called. @@ -256,14 +309,15 @@ bool RenderingServerRaster::is_low_end() const { return false; } -RenderingServerRaster::RenderingServerRaster() { - RSG::canvas = memnew(RenderingServerCanvas); - RSG::viewport = memnew(RenderingServerViewport); - RSG::scene = memnew(RenderingServerScene); - RSG::rasterizer = Rasterizer::create(); +RenderingServerDefault::RenderingServerDefault() { + RSG::canvas = memnew(RendererCanvasCull); + RSG::viewport = memnew(RendererViewport); + RendererSceneCull *sr = memnew(RendererSceneCull); + RSG::scene = sr; + RSG::rasterizer = RendererCompositor::create(); RSG::storage = RSG::rasterizer->get_storage(); RSG::canvas_render = RSG::rasterizer->get_canvas(); - RSG::scene_render = RSG::rasterizer->get_scene(); + sr->set_scene_render(RSG::rasterizer->get_scene()); frame_profile_frame = 0; @@ -273,7 +327,7 @@ RenderingServerRaster::RenderingServerRaster() { } } -RenderingServerRaster::~RenderingServerRaster() { +RenderingServerDefault::~RenderingServerDefault() { memdelete(RSG::canvas); memdelete(RSG::viewport); memdelete(RSG::rasterizer); diff --git a/servers/rendering/rendering_server_raster.h b/servers/rendering/rendering_server_default.h index a89d4db1f8..83afd9096d 100644 --- a/servers/rendering/rendering_server_raster.h +++ b/servers/rendering/rendering_server_default.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* rendering_server_raster.h */ +/* rendering_server_default.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,20 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RENDERING_SERVER_RASTER_H -#define RENDERING_SERVER_RASTER_H +#ifndef RENDERING_SERVER_DEFAULT_H +#define RENDERING_SERVER_DEFAULT_H #include "core/math/octree.h" -#include "rendering_server_canvas.h" +#include "core/templates/ordered_hash_map.h" +#include "renderer_canvas_cull.h" +#include "renderer_scene_cull.h" +#include "renderer_viewport.h" #include "rendering_server_globals.h" -#include "rendering_server_scene.h" -#include "rendering_server_viewport.h" -#include "servers/rendering/rasterizer.h" +#include "servers/rendering/renderer_compositor.h" #include "servers/rendering_server.h" -class RenderingServerRaster : public RenderingServer { +class RenderingServerDefault : public RenderingServer { enum { - MAX_INSTANCE_CULL = 8192, MAX_INSTANCE_LIGHTS = 4, LIGHT_CACHE_DIRTY = -1, @@ -73,6 +73,14 @@ class RenderingServerRaster : public RenderingServer { uint64_t frame_profile_frame; Vector<FrameProfileArea> frame_profile; + float frame_setup_time = 0; + + //for printing + bool print_gpu_profile = false; + OrderedHashMap<String, float> print_gpu_profile_task_time; + uint64_t print_frame_profile_ticks_from = 0; + uint32_t print_frame_profile_frame_count = 0; + public: //if editor is redrawing when it shouldn't, enable this and put a breakpoint in _changes_changed() //#define DEBUG_CHANGES @@ -218,6 +226,8 @@ public: BIND2RC(RID, shader_get_default_texture_param, RID, const StringName &) BIND2RC(Variant, shader_get_param_default, RID, const StringName &) + BIND1RC(ShaderNativeSourceCode, shader_get_native_source_code, RID) + /* COMMON MATERIAL API */ BIND0R(RID, material_create) @@ -232,14 +242,17 @@ public: /* MESH API */ - virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces) { + virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces, int p_blend_shape_count = 0) { RID mesh = mesh_create(); + mesh_set_blend_shape_count(mesh, p_blend_shape_count); for (int i = 0; i < p_surfaces.size(); i++) { mesh_add_surface(mesh, p_surfaces[i]); } return mesh; } + BIND2(mesh_set_blend_shape_count, RID, int) + BIND0R(RID, mesh_create) BIND2(mesh_add_surface, RID, const SurfaceData &) @@ -261,6 +274,8 @@ public: BIND2(mesh_set_custom_aabb, RID, const AABB &) BIND1RC(AABB, mesh_get_custom_aabb, RID) + BIND2(mesh_set_shadow_mesh, RID, RID) + BIND1(mesh_clear, RID) /* MULTIMESH API */ @@ -337,6 +352,7 @@ public: BIND2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode) BIND2(light_directional_set_blend_splits, RID, bool) + BIND2(light_directional_set_sky_only, RID, bool) BIND2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode) /* PROBE API */ @@ -356,6 +372,7 @@ public: BIND2(reflection_probe_set_enable_shadows, RID, bool) BIND2(reflection_probe_set_cull_mask, RID, uint32_t) BIND2(reflection_probe_set_resolution, RID, int) + BIND2(reflection_probe_set_lod_threshold, RID, float) /* DECAL API */ @@ -536,11 +553,13 @@ public: BIND2(viewport_set_global_canvas_transform, RID, const Transform2D &) BIND4(viewport_set_canvas_stacking, RID, RID, int, int) - BIND2(viewport_set_shadow_atlas_size, RID, int) + BIND3(viewport_set_shadow_atlas_size, RID, int, bool) + BIND3(viewport_set_sdf_oversize_and_scale, RID, ViewportSDFOversize, ViewportSDFScale) BIND3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int) BIND2(viewport_set_msaa, RID, ViewportMSAA) BIND2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA) BIND2(viewport_set_use_debanding, RID, bool) + BIND2(viewport_set_lod_threshold, RID, float) BIND2R(int, viewport_get_render_info, RID, ViewportRenderInfo) BIND2(viewport_set_debug_draw, RID, ViewportDebugDraw) @@ -553,9 +572,9 @@ public: #undef BINDBASE //from now on, calls forwarded to this singleton -#define BINDBASE RSG::scene_render +#define BINDBASE RSG::scene - BIND1(directional_shadow_atlas_set_size, int) + BIND2(directional_shadow_atlas_set_size, int, bool) BIND1(gi_probe_set_quality, GIProbeQuality) /* SKY API */ @@ -584,8 +603,8 @@ public: BIND6(environment_set_ssr, RID, bool, int, float, float, float) BIND1(environment_set_ssr_roughness_quality, EnvironmentSSRRoughnessQuality) - BIND9(environment_set_ssao, RID, bool, float, float, float, float, float, EnvironmentSSAOBlur, float) - BIND2(environment_set_ssao_quality, EnvironmentSSAOQuality, bool) + BIND10(environment_set_ssao, RID, bool, float, float, float, float, float, float, float, float) + BIND6(environment_set_ssao_quality, EnvironmentSSAOQuality, bool, float, int, float, float) BIND11(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, EnvironmentGlowBlendMode, float, float, float) BIND1(environment_glow_set_use_bicubic_upscale, bool) @@ -593,7 +612,7 @@ public: BIND9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float) - BIND6(environment_set_adjustment, RID, bool, float, float, float, RID) + BIND7(environment_set_adjustment, RID, bool, float, float, float, bool, RID) BIND9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float) BIND9(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, EnvVolumetricFogShadowFilter) @@ -606,6 +625,7 @@ public: BIND11(environment_set_sdfgi, RID, bool, EnvironmentSDFGICascades, float, EnvironmentSDFGIYScale, bool, bool, bool, float, float, float) BIND1(environment_set_sdfgi_ray_count, EnvironmentSDFGIRayCount) BIND1(environment_set_sdfgi_frames_to_converge, EnvironmentSDFGIFramesToConverge) + BIND1(environment_set_sdfgi_frames_to_update_light, EnvironmentSDFGIFramesToUpdateLight) BIND3R(Ref<Image>, environment_bake_panorama, RID, bool, const Size2i &) @@ -669,6 +689,7 @@ public: BIND5(instance_geometry_set_draw_range, RID, float, float, float, float) BIND2(instance_geometry_set_as_instance_lod, RID, RID) BIND4(instance_geometry_set_lightmap, RID, RID, const Rect2 &, int) + BIND2(instance_geometry_set_lod_bias, RID, float) BIND3(instance_geometry_set_shader_parameter, RID, const StringName &, const Variant &) BIND2RC(Variant, instance_geometry_get_shader_parameter, RID, const StringName &) @@ -677,6 +698,8 @@ public: BIND3R(TypedArray<Image>, bake_render_uv2, RID, const Vector<RID> &, const Size2i &) + BIND1(gi_set_use_half_resolution, bool) + #undef BINDBASE //from now on, calls forwarded to this singleton #define BINDBASE RSG::canvas @@ -717,7 +740,7 @@ public: BIND2(canvas_item_set_draw_behind_parent, RID, bool) BIND5(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float) - BIND4(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float) + BIND5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool) BIND4(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float) BIND3(canvas_item_add_rect, RID, const Rect2 &, const Color &) BIND4(canvas_item_add_circle, RID, const Point2 &, float, const Color &) @@ -748,9 +771,12 @@ public: BIND6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool) BIND0R(RID, canvas_light_create) + + BIND2(canvas_light_set_mode, RID, CanvasLightMode) + BIND2(canvas_light_attach_to_canvas, RID, RID) BIND2(canvas_light_set_enabled, RID, bool) - BIND2(canvas_light_set_scale, RID, float) + BIND2(canvas_light_set_texture_scale, RID, float) BIND2(canvas_light_set_transform, RID, const Transform2D &) BIND2(canvas_light_set_texture, RID, RID) BIND2(canvas_light_set_texture_offset, RID, const Vector2 &) @@ -761,8 +787,9 @@ public: BIND3(canvas_light_set_layer_range, RID, int, int) BIND2(canvas_light_set_item_cull_mask, RID, int) BIND2(canvas_light_set_item_shadow_cull_mask, RID, int) + BIND2(canvas_light_set_directional_distance, RID, float) - BIND2(canvas_light_set_mode, RID, CanvasLightMode) + BIND2(canvas_light_set_blend_mode, RID, CanvasLightBlendMode) BIND2(canvas_light_set_shadow_enabled, RID, bool) BIND2(canvas_light_set_shadow_filter, RID, CanvasLightShadowFilter) @@ -773,12 +800,12 @@ public: BIND2(canvas_light_occluder_attach_to_canvas, RID, RID) BIND2(canvas_light_occluder_set_enabled, RID, bool) BIND2(canvas_light_occluder_set_polygon, RID, RID) + BIND2(canvas_light_occluder_set_as_sdf_collision, RID, bool) BIND2(canvas_light_occluder_set_transform, RID, const Transform2D &) BIND2(canvas_light_occluder_set_light_mask, RID, int) BIND0R(RID, canvas_occluder_polygon_create) BIND3(canvas_occluder_polygon_set_shape, RID, const Vector<Vector2> &, bool) - BIND2(canvas_occluder_polygon_set_shape_as_lines, RID, const Vector<Vector2> &) BIND2(canvas_occluder_polygon_set_cull_mode, RID, CanvasOccluderPolygonCullMode) @@ -834,6 +861,8 @@ public: /* TESTING */ + virtual float get_frame_setup_time_cpu() const; + virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true); virtual void set_default_clear_color(const Color &p_color); @@ -848,8 +877,10 @@ public: virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir); - RenderingServerRaster(); - ~RenderingServerRaster(); + virtual void set_print_gpu_profile(bool p_enable); + + RenderingServerDefault(); + ~RenderingServerDefault(); #undef DISPLAY_CHANGED diff --git a/servers/rendering/rendering_server_globals.cpp b/servers/rendering/rendering_server_globals.cpp index 5a270520a9..c0d9988e85 100644 --- a/servers/rendering/rendering_server_globals.cpp +++ b/servers/rendering/rendering_server_globals.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,11 +30,10 @@ #include "rendering_server_globals.h" -RasterizerStorage *RenderingServerGlobals::storage = nullptr; -RasterizerCanvas *RenderingServerGlobals::canvas_render = nullptr; -RasterizerScene *RenderingServerGlobals::scene_render = nullptr; -Rasterizer *RenderingServerGlobals::rasterizer = nullptr; +RendererStorage *RenderingServerGlobals::storage = nullptr; +RendererCanvasRender *RenderingServerGlobals::canvas_render = nullptr; +RendererCompositor *RenderingServerGlobals::rasterizer = nullptr; -RenderingServerCanvas *RenderingServerGlobals::canvas = nullptr; -RenderingServerViewport *RenderingServerGlobals::viewport = nullptr; -RenderingServerScene *RenderingServerGlobals::scene = nullptr; +RendererCanvasCull *RenderingServerGlobals::canvas = nullptr; +RendererViewport *RenderingServerGlobals::viewport = nullptr; +RendererScene *RenderingServerGlobals::scene = nullptr; diff --git a/servers/rendering/rendering_server_globals.h b/servers/rendering/rendering_server_globals.h index b33f328b69..a28a0f5180 100644 --- a/servers/rendering/rendering_server_globals.h +++ b/servers/rendering/rendering_server_globals.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,22 +31,23 @@ #ifndef RENDERING_SERVER_GLOBALS_H #define RENDERING_SERVER_GLOBALS_H -#include "rasterizer.h" +#include "servers/rendering/renderer_canvas_cull.h" +#include "servers/rendering/renderer_canvas_render.h" +#include "servers/rendering/renderer_scene.h" -class RenderingServerCanvas; -class RenderingServerViewport; -class RenderingServerScene; +class RendererCanvasCull; +class RendererViewport; +class RendererScene; class RenderingServerGlobals { public: - static RasterizerStorage *storage; - static RasterizerCanvas *canvas_render; - static RasterizerScene *scene_render; - static Rasterizer *rasterizer; + static RendererStorage *storage; + static RendererCanvasRender *canvas_render; + static RendererCompositor *rasterizer; - static RenderingServerCanvas *canvas; - static RenderingServerViewport *viewport; - static RenderingServerScene *scene; + static RendererCanvasCull *canvas; + static RendererViewport *viewport; + static RendererScene *scene; }; #define RSG RenderingServerGlobals diff --git a/servers/rendering/rendering_server_scene.cpp b/servers/rendering/rendering_server_scene.cpp deleted file mode 100644 index ae6786090a..0000000000 --- a/servers/rendering/rendering_server_scene.cpp +++ /dev/null @@ -1,3040 +0,0 @@ -/*************************************************************************/ -/* rendering_server_scene.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "rendering_server_scene.h" - -#include "core/os/os.h" -#include "rendering_server_globals.h" -#include "rendering_server_raster.h" - -#include <new> - -/* CAMERA API */ - -RID RenderingServerScene::camera_create() { - Camera *camera = memnew(Camera); - return camera_owner.make_rid(camera); -} - -void RenderingServerScene::camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) { - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - camera->type = Camera::PERSPECTIVE; - camera->fov = p_fovy_degrees; - camera->znear = p_z_near; - camera->zfar = p_z_far; -} - -void RenderingServerScene::camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) { - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - camera->type = Camera::ORTHOGONAL; - camera->size = p_size; - camera->znear = p_z_near; - camera->zfar = p_z_far; -} - -void RenderingServerScene::camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) { - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - camera->type = Camera::FRUSTUM; - camera->size = p_size; - camera->offset = p_offset; - camera->znear = p_z_near; - camera->zfar = p_z_far; -} - -void RenderingServerScene::camera_set_transform(RID p_camera, const Transform &p_transform) { - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - camera->transform = p_transform.orthonormalized(); -} - -void RenderingServerScene::camera_set_cull_mask(RID p_camera, uint32_t p_layers) { - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - - camera->visible_layers = p_layers; -} - -void RenderingServerScene::camera_set_environment(RID p_camera, RID p_env) { - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - camera->env = p_env; -} - -void RenderingServerScene::camera_set_camera_effects(RID p_camera, RID p_fx) { - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - camera->effects = p_fx; -} - -void RenderingServerScene::camera_set_use_vertical_aspect(RID p_camera, bool p_enable) { - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - camera->vaspect = p_enable; -} - -/* SCENARIO API */ - -void *RenderingServerScene::_instance_pair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int) { - //RenderingServerScene *self = (RenderingServerScene*)p_self; - Instance *A = p_A; - Instance *B = p_B; - - //instance indices are designed so greater always contains lesser - if (A->base_type > B->base_type) { - SWAP(A, B); //lesser always first - } - - if (B->base_type == RS::INSTANCE_LIGHT && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - InstanceLightData::PairInfo pinfo; - pinfo.geometry = A; - pinfo.L = geom->lighting.push_back(B); - - List<InstanceLightData::PairInfo>::Element *E = light->geometries.push_back(pinfo); - - if (geom->can_cast_shadows) { - light->shadow_dirty = true; - } - geom->lighting_dirty = true; - - return E; //this element should make freeing faster - } else if (B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - InstanceReflectionProbeData::PairInfo pinfo; - pinfo.geometry = A; - pinfo.L = geom->reflection_probes.push_back(B); - - List<InstanceReflectionProbeData::PairInfo>::Element *E = reflection_probe->geometries.push_back(pinfo); - - geom->reflection_dirty = true; - - return E; //this element should make freeing faster - } else if (B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - InstanceDecalData::PairInfo pinfo; - pinfo.geometry = A; - pinfo.L = geom->decals.push_back(B); - - List<InstanceDecalData::PairInfo>::Element *E = decal->geometries.push_back(pinfo); - - geom->decal_dirty = true; - - return E; //this element should make freeing faster - } else if (B->base_type == RS::INSTANCE_LIGHTMAP && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - if (A->dynamic_gi) { - InstanceLightmapData::PairInfo pinfo; - pinfo.geometry = A; - pinfo.L = geom->lightmap_captures.push_back(B); - List<InstanceLightmapData::PairInfo>::Element *E = lightmap_data->geometries.push_back(pinfo); - ((RenderingServerScene *)p_self)->_instance_queue_update(A, false, false); //need to update capture - return E; //this element should make freeing faster - } else { - return nullptr; - } - - } else if (B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - InstanceGIProbeData::PairInfo pinfo; - pinfo.geometry = A; - pinfo.L = geom->gi_probes.push_back(B); - - List<InstanceGIProbeData::PairInfo>::Element *E; - if (A->dynamic_gi) { - E = gi_probe->dynamic_geometries.push_back(pinfo); - } else { - E = gi_probe->geometries.push_back(pinfo); - } - - geom->gi_probes_dirty = true; - - return E; //this element should make freeing faster - - } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); - return gi_probe->lights.insert(A); - } else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) { - RSG::storage->particles_add_collision(A->base, B); - } - - return nullptr; -} - -void RenderingServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int, void *udata) { - //RenderingServerScene *self = (RenderingServerScene*)p_self; - Instance *A = p_A; - Instance *B = p_B; - - //instance indices are designed so greater always contains lesser - if (A->base_type > B->base_type) { - SWAP(A, B); //lesser always first - } - - if (B->base_type == RS::INSTANCE_LIGHT && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - List<InstanceLightData::PairInfo>::Element *E = reinterpret_cast<List<InstanceLightData::PairInfo>::Element *>(udata); - - geom->lighting.erase(E->get().L); - light->geometries.erase(E); - - if (geom->can_cast_shadows) { - light->shadow_dirty = true; - } - geom->lighting_dirty = true; - - } else if (B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - List<InstanceReflectionProbeData::PairInfo>::Element *E = reinterpret_cast<List<InstanceReflectionProbeData::PairInfo>::Element *>(udata); - - geom->reflection_probes.erase(E->get().L); - reflection_probe->geometries.erase(E); - - geom->reflection_dirty = true; - } else if (B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - List<InstanceDecalData::PairInfo>::Element *E = reinterpret_cast<List<InstanceDecalData::PairInfo>::Element *>(udata); - - geom->decals.erase(E->get().L); - decal->geometries.erase(E); - - geom->decal_dirty = true; - } else if (B->base_type == RS::INSTANCE_LIGHTMAP && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - if (udata) { //only for dynamic geometries - InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - List<InstanceLightmapData::PairInfo>::Element *E = reinterpret_cast<List<InstanceLightmapData::PairInfo>::Element *>(udata); - - geom->lightmap_captures.erase(E->get().L); - lightmap_data->geometries.erase(E); - ((RenderingServerScene *)p_self)->_instance_queue_update(A, false, false); //need to update capture - } - - } else if (B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - - List<InstanceGIProbeData::PairInfo>::Element *E = reinterpret_cast<List<InstanceGIProbeData::PairInfo>::Element *>(udata); - - geom->gi_probes.erase(E->get().L); - if (A->dynamic_gi) { - gi_probe->dynamic_geometries.erase(E); - } else { - gi_probe->geometries.erase(E); - } - - geom->gi_probes_dirty = true; - - } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); - Set<Instance *>::Element *E = reinterpret_cast<Set<Instance *>::Element *>(udata); - - gi_probe->lights.erase(E); - } else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) { - RSG::storage->particles_remove_collision(A->base, B); - } -} - -RID RenderingServerScene::scenario_create() { - Scenario *scenario = memnew(Scenario); - ERR_FAIL_COND_V(!scenario, RID()); - RID scenario_rid = scenario_owner.make_rid(scenario); - scenario->self = scenario_rid; - - scenario->octree.set_pair_callback(_instance_pair, this); - scenario->octree.set_unpair_callback(_instance_unpair, this); - scenario->reflection_probe_shadow_atlas = RSG::scene_render->shadow_atlas_create(); - RSG::scene_render->shadow_atlas_set_size(scenario->reflection_probe_shadow_atlas, 1024); //make enough shadows for close distance, don't bother with rest - RSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 0, 4); - RSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 1, 4); - RSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 2, 4); - RSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 3, 8); - scenario->reflection_atlas = RSG::scene_render->reflection_atlas_create(); - return scenario_rid; -} - -void RenderingServerScene::scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND(!scenario); - scenario->debug = p_debug_mode; -} - -void RenderingServerScene::scenario_set_environment(RID p_scenario, RID p_environment) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND(!scenario); - scenario->environment = p_environment; -} - -void RenderingServerScene::scenario_set_camera_effects(RID p_scenario, RID p_camera_effects) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND(!scenario); - scenario->camera_effects = p_camera_effects; -} - -void RenderingServerScene::scenario_set_fallback_environment(RID p_scenario, RID p_environment) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND(!scenario); - scenario->fallback_environment = p_environment; -} - -void RenderingServerScene::scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND(!scenario); - RSG::scene_render->reflection_atlas_set_size(scenario->reflection_atlas, p_reflection_size, p_reflection_count); -} - -/* INSTANCING API */ - -void RenderingServerScene::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies) { - if (p_update_aabb) { - p_instance->update_aabb = true; - } - if (p_update_dependencies) { - p_instance->update_dependencies = true; - } - - if (p_instance->update_item.in_list()) { - return; - } - - _instance_update_list.add(&p_instance->update_item); -} - -RID RenderingServerScene::instance_create() { - Instance *instance = memnew(Instance); - ERR_FAIL_COND_V(!instance, RID()); - - RID instance_rid = instance_owner.make_rid(instance); - instance->self = instance_rid; - - return instance_rid; -} - -void RenderingServerScene::instance_set_base(RID p_instance, RID p_base) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - Scenario *scenario = instance->scenario; - - if (instance->base_type != RS::INSTANCE_NONE) { - //free anything related to that base - - if (scenario && instance->octree_id) { - scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away - instance->octree_id = 0; - } - - switch (instance->base_type) { - case RS::INSTANCE_LIGHT: { - InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); - - if (scenario && RSG::storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { - scenario->dynamic_lights.erase(light->instance); - } - -#ifdef DEBUG_ENABLED - if (light->geometries.size()) { - ERR_PRINT("BUG, indexing did not unpair geometries from light."); - } -#endif - if (scenario && light->D) { - scenario->directional_lights.erase(light->D); - light->D = nullptr; - } - RSG::scene_render->free(light->instance); - } break; - case RS::INSTANCE_REFLECTION_PROBE: { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data); - RSG::scene_render->free(reflection_probe->instance); - if (reflection_probe->update_list.in_list()) { - reflection_probe_render_list.remove(&reflection_probe->update_list); - } - } break; - case RS::INSTANCE_DECAL: { - InstanceDecalData *decal = static_cast<InstanceDecalData *>(instance->base_data); - RSG::scene_render->free(decal->instance); - - } break; - case RS::INSTANCE_LIGHTMAP: { - InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(instance->base_data); - //erase dependencies, since no longer a lightmap - while (lightmap_data->users.front()) { - instance_geometry_set_lightmap(lightmap_data->users.front()->get()->self, RID(), Rect2(), 0); - } - } break; - case RS::INSTANCE_GI_PROBE: { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); -#ifdef DEBUG_ENABLED - if (gi_probe->geometries.size()) { - ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe."); - } -#endif -#ifdef DEBUG_ENABLED - if (gi_probe->lights.size()) { - ERR_PRINT("BUG, indexing did not unpair lights from GIProbe."); - } -#endif - if (gi_probe->update_element.in_list()) { - gi_probe_update_list.remove(&gi_probe->update_element); - } - - RSG::scene_render->free(gi_probe->probe_instance); - - } break; - default: { - } - } - - if (instance->base_data) { - memdelete(instance->base_data); - instance->base_data = nullptr; - } - - instance->blend_values.clear(); - instance->materials.clear(); - } - - instance->base_type = RS::INSTANCE_NONE; - instance->base = RID(); - - if (p_base.is_valid()) { - instance->base_type = RSG::storage->get_base_type(p_base); - ERR_FAIL_COND(instance->base_type == RS::INSTANCE_NONE); - - switch (instance->base_type) { - case RS::INSTANCE_LIGHT: { - InstanceLightData *light = memnew(InstanceLightData); - - if (scenario && RSG::storage->light_get_type(p_base) == RS::LIGHT_DIRECTIONAL) { - light->D = scenario->directional_lights.push_back(instance); - } - - light->instance = RSG::scene_render->light_instance_create(p_base); - - instance->base_data = light; - } break; - case RS::INSTANCE_MESH: - case RS::INSTANCE_MULTIMESH: - case RS::INSTANCE_IMMEDIATE: - case RS::INSTANCE_PARTICLES: { - InstanceGeometryData *geom = memnew(InstanceGeometryData); - instance->base_data = geom; - if (instance->base_type == RS::INSTANCE_MESH) { - instance->blend_values.resize(RSG::storage->mesh_get_blend_shape_count(p_base)); - } - } break; - case RS::INSTANCE_REFLECTION_PROBE: { - InstanceReflectionProbeData *reflection_probe = memnew(InstanceReflectionProbeData); - reflection_probe->owner = instance; - instance->base_data = reflection_probe; - - reflection_probe->instance = RSG::scene_render->reflection_probe_instance_create(p_base); - } break; - case RS::INSTANCE_DECAL: { - InstanceDecalData *decal = memnew(InstanceDecalData); - decal->owner = instance; - instance->base_data = decal; - - decal->instance = RSG::scene_render->decal_instance_create(p_base); - } break; - case RS::INSTANCE_LIGHTMAP: { - InstanceLightmapData *lightmap_data = memnew(InstanceLightmapData); - instance->base_data = lightmap_data; - //lightmap_data->instance = RSG::scene_render->lightmap_data_instance_create(p_base); - } break; - case RS::INSTANCE_GI_PROBE: { - InstanceGIProbeData *gi_probe = memnew(InstanceGIProbeData); - instance->base_data = gi_probe; - gi_probe->owner = instance; - - if (scenario && !gi_probe->update_element.in_list()) { - gi_probe_update_list.add(&gi_probe->update_element); - } - - gi_probe->probe_instance = RSG::scene_render->gi_probe_instance_create(p_base); - - } break; - default: { - } - } - - instance->base = p_base; - - //forcefully update the dependency now, so if for some reason it gets removed, we can immediately clear it - RSG::storage->base_update_dependency(p_base, instance); - } - - _instance_queue_update(instance, true, true); -} - -void RenderingServerScene::instance_set_scenario(RID p_instance, RID p_scenario) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - if (instance->scenario) { - instance->scenario->instances.remove(&instance->scenario_item); - - if (instance->octree_id) { - instance->scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away - instance->octree_id = 0; - } - - switch (instance->base_type) { - case RS::INSTANCE_LIGHT: { - InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); -#ifdef DEBUG_ENABLED - if (light->geometries.size()) { - ERR_PRINT("BUG, indexing did not unpair geometries from light."); - } -#endif - if (light->D) { - instance->scenario->directional_lights.erase(light->D); - light->D = nullptr; - } - } break; - case RS::INSTANCE_REFLECTION_PROBE: { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data); - RSG::scene_render->reflection_probe_release_atlas_index(reflection_probe->instance); - - } break; - case RS::INSTANCE_PARTICLES_COLLISION: { - heightfield_particle_colliders_update_list.erase(instance); - } break; - case RS::INSTANCE_GI_PROBE: { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); - -#ifdef DEBUG_ENABLED - if (gi_probe->geometries.size()) { - ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe."); - } -#endif -#ifdef DEBUG_ENABLED - if (gi_probe->lights.size()) { - ERR_PRINT("BUG, indexing did not unpair lights from GIProbe."); - } -#endif - - if (gi_probe->update_element.in_list()) { - gi_probe_update_list.remove(&gi_probe->update_element); - } - } break; - default: { - } - } - - instance->scenario = nullptr; - } - - if (p_scenario.is_valid()) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND(!scenario); - - instance->scenario = scenario; - - scenario->instances.add(&instance->scenario_item); - - switch (instance->base_type) { - case RS::INSTANCE_LIGHT: { - InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); - - if (RSG::storage->light_get_type(instance->base) == RS::LIGHT_DIRECTIONAL) { - light->D = scenario->directional_lights.push_back(instance); - } - } break; - case RS::INSTANCE_GI_PROBE: { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); - if (!gi_probe->update_element.in_list()) { - gi_probe_update_list.add(&gi_probe->update_element); - } - } break; - default: { - } - } - - _instance_queue_update(instance, true, true); - } -} - -void RenderingServerScene::instance_set_layer_mask(RID p_instance, uint32_t p_mask) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - instance->layer_mask = p_mask; -} - -void RenderingServerScene::instance_set_transform(RID p_instance, const Transform &p_transform) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - if (instance->transform == p_transform) { - return; //must be checked to avoid worst evil - } - -#ifdef DEBUG_ENABLED - - for (int i = 0; i < 4; i++) { - const Vector3 &v = i < 3 ? p_transform.basis.elements[i] : p_transform.origin; - ERR_FAIL_COND(Math::is_inf(v.x)); - ERR_FAIL_COND(Math::is_nan(v.x)); - ERR_FAIL_COND(Math::is_inf(v.y)); - ERR_FAIL_COND(Math::is_nan(v.y)); - ERR_FAIL_COND(Math::is_inf(v.z)); - ERR_FAIL_COND(Math::is_nan(v.z)); - } - -#endif - instance->transform = p_transform; - _instance_queue_update(instance, true); -} - -void RenderingServerScene::instance_attach_object_instance_id(RID p_instance, ObjectID p_id) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - instance->object_id = p_id; -} - -void RenderingServerScene::instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - if (instance->update_item.in_list()) { - _update_dirty_instance(instance); - } - - ERR_FAIL_INDEX(p_shape, instance->blend_values.size()); - instance->blend_values.write[p_shape] = p_weight; -} - -void RenderingServerScene::instance_set_surface_material(RID p_instance, int p_surface, RID p_material) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - if (instance->base_type == RS::INSTANCE_MESH) { - //may not have been updated yet, may also have not been set yet. When updated will be correcte, worst case - instance->materials.resize(MAX(p_surface + 1, RSG::storage->mesh_get_surface_count(instance->base))); - } - - ERR_FAIL_INDEX(p_surface, instance->materials.size()); - - instance->materials.write[p_surface] = p_material; - - _instance_queue_update(instance, false, true); -} - -void RenderingServerScene::instance_set_visible(RID p_instance, bool p_visible) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - if (instance->visible == p_visible) { - return; - } - - instance->visible = p_visible; - - switch (instance->base_type) { - case RS::INSTANCE_LIGHT: { - if (RSG::storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && instance->octree_id && instance->scenario) { - instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_LIGHT, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0); - } - - } break; - case RS::INSTANCE_REFLECTION_PROBE: { - if (instance->octree_id && instance->scenario) { - instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_REFLECTION_PROBE, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0); - } - - } break; - case RS::INSTANCE_DECAL: { - if (instance->octree_id && instance->scenario) { - instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_DECAL, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0); - } - - } break; - case RS::INSTANCE_LIGHTMAP: { - if (instance->octree_id && instance->scenario) { - instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_LIGHTMAP, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0); - } - - } break; - case RS::INSTANCE_GI_PROBE: { - if (instance->octree_id && instance->scenario) { - instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_GI_PROBE, p_visible ? (RS::INSTANCE_GEOMETRY_MASK | (1 << RS::INSTANCE_LIGHT)) : 0); - } - - } break; - case RS::INSTANCE_PARTICLES_COLLISION: { - if (instance->octree_id && instance->scenario) { - instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_PARTICLES_COLLISION, p_visible ? (1 << RS::INSTANCE_PARTICLES) : 0); - } - - } break; - default: { - } - } -} - -inline bool is_geometry_instance(RenderingServer::InstanceType p_type) { - return p_type == RS::INSTANCE_MESH || p_type == RS::INSTANCE_MULTIMESH || p_type == RS::INSTANCE_PARTICLES || p_type == RS::INSTANCE_IMMEDIATE; -} - -void RenderingServerScene::instance_set_custom_aabb(RID p_instance, AABB p_aabb) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - ERR_FAIL_COND(!is_geometry_instance(instance->base_type)); - - if (p_aabb != AABB()) { - // Set custom AABB - if (instance->custom_aabb == nullptr) { - instance->custom_aabb = memnew(AABB); - } - *instance->custom_aabb = p_aabb; - - } else { - // Clear custom AABB - if (instance->custom_aabb != nullptr) { - memdelete(instance->custom_aabb); - instance->custom_aabb = nullptr; - } - } - - if (instance->scenario) { - _instance_queue_update(instance, true, false); - } -} - -void RenderingServerScene::instance_attach_skeleton(RID p_instance, RID p_skeleton) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - if (instance->skeleton == p_skeleton) { - return; - } - - instance->skeleton = p_skeleton; - - if (p_skeleton.is_valid()) { - //update the dependency now, so if cleared, we remove it - RSG::storage->skeleton_update_dependency(p_skeleton, instance); - } - _instance_queue_update(instance, true, true); -} - -void RenderingServerScene::instance_set_exterior(RID p_instance, bool p_enabled) { -} - -void RenderingServerScene::instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - instance->extra_margin = p_margin; - _instance_queue_update(instance, true, false); -} - -Vector<ObjectID> RenderingServerScene::instances_cull_aabb(const AABB &p_aabb, RID p_scenario) const { - Vector<ObjectID> instances; - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND_V(!scenario, instances); - - const_cast<RenderingServerScene *>(this)->update_dirty_instances(); // check dirty instances before culling - - int culled = 0; - Instance *cull[1024]; - culled = scenario->octree.cull_aabb(p_aabb, cull, 1024); - - for (int i = 0; i < culled; i++) { - Instance *instance = cull[i]; - ERR_CONTINUE(!instance); - if (instance->object_id.is_null()) { - continue; - } - - instances.push_back(instance->object_id); - } - - return instances; -} - -Vector<ObjectID> RenderingServerScene::instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const { - Vector<ObjectID> instances; - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND_V(!scenario, instances); - const_cast<RenderingServerScene *>(this)->update_dirty_instances(); // check dirty instances before culling - - int culled = 0; - Instance *cull[1024]; - culled = scenario->octree.cull_segment(p_from, p_from + p_to * 10000, cull, 1024); - - for (int i = 0; i < culled; i++) { - Instance *instance = cull[i]; - ERR_CONTINUE(!instance); - if (instance->object_id.is_null()) { - continue; - } - - instances.push_back(instance->object_id); - } - - return instances; -} - -Vector<ObjectID> RenderingServerScene::instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario) const { - Vector<ObjectID> instances; - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND_V(!scenario, instances); - const_cast<RenderingServerScene *>(this)->update_dirty_instances(); // check dirty instances before culling - - int culled = 0; - Instance *cull[1024]; - - culled = scenario->octree.cull_convex(p_convex, cull, 1024); - - for (int i = 0; i < culled; i++) { - Instance *instance = cull[i]; - ERR_CONTINUE(!instance); - if (instance->object_id.is_null()) { - continue; - } - - instances.push_back(instance->object_id); - } - - return instances; -} - -void RenderingServerScene::instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - //ERR_FAIL_COND(((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK)); - - switch (p_flags) { - case RS::INSTANCE_FLAG_USE_BAKED_LIGHT: { - instance->baked_light = p_enabled; - - } break; - case RS::INSTANCE_FLAG_USE_DYNAMIC_GI: { - if (p_enabled == instance->dynamic_gi) { - //bye, redundant - return; - } - - if (instance->octree_id != 0) { - //remove from octree, it needs to be re-paired - instance->scenario->octree.erase(instance->octree_id); - instance->octree_id = 0; - _instance_queue_update(instance, true, true); - } - - //once out of octree, can be changed - instance->dynamic_gi = p_enabled; - - } break; - case RS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE: { - instance->redraw_if_visible = p_enabled; - - } break; - default: { - } - } -} - -void RenderingServerScene::instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - instance->cast_shadows = p_shadow_casting_setting; - _instance_queue_update(instance, false, true); -} - -void RenderingServerScene::instance_geometry_set_material_override(RID p_instance, RID p_material) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - instance->material_override = p_material; - _instance_queue_update(instance, false, true); -} - -void RenderingServerScene::instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) { -} - -void RenderingServerScene::instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) { -} - -void RenderingServerScene::instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - if (instance->lightmap) { - InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(((Instance *)instance->lightmap)->base_data); - lightmap_data->users.erase(instance); - instance->lightmap = nullptr; - } - - Instance *lightmap_instance = instance_owner.getornull(p_lightmap); - - instance->lightmap = lightmap_instance; - instance->lightmap_uv_scale = p_lightmap_uv_scale; - instance->lightmap_slice_index = p_slice_index; - - if (lightmap_instance) { - InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(lightmap_instance->base_data); - lightmap_data->users.insert(instance); - } -} - -void RenderingServerScene::instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) { - Instance *instance = instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - Map<StringName, RasterizerScene::InstanceBase::InstanceShaderParameter>::Element *E = instance->instance_shader_parameters.find(p_parameter); - - if (!E) { - RasterizerScene::InstanceBase::InstanceShaderParameter isp; - isp.index = -1; - isp.info = PropertyInfo(); - isp.value = p_value; - instance->instance_shader_parameters[p_parameter] = isp; - } else { - E->get().value = p_value; - if (E->get().index >= 0 && instance->instance_allocated_shader_parameters) { - //update directly - RSG::storage->global_variables_instance_update(p_instance, E->get().index, p_value); - } - } -} - -Variant RenderingServerScene::instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const { - const Instance *instance = const_cast<RenderingServerScene *>(this)->instance_owner.getornull(p_instance); - ERR_FAIL_COND_V(!instance, Variant()); - - if (instance->instance_shader_parameters.has(p_parameter)) { - return instance->instance_shader_parameters[p_parameter].value; - } - return Variant(); -} - -Variant RenderingServerScene::instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const { - const Instance *instance = const_cast<RenderingServerScene *>(this)->instance_owner.getornull(p_instance); - ERR_FAIL_COND_V(!instance, Variant()); - - if (instance->instance_shader_parameters.has(p_parameter)) { - return instance->instance_shader_parameters[p_parameter].default_value; - } - return Variant(); -} - -void RenderingServerScene::instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const { - const Instance *instance = const_cast<RenderingServerScene *>(this)->instance_owner.getornull(p_instance); - ERR_FAIL_COND(!instance); - - const_cast<RenderingServerScene *>(this)->update_dirty_instances(); - - Vector<StringName> names; - for (Map<StringName, RasterizerScene::InstanceBase::InstanceShaderParameter>::Element *E = instance->instance_shader_parameters.front(); E; E = E->next()) { - names.push_back(E->key()); - } - names.sort_custom<StringName::AlphCompare>(); - for (int i = 0; i < names.size(); i++) { - PropertyInfo pinfo = instance->instance_shader_parameters[names[i]].info; - p_parameters->push_back(pinfo); - } -} - -void RenderingServerScene::_update_instance(Instance *p_instance) { - p_instance->version++; - - if (p_instance->base_type == RS::INSTANCE_LIGHT) { - InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); - - RSG::scene_render->light_instance_set_transform(light->instance, p_instance->transform); - RSG::scene_render->light_instance_set_aabb(light->instance, p_instance->transform.xform(p_instance->aabb)); - light->shadow_dirty = true; - - RS::LightBakeMode bake_mode = RSG::storage->light_get_bake_mode(p_instance->base); - if (RSG::storage->light_get_type(p_instance->base) != RS::LIGHT_DIRECTIONAL && bake_mode != light->bake_mode) { - if (p_instance->scenario && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { - p_instance->scenario->dynamic_lights.erase(light->instance); - } - - light->bake_mode = bake_mode; - - if (p_instance->scenario && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { - p_instance->scenario->dynamic_lights.push_back(light->instance); - } - } - - uint32_t max_sdfgi_cascade = RSG::storage->light_get_max_sdfgi_cascade(p_instance->base); - if (light->max_sdfgi_cascade != max_sdfgi_cascade) { - light->max_sdfgi_cascade = max_sdfgi_cascade; //should most likely make sdfgi dirty in scenario - } - } - - if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data); - - RSG::scene_render->reflection_probe_instance_set_transform(reflection_probe->instance, p_instance->transform); - reflection_probe->reflection_dirty = true; - } - - if (p_instance->base_type == RS::INSTANCE_DECAL) { - InstanceDecalData *decal = static_cast<InstanceDecalData *>(p_instance->base_data); - - RSG::scene_render->decal_instance_set_transform(decal->instance, p_instance->transform); - } - - if (p_instance->base_type == RS::INSTANCE_GI_PROBE) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(p_instance->base_data); - - RSG::scene_render->gi_probe_instance_set_transform_to_data(gi_probe->probe_instance, p_instance->transform); - } - - if (p_instance->base_type == RS::INSTANCE_PARTICLES) { - RSG::storage->particles_set_emission_transform(p_instance->base, p_instance->transform); - } - - if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { - //remove materials no longer used and un-own them - if (RSG::storage->particles_collision_is_heightfield(p_instance->base)) { - heightfield_particle_colliders_update_list.insert(p_instance); - } - } - - if (p_instance->aabb.has_no_surface()) { - return; - } - - if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); - //make sure lights are updated if it casts shadow - - if (geom->can_cast_shadows) { - for (List<Instance *>::Element *E = geom->lighting.front(); E; E = E->next()) { - InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); - light->shadow_dirty = true; - } - } - - if (!p_instance->lightmap && geom->lightmap_captures.size()) { - //affected by lightmap captures, must update capture info! - _update_instance_lightmap_captures(p_instance); - } else { - if (!p_instance->lightmap_sh.empty()) { - p_instance->lightmap_sh.clear(); //don't need SH - p_instance->lightmap_target_sh.clear(); //don't need SH - } - } - } - - if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) { - //if this moved, update the captured objects - InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(p_instance->base_data); - //erase dependencies, since no longer a lightmap - - for (List<InstanceLightmapData::PairInfo>::Element *E = lightmap_data->geometries.front(); E; E = E->next()) { - Instance *geom = E->get().geometry; - _instance_queue_update(geom, true, false); - } - } - - p_instance->mirror = p_instance->transform.basis.determinant() < 0.0; - - AABB new_aabb; - - new_aabb = p_instance->transform.xform(p_instance->aabb); - - p_instance->transformed_aabb = new_aabb; - - if (!p_instance->scenario) { - return; - } - - if (p_instance->octree_id == 0) { - uint32_t base_type = 1 << p_instance->base_type; - uint32_t pairable_mask = 0; - bool pairable = false; - - if (p_instance->base_type == RS::INSTANCE_LIGHT || p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE || p_instance->base_type == RS::INSTANCE_DECAL || p_instance->base_type == RS::INSTANCE_LIGHTMAP) { - pairable_mask = p_instance->visible ? RS::INSTANCE_GEOMETRY_MASK : 0; - pairable = true; - } - - if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { - pairable_mask = p_instance->visible ? (1 << RS::INSTANCE_PARTICLES) : 0; - pairable = true; - } - - if (p_instance->base_type == RS::INSTANCE_GI_PROBE) { - //lights and geometries - pairable_mask = p_instance->visible ? RS::INSTANCE_GEOMETRY_MASK | (1 << RS::INSTANCE_LIGHT) : 0; - pairable = true; - } - - // not inside octree - p_instance->octree_id = p_instance->scenario->octree.create(p_instance, new_aabb, 0, pairable, base_type, pairable_mask); - - } else { - /* - if (new_aabb==p_instance->data.transformed_aabb) - return; - */ - - p_instance->scenario->octree.move(p_instance->octree_id, new_aabb); - } -} - -void RenderingServerScene::_update_instance_aabb(Instance *p_instance) { - AABB new_aabb; - - ERR_FAIL_COND(p_instance->base_type != RS::INSTANCE_NONE && !p_instance->base.is_valid()); - - switch (p_instance->base_type) { - case RenderingServer::INSTANCE_NONE: { - // do nothing - } break; - case RenderingServer::INSTANCE_MESH: { - if (p_instance->custom_aabb) { - new_aabb = *p_instance->custom_aabb; - } else { - new_aabb = RSG::storage->mesh_get_aabb(p_instance->base, p_instance->skeleton); - } - - } break; - - case RenderingServer::INSTANCE_MULTIMESH: { - if (p_instance->custom_aabb) { - new_aabb = *p_instance->custom_aabb; - } else { - new_aabb = RSG::storage->multimesh_get_aabb(p_instance->base); - } - - } break; - case RenderingServer::INSTANCE_IMMEDIATE: { - if (p_instance->custom_aabb) { - new_aabb = *p_instance->custom_aabb; - } else { - new_aabb = RSG::storage->immediate_get_aabb(p_instance->base); - } - - } break; - case RenderingServer::INSTANCE_PARTICLES: { - if (p_instance->custom_aabb) { - new_aabb = *p_instance->custom_aabb; - } else { - new_aabb = RSG::storage->particles_get_aabb(p_instance->base); - } - - } break; - case RenderingServer::INSTANCE_PARTICLES_COLLISION: { - new_aabb = RSG::storage->particles_collision_get_aabb(p_instance->base); - - } break; - case RenderingServer::INSTANCE_LIGHT: { - new_aabb = RSG::storage->light_get_aabb(p_instance->base); - - } break; - case RenderingServer::INSTANCE_REFLECTION_PROBE: { - new_aabb = RSG::storage->reflection_probe_get_aabb(p_instance->base); - - } break; - case RenderingServer::INSTANCE_DECAL: { - new_aabb = RSG::storage->decal_get_aabb(p_instance->base); - - } break; - case RenderingServer::INSTANCE_GI_PROBE: { - new_aabb = RSG::storage->gi_probe_get_bounds(p_instance->base); - - } break; - case RenderingServer::INSTANCE_LIGHTMAP: { - new_aabb = RSG::storage->lightmap_get_aabb(p_instance->base); - - } break; - default: { - } - } - - // <Zylann> This is why I didn't re-use Instance::aabb to implement custom AABBs - if (p_instance->extra_margin) { - new_aabb.grow_by(p_instance->extra_margin); - } - - p_instance->aabb = new_aabb; -} - -void RenderingServerScene::_update_instance_lightmap_captures(Instance *p_instance) { - bool first_set = p_instance->lightmap_sh.size() == 0; - p_instance->lightmap_sh.resize(9); //using SH - p_instance->lightmap_target_sh.resize(9); //using SH - Color *instance_sh = p_instance->lightmap_target_sh.ptrw(); - bool inside = false; - Color accum_sh[9]; - float accum_blend = 0.0; - - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); - for (List<Instance *>::Element *E = geom->lightmap_captures.front(); E; E = E->next()) { - Instance *lightmap = E->get(); - - bool interior = RSG::storage->lightmap_is_interior(lightmap->base); - - if (inside && !interior) { - continue; //we are inside, ignore exteriors - } - - Transform to_bounds = lightmap->transform.affine_inverse(); - Vector3 center = p_instance->transform.xform(p_instance->aabb.position + p_instance->aabb.size * 0.5); //use aabb center - - Vector3 lm_pos = to_bounds.xform(center); - - AABB bounds = RSG::storage->lightmap_get_aabb(lightmap->base); - if (!bounds.has_point(lm_pos)) { - continue; //not in this lightmap - } - - Color sh[9]; - RSG::storage->lightmap_tap_sh_light(lightmap->base, lm_pos, sh); - - //rotate it - Basis rot = lightmap->transform.basis.orthonormalized(); - for (int i = 0; i < 3; i++) { - float csh[9]; - for (int j = 0; j < 9; j++) { - csh[j] = sh[j][i]; - } - rot.rotate_sh(csh); - for (int j = 0; j < 9; j++) { - sh[j][i] = csh[j]; - } - } - - Vector3 inner_pos = ((lm_pos - bounds.position) / bounds.size) * 2.0 - Vector3(1.0, 1.0, 1.0); - - float blend = MAX(inner_pos.x, MAX(inner_pos.y, inner_pos.z)); - //make blend more rounded - blend = Math::lerp(inner_pos.length(), blend, blend); - blend *= blend; - blend = MAX(0.0, 1.0 - blend); - - if (interior && !inside) { - //do not blend, just replace - for (int j = 0; j < 9; j++) { - accum_sh[j] = sh[j] * blend; - } - accum_blend = blend; - inside = true; - } else { - for (int j = 0; j < 9; j++) { - accum_sh[j] += sh[j] * blend; - } - accum_blend += blend; - } - } - - if (accum_blend > 0.0) { - for (int j = 0; j < 9; j++) { - instance_sh[j] = accum_sh[j] / accum_blend; - if (first_set) { - p_instance->lightmap_sh.write[j] = instance_sh[j]; - } - } - } -} - -bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario) { - InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); - - Transform light_transform = p_instance->transform; - light_transform.orthonormalize(); //scale does not count on lights - - bool animated_material_found = false; - - switch (RSG::storage->light_get_type(p_instance->base)) { - case RS::LIGHT_DIRECTIONAL: { - real_t max_distance = p_cam_projection.get_z_far(); - real_t shadow_max = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE); - if (shadow_max > 0 && !p_cam_orthogonal) { //its impractical (and leads to unwanted behaviors) to set max distance in orthogonal camera - max_distance = MIN(shadow_max, max_distance); - } - max_distance = MAX(max_distance, p_cam_projection.get_z_near() + 0.001); - real_t min_distance = MIN(p_cam_projection.get_z_near(), max_distance); - - RS::LightDirectionalShadowDepthRangeMode depth_range_mode = RSG::storage->light_directional_get_shadow_depth_range_mode(p_instance->base); - - real_t pancake_size = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE); - - if (depth_range_mode == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED) { - //optimize min/max - Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform); - int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK); - Plane base(p_cam_transform.origin, -p_cam_transform.basis.get_axis(2)); - //check distance max and min - - bool found_items = false; - real_t z_max = -1e20; - real_t z_min = 1e20; - - for (int i = 0; i < cull_count; i++) { - Instance *instance = instance_shadow_cull_result[i]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { - continue; - } - - if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { - animated_material_found = true; - } - - real_t max, min; - instance->transformed_aabb.project_range_in_plane(base, min, max); - - if (max > z_max) { - z_max = max; - } - - if (min < z_min) { - z_min = min; - } - - found_items = true; - } - - if (found_items) { - min_distance = MAX(min_distance, z_min); - max_distance = MIN(max_distance, z_max); - } - } - - real_t range = max_distance - min_distance; - - int splits = 0; - switch (RSG::storage->light_directional_get_shadow_mode(p_instance->base)) { - case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: - splits = 1; - break; - case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: - splits = 2; - break; - case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: - splits = 4; - break; - } - - real_t distances[5]; - - distances[0] = min_distance; - for (int i = 0; i < splits; i++) { - distances[i + 1] = min_distance + RSG::storage->light_get_param(p_instance->base, RS::LightParam(RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET + i)) * range; - }; - - distances[splits] = max_distance; - - real_t texture_size = RSG::scene_render->get_directional_light_shadow_size(light->instance); - - bool overlap = RSG::storage->light_directional_get_blend_splits(p_instance->base); - - real_t first_radius = 0.0; - - real_t min_distance_bias_scale = pancake_size > 0 ? distances[1] / 10.0 : 0; - - for (int i = 0; i < splits; i++) { - RENDER_TIMESTAMP("Culling Directional Light split" + itos(i)); - - // setup a camera matrix for that range! - CameraMatrix camera_matrix; - - real_t aspect = p_cam_projection.get_aspect(); - - if (p_cam_orthogonal) { - Vector2 vp_he = p_cam_projection.get_viewport_half_extents(); - - camera_matrix.set_orthogonal(vp_he.y * 2.0, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); - } else { - real_t fov = p_cam_projection.get_fov(); //this is actually yfov, because set aspect tries to keep it - camera_matrix.set_perspective(fov, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); - } - - //obtain the frustum endpoints - - Vector3 endpoints[8]; // frustum plane endpoints - bool res = camera_matrix.get_endpoints(p_cam_transform, endpoints); - ERR_CONTINUE(!res); - - // obtain the light frustm ranges (given endpoints) - - Transform transform = light_transform; //discard scale and stabilize light - - Vector3 x_vec = transform.basis.get_axis(Vector3::AXIS_X).normalized(); - Vector3 y_vec = transform.basis.get_axis(Vector3::AXIS_Y).normalized(); - Vector3 z_vec = transform.basis.get_axis(Vector3::AXIS_Z).normalized(); - //z_vec points agsint the camera, like in default opengl - - real_t x_min = 0.f, x_max = 0.f; - real_t y_min = 0.f, y_max = 0.f; - real_t z_min = 0.f, z_max = 0.f; - - // FIXME: z_max_cam is defined, computed, but not used below when setting up - // ortho_camera. Commented out for now to fix warnings but should be investigated. - real_t x_min_cam = 0.f, x_max_cam = 0.f; - real_t y_min_cam = 0.f, y_max_cam = 0.f; - real_t z_min_cam = 0.f; - //real_t z_max_cam = 0.f; - - real_t bias_scale = 1.0; - real_t aspect_bias_scale = 1.0; - - //used for culling - - for (int j = 0; j < 8; j++) { - real_t d_x = x_vec.dot(endpoints[j]); - real_t d_y = y_vec.dot(endpoints[j]); - real_t d_z = z_vec.dot(endpoints[j]); - - if (j == 0 || d_x < x_min) { - x_min = d_x; - } - if (j == 0 || d_x > x_max) { - x_max = d_x; - } - - if (j == 0 || d_y < y_min) { - y_min = d_y; - } - if (j == 0 || d_y > y_max) { - y_max = d_y; - } - - if (j == 0 || d_z < z_min) { - z_min = d_z; - } - if (j == 0 || d_z > z_max) { - z_max = d_z; - } - } - - real_t radius = 0; - real_t soft_shadow_expand = 0; - Vector3 center; - - { - //camera viewport stuff - - for (int j = 0; j < 8; j++) { - center += endpoints[j]; - } - center /= 8.0; - - //center=x_vec*(x_max-x_min)*0.5 + y_vec*(y_max-y_min)*0.5 + z_vec*(z_max-z_min)*0.5; - - for (int j = 0; j < 8; j++) { - real_t d = center.distance_to(endpoints[j]); - if (d > radius) { - radius = d; - } - } - - radius *= texture_size / (texture_size - 2.0); //add a texel by each side - - if (i == 0) { - first_radius = radius; - } else { - bias_scale = radius / first_radius; - } - - z_min_cam = z_vec.dot(center) - radius; - - { - float soft_shadow_angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SIZE); - - if (soft_shadow_angle > 0.0 && pancake_size > 0.0) { - float z_range = (z_vec.dot(center) + radius + pancake_size) - z_min_cam; - soft_shadow_expand = Math::tan(Math::deg2rad(soft_shadow_angle)) * z_range; - - x_max += soft_shadow_expand; - y_max += soft_shadow_expand; - - x_min -= soft_shadow_expand; - y_min -= soft_shadow_expand; - } - } - - x_max_cam = x_vec.dot(center) + radius + soft_shadow_expand; - x_min_cam = x_vec.dot(center) - radius - soft_shadow_expand; - y_max_cam = y_vec.dot(center) + radius + soft_shadow_expand; - y_min_cam = y_vec.dot(center) - radius - soft_shadow_expand; - - if (depth_range_mode == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE) { - //this trick here is what stabilizes the shadow (make potential jaggies to not move) - //at the cost of some wasted resolution. Still the quality increase is very well worth it - - real_t unit = radius * 2.0 / texture_size; - - x_max_cam = Math::stepify(x_max_cam, unit); - x_min_cam = Math::stepify(x_min_cam, unit); - y_max_cam = Math::stepify(y_max_cam, unit); - y_min_cam = Math::stepify(y_min_cam, unit); - } - } - - //now that we now all ranges, we can proceed to make the light frustum planes, for culling octree - - Vector<Plane> light_frustum_planes; - light_frustum_planes.resize(6); - - //right/left - light_frustum_planes.write[0] = Plane(x_vec, x_max); - light_frustum_planes.write[1] = Plane(-x_vec, -x_min); - //top/bottom - light_frustum_planes.write[2] = Plane(y_vec, y_max); - light_frustum_planes.write[3] = Plane(-y_vec, -y_min); - //near/far - light_frustum_planes.write[4] = Plane(z_vec, z_max + 1e6); - light_frustum_planes.write[5] = Plane(-z_vec, -z_min); // z_min is ok, since casters further than far-light plane are not needed - - int cull_count = p_scenario->octree.cull_convex(light_frustum_planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK); - - // a pre pass will need to be needed to determine the actual z-near to be used - - Plane near_plane(light_transform.origin, -light_transform.basis.get_axis(2)); - - real_t cull_max = 0; - for (int j = 0; j < cull_count; j++) { - real_t min, max; - Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { - cull_count--; - SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]); - j--; - continue; - } - - instance->transformed_aabb.project_range_in_plane(Plane(z_vec, 0), min, max); - instance->depth = near_plane.distance_to(instance->transform.origin); - instance->depth_layer = 0; - if (j == 0 || max > cull_max) { - cull_max = max; - } - } - - if (cull_max > z_max) { - z_max = cull_max; - } - - if (pancake_size > 0) { - z_max = z_vec.dot(center) + radius + pancake_size; - } - - if (aspect != 1.0) { - // if the aspect is different, then the radius will become larger. - // if this happens, then bias needs to be adjusted too, as depth will increase - // to do this, compare the depth of one that would have resulted from a square frustum - - CameraMatrix camera_matrix_square; - if (p_cam_orthogonal) { - Vector2 vp_he = camera_matrix.get_viewport_half_extents(); - if (p_cam_vaspect) { - camera_matrix_square.set_orthogonal(vp_he.x * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); - } else { - camera_matrix_square.set_orthogonal(vp_he.y * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); - } - } else { - Vector2 vp_he = camera_matrix.get_viewport_half_extents(); - if (p_cam_vaspect) { - camera_matrix_square.set_frustum(vp_he.x * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); - } else { - camera_matrix_square.set_frustum(vp_he.y * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); - } - } - - Vector3 endpoints_square[8]; // frustum plane endpoints - res = camera_matrix_square.get_endpoints(p_cam_transform, endpoints_square); - ERR_CONTINUE(!res); - Vector3 center_square; - real_t z_max_square = 0; - - for (int j = 0; j < 8; j++) { - center_square += endpoints_square[j]; - - real_t d_z = z_vec.dot(endpoints_square[j]); - - if (j == 0 || d_z > z_max_square) { - z_max_square = d_z; - } - } - - if (cull_max > z_max_square) { - z_max_square = cull_max; - } - - center_square /= 8.0; - - real_t radius_square = 0; - - for (int j = 0; j < 8; j++) { - real_t d = center_square.distance_to(endpoints_square[j]); - if (d > radius_square) { - radius_square = d; - } - } - - radius_square *= texture_size / (texture_size - 2.0); //add a texel by each side - - if (pancake_size > 0) { - z_max_square = z_vec.dot(center_square) + radius_square + pancake_size; - } - - real_t z_min_cam_square = z_vec.dot(center_square) - radius_square; - - aspect_bias_scale = (z_max - z_min_cam) / (z_max_square - z_min_cam_square); - - // this is not entirely perfect, because the cull-adjusted z-max may be different - // but at least it's warranted that it results in a greater bias, so no acne should be present either way. - // pancaking also helps with this. - } - - { - CameraMatrix ortho_camera; - real_t half_x = (x_max_cam - x_min_cam) * 0.5; - real_t half_y = (y_max_cam - y_min_cam) * 0.5; - - ortho_camera.set_orthogonal(-half_x, half_x, -half_y, half_y, 0, (z_max - z_min_cam)); - - Vector2 uv_scale(1.0 / (x_max_cam - x_min_cam), 1.0 / (y_max_cam - y_min_cam)); - - Transform ortho_transform; - ortho_transform.basis = transform.basis; - ortho_transform.origin = x_vec * (x_min_cam + half_x) + y_vec * (y_min_cam + half_y) + z_vec * z_max; - - { - Vector3 max_in_view = p_cam_transform.affine_inverse().xform(z_vec * cull_max); - Vector3 dir_in_view = p_cam_transform.xform_inv(z_vec).normalized(); - cull_max = dir_in_view.dot(max_in_view); - } - - RSG::scene_render->light_instance_set_shadow_transform(light->instance, ortho_camera, ortho_transform, z_max - z_min_cam, distances[i + 1], i, radius * 2.0 / texture_size, bias_scale * aspect_bias_scale * min_distance_bias_scale, z_max, uv_scale); - } - - RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); - } - - } break; - case RS::LIGHT_OMNI: { - RS::LightOmniShadowMode shadow_mode = RSG::storage->light_omni_get_shadow_mode(p_instance->base); - - if (shadow_mode == RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID || !RSG::scene_render->light_instances_can_render_shadow_cube()) { - for (int i = 0; i < 2; i++) { - //using this one ensures that raster deferred will have it - RENDER_TIMESTAMP("Culling Shadow Paraboloid" + itos(i)); - - real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); - - real_t z = i == 0 ? -1 : 1; - Vector<Plane> planes; - planes.resize(6); - planes.write[0] = light_transform.xform(Plane(Vector3(0, 0, z), radius)); - planes.write[1] = light_transform.xform(Plane(Vector3(1, 0, z).normalized(), radius)); - planes.write[2] = light_transform.xform(Plane(Vector3(-1, 0, z).normalized(), radius)); - planes.write[3] = light_transform.xform(Plane(Vector3(0, 1, z).normalized(), radius)); - planes.write[4] = light_transform.xform(Plane(Vector3(0, -1, z).normalized(), radius)); - planes.write[5] = light_transform.xform(Plane(Vector3(0, 0, -z), 0)); - - int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK); - Plane near_plane(light_transform.origin, light_transform.basis.get_axis(2) * z); - - for (int j = 0; j < cull_count; j++) { - Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { - cull_count--; - SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]); - j--; - } else { - if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { - animated_material_found = true; - } - - instance->depth = near_plane.distance_to(instance->transform.origin); - instance->depth_layer = 0; - } - } - - RSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i, 0); - RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); - } - } else { //shadow cube - - real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); - CameraMatrix cm; - cm.set_perspective(90, 1, 0.01, radius); - - for (int i = 0; i < 6; i++) { - RENDER_TIMESTAMP("Culling Shadow Cube side" + itos(i)); - //using this one ensures that raster deferred will have it - - static const Vector3 view_normals[6] = { - Vector3(+1, 0, 0), - Vector3(-1, 0, 0), - Vector3(0, -1, 0), - Vector3(0, +1, 0), - Vector3(0, 0, +1), - Vector3(0, 0, -1) - }; - static const Vector3 view_up[6] = { - Vector3(0, -1, 0), - Vector3(0, -1, 0), - Vector3(0, 0, -1), - Vector3(0, 0, +1), - Vector3(0, -1, 0), - Vector3(0, -1, 0) - }; - - Transform xform = light_transform * Transform().looking_at(view_normals[i], view_up[i]); - - Vector<Plane> planes = cm.get_projection_planes(xform); - - int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK); - - Plane near_plane(xform.origin, -xform.basis.get_axis(2)); - for (int j = 0; j < cull_count; j++) { - Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { - cull_count--; - SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]); - j--; - } else { - if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { - animated_material_found = true; - } - instance->depth = near_plane.distance_to(instance->transform.origin); - instance->depth_layer = 0; - } - } - - RSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0); - RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); - } - - //restore the regular DP matrix - RSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, 0, 0); - } - - } break; - case RS::LIGHT_SPOT: { - RENDER_TIMESTAMP("Culling Spot Light"); - - real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); - real_t angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); - - CameraMatrix cm; - cm.set_perspective(angle * 2.0, 1.0, 0.01, radius); - - Vector<Plane> planes = cm.get_projection_planes(light_transform); - int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK); - - Plane near_plane(light_transform.origin, -light_transform.basis.get_axis(2)); - for (int j = 0; j < cull_count; j++) { - Instance *instance = instance_shadow_cull_result[j]; - if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { - cull_count--; - SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]); - j--; - } else { - if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { - animated_material_found = true; - } - instance->depth = near_plane.distance_to(instance->transform.origin); - instance->depth_layer = 0; - } - } - - RSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0); - RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, 0, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count); - - } break; - } - - return animated_material_found; -} - -void RenderingServerScene::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) { -// render to mono camera -#ifndef _3D_DISABLED - - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - - /* STEP 1 - SETUP CAMERA */ - CameraMatrix camera_matrix; - bool ortho = false; - - switch (camera->type) { - case Camera::ORTHOGONAL: { - camera_matrix.set_orthogonal( - camera->size, - p_viewport_size.width / (float)p_viewport_size.height, - camera->znear, - camera->zfar, - camera->vaspect); - ortho = true; - } break; - case Camera::PERSPECTIVE: { - camera_matrix.set_perspective( - camera->fov, - p_viewport_size.width / (float)p_viewport_size.height, - camera->znear, - camera->zfar, - camera->vaspect); - ortho = false; - - } break; - case Camera::FRUSTUM: { - camera_matrix.set_frustum( - camera->size, - p_viewport_size.width / (float)p_viewport_size.height, - camera->offset, - camera->znear, - camera->zfar, - camera->vaspect); - ortho = false; - } break; - } - - RID environment = _render_get_environment(p_camera, p_scenario); - - _prepare_scene(camera->transform, camera_matrix, ortho, camera->vaspect, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); - _render_scene(p_render_buffers, camera->transform, camera_matrix, ortho, environment, camera->effects, p_scenario, p_shadow_atlas, RID(), -1); -#endif -} - -void RenderingServerScene::render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) { - // render for AR/VR interface - - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - - /* SETUP CAMERA, we are ignoring type and FOV here */ - float aspect = p_viewport_size.width / (float)p_viewport_size.height; - CameraMatrix camera_matrix = p_interface->get_projection_for_eye(p_eye, aspect, camera->znear, camera->zfar); - - // We also ignore our camera position, it will have been positioned with a slightly old tracking position. - // Instead we take our origin point and have our ar/vr interface add fresh tracking data! Whoohoo! - Transform world_origin = XRServer::get_singleton()->get_world_origin(); - Transform cam_transform = p_interface->get_transform_for_eye(p_eye, world_origin); - - RID environment = _render_get_environment(p_camera, p_scenario); - - // For stereo render we only prepare for our left eye and then reuse the outcome for our right eye - if (p_eye == XRInterface::EYE_LEFT) { - // Center our transform, we assume basis is equal. - Transform mono_transform = cam_transform; - Transform right_transform = p_interface->get_transform_for_eye(XRInterface::EYE_RIGHT, world_origin); - mono_transform.origin += right_transform.origin; - mono_transform.origin *= 0.5; - - // We need to combine our projection frustums for culling. - // Ideally we should use our clipping planes for this and combine them, - // however our shadow map logic uses our projection matrix. - // Note: as our left and right frustums should be mirrored, we don't need our right projection matrix. - - // - get some base values we need - float eye_dist = (mono_transform.origin - cam_transform.origin).length(); - float z_near = camera_matrix.get_z_near(); // get our near plane - float z_far = camera_matrix.get_z_far(); // get our far plane - float width = (2.0 * z_near) / camera_matrix.matrix[0][0]; - float x_shift = width * camera_matrix.matrix[2][0]; - float height = (2.0 * z_near) / camera_matrix.matrix[1][1]; - float y_shift = height * camera_matrix.matrix[2][1]; - - // printf("Eye_dist = %f, Near = %f, Far = %f, Width = %f, Shift = %f\n", eye_dist, z_near, z_far, width, x_shift); - - // - calculate our near plane size (horizontal only, right_near is mirrored) - float left_near = -eye_dist - ((width - x_shift) * 0.5); - - // - calculate our far plane size (horizontal only, right_far is mirrored) - float left_far = -eye_dist - (z_far * (width - x_shift) * 0.5 / z_near); - float left_far_right_eye = eye_dist - (z_far * (width + x_shift) * 0.5 / z_near); - if (left_far > left_far_right_eye) { - // on displays smaller then double our iod, the right eye far frustrum can overtake the left eyes. - left_far = left_far_right_eye; - } - - // - figure out required z-shift - float slope = (left_far - left_near) / (z_far - z_near); - float z_shift = (left_near / slope) - z_near; - - // - figure out new vertical near plane size (this will be slightly oversized thanks to our z-shift) - float top_near = (height - y_shift) * 0.5; - top_near += (top_near / z_near) * z_shift; - float bottom_near = -(height + y_shift) * 0.5; - bottom_near += (bottom_near / z_near) * z_shift; - - // printf("Left_near = %f, Left_far = %f, Top_near = %f, Bottom_near = %f, Z_shift = %f\n", left_near, left_far, top_near, bottom_near, z_shift); - - // - generate our frustum - CameraMatrix combined_matrix; - combined_matrix.set_frustum(left_near, -left_near, bottom_near, top_near, z_near + z_shift, z_far + z_shift); - - // and finally move our camera back - Transform apply_z_shift; - apply_z_shift.origin = Vector3(0.0, 0.0, z_shift); // z negative is forward so this moves it backwards - mono_transform *= apply_z_shift; - - // now prepare our scene with our adjusted transform projection matrix - _prepare_scene(mono_transform, combined_matrix, false, false, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); - } else if (p_eye == XRInterface::EYE_MONO) { - // For mono render, prepare as per usual - _prepare_scene(cam_transform, camera_matrix, false, false, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); - } - - // And render our scene... - _render_scene(p_render_buffers, cam_transform, camera_matrix, false, environment, camera->effects, p_scenario, p_shadow_atlas, RID(), -1); -}; - -void RenderingServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows) { - // Note, in stereo rendering: - // - p_cam_transform will be a transform in the middle of our two eyes - // - p_cam_projection is a wider frustrum that encompasses both eyes - - Scenario *scenario = scenario_owner.getornull(p_scenario); - - render_pass++; - uint32_t camera_layer_mask = p_visible_layers; - - RSG::scene_render->set_scene_pass(render_pass); - - if (p_render_buffers.is_valid()) { - RSG::scene_render->sdfgi_update(p_render_buffers, p_environment, p_cam_transform.origin); //update conditions for SDFGI (whether its used or not) - } - - RENDER_TIMESTAMP("Frustum Culling"); - - //rasterizer->set_camera(camera->transform, camera_matrix,ortho); - - Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform); - - Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(2).normalized()); - float z_far = p_cam_projection.get_z_far(); - - /* STEP 2 - CULL */ - instance_cull_count = scenario->octree.cull_convex(planes, instance_cull_result, MAX_INSTANCE_CULL); - light_cull_count = 0; - - reflection_probe_cull_count = 0; - decal_cull_count = 0; - gi_probe_cull_count = 0; - lightmap_cull_count = 0; - - //light_samplers_culled=0; - - /* - print_line("OT: "+rtos( (OS::get_singleton()->get_ticks_usec()-t)/1000.0)); - print_line("OTO: "+itos(p_scenario->octree.get_octant_count())); - print_line("OTE: "+itos(p_scenario->octree.get_elem_count())); - print_line("OTP: "+itos(p_scenario->octree.get_pair_count())); - */ - - /* STEP 3 - PROCESS PORTALS, VALIDATE ROOMS */ - //removed, will replace with culling - - /* STEP 4 - REMOVE FURTHER CULLED OBJECTS, ADD LIGHTS */ - uint64_t frame_number = RSG::rasterizer->get_frame_number(); - float lightmap_probe_update_speed = RSG::storage->lightmap_get_probe_capture_update_speed() * RSG::rasterizer->get_frame_delta_time(); - - for (int i = 0; i < instance_cull_count; i++) { - Instance *ins = instance_cull_result[i]; - - bool keep = false; - - if ((camera_layer_mask & ins->layer_mask) == 0) { - //failure - } else if (ins->base_type == RS::INSTANCE_LIGHT && ins->visible) { - if (light_cull_count < MAX_LIGHTS_CULLED) { - InstanceLightData *light = static_cast<InstanceLightData *>(ins->base_data); - - if (!light->geometries.empty()) { - //do not add this light if no geometry is affected by it.. - light_cull_result[light_cull_count] = ins; - light_instance_cull_result[light_cull_count] = light->instance; - if (p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(ins->base)) { - RSG::scene_render->light_instance_mark_visible(light->instance); //mark it visible for shadow allocation later - } - - light_cull_count++; - } - } - } else if (ins->base_type == RS::INSTANCE_REFLECTION_PROBE && ins->visible) { - if (reflection_probe_cull_count < MAX_REFLECTION_PROBES_CULLED) { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(ins->base_data); - - if (p_reflection_probe != reflection_probe->instance) { - //avoid entering The Matrix - - if (!reflection_probe->geometries.empty()) { - //do not add this light if no geometry is affected by it.. - - if (reflection_probe->reflection_dirty || RSG::scene_render->reflection_probe_instance_needs_redraw(reflection_probe->instance)) { - if (!reflection_probe->update_list.in_list()) { - reflection_probe->render_step = 0; - reflection_probe_render_list.add_last(&reflection_probe->update_list); - } - - reflection_probe->reflection_dirty = false; - } - - if (RSG::scene_render->reflection_probe_instance_has_reflection(reflection_probe->instance)) { - reflection_probe_instance_cull_result[reflection_probe_cull_count] = reflection_probe->instance; - reflection_probe_cull_count++; - } - } - } - } - } else if (ins->base_type == RS::INSTANCE_DECAL && ins->visible) { - if (decal_cull_count < MAX_DECALS_CULLED) { - InstanceDecalData *decal = static_cast<InstanceDecalData *>(ins->base_data); - - if (!decal->geometries.empty()) { - //do not add this decal if no geometry is affected by it.. - decal_instance_cull_result[decal_cull_count] = decal->instance; - decal_cull_count++; - } - } - - } else if (ins->base_type == RS::INSTANCE_GI_PROBE && ins->visible) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(ins->base_data); - if (!gi_probe->update_element.in_list()) { - gi_probe_update_list.add(&gi_probe->update_element); - } - - if (gi_probe_cull_count < MAX_GI_PROBES_CULLED) { - gi_probe_instance_cull_result[gi_probe_cull_count] = gi_probe->probe_instance; - gi_probe_cull_count++; - } - } else if (ins->base_type == RS::INSTANCE_LIGHTMAP && ins->visible) { - if (lightmap_cull_count < MAX_LIGHTMAPS_CULLED) { - lightmap_cull_result[lightmap_cull_count] = ins; - lightmap_cull_count++; - } - - } else if (((1 << ins->base_type) & RS::INSTANCE_GEOMETRY_MASK) && ins->visible && ins->cast_shadows != RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { - keep = true; - - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(ins->base_data); - - if (ins->redraw_if_visible) { - RenderingServerRaster::redraw_request(); - } - - if (ins->base_type == RS::INSTANCE_PARTICLES) { - //particles visible? process them - if (RSG::storage->particles_is_inactive(ins->base)) { - //but if nothing is going on, don't do it. - keep = false; - } else { - RSG::storage->particles_request_process(ins->base); - RSG::storage->particles_set_view_axis(ins->base, -p_cam_transform.basis.get_axis(2).normalized()); - //particles visible? request redraw - RenderingServerRaster::redraw_request(); - } - } - - if (geom->lighting_dirty) { - int l = 0; - //only called when lights AABB enter/exit this geometry - ins->light_instances.resize(geom->lighting.size()); - - for (List<Instance *>::Element *E = geom->lighting.front(); E; E = E->next()) { - InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); - - ins->light_instances.write[l++] = light->instance; - } - - geom->lighting_dirty = false; - } - - if (geom->reflection_dirty) { - int l = 0; - //only called when reflection probe AABB enter/exit this geometry - ins->reflection_probe_instances.resize(geom->reflection_probes.size()); - - for (List<Instance *>::Element *E = geom->reflection_probes.front(); E; E = E->next()) { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data); - - ins->reflection_probe_instances.write[l++] = reflection_probe->instance; - } - - geom->reflection_dirty = false; - } - - if (geom->gi_probes_dirty) { - int l = 0; - //only called when reflection probe AABB enter/exit this geometry - ins->gi_probe_instances.resize(geom->gi_probes.size()); - - for (List<Instance *>::Element *E = geom->gi_probes.front(); E; E = E->next()) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(E->get()->base_data); - - ins->gi_probe_instances.write[l++] = gi_probe->probe_instance; - } - - geom->gi_probes_dirty = false; - } - - if (ins->last_frame_pass != frame_number && !ins->lightmap_target_sh.empty() && !ins->lightmap_sh.empty()) { - Color *sh = ins->lightmap_sh.ptrw(); - const Color *target_sh = ins->lightmap_target_sh.ptr(); - for (uint32_t j = 0; j < 9; j++) { - sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed)); - } - } - - ins->depth = near_plane.distance_to(ins->transform.origin); - ins->depth_layer = CLAMP(int(ins->depth * 16 / z_far), 0, 15); - } - - if (!keep) { - // remove, no reason to keep - instance_cull_count--; - SWAP(instance_cull_result[i], instance_cull_result[instance_cull_count]); - i--; - ins->last_render_pass = 0; // make invalid - } else { - ins->last_render_pass = render_pass; - } - ins->last_frame_pass = frame_number; - } - - /* STEP 5 - PROCESS LIGHTS */ - - RID *directional_light_ptr = &light_instance_cull_result[light_cull_count]; - directional_light_count = 0; - - // directional lights - { - Instance **lights_with_shadow = (Instance **)alloca(sizeof(Instance *) * scenario->directional_lights.size()); - int directional_shadow_count = 0; - - for (List<Instance *>::Element *E = scenario->directional_lights.front(); E; E = E->next()) { - if (light_cull_count + directional_light_count >= MAX_LIGHTS_CULLED) { - break; - } - - if (!E->get()->visible) { - continue; - } - - InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); - - //check shadow.. - - if (light) { - if (p_using_shadows && p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(E->get()->base)) { - lights_with_shadow[directional_shadow_count++] = E->get(); - } - //add to list - directional_light_ptr[directional_light_count++] = light->instance; - } - } - - RSG::scene_render->set_directional_shadow_count(directional_shadow_count); - - for (int i = 0; i < directional_shadow_count; i++) { - RENDER_TIMESTAMP(">Rendering Directional Light " + itos(i)); - - _light_instance_update_shadow(lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario); - - RENDER_TIMESTAMP("<Rendering Directional Light " + itos(i)); - } - } - - if (p_using_shadows) { //setup shadow maps - - //SortArray<Instance*,_InstanceLightsort> sorter; - //sorter.sort(light_cull_result,light_cull_count); - for (int i = 0; i < light_cull_count; i++) { - Instance *ins = light_cull_result[i]; - - if (!p_shadow_atlas.is_valid() || !RSG::storage->light_has_shadow(ins->base)) { - continue; - } - - InstanceLightData *light = static_cast<InstanceLightData *>(ins->base_data); - - float coverage = 0.f; - - { //compute coverage - - Transform cam_xf = p_cam_transform; - float zn = p_cam_projection.get_z_near(); - Plane p(cam_xf.origin + cam_xf.basis.get_axis(2) * -zn, -cam_xf.basis.get_axis(2)); //camera near plane - - // near plane half width and height - Vector2 vp_half_extents = p_cam_projection.get_viewport_half_extents(); - - switch (RSG::storage->light_get_type(ins->base)) { - case RS::LIGHT_OMNI: { - float radius = RSG::storage->light_get_param(ins->base, RS::LIGHT_PARAM_RANGE); - - //get two points parallel to near plane - Vector3 points[2] = { - ins->transform.origin, - ins->transform.origin + cam_xf.basis.get_axis(0) * radius - }; - - if (!p_cam_orthogonal) { - //if using perspetive, map them to near plane - for (int j = 0; j < 2; j++) { - if (p.distance_to(points[j]) < 0) { - points[j].z = -zn; //small hack to keep size constant when hitting the screen - } - - p.intersects_segment(cam_xf.origin, points[j], &points[j]); //map to plane - } - } - - float screen_diameter = points[0].distance_to(points[1]) * 2; - coverage = screen_diameter / (vp_half_extents.x + vp_half_extents.y); - } break; - case RS::LIGHT_SPOT: { - float radius = RSG::storage->light_get_param(ins->base, RS::LIGHT_PARAM_RANGE); - float angle = RSG::storage->light_get_param(ins->base, RS::LIGHT_PARAM_SPOT_ANGLE); - - float w = radius * Math::sin(Math::deg2rad(angle)); - float d = radius * Math::cos(Math::deg2rad(angle)); - - Vector3 base = ins->transform.origin - ins->transform.basis.get_axis(2).normalized() * d; - - Vector3 points[2] = { - base, - base + cam_xf.basis.get_axis(0) * w - }; - - if (!p_cam_orthogonal) { - //if using perspetive, map them to near plane - for (int j = 0; j < 2; j++) { - if (p.distance_to(points[j]) < 0) { - points[j].z = -zn; //small hack to keep size constant when hitting the screen - } - - p.intersects_segment(cam_xf.origin, points[j], &points[j]); //map to plane - } - } - - float screen_diameter = points[0].distance_to(points[1]) * 2; - coverage = screen_diameter / (vp_half_extents.x + vp_half_extents.y); - - } break; - default: { - ERR_PRINT("Invalid Light Type"); - } - } - } - - if (light->shadow_dirty) { - light->last_version++; - light->shadow_dirty = false; - } - - bool redraw = RSG::scene_render->shadow_atlas_update_light(p_shadow_atlas, light->instance, coverage, light->last_version); - - if (redraw) { - //must redraw! - RENDER_TIMESTAMP(">Rendering Light " + itos(i)); - light->shadow_dirty = _light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario); - RENDER_TIMESTAMP("<Rendering Light " + itos(i)); - } - } - } - - /* UPDATE SDFGI */ - - if (p_render_buffers.is_valid()) { - uint32_t cascade_index[8]; - uint32_t cascade_sizes[8]; - const RID *cascade_ptrs[8]; - uint32_t cascade_count = 0; - uint32_t sdfgi_light_cull_count = 0; - - uint32_t prev_cascade = 0xFFFFFFFF; - for (int i = 0; i < RSG::scene_render->sdfgi_get_pending_region_count(p_render_buffers); i++) { - AABB region = RSG::scene_render->sdfgi_get_pending_region_bounds(p_render_buffers, i); - uint32_t region_cascade = RSG::scene_render->sdfgi_get_pending_region_cascade(p_render_buffers, i); - - if (region_cascade != prev_cascade) { - cascade_sizes[cascade_count] = 0; - cascade_index[cascade_count] = region_cascade; - cascade_ptrs[cascade_count] = &sdfgi_light_cull_result[sdfgi_light_cull_count]; - cascade_count++; - sdfgi_light_cull_pass++; - prev_cascade = region_cascade; - } - uint32_t sdfgi_cull_count = scenario->octree.cull_aabb(region, instance_shadow_cull_result, MAX_INSTANCE_CULL); - - for (uint32_t j = 0; j < sdfgi_cull_count; j++) { - Instance *ins = instance_shadow_cull_result[j]; - - bool keep = false; - - if (ins->base_type == RS::INSTANCE_LIGHT && ins->visible) { - InstanceLightData *instance_light = (InstanceLightData *)ins->base_data; - if (instance_light->bake_mode != RS::LIGHT_BAKE_STATIC || region_cascade > instance_light->max_sdfgi_cascade) { - continue; - } - - if (sdfgi_light_cull_pass != instance_light->sdfgi_cascade_light_pass && sdfgi_light_cull_count < MAX_LIGHTS_CULLED) { - instance_light->sdfgi_cascade_light_pass = sdfgi_light_cull_pass; - sdfgi_light_cull_result[sdfgi_light_cull_count++] = instance_light->instance; - cascade_sizes[cascade_count - 1]++; - } - } else if ((1 << ins->base_type) & RS::INSTANCE_GEOMETRY_MASK) { - if (ins->baked_light) { - keep = true; - } - } - - if (!keep) { - // remove, no reason to keep - sdfgi_cull_count--; - SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[sdfgi_cull_count]); - j--; - } - } - - RSG::scene_render->render_sdfgi(p_render_buffers, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, sdfgi_cull_count); - //have to save updated cascades, then update static lights. - } - - if (sdfgi_light_cull_count) { - RSG::scene_render->render_sdfgi_static_lights(p_render_buffers, cascade_count, cascade_index, cascade_ptrs, cascade_sizes); - } - - RSG::scene_render->sdfgi_update_probes(p_render_buffers, p_environment, directional_light_ptr, directional_light_count, scenario->dynamic_lights.ptr(), scenario->dynamic_lights.size()); - } -} - -RID RenderingServerScene::_render_get_environment(RID p_camera, RID p_scenario) { - Camera *camera = camera_owner.getornull(p_camera); - if (camera && RSG::scene_render->is_environment(camera->env)) { - return camera->env; - } - - Scenario *scenario = scenario_owner.getornull(p_scenario); - if (!scenario) { - return RID(); - } - if (RSG::scene_render->is_environment(scenario->environment)) { - return scenario->environment; - } - - if (RSG::scene_render->is_environment(scenario->fallback_environment)) { - return scenario->fallback_environment; - } - - return RID(); -} - -void RenderingServerScene::_render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - - RID camera_effects; - if (p_force_camera_effects.is_valid()) { - camera_effects = p_force_camera_effects; - } else { - camera_effects = scenario->camera_effects; - } - /* PROCESS GEOMETRY AND DRAW SCENE */ - - RENDER_TIMESTAMP("Render Scene "); - RSG::scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, gi_probe_instance_cull_result, gi_probe_cull_count, decal_instance_cull_result, decal_cull_count, (RasterizerScene::InstanceBase **)lightmap_cull_result, lightmap_cull_count, p_environment, camera_effects, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass); -} - -void RenderingServerScene::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) { -#ifndef _3D_DISABLED - - Scenario *scenario = scenario_owner.getornull(p_scenario); - - RID environment; - if (scenario->environment.is_valid()) { - environment = scenario->environment; - } else { - environment = scenario->fallback_environment; - } - RENDER_TIMESTAMP("Render Empty Scene "); - RSG::scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, environment, RID(), p_shadow_atlas, scenario->reflection_atlas, RID(), 0); -#endif -} - -bool RenderingServerScene::_render_reflection_probe_step(Instance *p_instance, int p_step) { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data); - Scenario *scenario = p_instance->scenario; - ERR_FAIL_COND_V(!scenario, true); - - RenderingServerRaster::redraw_request(); //update, so it updates in editor - - if (p_step == 0) { - if (!RSG::scene_render->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) { - return true; //all full - } - } - - if (p_step >= 0 && p_step < 6) { - static const Vector3 view_normals[6] = { - Vector3(+1, 0, 0), - Vector3(-1, 0, 0), - Vector3(0, +1, 0), - Vector3(0, -1, 0), - Vector3(0, 0, +1), - Vector3(0, 0, -1) - }; - static const Vector3 view_up[6] = { - Vector3(0, -1, 0), - Vector3(0, -1, 0), - Vector3(0, 0, +1), - Vector3(0, 0, -1), - Vector3(0, -1, 0), - Vector3(0, -1, 0) - }; - - Vector3 extents = RSG::storage->reflection_probe_get_extents(p_instance->base); - Vector3 origin_offset = RSG::storage->reflection_probe_get_origin_offset(p_instance->base); - float max_distance = RSG::storage->reflection_probe_get_origin_max_distance(p_instance->base); - - Vector3 edge = view_normals[p_step] * extents; - float distance = ABS(view_normals[p_step].dot(edge) - view_normals[p_step].dot(origin_offset)); //distance from origin offset to actual view distance limit - - max_distance = MAX(max_distance, distance); - - //render cubemap side - CameraMatrix cm; - cm.set_perspective(90, 1, 0.01, max_distance); - - Transform local_view; - local_view.set_look_at(origin_offset, origin_offset + view_normals[p_step], view_up[p_step]); - - Transform xform = p_instance->transform * local_view; - - RID shadow_atlas; - - bool use_shadows = RSG::storage->reflection_probe_renders_shadows(p_instance->base); - if (use_shadows) { - shadow_atlas = scenario->reflection_probe_shadow_atlas; - } - - RENDER_TIMESTAMP("Render Reflection Probe, Step " + itos(p_step)); - _prepare_scene(xform, cm, false, false, RID(), RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, use_shadows); - _render_scene(RID(), xform, cm, false, RID(), RID(), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step); - - } else { - //do roughness postprocess step until it believes it's done - RENDER_TIMESTAMP("Post-Process Reflection Probe, Step " + itos(p_step)); - return RSG::scene_render->reflection_probe_instance_postprocess_step(reflection_probe->instance); - } - - return false; -} - -void RenderingServerScene::render_probes() { - /* REFLECTION PROBES */ - - SelfList<InstanceReflectionProbeData> *ref_probe = reflection_probe_render_list.first(); - - bool busy = false; - - while (ref_probe) { - SelfList<InstanceReflectionProbeData> *next = ref_probe->next(); - RID base = ref_probe->self()->owner->base; - - switch (RSG::storage->reflection_probe_get_update_mode(base)) { - case RS::REFLECTION_PROBE_UPDATE_ONCE: { - if (busy) { //already rendering something - break; - } - - bool done = _render_reflection_probe_step(ref_probe->self()->owner, ref_probe->self()->render_step); - if (done) { - reflection_probe_render_list.remove(ref_probe); - } else { - ref_probe->self()->render_step++; - } - - busy = true; //do not render another one of this kind - } break; - case RS::REFLECTION_PROBE_UPDATE_ALWAYS: { - int step = 0; - bool done = false; - while (!done) { - done = _render_reflection_probe_step(ref_probe->self()->owner, step); - step++; - } - - reflection_probe_render_list.remove(ref_probe); - } break; - } - - ref_probe = next; - } - - /* GI PROBES */ - - SelfList<InstanceGIProbeData> *gi_probe = gi_probe_update_list.first(); - - if (gi_probe) { - RENDER_TIMESTAMP("Render GI Probes"); - } - - while (gi_probe) { - SelfList<InstanceGIProbeData> *next = gi_probe->next(); - - InstanceGIProbeData *probe = gi_probe->self(); - //Instance *instance_probe = probe->owner; - - //check if probe must be setup, but don't do if on the lighting thread - - bool cache_dirty = false; - int cache_count = 0; - { - int light_cache_size = probe->light_cache.size(); - const InstanceGIProbeData::LightCache *caches = probe->light_cache.ptr(); - const RID *instance_caches = probe->light_instances.ptr(); - - int idx = 0; //must count visible lights - for (Set<Instance *>::Element *E = probe->lights.front(); E; E = E->next()) { - Instance *instance = E->get(); - InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; - if (!instance->visible) { - continue; - } - if (cache_dirty) { - //do nothing, since idx must count all visible lights anyway - } else if (idx >= light_cache_size) { - cache_dirty = true; - } else { - const InstanceGIProbeData::LightCache *cache = &caches[idx]; - - if ( - instance_caches[idx] != instance_light->instance || - cache->has_shadow != RSG::storage->light_has_shadow(instance->base) || - cache->type != RSG::storage->light_get_type(instance->base) || - cache->transform != instance->transform || - cache->color != RSG::storage->light_get_color(instance->base) || - cache->energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY) || - cache->bake_energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY) || - cache->radius != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE) || - cache->attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION) || - cache->spot_angle != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE) || - cache->spot_attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION)) { - cache_dirty = true; - } - } - - idx++; - } - - for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) { - Instance *instance = E->get(); - InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; - if (!instance->visible) { - continue; - } - if (cache_dirty) { - //do nothing, since idx must count all visible lights anyway - } else if (idx >= light_cache_size) { - cache_dirty = true; - } else { - const InstanceGIProbeData::LightCache *cache = &caches[idx]; - - if ( - instance_caches[idx] != instance_light->instance || - cache->has_shadow != RSG::storage->light_has_shadow(instance->base) || - cache->type != RSG::storage->light_get_type(instance->base) || - cache->transform != instance->transform || - cache->color != RSG::storage->light_get_color(instance->base) || - cache->energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY) || - cache->bake_energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY) || - cache->radius != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE) || - cache->attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION) || - cache->spot_angle != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE) || - cache->spot_attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION)) { - cache_dirty = true; - } - } - - idx++; - } - - if (idx != light_cache_size) { - cache_dirty = true; - } - - cache_count = idx; - } - - bool update_lights = RSG::scene_render->gi_probe_needs_update(probe->probe_instance); - - if (cache_dirty) { - probe->light_cache.resize(cache_count); - probe->light_instances.resize(cache_count); - - if (cache_count) { - InstanceGIProbeData::LightCache *caches = probe->light_cache.ptrw(); - RID *instance_caches = probe->light_instances.ptrw(); - - int idx = 0; //must count visible lights - for (Set<Instance *>::Element *E = probe->lights.front(); E; E = E->next()) { - Instance *instance = E->get(); - InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; - if (!instance->visible) { - continue; - } - - InstanceGIProbeData::LightCache *cache = &caches[idx]; - - instance_caches[idx] = instance_light->instance; - cache->has_shadow = RSG::storage->light_has_shadow(instance->base); - cache->type = RSG::storage->light_get_type(instance->base); - cache->transform = instance->transform; - cache->color = RSG::storage->light_get_color(instance->base); - cache->energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY); - cache->bake_energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY); - cache->radius = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE); - cache->attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION); - cache->spot_angle = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); - cache->spot_attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION); - - idx++; - } - for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) { - Instance *instance = E->get(); - InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; - if (!instance->visible) { - continue; - } - - InstanceGIProbeData::LightCache *cache = &caches[idx]; - - instance_caches[idx] = instance_light->instance; - cache->has_shadow = RSG::storage->light_has_shadow(instance->base); - cache->type = RSG::storage->light_get_type(instance->base); - cache->transform = instance->transform; - cache->color = RSG::storage->light_get_color(instance->base); - cache->energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY); - cache->bake_energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY); - cache->radius = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE); - cache->attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION); - cache->spot_angle = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); - cache->spot_attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION); - - idx++; - } - } - - update_lights = true; - } - - instance_cull_count = 0; - for (List<InstanceGIProbeData::PairInfo>::Element *E = probe->dynamic_geometries.front(); E; E = E->next()) { - if (instance_cull_count < MAX_INSTANCE_CULL) { - Instance *ins = E->get().geometry; - if (!ins->visible) { - continue; - } - InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data; - - if (geom->gi_probes_dirty) { - //giprobes may be dirty, so update - int l = 0; - //only called when reflection probe AABB enter/exit this geometry - ins->gi_probe_instances.resize(geom->gi_probes.size()); - - for (List<Instance *>::Element *F = geom->gi_probes.front(); F; F = F->next()) { - InstanceGIProbeData *gi_probe2 = static_cast<InstanceGIProbeData *>(F->get()->base_data); - - ins->gi_probe_instances.write[l++] = gi_probe2->probe_instance; - } - - geom->gi_probes_dirty = false; - } - - instance_cull_result[instance_cull_count++] = E->get().geometry; - } - } - - RSG::scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, instance_cull_count, (RasterizerScene::InstanceBase **)instance_cull_result); - - gi_probe_update_list.remove(gi_probe); - - gi_probe = next; - } -} - -void RenderingServerScene::render_particle_colliders() { - while (heightfield_particle_colliders_update_list.front()) { - Instance *hfpc = heightfield_particle_colliders_update_list.front()->get(); - - if (hfpc->scenario && hfpc->base_type == RS::INSTANCE_PARTICLES_COLLISION && RSG::storage->particles_collision_is_heightfield(hfpc->base)) { - //update heightfield - int cull_count = hfpc->scenario->octree.cull_aabb(hfpc->transformed_aabb, instance_cull_result, MAX_INSTANCE_CULL); //@TODO: cull mask missing - for (int i = 0; i < cull_count; i++) { - Instance *instance = instance_cull_result[i]; - if (!instance->visible || !((1 << instance->base_type) & (RS::INSTANCE_GEOMETRY_MASK & (~(1 << RS::INSTANCE_PARTICLES))))) { //all but particles to avoid self collision - cull_count--; - SWAP(instance_cull_result[i], instance_cull_result[cull_count]); - } - } - - RSG::scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, (RasterizerScene::InstanceBase **)instance_cull_result, cull_count); - } - heightfield_particle_colliders_update_list.erase(heightfield_particle_colliders_update_list.front()); - } -} - -void RenderingServerScene::_update_instance_shader_parameters_from_material(Map<StringName, RasterizerScene::InstanceBase::InstanceShaderParameter> &isparams, const Map<StringName, RasterizerScene::InstanceBase::InstanceShaderParameter> &existing_isparams, RID p_material) { - List<RasterizerStorage::InstanceShaderParam> plist; - RSG::storage->material_get_instance_shader_parameters(p_material, &plist); - for (List<RasterizerStorage::InstanceShaderParam>::Element *E = plist.front(); E; E = E->next()) { - StringName name = E->get().info.name; - if (isparams.has(name)) { - if (isparams[name].info.type != E->get().info.type) { - WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E->get().info.name + "', but they do it with different data types. Only the first one (in order) will display correctly."); - } - if (isparams[name].index != E->get().index) { - WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E->get().info.name + "', but they do it with different indices. Only the first one (in order) will display correctly."); - } - continue; //first one found always has priority - } - - RasterizerScene::InstanceBase::InstanceShaderParameter isp; - isp.index = E->get().index; - isp.info = E->get().info; - isp.default_value = E->get().default_value; - if (existing_isparams.has(name)) { - isp.value = existing_isparams[name].value; - } else { - isp.value = E->get().default_value; - } - isparams[name] = isp; - } -} - -void RenderingServerScene::_update_dirty_instance(Instance *p_instance) { - if (p_instance->update_aabb) { - _update_instance_aabb(p_instance); - } - - if (p_instance->update_dependencies) { - p_instance->instance_increase_version(); - - if (p_instance->base.is_valid()) { - RSG::storage->base_update_dependency(p_instance->base, p_instance); - } - - if (p_instance->material_override.is_valid()) { - RSG::storage->material_update_dependency(p_instance->material_override, p_instance); - } - - if (p_instance->base_type == RS::INSTANCE_MESH) { - //remove materials no longer used and un-own them - - int new_mat_count = RSG::storage->mesh_get_surface_count(p_instance->base); - p_instance->materials.resize(new_mat_count); - - int new_blend_shape_count = RSG::storage->mesh_get_blend_shape_count(p_instance->base); - if (new_blend_shape_count != p_instance->blend_values.size()) { - p_instance->blend_values.resize(new_blend_shape_count); - for (int i = 0; i < new_blend_shape_count; i++) { - p_instance->blend_values.write[i] = 0; - } - } - } - - if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); - - bool can_cast_shadows = true; - bool is_animated = false; - Map<StringName, RasterizerScene::InstanceBase::InstanceShaderParameter> isparams; - - if (p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_OFF) { - can_cast_shadows = false; - } - - if (p_instance->material_override.is_valid()) { - if (!RSG::storage->material_casts_shadows(p_instance->material_override)) { - can_cast_shadows = false; - } - is_animated = RSG::storage->material_is_animated(p_instance->material_override); - _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, p_instance->material_override); - } else { - if (p_instance->base_type == RS::INSTANCE_MESH) { - RID mesh = p_instance->base; - - if (mesh.is_valid()) { - bool cast_shadows = false; - - for (int i = 0; i < p_instance->materials.size(); i++) { - RID mat = p_instance->materials[i].is_valid() ? p_instance->materials[i] : RSG::storage->mesh_surface_get_material(mesh, i); - - if (!mat.is_valid()) { - cast_shadows = true; - } else { - if (RSG::storage->material_casts_shadows(mat)) { - cast_shadows = true; - } - - if (RSG::storage->material_is_animated(mat)) { - is_animated = true; - } - - _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); - - RSG::storage->material_update_dependency(mat, p_instance); - } - } - - if (!cast_shadows) { - can_cast_shadows = false; - } - } - - } else if (p_instance->base_type == RS::INSTANCE_MULTIMESH) { - RID mesh = RSG::storage->multimesh_get_mesh(p_instance->base); - if (mesh.is_valid()) { - bool cast_shadows = false; - - int sc = RSG::storage->mesh_get_surface_count(mesh); - for (int i = 0; i < sc; i++) { - RID mat = RSG::storage->mesh_surface_get_material(mesh, i); - - if (!mat.is_valid()) { - cast_shadows = true; - - } else { - if (RSG::storage->material_casts_shadows(mat)) { - cast_shadows = true; - } - if (RSG::storage->material_is_animated(mat)) { - is_animated = true; - } - - _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); - - RSG::storage->material_update_dependency(mat, p_instance); - } - } - - if (!cast_shadows) { - can_cast_shadows = false; - } - - RSG::storage->base_update_dependency(mesh, p_instance); - } - } else if (p_instance->base_type == RS::INSTANCE_IMMEDIATE) { - RID mat = RSG::storage->immediate_get_material(p_instance->base); - - if (!(!mat.is_valid() || RSG::storage->material_casts_shadows(mat))) { - can_cast_shadows = false; - } - - if (mat.is_valid() && RSG::storage->material_is_animated(mat)) { - is_animated = true; - } - - if (mat.is_valid()) { - _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); - } - - if (mat.is_valid()) { - RSG::storage->material_update_dependency(mat, p_instance); - } - - } else if (p_instance->base_type == RS::INSTANCE_PARTICLES) { - bool cast_shadows = false; - - int dp = RSG::storage->particles_get_draw_passes(p_instance->base); - - for (int i = 0; i < dp; i++) { - RID mesh = RSG::storage->particles_get_draw_pass_mesh(p_instance->base, i); - if (!mesh.is_valid()) { - continue; - } - - int sc = RSG::storage->mesh_get_surface_count(mesh); - for (int j = 0; j < sc; j++) { - RID mat = RSG::storage->mesh_surface_get_material(mesh, j); - - if (!mat.is_valid()) { - cast_shadows = true; - } else { - if (RSG::storage->material_casts_shadows(mat)) { - cast_shadows = true; - } - - if (RSG::storage->material_is_animated(mat)) { - is_animated = true; - } - - _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); - - RSG::storage->material_update_dependency(mat, p_instance); - } - } - } - - if (!cast_shadows) { - can_cast_shadows = false; - } - } - } - - if (can_cast_shadows != geom->can_cast_shadows) { - //ability to cast shadows change, let lights now - for (List<Instance *>::Element *E = geom->lighting.front(); E; E = E->next()) { - InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); - light->shadow_dirty = true; - } - - geom->can_cast_shadows = can_cast_shadows; - } - - geom->material_is_animated = is_animated; - p_instance->instance_shader_parameters = isparams; - - if (p_instance->instance_allocated_shader_parameters != (p_instance->instance_shader_parameters.size() > 0)) { - p_instance->instance_allocated_shader_parameters = (p_instance->instance_shader_parameters.size() > 0); - if (p_instance->instance_allocated_shader_parameters) { - p_instance->instance_allocated_shader_parameters_offset = RSG::storage->global_variables_instance_allocate(p_instance->self); - for (Map<StringName, RasterizerScene::InstanceBase::InstanceShaderParameter>::Element *E = p_instance->instance_shader_parameters.front(); E; E = E->next()) { - if (E->get().value.get_type() != Variant::NIL) { - RSG::storage->global_variables_instance_update(p_instance->self, E->get().index, E->get().value); - } - } - } else { - RSG::storage->global_variables_instance_free(p_instance->self); - p_instance->instance_allocated_shader_parameters_offset = -1; - } - } - } - - if (p_instance->skeleton.is_valid()) { - RSG::storage->skeleton_update_dependency(p_instance->skeleton, p_instance); - } - - p_instance->clean_up_dependencies(); - } - - _instance_update_list.remove(&p_instance->update_item); - - _update_instance(p_instance); - - p_instance->update_aabb = false; - p_instance->update_dependencies = false; -} - -void RenderingServerScene::update_dirty_instances() { - RSG::storage->update_dirty_resources(); - - while (_instance_update_list.first()) { - _update_dirty_instance(_instance_update_list.first()->self()); - } -} - -bool RenderingServerScene::free(RID p_rid) { - if (camera_owner.owns(p_rid)) { - Camera *camera = camera_owner.getornull(p_rid); - - camera_owner.free(p_rid); - memdelete(camera); - - } else if (scenario_owner.owns(p_rid)) { - Scenario *scenario = scenario_owner.getornull(p_rid); - - while (scenario->instances.first()) { - instance_set_scenario(scenario->instances.first()->self()->self, RID()); - } - RSG::scene_render->free(scenario->reflection_probe_shadow_atlas); - RSG::scene_render->free(scenario->reflection_atlas); - scenario_owner.free(p_rid); - memdelete(scenario); - - } else if (instance_owner.owns(p_rid)) { - // delete the instance - - update_dirty_instances(); - - Instance *instance = instance_owner.getornull(p_rid); - - instance_geometry_set_lightmap(p_rid, RID(), Rect2(), 0); - instance_set_scenario(p_rid, RID()); - instance_set_base(p_rid, RID()); - instance_geometry_set_material_override(p_rid, RID()); - instance_attach_skeleton(p_rid, RID()); - - if (instance->instance_allocated_shader_parameters) { - //free the used shader parameters - RSG::storage->global_variables_instance_free(instance->self); - } - update_dirty_instances(); //in case something changed this - - instance_owner.free(p_rid); - memdelete(instance); - } else { - return false; - } - - return true; -} - -TypedArray<Image> RenderingServerScene::bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) { - return RSG::scene_render->bake_render_uv2(p_base, p_material_overrides, p_image_size); -} - -RenderingServerScene *RenderingServerScene::singleton = nullptr; - -RenderingServerScene::RenderingServerScene() { - render_pass = 1; - singleton = this; -} - -RenderingServerScene::~RenderingServerScene() { -} diff --git a/servers/rendering/rendering_server_scene.h b/servers/rendering/rendering_server_scene.h deleted file mode 100644 index 1b0a617627..0000000000 --- a/servers/rendering/rendering_server_scene.h +++ /dev/null @@ -1,477 +0,0 @@ -/*************************************************************************/ -/* rendering_server_scene.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef VISUALSERVERSCENE_H -#define VISUALSERVERSCENE_H - -#include "servers/rendering/rasterizer.h" - -#include "core/local_vector.h" -#include "core/math/geometry_3d.h" -#include "core/math/octree.h" -#include "core/os/semaphore.h" -#include "core/os/thread.h" -#include "core/rid_owner.h" -#include "core/self_list.h" -#include "servers/xr/xr_interface.h" - -class RenderingServerScene { -public: - enum { - - MAX_INSTANCE_CULL = 65536, - MAX_LIGHTS_CULLED = 4096, - MAX_REFLECTION_PROBES_CULLED = 4096, - MAX_DECALS_CULLED = 4096, - MAX_GI_PROBES_CULLED = 4096, - MAX_ROOM_CULL = 32, - MAX_LIGHTMAPS_CULLED = 4096, - MAX_EXTERIOR_PORTALS = 128, - }; - - uint64_t render_pass; - - static RenderingServerScene *singleton; - - /* CAMERA API */ - - struct Camera { - enum Type { - PERSPECTIVE, - ORTHOGONAL, - FRUSTUM - }; - Type type; - float fov; - float znear, zfar; - float size; - Vector2 offset; - uint32_t visible_layers; - bool vaspect; - RID env; - RID effects; - - Transform transform; - - Camera() { - visible_layers = 0xFFFFFFFF; - fov = 75; - type = PERSPECTIVE; - znear = 0.05; - zfar = 100; - size = 1.0; - offset = Vector2(); - vaspect = false; - } - }; - - mutable RID_PtrOwner<Camera> camera_owner; - - virtual RID camera_create(); - virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far); - virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far); - virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far); - virtual void camera_set_transform(RID p_camera, const Transform &p_transform); - virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers); - virtual void camera_set_environment(RID p_camera, RID p_env); - virtual void camera_set_camera_effects(RID p_camera, RID p_fx); - virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable); - - /* SCENARIO API */ - - struct Instance; - - struct Scenario { - RS::ScenarioDebugMode debug; - RID self; - - Octree<Instance, true> octree; - - List<Instance *> directional_lights; - RID environment; - RID fallback_environment; - RID camera_effects; - RID reflection_probe_shadow_atlas; - RID reflection_atlas; - - SelfList<Instance>::List instances; - - LocalVector<RID> dynamic_lights; - - Scenario() { debug = RS::SCENARIO_DEBUG_DISABLED; } - }; - - mutable RID_PtrOwner<Scenario> scenario_owner; - - static void *_instance_pair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int); - static void _instance_unpair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int, void *); - - virtual RID scenario_create(); - - virtual void scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode); - virtual void scenario_set_environment(RID p_scenario, RID p_environment); - virtual void scenario_set_camera_effects(RID p_scenario, RID p_fx); - virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment); - virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count); - - /* INSTANCING API */ - - struct InstanceBaseData { - virtual ~InstanceBaseData() {} - }; - - struct Instance : RasterizerScene::InstanceBase { - RID self; - //scenario stuff - OctreeElementID octree_id; - Scenario *scenario; - SelfList<Instance> scenario_item; - - //aabb stuff - bool update_aabb; - bool update_dependencies; - - SelfList<Instance> update_item; - - AABB *custom_aabb; // <Zylann> would using aabb directly with a bool be better? - float extra_margin; - ObjectID object_id; - - float lod_begin; - float lod_end; - float lod_begin_hysteresis; - float lod_end_hysteresis; - RID lod_instance; - - Vector<Color> lightmap_target_sh; //target is used for incrementally changing the SH over time, this avoids pops in some corner cases and when going interior <-> exterior - - uint64_t last_render_pass; - uint64_t last_frame_pass; - - uint64_t version; // changes to this, and changes to base increase version - - InstanceBaseData *base_data; - - virtual void dependency_deleted(RID p_dependency) { - if (p_dependency == base) { - singleton->instance_set_base(self, RID()); - } else if (p_dependency == skeleton) { - singleton->instance_attach_skeleton(self, RID()); - } else { - singleton->_instance_queue_update(this, false, true); - } - } - - virtual void dependency_changed(bool p_aabb, bool p_dependencies) { - singleton->_instance_queue_update(this, p_aabb, p_dependencies); - } - - Instance() : - scenario_item(this), - update_item(this) { - octree_id = 0; - scenario = nullptr; - - update_aabb = false; - update_dependencies = false; - - extra_margin = 0; - - visible = true; - - lod_begin = 0; - lod_end = 0; - lod_begin_hysteresis = 0; - lod_end_hysteresis = 0; - - last_render_pass = 0; - last_frame_pass = 0; - version = 1; - base_data = nullptr; - - custom_aabb = nullptr; - } - - ~Instance() { - if (base_data) { - memdelete(base_data); - } - if (custom_aabb) { - memdelete(custom_aabb); - } - } - }; - - SelfList<Instance>::List _instance_update_list; - void _instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies = false); - - struct InstanceGeometryData : public InstanceBaseData { - List<Instance *> lighting; - bool lighting_dirty; - bool can_cast_shadows; - bool material_is_animated; - - List<Instance *> decals; - bool decal_dirty; - - List<Instance *> reflection_probes; - bool reflection_dirty; - - List<Instance *> gi_probes; - bool gi_probes_dirty; - - List<Instance *> lightmap_captures; - - InstanceGeometryData() { - lighting_dirty = false; - reflection_dirty = true; - can_cast_shadows = true; - material_is_animated = true; - gi_probes_dirty = true; - decal_dirty = true; - } - }; - - struct InstanceReflectionProbeData : public InstanceBaseData { - Instance *owner; - - struct PairInfo { - List<Instance *>::Element *L; //reflection iterator in geometry - Instance *geometry; - }; - List<PairInfo> geometries; - - RID instance; - bool reflection_dirty; - SelfList<InstanceReflectionProbeData> update_list; - - int render_step; - - InstanceReflectionProbeData() : - update_list(this) { - reflection_dirty = true; - render_step = -1; - } - }; - - struct InstanceDecalData : public InstanceBaseData { - Instance *owner; - RID instance; - - struct PairInfo { - List<Instance *>::Element *L; //reflection iterator in geometry - Instance *geometry; - }; - List<PairInfo> geometries; - - InstanceDecalData() { - } - }; - - SelfList<InstanceReflectionProbeData>::List reflection_probe_render_list; - - struct InstanceLightData : public InstanceBaseData { - struct PairInfo { - List<Instance *>::Element *L; //light iterator in geometry - Instance *geometry; - }; - - RID instance; - uint64_t last_version; - List<Instance *>::Element *D; // directional light in scenario - - bool shadow_dirty; - - List<PairInfo> geometries; - - Instance *baked_light; - - RS::LightBakeMode bake_mode; - uint32_t max_sdfgi_cascade = 2; - - uint64_t sdfgi_cascade_light_pass = 0; - - InstanceLightData() { - bake_mode = RS::LIGHT_BAKE_DISABLED; - shadow_dirty = true; - D = nullptr; - last_version = 0; - baked_light = nullptr; - } - }; - - struct InstanceGIProbeData : public InstanceBaseData { - Instance *owner; - - struct PairInfo { - List<Instance *>::Element *L; //gi probe iterator in geometry - Instance *geometry; - }; - - List<PairInfo> geometries; - List<PairInfo> dynamic_geometries; - - Set<Instance *> lights; - - struct LightCache { - RS::LightType type; - Transform transform; - Color color; - float energy; - float bake_energy; - float radius; - float attenuation; - float spot_angle; - float spot_attenuation; - bool has_shadow; - }; - - Vector<LightCache> light_cache; - Vector<RID> light_instances; - - RID probe_instance; - - bool invalid; - uint32_t base_version; - - SelfList<InstanceGIProbeData> update_element; - - InstanceGIProbeData() : - update_element(this) { - invalid = true; - base_version = 0; - } - }; - - SelfList<InstanceGIProbeData>::List gi_probe_update_list; - - struct InstanceLightmapData : public InstanceBaseData { - struct PairInfo { - List<Instance *>::Element *L; //iterator in geometry - Instance *geometry; - }; - List<PairInfo> geometries; - - Set<Instance *> users; - - InstanceLightmapData() { - } - }; - - Set<Instance *> heightfield_particle_colliders_update_list; - - int instance_cull_count; - Instance *instance_cull_result[MAX_INSTANCE_CULL]; - Instance *instance_shadow_cull_result[MAX_INSTANCE_CULL]; //used for generating shadowmaps - Instance *light_cull_result[MAX_LIGHTS_CULLED]; - RID sdfgi_light_cull_result[MAX_LIGHTS_CULLED]; - RID light_instance_cull_result[MAX_LIGHTS_CULLED]; - uint64_t sdfgi_light_cull_pass = 0; - int light_cull_count; - int directional_light_count; - RID reflection_probe_instance_cull_result[MAX_REFLECTION_PROBES_CULLED]; - RID decal_instance_cull_result[MAX_DECALS_CULLED]; - int reflection_probe_cull_count; - int decal_cull_count; - RID gi_probe_instance_cull_result[MAX_GI_PROBES_CULLED]; - int gi_probe_cull_count; - Instance *lightmap_cull_result[MAX_LIGHTS_CULLED]; - int lightmap_cull_count; - - RID_PtrOwner<Instance> instance_owner; - - virtual RID instance_create(); - - virtual void instance_set_base(RID p_instance, RID p_base); - virtual void instance_set_scenario(RID p_instance, RID p_scenario); - virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask); - virtual void instance_set_transform(RID p_instance, const Transform &p_transform); - virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id); - virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight); - virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material); - virtual void instance_set_visible(RID p_instance, bool p_visible); - - virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb); - - virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton); - virtual void instance_set_exterior(RID p_instance, bool p_enabled); - - virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin); - - // don't use these in a game! - virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const; - virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const; - virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario = RID()) const; - - virtual void instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled); - virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting); - virtual void instance_geometry_set_material_override(RID p_instance, RID p_material); - - virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin); - virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance); - virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index); - - void _update_instance_shader_parameters_from_material(Map<StringName, RasterizerScene::InstanceBase::InstanceShaderParameter> &isparams, const Map<StringName, RasterizerScene::InstanceBase::InstanceShaderParameter> &existing_isparams, RID p_material); - - virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value); - virtual void instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const; - virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const; - virtual Variant instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const; - - _FORCE_INLINE_ void _update_instance(Instance *p_instance); - _FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance); - _FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance); - _FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance); - - _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario); - - RID _render_get_environment(RID p_camera, RID p_scenario); - - bool _render_reflection_probe_step(Instance *p_instance, int p_step); - void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows = true); - void _render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass); - void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas); - - void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); - void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); - void update_dirty_instances(); - - void render_particle_colliders(); - void render_probes(); - - TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size); - - bool free(RID p_rid); - - RenderingServerScene(); - virtual ~RenderingServerScene(); -}; - -#endif // VISUALSERVERSCENE_H diff --git a/servers/rendering/rendering_server_wrap_mt.cpp b/servers/rendering/rendering_server_wrap_mt.cpp index ab9856e06e..3572c4dc78 100644 --- a/servers/rendering/rendering_server_wrap_mt.cpp +++ b/servers/rendering/rendering_server_wrap_mt.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,8 +29,8 @@ /*************************************************************************/ #include "rendering_server_wrap_mt.h" +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" #include "servers/display_server.h" void RenderingServerWrapMT::thread_exit() { diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h index 42f1b5bcc8..2f76577474 100644 --- a/servers/rendering/rendering_server_wrap_mt.h +++ b/servers/rendering/rendering_server_wrap_mt.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,8 +31,8 @@ #ifndef RENDERING_SERVER_WRAP_MT_H #define RENDERING_SERVER_WRAP_MT_H -#include "core/command_queue_mt.h" #include "core/os/thread.h" +#include "core/templates/command_queue_mt.h" #include "servers/rendering_server.h" class RenderingServerWrapMT : public RenderingServer { @@ -129,6 +129,8 @@ public: FUNC2RC(RID, shader_get_default_texture_param, RID, const StringName &) FUNC2RC(Variant, shader_get_param_default, RID, const StringName &) + FUNC1RC(ShaderNativeSourceCode, shader_get_native_source_code, RID) + /* COMMON MATERIAL API */ FUNCRID(material) @@ -143,10 +145,12 @@ public: /* MESH API */ - virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces) { - return rendering_server->mesh_create_from_surfaces(p_surfaces); + virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces, int p_blend_shape_count = 0) { + return rendering_server->mesh_create_from_surfaces(p_surfaces, p_blend_shape_count); } + FUNC2(mesh_set_blend_shape_count, RID, int) + FUNCRID(mesh) FUNC2(mesh_add_surface, RID, const SurfaceData &) @@ -168,6 +172,7 @@ public: FUNC2(mesh_set_custom_aabb, RID, const AABB &) FUNC1RC(AABB, mesh_get_custom_aabb, RID) + FUNC2(mesh_set_shadow_mesh, RID, RID) FUNC1(mesh_clear, RID) /* MULTIMESH API */ @@ -244,6 +249,7 @@ public: FUNC2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode) FUNC2(light_directional_set_blend_splits, RID, bool) + FUNC2(light_directional_set_sky_only, RID, bool) FUNC2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode) /* PROBE API */ @@ -263,6 +269,7 @@ public: FUNC2(reflection_probe_set_enable_shadows, RID, bool) FUNC2(reflection_probe_set_cull_mask, RID, uint32_t) FUNC2(reflection_probe_set_resolution, RID, int) + FUNC2(reflection_probe_set_lod_threshold, RID, float) /* DECAL API */ @@ -439,12 +446,16 @@ public: FUNC2(viewport_set_global_canvas_transform, RID, const Transform2D &) FUNC4(viewport_set_canvas_stacking, RID, RID, int, int) - FUNC2(viewport_set_shadow_atlas_size, RID, int) + FUNC3(viewport_set_shadow_atlas_size, RID, int, bool) + FUNC3(viewport_set_sdf_oversize_and_scale, RID, ViewportSDFOversize, ViewportSDFScale) + FUNC3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int) FUNC2(viewport_set_msaa, RID, ViewportMSAA) FUNC2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA) FUNC2(viewport_set_use_debanding, RID, bool) + FUNC2(viewport_set_lod_threshold, RID, float) + //this passes directly to avoid stalling, but it's pretty dangerous, so don't call after freeing a viewport virtual int viewport_get_render_info(RID p_viewport, ViewportRenderInfo p_info) { return rendering_server->viewport_get_render_info(p_viewport, p_info); @@ -460,7 +471,7 @@ public: return rendering_server->viewport_get_measured_render_time_gpu(p_viewport); } - FUNC1(directional_shadow_atlas_set_size, int) + FUNC2(directional_shadow_atlas_set_size, int, bool) /* SKY API */ @@ -490,13 +501,14 @@ public: FUNC6(environment_set_ssr, RID, bool, int, float, float, float) FUNC1(environment_set_ssr_roughness_quality, EnvironmentSSRRoughnessQuality) - FUNC9(environment_set_ssao, RID, bool, float, float, float, float, float, EnvironmentSSAOBlur, float) + FUNC10(environment_set_ssao, RID, bool, float, float, float, float, float, float, float, float) - FUNC2(environment_set_ssao_quality, EnvironmentSSAOQuality, bool) + FUNC6(environment_set_ssao_quality, EnvironmentSSAOQuality, bool, float, int, float, float) FUNC11(environment_set_sdfgi, RID, bool, EnvironmentSDFGICascades, float, EnvironmentSDFGIYScale, bool, bool, bool, float, float, float) FUNC1(environment_set_sdfgi_ray_count, EnvironmentSDFGIRayCount) FUNC1(environment_set_sdfgi_frames_to_converge, EnvironmentSDFGIFramesToConverge) + FUNC1(environment_set_sdfgi_frames_to_update_light, EnvironmentSDFGIFramesToUpdateLight) FUNC11(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, EnvironmentGlowBlendMode, float, float, float) FUNC1(environment_glow_set_use_bicubic_upscale, bool) @@ -504,7 +516,7 @@ public: FUNC9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float) - FUNC6(environment_set_adjustment, RID, bool, float, float, float, RID) + FUNC7(environment_set_adjustment, RID, bool, float, float, float, bool, RID) FUNC9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float) @@ -570,6 +582,7 @@ public: FUNC5(instance_geometry_set_draw_range, RID, float, float, float, float) FUNC2(instance_geometry_set_as_instance_lod, RID, RID) FUNC4(instance_geometry_set_lightmap, RID, RID, const Rect2 &, int) + FUNC2(instance_geometry_set_lod_bias, RID, float) FUNC3(instance_geometry_set_shader_parameter, RID, const StringName &, const Variant &) FUNC2RC(Variant, instance_geometry_get_shader_parameter, RID, const StringName &) @@ -616,7 +629,7 @@ public: FUNC2(canvas_item_set_draw_behind_parent, RID, bool) FUNC5(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float) - FUNC4(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float) + FUNC5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool) FUNC4(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float) FUNC3(canvas_item_add_rect, RID, const Rect2 &, const Color &) FUNC4(canvas_item_add_circle, RID, const Point2 &, float, const Color &) @@ -647,9 +660,12 @@ public: FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool) FUNC0R(RID, canvas_light_create) + + FUNC2(canvas_light_set_mode, RID, CanvasLightMode) + FUNC2(canvas_light_attach_to_canvas, RID, RID) FUNC2(canvas_light_set_enabled, RID, bool) - FUNC2(canvas_light_set_scale, RID, float) + FUNC2(canvas_light_set_texture_scale, RID, float) FUNC2(canvas_light_set_transform, RID, const Transform2D &) FUNC2(canvas_light_set_texture, RID, RID) FUNC2(canvas_light_set_texture_offset, RID, const Vector2 &) @@ -660,8 +676,9 @@ public: FUNC3(canvas_light_set_layer_range, RID, int, int) FUNC2(canvas_light_set_item_cull_mask, RID, int) FUNC2(canvas_light_set_item_shadow_cull_mask, RID, int) + FUNC2(canvas_light_set_directional_distance, RID, float) - FUNC2(canvas_light_set_mode, RID, CanvasLightMode) + FUNC2(canvas_light_set_blend_mode, RID, CanvasLightBlendMode) FUNC2(canvas_light_set_shadow_enabled, RID, bool) FUNC2(canvas_light_set_shadow_filter, RID, CanvasLightShadowFilter) @@ -672,12 +689,12 @@ public: FUNC2(canvas_light_occluder_attach_to_canvas, RID, RID) FUNC2(canvas_light_occluder_set_enabled, RID, bool) FUNC2(canvas_light_occluder_set_polygon, RID, RID) + FUNC2(canvas_light_occluder_set_as_sdf_collision, RID, bool) FUNC2(canvas_light_occluder_set_transform, RID, const Transform2D &) FUNC2(canvas_light_occluder_set_light_mask, RID, int) FUNCRID(canvas_occluder_polygon) FUNC3(canvas_occluder_polygon_set_shape, RID, const Vector<Vector2> &, bool) - FUNC2(canvas_occluder_polygon_set_shape_as_lines, RID, const Vector<Vector2> &) FUNC2(canvas_occluder_polygon_set_cull_mode, RID, CanvasOccluderPolygonCullMode) @@ -729,6 +746,8 @@ public: return rendering_server->get_video_adapter_vendor(); } + FUNC1(gi_set_use_half_resolution, bool) + FUNC4(set_boot_image, const Ref<Image> &, const Color &, bool, bool) FUNC1(set_default_clear_color, const Color &) @@ -763,10 +782,18 @@ public: return rendering_server->get_frame_profile(); } + virtual float get_frame_setup_time_cpu() const { + return rendering_server->get_frame_setup_time_cpu(); + } + virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) { rendering_server->sdfgi_set_debug_probe_select(p_position, p_dir); } + virtual void set_print_gpu_profile(bool p_enable) { + rendering_server->set_print_gpu_profile(p_enable); + } + RenderingServerWrapMT(RenderingServer *p_contained, bool p_create_thread); ~RenderingServerWrapMT(); diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 1883b6b338..e6415c0258 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,7 +30,7 @@ #include "shader_language.h" #include "core/os/os.h" -#include "core/print_string.h" +#include "core/string/print_string.h" #include "servers/rendering_server.h" static bool _is_text_char(char32_t c) { @@ -223,7 +223,7 @@ const char *ShaderLanguage::token_names[TK_MAX] = { String ShaderLanguage::get_token_text(Token p_token) { String name = token_names[p_token.type]; - if (p_token.type == TK_INT_CONSTANT || p_token.type == TK_REAL_CONSTANT) { + if (p_token.type == TK_INT_CONSTANT || p_token.type == TK_FLOAT_CONSTANT) { name += "(" + rtos(p_token.constant) + ")"; } else if (p_token.type == TK_IDENTIFIER) { name += "(" + String(p_token.text) + ")"; @@ -637,13 +637,13 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { char_idx += str.length(); Token tk; if (period_found || exponent_found || float_suffix_found) { - tk.type = TK_REAL_CONSTANT; + tk.type = TK_FLOAT_CONSTANT; } else { tk.type = TK_INT_CONSTANT; } if (hexa_found) { - tk.constant = (double)str.hex_to_int(true); + tk.constant = (double)str.hex_to_int(); } else { tk.constant = str.to_float(); } @@ -913,6 +913,7 @@ void ShaderLanguage::clear() { char_idx = 0; error_set = false; error_str = ""; + last_const = false; while (nodes) { Node *n = nodes; nodes = nodes->next; @@ -920,7 +921,7 @@ void ShaderLanguage::clear() { } } -bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name) { +bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name, ConstantNode::Value *r_constant_value) { if (p_function_info.built_ins.has(p_identifier)) { if (r_data_type) { *r_data_type = p_function_info.built_ins[p_identifier].type; @@ -968,6 +969,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea if (r_struct_name) { *r_struct_name = p_block->variables[p_identifier].struct_name; } + if (r_constant_value) { + *r_constant_value = p_block->variables[p_identifier].value; + } return true; } @@ -1028,6 +1032,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea } if (shader->constants.has(p_identifier)) { + if (r_is_const) { + *r_is_const = true; + } if (r_data_type) { *r_data_type = shader->constants[p_identifier].type; } @@ -1040,6 +1047,11 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea if (r_struct_name) { *r_struct_name = shader->constants[p_identifier].type_str; } + if (r_constant_value) { + if (shader->constants[p_identifier].initializer && shader->constants[p_identifier].initializer->values.size() == 1) { + *r_constant_value = shader->constants[p_identifier].initializer->values[0]; + } + } return true; } @@ -2157,7 +2169,6 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "fma", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false }, { nullptr, TYPE_VOID, { TYPE_VOID }, TAG_GLOBAL, false } - }; const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[] = { @@ -3175,7 +3186,7 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_functi } bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat) { - for (int i = 0; shader->functions.size(); i++) { + for (int i = 0; i < shader->functions.size(); i++) { if (shader->functions[i].name == p_name) { ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false); FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument]; @@ -3209,7 +3220,7 @@ bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringNam } bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin) { - for (int i = 0; shader->functions.size(); i++) { + for (int i = 0; i < shader->functions.size(); i++) { if (shader->functions[i].name == p_name) { ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false); FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument]; @@ -3242,6 +3253,137 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa ERR_FAIL_V(false); //bug? function not found } +ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size) { + DataType type = TYPE_VOID; + String struct_name = ""; + int array_size = 0; + bool auto_size = false; + Token tk = _get_token(); + + if (tk.type == TK_CURLY_BRACKET_OPEN) { + auto_size = true; + } else { + if (shader->structs.has(tk.text)) { + type = TYPE_STRUCT; + struct_name = tk.text; + } else { + if (!is_token_variable_datatype(tk.type)) { + _set_error("Invalid data type for array"); + return nullptr; + } + type = get_token_datatype(tk.type); + } + tk = _get_token(); + if (tk.type == TK_BRACKET_OPEN) { + TkPos pos = _get_tkpos(); + tk = _get_token(); + if (tk.type == TK_BRACKET_CLOSE) { + array_size = p_array_size; + tk = _get_token(); + } else { + _set_tkpos(pos); + + Node *n = _parse_and_reduce_expression(p_block, p_function_info); + if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) { + _set_error("Expected single integer constant > 0"); + return nullptr; + } + + ConstantNode *cnode = (ConstantNode *)n; + if (cnode->values.size() == 1) { + array_size = cnode->values[0].sint; + if (array_size <= 0) { + _set_error("Expected single integer constant > 0"); + return nullptr; + } + } else { + _set_error("Expected single integer constant > 0"); + return nullptr; + } + + tk = _get_token(); + if (tk.type != TK_BRACKET_CLOSE) { + _set_error("Expected ']'"); + return nullptr; + } else { + tk = _get_token(); + } + } + } else { + _set_error("Expected '['"); + return nullptr; + } + + if (type != p_type || struct_name != p_struct_name || array_size != p_array_size) { + String error_str = "Cannot convert from '"; + if (type == TYPE_STRUCT) { + error_str += struct_name; + } else { + error_str += get_datatype_name(type); + } + error_str += "["; + error_str += itos(array_size); + error_str += "]'"; + error_str += " to '"; + if (type == TYPE_STRUCT) { + error_str += p_struct_name; + } else { + error_str += get_datatype_name(p_type); + } + error_str += "["; + error_str += itos(p_array_size); + error_str += "]'"; + _set_error(error_str); + return nullptr; + } + } + + ArrayConstructNode *an = alloc_node<ArrayConstructNode>(); + an->datatype = p_type; + an->struct_name = p_struct_name; + + if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization + while (true) { + Node *n = _parse_and_reduce_expression(p_block, p_function_info); + if (!n) { + return nullptr; + } + + if (p_type != n->get_datatype() || p_struct_name != n->get_datatype_name()) { + _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (type == TYPE_STRUCT ? struct_name : get_datatype_name(type)) + "'"); + return nullptr; + } + + tk = _get_token(); + if (tk.type == TK_COMMA) { + an->initializer.push_back(n); + } else if (!auto_size && tk.type == TK_PARENTHESIS_CLOSE) { + an->initializer.push_back(n); + break; + } else if (auto_size && tk.type == TK_CURLY_BRACKET_CLOSE) { + an->initializer.push_back(n); + break; + } else { + if (auto_size) { + _set_error("Expected '}' or ','"); + } else { + _set_error("Expected ')' or ','"); + } + return nullptr; + } + } + if (an->initializer.size() != p_array_size) { + _set_error("Array size mismatch"); + return nullptr; + } + } else { + _set_error("Expected array initialization!"); + return nullptr; + } + + return an; +} + ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info) { Vector<Expression> expression; @@ -3270,7 +3412,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons return nullptr; } - } else if (tk.type == TK_REAL_CONSTANT) { + } else if (tk.type == TK_FLOAT_CONSTANT) { ConstantNode *constant = alloc_node<ConstantNode>(); ConstantNode::Value v; v.real = tk.constant; @@ -3385,142 +3527,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons Node *nexpr; if (pstruct->members[i]->array_size != 0) { - DataType type = pstruct->members[i]->get_datatype(); - String struct_name = pstruct->members[i]->struct_name; - int array_size = pstruct->members[i]->array_size; - - DataType type2; - String struct_name2 = ""; - int array_size2 = 0; - - bool auto_size = false; - - tk = _get_token(); - - if (tk.type == TK_CURLY_BRACKET_OPEN) { - auto_size = true; - } else { - if (shader->structs.has(tk.text)) { - type2 = TYPE_STRUCT; - struct_name2 = tk.text; - } else { - if (!is_token_variable_datatype(tk.type)) { - _set_error("Invalid data type for array"); - return nullptr; - } - type2 = get_token_datatype(tk.type); - } - - tk = _get_token(); - if (tk.type == TK_BRACKET_OPEN) { - TkPos pos2 = _get_tkpos(); - tk = _get_token(); - if (tk.type == TK_BRACKET_CLOSE) { - array_size2 = array_size; - tk = _get_token(); - } else { - _set_tkpos(pos2); - - Node *n = _parse_and_reduce_expression(p_block, p_function_info); - if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) { - _set_error("Expected single integer constant > 0"); - return nullptr; - } - - ConstantNode *cnode = (ConstantNode *)n; - if (cnode->values.size() == 1) { - array_size2 = cnode->values[0].sint; - if (array_size2 <= 0) { - _set_error("Expected single integer constant > 0"); - return nullptr; - } - } else { - _set_error("Expected single integer constant > 0"); - return nullptr; - } - - tk = _get_token(); - if (tk.type != TK_BRACKET_CLOSE) { - _set_error("Expected ']'"); - return nullptr; - } else { - tk = _get_token(); - } - } - } else { - _set_error("Expected '['"); - return nullptr; - } - - if (type != type2 || struct_name != struct_name2 || array_size != array_size2) { - String error_str = "Cannot convert from '"; - if (type2 == TYPE_STRUCT) { - error_str += struct_name2; - } else { - error_str += get_datatype_name(type2); - } - error_str += "["; - error_str += itos(array_size2); - error_str += "]'"; - error_str += " to '"; - if (type == TYPE_STRUCT) { - error_str += struct_name; - } else { - error_str += get_datatype_name(type); - } - error_str += "["; - error_str += itos(array_size); - error_str += "]'"; - _set_error(error_str); - return nullptr; - } - } - - ArrayConstructNode *an = alloc_node<ArrayConstructNode>(); - an->datatype = type; - an->struct_name = struct_name; - - if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization - while (true) { - Node *n = _parse_and_reduce_expression(p_block, p_function_info); - if (!n) { - return nullptr; - } - - if (type != n->get_datatype() || struct_name != n->get_datatype_name()) { - _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (type == TYPE_STRUCT ? struct_name : get_datatype_name(type)) + "'"); - return nullptr; - } - - tk = _get_token(); - if (tk.type == TK_COMMA) { - an->initializer.push_back(n); - continue; - } else if (!auto_size && tk.type == TK_PARENTHESIS_CLOSE) { - an->initializer.push_back(n); - break; - } else if (auto_size && tk.type == TK_CURLY_BRACKET_CLOSE) { - an->initializer.push_back(n); - break; - } else { - if (auto_size) { - _set_error("Expected '}' or ','"); - } else { - _set_error("Expected ')' or ','"); - } - return nullptr; - } - } - if (an->initializer.size() != array_size) { - _set_error("Array size mismatch"); - return nullptr; - } - } else { - _set_error("Expected array initialization!"); + nexpr = _parse_array_constructor(p_block, p_function_info, pstruct->members[i]->get_datatype(), pstruct->members[i]->struct_name, pstruct->members[i]->array_size); + if (!nexpr) { return nullptr; } - - nexpr = an; } else { nexpr = _parse_and_reduce_expression(p_block, p_function_info); if (!nexpr) { @@ -3723,6 +3733,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } else { //an identifier + last_const = false; _set_tkpos(pos); DataType data_type; @@ -3750,6 +3761,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons _set_error("Unknown identifier in expression: " + String(identifier)); return nullptr; } + last_const = is_const; if (ident_type == IDENTIFIER_FUNCTION) { _set_error("Can't use function as identifier: " + String(identifier)); @@ -3759,16 +3771,30 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons Node *index_expression = nullptr; Node *call_expression = nullptr; + Node *assign_expression = nullptr; if (array_size > 0) { tk = _get_token(); - if (tk.type != TK_BRACKET_OPEN && tk.type != TK_PERIOD) { - _set_error("Expected '[' or '.'"); + if (tk.type != TK_BRACKET_OPEN && tk.type != TK_PERIOD && tk.type != TK_OP_ASSIGN) { + _set_error("Expected '[','.' or '='"); return nullptr; } - if (tk.type == TK_PERIOD) { + if (tk.type == TK_OP_ASSIGN) { + if (is_const) { + _set_error("Constants cannot be modified."); + return nullptr; + } + if (shader->varyings.has(identifier) && current_function != String("vertex")) { + _set_error("Varyings can only be assigned in vertex function."); + return nullptr; + } + assign_expression = _parse_array_constructor(p_block, p_function_info, data_type, struct_name, array_size); + if (!assign_expression) { + return nullptr; + } + } else if (tk.type == TK_PERIOD) { completion_class = TAG_ARRAY; p_block->block_tag = SubClassTag::TAG_ARRAY; call_expression = _parse_and_reduce_expression(p_block, p_function_info); @@ -3792,7 +3818,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (index_expression->type == Node::TYPE_CONSTANT) { ConstantNode *cnode = (ConstantNode *)index_expression; if (cnode) { - if (!cnode->values.empty()) { + if (!cnode->values.is_empty()) { int value = cnode->values[0].sint; if (value < 0 || value >= array_size) { _set_error(vformat("Index [%s] out of range [%s..%s]", value, 0, array_size - 1)); @@ -3815,6 +3841,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons arrname->struct_name = struct_name; arrname->index_expression = index_expression; arrname->call_expression = call_expression; + arrname->assign_expression = assign_expression; arrname->is_const = is_const; expr = arrname; @@ -4155,7 +4182,18 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (array_size > 0) { tk = _get_token(); - if (tk.type == TK_PERIOD) { + if (tk.type == TK_OP_ASSIGN) { + if (last_const) { + last_const = false; + _set_error("Constants cannot be modified."); + return nullptr; + } + Node *assign_expression = _parse_array_constructor(p_block, p_function_info, member_type, member_struct_name, array_size); + if (!assign_expression) { + return nullptr; + } + mn->assign_expression = assign_expression; + } else if (tk.type == TK_PERIOD) { _set_error("Nested array length() is not yet implemented"); return nullptr; } else if (tk.type == TK_BRACKET_OPEN) { @@ -4172,7 +4210,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (index_expression->type == Node::TYPE_CONSTANT) { ConstantNode *cnode = (ConstantNode *)index_expression; if (cnode) { - if (!cnode->values.empty()) { + if (!cnode->values.is_empty()) { int value = cnode->values[0].sint; if (value < 0 || value >= array_size) { _set_error(vformat("Index [%s] out of range [%s..%s]", value, 0, array_size - 1)); @@ -4190,7 +4228,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons mn->index_expression = index_expression; } else { - _set_error("Expected '[' or '.'"); + _set_error("Expected '[','.' or '='"); return nullptr; } } @@ -5011,17 +5049,53 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun decl.name = name; decl.size = 0U; + pos = _get_tkpos(); tk = _get_token(); if (tk.type == TK_BRACKET_CLOSE) { unknown_size = true; } else { if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) { + _set_tkpos(pos); + Node *n = _parse_and_reduce_expression(p_block, p_function_info); + if (n) { + if (n->type == Node::TYPE_VARIABLE) { + VariableNode *vn = static_cast<VariableNode *>(n); + if (vn) { + ConstantNode::Value v; + DataType data_type; + + _find_identifier(p_block, false, p_function_info, vn->name, &data_type, nullptr, &is_const, nullptr, nullptr, &v); + + if (is_const) { + if (data_type == TYPE_INT) { + int32_t value = v.sint; + if (value > 0) { + node->size_expression = n; + decl.size = (uint32_t)value; + } + } else if (data_type == TYPE_UINT) { + uint32_t value = v.uint; + if (value > 0U) { + node->size_expression = n; + decl.size = value; + } + } + } + } + } else if (n->type == Node::TYPE_OPERATOR) { + _set_error("Array size expressions are not yet implemented."); + return ERR_PARSE_ERROR; + } + } + } else if (((int)tk.constant) > 0) { + decl.size = (uint32_t)tk.constant; + } + + if (decl.size == 0U) { _set_error("Expected integer constant > 0 or ']'"); return ERR_PARSE_ERROR; } - - decl.size = ((uint32_t)tk.constant); tk = _get_token(); if (tk.type != TK_BRACKET_CLOSE) { @@ -5219,7 +5293,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun _set_error("Expected array initialization"); return ERR_PARSE_ERROR; } - if (is_const) { + if (node->is_const) { _set_error("Expected initialization of constant"); return ERR_PARSE_ERROR; } @@ -5253,6 +5327,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } decl.initializer = n; + if (n->type == Node::TYPE_CONSTANT) { + ConstantNode *const_node = static_cast<ConstantNode *>(n); + if (const_node && const_node->values.size() == 1) { + var.value = const_node->values[0]; + } + } + if (var.type == TYPE_STRUCT ? (var.struct_name != n->get_datatype_name()) : (var.type != n->get_datatype())) { _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (var.type == TYPE_STRUCT ? String(var.struct_name) : get_datatype_name(var.type)) + "'"); return ERR_PARSE_ERROR; @@ -5421,18 +5502,29 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun ControlFlowNode *flow = (ControlFlowNode *)switch_block->statements[i]; if (flow) { if (flow->flow_op == FLOW_OP_CASE) { - ConstantNode *n2 = static_cast<ConstantNode *>(flow->expressions[0]); - if (!n2) { - return ERR_PARSE_ERROR; - } - if (n2->values.empty()) { - return ERR_PARSE_ERROR; - } - if (constants.has(n2->values[0].sint)) { - _set_error("Duplicated case label: '" + itos(n2->values[0].sint) + "'"); - return ERR_PARSE_ERROR; + if (flow->expressions[0]->type == Node::TYPE_CONSTANT) { + ConstantNode *cn = static_cast<ConstantNode *>(flow->expressions[0]); + if (!cn || cn->values.is_empty()) { + return ERR_PARSE_ERROR; + } + if (constants.has(cn->values[0].sint)) { + _set_error("Duplicated case label: '" + itos(cn->values[0].sint) + "'"); + return ERR_PARSE_ERROR; + } + constants.insert(cn->values[0].sint); + } else if (flow->expressions[0]->type == Node::TYPE_VARIABLE) { + VariableNode *vn = static_cast<VariableNode *>(flow->expressions[0]); + if (!vn) { + return ERR_PARSE_ERROR; + } + ConstantNode::Value v; + _find_identifier(p_block, false, p_function_info, vn->name, nullptr, nullptr, nullptr, nullptr, nullptr, &v); + if (constants.has(v.sint)) { + _set_error("Duplicated case label: '" + itos(v.sint) + "'"); + return ERR_PARSE_ERROR; + } + constants.insert(v.sint); } - constants.insert(n2->values[0].sint); } else if (flow->flow_op == FLOW_OP_DEFAULT) { continue; } else { @@ -5468,12 +5560,38 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun tk = _get_token(); } + Node *n = nullptr; + if (tk.type != TK_INT_CONSTANT) { - _set_error("Expected integer constant"); - return ERR_PARSE_ERROR; - } + bool correct_constant_expression = false; + DataType data_type; - int constant = (int)tk.constant * sign; + if (tk.type == TK_IDENTIFIER) { + bool is_const; + _find_identifier(p_block, false, p_function_info, tk.text, &data_type, nullptr, &is_const); + if (is_const) { + if (data_type == TYPE_INT) { + correct_constant_expression = true; + } + } + } + if (!correct_constant_expression) { + _set_error("Expected integer constant"); + return ERR_PARSE_ERROR; + } + + VariableNode *vn = alloc_node<VariableNode>(); + vn->name = tk.text; + n = vn; + } else { + ConstantNode::Value v; + v.sint = (int)tk.constant * sign; + + ConstantNode *cn = alloc_node<ConstantNode>(); + cn->values.push_back(v); + cn->datatype = TYPE_INT; + n = cn; + } tk = _get_token(); @@ -5485,12 +5603,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun ControlFlowNode *cf = alloc_node<ControlFlowNode>(); cf->flow_op = FLOW_OP_CASE; - ConstantNode *n = alloc_node<ConstantNode>(); - ConstantNode::Value v; - v.sint = constant; - n->values.push_back(v); - n->datatype = TYPE_INT; - BlockNode *case_block = alloc_node<BlockNode>(); case_block->block_type = BlockNode::BLOCK_TYPE_CASE; case_block->parent_block = p_block; @@ -6193,7 +6305,9 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } uniform2.texture_order = -1; - uniform2.order = uniforms++; + if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) { + uniform2.order = uniforms++; + } } uniform2.type = type; uniform2.scope = uniform_scope; @@ -6261,7 +6375,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); } - if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) { + if (tk.type != TK_FLOAT_CONSTANT && tk.type != TK_INT_CONSTANT) { _set_error("Expected integer constant"); return ERR_PARSE_ERROR; } @@ -6285,7 +6399,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); } - if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) { + if (tk.type != TK_FLOAT_CONSTANT && tk.type != TK_INT_CONSTANT) { _set_error("Expected integer constant after ','"); return ERR_PARSE_ERROR; } @@ -6298,7 +6412,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct if (tk.type == TK_COMMA) { tk = _get_token(); - if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) { + if (tk.type != TK_FLOAT_CONSTANT && tk.type != TK_INT_CONSTANT) { _set_error("Expected integer constant after ','"); return ERR_PARSE_ERROR; } diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index 3c0a10809b..27767378f9 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,13 +31,13 @@ #ifndef SHADER_LANGUAGE_H #define SHADER_LANGUAGE_H -#include "core/list.h" -#include "core/map.h" -#include "core/script_language.h" -#include "core/string_name.h" +#include "core/object/script_language.h" +#include "core/string/string_name.h" +#include "core/string/ustring.h" +#include "core/templates/list.h" +#include "core/templates/map.h" #include "core/typedefs.h" -#include "core/ustring.h" -#include "core/variant.h" +#include "core/variant/variant.h" class ShaderLanguage { public: @@ -46,7 +46,7 @@ public: TK_IDENTIFIER, TK_TRUE, TK_FALSE, - TK_REAL_CONSTANT, + TK_FLOAT_CONSTANT, TK_INT_CONSTANT, TK_TYPE_VOID, TK_TYPE_BOOL, @@ -414,6 +414,7 @@ public: StringName name; Node *index_expression = nullptr; Node *call_expression = nullptr; + Node *assign_expression = nullptr; bool is_const = false; virtual DataType get_datatype() const { return datatype_cache; } @@ -437,6 +438,7 @@ public: DataType datatype = TYPE_VOID; String struct_name; bool is_const = false; + Node *size_expression = nullptr; struct Declaration { StringName name; @@ -496,6 +498,7 @@ public: int line; //for completion int array_size; bool is_const; + ConstantNode::Value value; }; Map<StringName, Variable> variables; @@ -519,13 +522,14 @@ public: DataType basetype = TYPE_VOID; bool basetype_const = false; StringName base_struct_name; - DataPrecision precision; + DataPrecision precision = PRECISION_DEFAULT; DataType datatype = TYPE_VOID; int array_size = 0; StringName struct_name; StringName name; Node *owner = nullptr; Node *index_expression = nullptr; + Node *assign_expression = nullptr; bool has_swizzling_duplicates = false; virtual DataType get_datatype() const { return datatype; } @@ -774,6 +778,7 @@ private: int tk_line; StringName current_function; + bool last_const = false; struct TkPos { int char_idx; @@ -819,7 +824,7 @@ private: IDENTIFIER_CONSTANT, }; - bool _find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type = nullptr, IdentifierType *r_type = nullptr, bool *r_is_const = nullptr, int *r_array_size = nullptr, StringName *r_struct_name = nullptr); + bool _find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type = nullptr, IdentifierType *r_type = nullptr, bool *r_is_const = nullptr, int *r_array_size = nullptr, StringName *r_struct_name = nullptr, ConstantNode::Value *r_constant_value = nullptr); bool _is_operator_assign(Operator p_op) const; bool _validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message = nullptr); bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = nullptr); @@ -861,6 +866,7 @@ private: bool _propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin); Node *_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info); + Node *_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size); ShaderLanguage::Node *_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node); Node *_parse_and_reduce_expression(BlockNode *p_block, const FunctionInfo &p_function_info); diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index 48eaf1dd13..e99b8504bb 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -67,6 +67,12 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_ID"] = constt(ShaderLanguage::TYPE_INT); shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["ROUGHNESS"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["BONE_INDICES"] = ShaderLanguage::TYPE_UVEC4; + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["BONE_WEIGHTS"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM0"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM1"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM2"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM3"] = ShaderLanguage::TYPE_VEC4; shader_modes[RS::SHADER_SPATIAL].functions["vertex"].can_discard = false; //builtins @@ -88,8 +94,8 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["TANGENT"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["BINORMAL"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW"] = constt(ShaderLanguage::TYPE_VEC3); - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMALMAP"] = ShaderLanguage::TYPE_VEC3; - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMALMAP_DEPTH"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMAL_MAP"] = ShaderLanguage::TYPE_VEC3; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMAL_MAP_DEPTH"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["UV2"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["COLOR"] = constt(ShaderLanguage::TYPE_VEC4); @@ -134,6 +140,11 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["IRRADIANCE"] = ShaderLanguage::TYPE_VEC4; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].can_discard = true; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA_SCISSOR_THRESHOLD"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA_HASH_SCALE"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA_ANTIALIASING_EDGE"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA_TEXTURE_COORDINATE"] = ShaderLanguage::TYPE_VEC2; + shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["INV_CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); @@ -206,6 +217,9 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].modes.push_back("vertex_lighting"); + shader_modes[RS::SHADER_SPATIAL].modes.push_back("alpha_to_coverage"); + shader_modes[RS::SHADER_SPATIAL].modes.push_back("alpha_to_coverage_and_one"); + /************ CANVAS ITEM **************************/ shader_modes[RS::SHADER_CANVAS_ITEM].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); @@ -228,8 +242,8 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["LIGHT_VERTEX"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3; - shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMALMAP"] = ShaderLanguage::TYPE_VEC3; - shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMALMAP_DEPTH"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL_MAP"] = ShaderLanguage::TYPE_VEC3; + shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL_MAP_DEPTH"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4; shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D); @@ -244,6 +258,27 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D); shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].can_discard = true; + { + ShaderLanguage::StageFunctionInfo func; + 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; + shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].stage_functions["texture_sdf"] = func; + func.return_type = ShaderLanguage::TYPE_VEC2; //whether it could emit + shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].stage_functions["sdf_to_screen_uv"] = func; + shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].stage_functions["sdf_to_screen_uv"] = func; + shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].stage_functions["texture_sdf_normal"] = func; + shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].stage_functions["texture_sdf_normal"] = func; + } + + { + ShaderLanguage::StageFunctionInfo func; + 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; + shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].stage_functions["screen_uv_to_sdf"] = func; + } + shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["NORMAL"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["COLOR"] = constt(ShaderLanguage::TYPE_VEC4); @@ -312,7 +347,7 @@ ShaderTypes::ShaderTypes() { emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("custom", ShaderLanguage::TYPE_VEC4)); emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("flags", ShaderLanguage::TYPE_UINT)); emit_vertex_func.return_type = ShaderLanguage::TYPE_BOOL; //whether it could emit - shader_modes[RS::SHADER_PARTICLES].functions["compute"].stage_functions["emit_particle"] = emit_vertex_func; + shader_modes[RS::SHADER_PARTICLES].functions["compute"].stage_functions["emit_subparticle"] = emit_vertex_func; } shader_modes[RS::SHADER_PARTICLES].modes.push_back("collision_use_scale"); diff --git a/servers/rendering/shader_types.h b/servers/rendering/shader_types.h index 7d8057a5c6..e59cef6b79 100644 --- a/servers/rendering/shader_types.h +++ b/servers/rendering/shader_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,7 +31,7 @@ #ifndef SHADERTYPES_H #define SHADERTYPES_H -#include "core/ordered_hash_map.h" +#include "core/templates/ordered_hash_map.h" #include "servers/rendering_server.h" #include "shader_language.h" diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 42a77101f7..9ac66cd4bf 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,7 +30,7 @@ #include "rendering_server.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h" RenderingServer *RenderingServer::singleton = nullptr; RenderingServer *(*RenderingServer::create_func)() = nullptr; @@ -315,8 +315,10 @@ RID RenderingServer::get_white_texture() { #define SMALL_VEC2 Vector2(0.00001, 0.00001) #define SMALL_VEC3 Vector3(0.00001, 0.00001, 0.00001) -Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_stride, Vector<uint8_t> &r_vertex_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb) { +Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_vertex_stride, uint32_t p_attrib_stride, uint32_t p_skin_stride, Vector<uint8_t> &r_vertex_array, Vector<uint8_t> &r_attrib_array, Vector<uint8_t> &r_skin_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb) { uint8_t *vw = r_vertex_array.ptrw(); + uint8_t *aw = r_attrib_array.ptrw(); + uint8_t *sw = r_skin_array.ptrw(); uint8_t *iw = nullptr; if (r_index_array.size()) { @@ -345,7 +347,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint for (int i = 0; i < p_vertex_array_len; i++) { float vector[2] = { src[i].x, src[i].y }; - copymem(&vw[p_offsets[ai] + i * p_stride], vector, sizeof(float) * 2); + copymem(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 2); if (i == 0) { aabb = Rect2(src[i], SMALL_VEC2); //must have a bit of size @@ -370,7 +372,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint for (int i = 0; i < p_vertex_array_len; i++) { float vector[3] = { src[i].x, src[i].y, src[i].z }; - copymem(&vw[p_offsets[ai] + i * p_stride], vector, sizeof(float) * 3); + copymem(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 3); if (i == 0) { aabb = AABB(src[i], SMALL_VEC3); @@ -391,26 +393,15 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER); const Vector3 *src = array.ptr(); + for (int i = 0; i < p_vertex_array_len; i++) { + Vector3 n = src[i] * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); - // setting vertices means regenerating the AABB + uint32_t value = 0; + value |= CLAMP(int(n.x * 1023.0), 0, 1023); + value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10; + value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20; - if (p_format & ARRAY_COMPRESS_NORMAL) { - for (int i = 0; i < p_vertex_array_len; i++) { - int8_t vector[4] = { - (int8_t)CLAMP(src[i].x * 127, -128, 127), - (int8_t)CLAMP(src[i].y * 127, -128, 127), - (int8_t)CLAMP(src[i].z * 127, -128, 127), - 0, - }; - - copymem(&vw[p_offsets[ai] + i * p_stride], vector, 4); - } - - } else { - for (int i = 0; i < p_vertex_array_len; i++) { - float vector[3] = { src[i].x, src[i].y, src[i].z }; - copymem(&vw[p_offsets[ai] + i * p_stride], vector, 3 * 4); - } + copymem(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4); } } break; @@ -424,29 +415,14 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint const real_t *src = array.ptr(); - if (p_format & ARRAY_COMPRESS_TANGENT) { - for (int i = 0; i < p_vertex_array_len; i++) { - int8_t xyzw[4] = { - (int8_t)CLAMP(src[i * 4 + 0] * 127, -128, 127), - (int8_t)CLAMP(src[i * 4 + 1] * 127, -128, 127), - (int8_t)CLAMP(src[i * 4 + 2] * 127, -128, 127), - (int8_t)CLAMP(src[i * 4 + 3] * 127, -128, 127) - }; - - copymem(&vw[p_offsets[ai] + i * p_stride], xyzw, 4); - } + for (int i = 0; i < p_vertex_array_len; i++) { + uint32_t value = 0; + value |= CLAMP(int((src[i * 4 + 0] * 0.5 + 0.5) * 1023.0), 0, 1023); + value |= CLAMP(int((src[i * 4 + 1] * 0.5 + 0.5) * 1023.0), 0, 1023) << 10; + value |= CLAMP(int((src[i * 4 + 2] * 0.5 + 0.5) * 1023.0), 0, 1023) << 20; + value |= CLAMP(int((src[i * 4 + 3] * 0.5 + 0.5) * 3.0), 0, 3) << 30; - } else { - for (int i = 0; i < p_vertex_array_len; i++) { - float xyzw[4] = { - src[i * 4 + 0], - src[i * 4 + 1], - src[i * 4 + 2], - src[i * 4 + 3] - }; - - copymem(&vw[p_offsets[ai] + i * p_stride], xyzw, 4 * 4); - } + copymem(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4); } } break; @@ -458,23 +434,14 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER); const Color *src = array.ptr(); - - if (p_format & ARRAY_COMPRESS_COLOR) { - for (int i = 0; i < p_vertex_array_len; i++) { - uint8_t colors[4]; - - for (int j = 0; j < 4; j++) { - colors[j] = CLAMP(int((src[i][j]) * 255.0), 0, 255); - } - - copymem(&vw[p_offsets[ai] + i * p_stride], colors, 4); - } - } else { - for (int i = 0; i < p_vertex_array_len; i++) { - copymem(&vw[p_offsets[ai] + i * p_stride], &src[i], 4 * 4); - } + uint16_t color16[4]; + for (int i = 0; i < p_vertex_array_len; i++) { + color16[0] = Math::make_half_float(src[i].r); + color16[1] = Math::make_half_float(src[i].g); + color16[2] = Math::make_half_float(src[i].b); + color16[3] = Math::make_half_float(src[i].a); + copymem(&aw[p_offsets[ai] + i * p_attrib_stride], color16, 8); } - } break; case RS::ARRAY_TEX_UV: { ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_VECTOR3_ARRAY && p_arrays[ai].get_type() != Variant::PACKED_VECTOR2_ARRAY, ERR_INVALID_PARAMETER); @@ -485,18 +452,10 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint const Vector2 *src = array.ptr(); - if (p_format & ARRAY_COMPRESS_TEX_UV) { - for (int i = 0; i < p_vertex_array_len; i++) { - uint16_t uv[2] = { Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) }; - copymem(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 2); - } - - } else { - for (int i = 0; i < p_vertex_array_len; i++) { - float uv[2] = { src[i].x, src[i].y }; + for (int i = 0; i < p_vertex_array_len; i++) { + float uv[2] = { src[i].x, src[i].y }; - copymem(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 4); - } + copymem(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4); } } break; @@ -510,37 +469,90 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint const Vector2 *src = array.ptr(); - if (p_format & ARRAY_COMPRESS_TEX_UV2) { - for (int i = 0; i < p_vertex_array_len; i++) { - uint16_t uv[2] = { Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) }; - copymem(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 2); - } + for (int i = 0; i < p_vertex_array_len; i++) { + uint16_t uv[2] = { Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) }; + copymem(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 2); + } + } break; + case RS::ARRAY_CUSTOM0: + case RS::ARRAY_CUSTOM1: + case RS::ARRAY_CUSTOM2: + case RS::ARRAY_CUSTOM3: { + uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (RS::ARRAY_CUSTOM0 - ai))) & ARRAY_FORMAT_CUSTOM_MASK; + switch (type) { + case ARRAY_CUSTOM_RGBA8_UNORM: + case ARRAY_CUSTOM_RGBA8_SNORM: + case ARRAY_CUSTOM_RG_HALF: { + //size 4 + ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_BYTE_ARRAY, ERR_INVALID_PARAMETER); - } else { - for (int i = 0; i < p_vertex_array_len; i++) { - float uv[2] = { src[i].x, src[i].y }; + Vector<uint8_t> array = p_arrays[ai]; + + ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); + + const uint8_t *src = array.ptr(); - copymem(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 4); + for (int i = 0; i < p_vertex_array_len; i++) { + copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 4], 4); + } + + } break; + case ARRAY_CUSTOM_RGBA_HALF: { + //size 8 + ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_BYTE_ARRAY, ERR_INVALID_PARAMETER); + + Vector<uint8_t> array = p_arrays[ai]; + + ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 8, ERR_INVALID_PARAMETER); + + const uint8_t *src = array.ptr(); + + for (int i = 0; i < p_vertex_array_len; i++) { + copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 8], 8); + } + } break; + case ARRAY_CUSTOM_R_FLOAT: + case ARRAY_CUSTOM_RG_FLOAT: + case ARRAY_CUSTOM_RGB_FLOAT: + case ARRAY_CUSTOM_RGBA_FLOAT: { + //RF + ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER); + + Vector<float> array = p_arrays[ai]; + int32_t s = ARRAY_CUSTOM_R_FLOAT - ai + 1; + + ERR_FAIL_COND_V(array.size() != p_vertex_array_len * s, ERR_INVALID_PARAMETER); + + const float *src = array.ptr(); + + for (int i = 0; i < p_vertex_array_len; i++) { + copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * s], 4 * s); + } + } break; + default: { } } + } break; case RS::ARRAY_WEIGHTS: { ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER); + uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4; + Vector<real_t> array = p_arrays[ai]; - ERR_FAIL_COND_V(array.size() != p_vertex_array_len * RS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(array.size() != (int32_t)(p_vertex_array_len * bone_count), ERR_INVALID_PARAMETER); const real_t *src = array.ptr(); { + uint16_t data[8]; for (int i = 0; i < p_vertex_array_len; i++) { - uint16_t data[RS::ARRAY_WEIGHTS_SIZE]; - for (int j = 0; j < RS::ARRAY_WEIGHTS_SIZE; j++) { - data[j] = CLAMP(src[i * RS::ARRAY_WEIGHTS_SIZE + j] * 65535, 0, 65535); + for (uint32_t j = 0; j < bone_count; j++) { + data[j] = CLAMP(src[i * bone_count + j] * 65535, 0, 65535); } - copymem(&vw[p_offsets[ai] + i * p_stride], data, 2 * 4); + copymem(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count); } } @@ -550,21 +562,25 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint Vector<int> array = p_arrays[ai]; - ERR_FAIL_COND_V(array.size() != p_vertex_array_len * RS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER); + uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4; + + ERR_FAIL_COND_V(array.size() != (int32_t)(p_vertex_array_len * bone_count), ERR_INVALID_PARAMETER); const int *src = array.ptr(); + uint16_t data[8]; + for (int i = 0; i < p_vertex_array_len; i++) { - uint16_t data[RS::ARRAY_WEIGHTS_SIZE]; - for (int j = 0; j < RS::ARRAY_WEIGHTS_SIZE; j++) { - data[j] = src[i * RS::ARRAY_WEIGHTS_SIZE + j]; + for (uint32_t j = 0; j < bone_count; j++) { + data[j] = src[i * bone_count + j]; max_bone = MAX(data[j], max_bone); } - copymem(&vw[p_offsets[ai] + i * p_stride], data, 2 * 4); + copymem(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count); } } break; + case RS::ARRAY_INDEX: { ERR_FAIL_NULL_V(iw, ERR_INVALID_DATA); ERR_FAIL_COND_V(p_index_array_len <= 0, ERR_INVALID_DATA); @@ -604,6 +620,8 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint r_bone_aabb.resize(total_bones); + int weight_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4; + if (first) { for (int i = 0; i < total_bones; i++) { r_bone_aabb.write[i].size = Vector3(-1, -1, -1); //negative means unused @@ -616,7 +634,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint bool any_valid = false; - if (vertices.size() && bones.size() == vertices.size() * 4 && weights.size() == bones.size()) { + if (vertices.size() && bones.size() == vertices.size() * weight_count && weights.size() == bones.size()) { int vs = vertices.size(); const Vector3 *rv = vertices.ptr(); const int *rb = bones.ptr(); @@ -626,9 +644,9 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint for (int i = 0; i < vs; i++) { Vector3 v = rv[i]; - for (int j = 0; j < 4; j++) { - int idx = rb[i * 4 + j]; - float w = rw[i * 4 + j]; + for (int j = 0; j < weight_count; j++) { + int idx = rb[i * weight_count + j]; + float w = rw[i * weight_count + j]; if (w == 0) { continue; //break; } @@ -652,23 +670,62 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint return OK; } -uint32_t RenderingServer::mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_index_len, int p_array_index) const { +uint32_t RenderingServer::mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_array_index) const { + p_format &= ~ARRAY_FORMAT_INDEX; uint32_t offsets[ARRAY_MAX]; - mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets); + uint32_t vstr; + uint32_t astr; + uint32_t sstr; + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr); return offsets[p_array_index]; } -uint32_t RenderingServer::mesh_surface_get_format_stride(uint32_t p_format, int p_vertex_len, int p_index_len) const { +uint32_t RenderingServer::mesh_surface_get_format_vertex_stride(uint32_t p_format, int p_vertex_len) const { + p_format &= ~ARRAY_FORMAT_INDEX; + uint32_t offsets[ARRAY_MAX]; + uint32_t vstr; + uint32_t astr; + uint32_t sstr; + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr); + return vstr; +} +uint32_t RenderingServer::mesh_surface_get_format_attribute_stride(uint32_t p_format, int p_vertex_len) const { + p_format &= ~ARRAY_FORMAT_INDEX; + uint32_t offsets[ARRAY_MAX]; + uint32_t vstr; + uint32_t astr; + uint32_t sstr; + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr); + return astr; +} +uint32_t RenderingServer::mesh_surface_get_format_skin_stride(uint32_t p_format, int p_vertex_len) const { + p_format &= ~ARRAY_FORMAT_INDEX; uint32_t offsets[ARRAY_MAX]; - return mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets); + uint32_t vstr; + uint32_t astr; + uint32_t sstr; + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr); + return sstr; } -uint32_t RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets) const { - int total_elem_size = 0; +void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets, uint32_t &r_vertex_element_size, uint32_t &r_attrib_element_size, uint32_t &r_skin_element_size) const { + r_vertex_element_size = 0; + r_attrib_element_size = 0; + r_skin_element_size = 0; + + uint32_t *size_accum; for (int i = 0; i < RS::ARRAY_MAX; i++) { r_offsets[i] = 0; //reset + if (i == RS::ARRAY_VERTEX) { + size_accum = &r_vertex_element_size; + } else if (i == RS::ARRAY_COLOR) { + size_accum = &r_attrib_element_size; + } else if (i == RS::ARRAY_BONES) { + size_accum = &r_skin_element_size; + } + if (!(p_format & (1 << i))) { // no array continue; } @@ -693,53 +750,64 @@ uint32_t RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_forma } break; case RS::ARRAY_NORMAL: { - if (p_format & ARRAY_COMPRESS_NORMAL) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 3; - } - + elem_size = 4; } break; case RS::ARRAY_TANGENT: { - if (p_format & ARRAY_COMPRESS_TANGENT) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 4; - } - + elem_size = 4; } break; case RS::ARRAY_COLOR: { - if (p_format & ARRAY_COMPRESS_COLOR) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 4; - } + elem_size = 8; } break; case RS::ARRAY_TEX_UV: { - if (p_format & ARRAY_COMPRESS_TEX_UV) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 2; - } + elem_size = 8; } break; case RS::ARRAY_TEX_UV2: { - if (p_format & ARRAY_COMPRESS_TEX_UV2) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 2; - } + elem_size = 8; } break; + case RS::ARRAY_CUSTOM0: + case RS::ARRAY_CUSTOM1: + case RS::ARRAY_CUSTOM2: + case RS::ARRAY_CUSTOM3: { + uint32_t format = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + (ARRAY_FORMAT_CUSTOM_BITS * (i - ARRAY_CUSTOM0)))) & ARRAY_FORMAT_CUSTOM_MASK; + switch (format) { + case ARRAY_CUSTOM_RGBA8_UNORM: { + elem_size = 4; + } break; + case ARRAY_CUSTOM_RGBA8_SNORM: { + elem_size = 4; + } break; + case ARRAY_CUSTOM_RG_HALF: { + elem_size = 4; + } break; + case ARRAY_CUSTOM_RGBA_HALF: { + elem_size = 8; + } break; + case ARRAY_CUSTOM_R_FLOAT: { + elem_size = 4; + } break; + case ARRAY_CUSTOM_RG_FLOAT: { + elem_size = 8; + } break; + case ARRAY_CUSTOM_RGB_FLOAT: { + elem_size = 12; + } break; + case ARRAY_CUSTOM_RGBA_FLOAT: { + elem_size = 16; + } break; + } + } break; case RS::ARRAY_WEIGHTS: { - elem_size = sizeof(uint16_t) * 4; + uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4; + elem_size = sizeof(uint16_t) * bone_count; } break; case RS::ARRAY_BONES: { - elem_size = sizeof(uint16_t) * 4; - + uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4; + elem_size = sizeof(uint16_t) * bone_count; } break; case RS::ARRAY_INDEX: { if (p_index_len <= 0) { @@ -757,14 +825,13 @@ uint32_t RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_forma continue; } default: { - ERR_FAIL_V(0); + ERR_FAIL(); } } - r_offsets[i] = total_elem_size; - total_elem_size += elem_size; + r_offsets[i] = (*size_accum); + (*size_accum) += elem_size; } - return total_elem_size; } Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint32_t p_compress_format) { @@ -785,21 +852,35 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa format |= (1 << i); if (i == RS::ARRAY_VERTEX) { - Variant var = p_arrays[i]; - switch (var.get_type()) { + switch (p_arrays[i].get_type()) { case Variant::PACKED_VECTOR2_ARRAY: { - Vector<Vector2> v2 = var; + Vector<Vector2> v2 = p_arrays[i]; + array_len = v2.size(); } break; case Variant::PACKED_VECTOR3_ARRAY: { - Vector<Vector3> v3 = var; + Vector<Vector3> v3 = p_arrays[i]; + array_len = v3.size(); } break; default: { - Array v = var; + ERR_FAIL_V(ERR_INVALID_DATA); } break; } - - array_len = PackedVector3Array(p_arrays[i]).size(); ERR_FAIL_COND_V(array_len == 0, ERR_INVALID_DATA); + } else if (i == RS::ARRAY_BONES) { + switch (p_arrays[i].get_type()) { + case Variant::PACKED_INT32_ARRAY: { + Vector<Vector3> vertexes = p_arrays[RS::ARRAY_VERTEX]; + Vector<int32_t> bones = p_arrays[i]; + int32_t bone_8_group_count = bones.size() / (ARRAY_WEIGHTS_SIZE * 2); + int32_t vertex_count = vertexes.size(); + if (vertex_count == bone_8_group_count) { + format |= RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS; + } + } break; + default: { + ERR_FAIL_V(ERR_INVALID_DATA); + } break; + } } else if (i == RS::ARRAY_INDEX) { index_array_len = PackedInt32Array(p_arrays[i]).size(); } @@ -824,117 +905,28 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa uint32_t offsets[RS::ARRAY_MAX]; - int total_elem_size = 0; - - for (int i = 0; i < RS::ARRAY_MAX; i++) { - offsets[i] = 0; //reset - - if (!(format & (1 << i))) { // no array - continue; - } - - int elem_size = 0; - - switch (i) { - case RS::ARRAY_VERTEX: { - Variant arr = p_arrays[0]; - if (arr.get_type() == Variant::PACKED_VECTOR2_ARRAY) { - elem_size = 2; - p_compress_format |= ARRAY_FLAG_USE_2D_VERTICES; - } else if (arr.get_type() == Variant::PACKED_VECTOR3_ARRAY) { - p_compress_format &= ~ARRAY_FLAG_USE_2D_VERTICES; - elem_size = 3; - } else { - elem_size = (p_compress_format & ARRAY_FLAG_USE_2D_VERTICES) ? 2 : 3; - } - - { - elem_size *= sizeof(float); - } - - } break; - case RS::ARRAY_NORMAL: { - if (p_compress_format & ARRAY_COMPRESS_NORMAL) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 3; - } - - } break; - - case RS::ARRAY_TANGENT: { - if (p_compress_format & ARRAY_COMPRESS_TANGENT) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 4; - } + uint32_t vertex_element_size; + uint32_t attrib_element_size; + uint32_t skin_element_size; - } break; - case RS::ARRAY_COLOR: { - if (p_compress_format & ARRAY_COMPRESS_COLOR) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 4; - } - } break; - case RS::ARRAY_TEX_UV: { - if (p_compress_format & ARRAY_COMPRESS_TEX_UV) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 2; - } - - } break; - - case RS::ARRAY_TEX_UV2: { - if (p_compress_format & ARRAY_COMPRESS_TEX_UV2) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 2; - } - - } break; - case RS::ARRAY_WEIGHTS: { - elem_size = sizeof(uint16_t) * 4; - - } break; - case RS::ARRAY_BONES: { - elem_size = sizeof(uint16_t) * 4; - - } break; - case RS::ARRAY_INDEX: { - if (index_array_len <= 0) { - ERR_PRINT("index_array_len==NO_INDEX_ARRAY"); - break; - } - /* determine whether using 16 or 32 bits indices */ - if (array_len >= (1 << 16)) { - elem_size = 4; - - } else { - elem_size = 2; - } - offsets[i] = elem_size; - continue; - } - default: { - ERR_FAIL_V(ERR_BUG); - } - } - - offsets[i] = total_elem_size; - total_elem_size += elem_size; - } + mesh_surface_make_offsets_from_format(format, array_len, index_array_len, offsets, vertex_element_size, attrib_element_size, skin_element_size); uint32_t mask = (1 << ARRAY_MAX) - 1; format |= (~mask) & p_compress_format; //make the full format - int array_size = total_elem_size * array_len; + int vertex_array_size = vertex_element_size * array_len; + int attrib_array_size = attrib_element_size * array_len; + int skin_array_size = skin_element_size * array_len; + int index_array_size = offsets[RS::ARRAY_INDEX] * index_array_len; Vector<uint8_t> vertex_array; - vertex_array.resize(array_size); + vertex_array.resize(vertex_array_size); - int index_array_size = offsets[RS::ARRAY_INDEX] * index_array_len; + Vector<uint8_t> attrib_array; + attrib_array.resize(attrib_array_size); + + Vector<uint8_t> skin_array; + skin_array.resize(skin_array_size); Vector<uint8_t> index_array; index_array.resize(index_array_size); @@ -942,22 +934,29 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa AABB aabb; Vector<AABB> bone_aabb; - Error err = _surface_set_data(p_arrays, format, offsets, total_elem_size, vertex_array, array_len, index_array, index_array_len, aabb, bone_aabb); + Error err = _surface_set_data(p_arrays, format, offsets, vertex_element_size, attrib_element_size, skin_element_size, vertex_array, attrib_array, skin_array, array_len, index_array, index_array_len, aabb, bone_aabb); ERR_FAIL_COND_V_MSG(err != OK, ERR_INVALID_DATA, "Invalid array format for surface."); - Vector<Vector<uint8_t>> blend_shape_data; - - for (int i = 0; i < p_blend_shapes.size(); i++) { - Vector<uint8_t> vertex_array_shape; - vertex_array_shape.resize(array_size); - Vector<uint8_t> noindex; - - AABB laabb; - Error err2 = _surface_set_data(p_blend_shapes[i], format & ~ARRAY_FORMAT_INDEX, offsets, total_elem_size, vertex_array_shape, array_len, noindex, 0, laabb, bone_aabb); - aabb.merge_with(laabb); - ERR_FAIL_COND_V_MSG(err2 != OK, ERR_INVALID_DATA, "Invalid blend shape array format for surface."); + Vector<uint8_t> blend_shape_data; + uint32_t blend_shape_count = 0; - blend_shape_data.push_back(vertex_array_shape); + if (p_blend_shapes.size()) { + uint32_t bs_format = format & RS::ARRAY_FORMAT_BLEND_SHAPE_MASK; + for (int i = 0; i < p_blend_shapes.size(); i++) { + Vector<uint8_t> vertex_array_shape; + vertex_array_shape.resize(vertex_array_size); + Vector<uint8_t> noindex; + Vector<uint8_t> noattrib; + Vector<uint8_t> noskin; + + AABB laabb; + Error err2 = _surface_set_data(p_blend_shapes[i], bs_format, offsets, vertex_element_size, 0, 0, vertex_array_shape, noattrib, noskin, array_len, noindex, 0, laabb, bone_aabb); + aabb.merge_with(laabb); + ERR_FAIL_COND_V_MSG(err2 != OK, ERR_INVALID_DATA, "Invalid blend shape array format for surface."); + + blend_shape_data.append_array(vertex_array_shape); + blend_shape_count++; + } } Vector<SurfaceData::LOD> lods; if (index_array_len) { @@ -1004,10 +1003,12 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa surface_data.primitive = p_primitive; surface_data.aabb = aabb; surface_data.vertex_data = vertex_array; + surface_data.attribute_data = attrib_array; + surface_data.skin_data = skin_array; surface_data.vertex_count = array_len; surface_data.index_data = index_array; surface_data.index_count = index_array_len; - surface_data.blend_shapes = blend_shape_data; + surface_data.blend_shape_data = blend_shape_data; surface_data.bone_aabbs = bone_aabb; surface_data.lods = lods; @@ -1023,110 +1024,20 @@ void RenderingServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_p mesh_add_surface(p_mesh, sd); } -Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const { - uint32_t offsets[ARRAY_MAX]; - - int total_elem_size = 0; - - for (int i = 0; i < RS::ARRAY_MAX; i++) { - offsets[i] = 0; //reset - - if (!(p_format & (1 << i))) { // no array - continue; - } - - int elem_size = 0; - - switch (i) { - case RS::ARRAY_VERTEX: { - if (p_format & ARRAY_FLAG_USE_2D_VERTICES) { - elem_size = 2; - } else { - elem_size = 3; - } - - { - elem_size *= sizeof(float); - } - - } break; - case RS::ARRAY_NORMAL: { - if (p_format & ARRAY_COMPRESS_NORMAL) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 3; - } - - } break; - - case RS::ARRAY_TANGENT: { - if (p_format & ARRAY_COMPRESS_TANGENT) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 4; - } - - } break; - case RS::ARRAY_COLOR: { - if (p_format & ARRAY_COMPRESS_COLOR) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 4; - } - } break; - case RS::ARRAY_TEX_UV: { - if (p_format & ARRAY_COMPRESS_TEX_UV) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 2; - } - - } break; - - case RS::ARRAY_TEX_UV2: { - if (p_format & ARRAY_COMPRESS_TEX_UV2) { - elem_size = sizeof(uint32_t); - } else { - elem_size = sizeof(float) * 2; - } - - } break; - case RS::ARRAY_WEIGHTS: { - elem_size = sizeof(uint16_t) * 4; - - } break; - case RS::ARRAY_BONES: { - elem_size = sizeof(uint16_t) * 4; - - } break; - case RS::ARRAY_INDEX: { - if (p_index_len <= 0) { - ERR_PRINT("index_array_len==NO_INDEX_ARRAY"); - break; - } - /* determine whether using 16 or 32 bits indices */ - if (p_vertex_len >= (1 << 16)) { - elem_size = 4; - - } else { - elem_size = 2; - } - offsets[i] = elem_size; - continue; - } - default: { - ERR_FAIL_V(Array()); - } - } +Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, Vector<uint8_t> p_attrib_data, Vector<uint8_t> p_skin_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const { + uint32_t offsets[RS::ARRAY_MAX]; - offsets[i] = total_elem_size; - total_elem_size += elem_size; - } + uint32_t vertex_elem_size; + uint32_t attrib_elem_size; + uint32_t skin_elem_size; + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets, vertex_elem_size, attrib_elem_size, skin_elem_size); Array ret; ret.resize(RS::ARRAY_MAX); const uint8_t *r = p_vertex_data.ptr(); + const uint8_t *ar = p_attrib_data.ptr(); + const uint8_t *sr = p_skin_data.ptr(); for (int i = 0; i < RS::ARRAY_MAX; i++) { if (!(p_format & (1 << i))) { @@ -1143,7 +1054,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t Vector2 *w = arr_2d.ptrw(); for (int j = 0; j < p_vertex_len; j++) { - const float *v = (const float *)&r[j * total_elem_size + offsets[i]]; + const float *v = (const float *)&r[j * vertex_elem_size + offsets[i]]; w[j] = Vector2(v[0], v[1]); } } @@ -1157,7 +1068,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t Vector3 *w = arr_3d.ptrw(); for (int j = 0; j < p_vertex_len; j++) { - const float *v = (const float *)&r[j * total_elem_size + offsets[i]]; + const float *v = (const float *)&r[j * vertex_elem_size + offsets[i]]; w[j] = Vector3(v[0], v[1], v[2]); } } @@ -1170,21 +1081,11 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t Vector<Vector3> arr; arr.resize(p_vertex_len); - if (p_format & ARRAY_COMPRESS_NORMAL) { - Vector3 *w = arr.ptrw(); - const float multiplier = 1.f / 127.f; - - for (int j = 0; j < p_vertex_len; j++) { - const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]]; - w[j] = Vector3(float(v[0]) * multiplier, float(v[1]) * multiplier, float(v[2]) * multiplier); - } - } else { - Vector3 *w = arr.ptrw(); + Vector3 *w = arr.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const float *v = (const float *)&r[j * total_elem_size + offsets[i]]; - w[j] = Vector3(v[0], v[1], v[2]); - } + for (int j = 0; j < p_vertex_len; j++) { + const uint32_t v = *(const uint32_t *)&r[j * vertex_elem_size + offsets[i]]; + w[j] = Vector3((v & 0x3FF) / 1023.0, ((v >> 10) & 0x3FF) / 1023.0, ((v >> 20) & 0x3FF) / 1023.0) * Vector3(2, 2, 2) - Vector3(1, 1, 1); } ret[i] = arr; @@ -1194,24 +1095,16 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t case RS::ARRAY_TANGENT: { Vector<float> arr; arr.resize(p_vertex_len * 4); - if (p_format & ARRAY_COMPRESS_TANGENT) { - float *w = arr.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]]; - for (int k = 0; k < 4; k++) { - w[j * 4 + k] = float(v[k] / 127.0); - } - } - } else { - float *w = arr.ptrw(); + float *w = arr.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const float *v = (const float *)&r[j * total_elem_size + offsets[i]]; - for (int k = 0; k < 4; k++) { - w[j * 4 + k] = v[k]; - } - } + for (int j = 0; j < p_vertex_len; j++) { + const uint32_t v = *(const uint32_t *)&r[j * vertex_elem_size + offsets[i]]; + + w[j * 4 + 0] = ((v & 0x3FF) / 1023.0) * 2.0 - 1.0; + w[j * 4 + 1] = (((v >> 10) & 0x3FF) / 1023.0) * 2.0 - 1.0; + w[j * 4 + 2] = (((v >> 20) & 0x3FF) / 1023.0) * 2.0 - 1.0; + w[j * 4 + 3] = ((v >> 30) / 3.0) * 2.0 - 1.0; } ret[i] = arr; @@ -1221,20 +1114,11 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t Vector<Color> arr; arr.resize(p_vertex_len); - if (p_format & ARRAY_COMPRESS_COLOR) { - Color *w = arr.ptrw(); - - for (int j = 0; j < p_vertex_len; j++) { - const uint8_t *v = (const uint8_t *)&r[j * total_elem_size + offsets[i]]; - w[j] = Color(float(v[0] / 255.0), float(v[1] / 255.0), float(v[2] / 255.0), float(v[3] / 255.0)); - } - } else { - Color *w = arr.ptrw(); + Color *w = arr.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const float *v = (const float *)&r[j * total_elem_size + offsets[i]]; - w[j] = Color(v[0], v[1], v[2], v[3]); - } + for (int32_t j = 0; j < p_vertex_len; j++) { + const uint16_t *v = (const uint16_t *)&ar[j * attrib_elem_size + offsets[i]]; + w[j] = Color(Math::half_to_float(v[0]), Math::half_to_float(v[1]), Math::half_to_float(v[2]), Math::half_to_float(v[3])); } ret[i] = arr; @@ -1243,20 +1127,11 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t Vector<Vector2> arr; arr.resize(p_vertex_len); - if (p_format & ARRAY_COMPRESS_TEX_UV) { - Vector2 *w = arr.ptrw(); - - for (int j = 0; j < p_vertex_len; j++) { - const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]]; - w[j] = Vector2(Math::halfptr_to_float(&v[0]), Math::halfptr_to_float(&v[1])); - } - } else { - Vector2 *w = arr.ptrw(); + Vector2 *w = arr.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const float *v = (const float *)&r[j * total_elem_size + offsets[i]]; - w[j] = Vector2(v[0], v[1]); - } + for (int j = 0; j < p_vertex_len; j++) { + const float *v = (const float *)&ar[j * attrib_elem_size + offsets[i]]; + w[j] = Vector2(v[0], v[1]); } ret[i] = arr; @@ -1266,35 +1141,74 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t Vector<Vector2> arr; arr.resize(p_vertex_len); - if (p_format & ARRAY_COMPRESS_TEX_UV2) { - Vector2 *w = arr.ptrw(); + Vector2 *w = arr.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]]; - w[j] = Vector2(Math::halfptr_to_float(&v[0]), Math::halfptr_to_float(&v[1])); - } - } else { - Vector2 *w = arr.ptrw(); - - for (int j = 0; j < p_vertex_len; j++) { - const float *v = (const float *)&r[j * total_elem_size + offsets[i]]; - w[j] = Vector2(v[0], v[1]); - } + for (int j = 0; j < p_vertex_len; j++) { + const float *v = (const float *)&ar[j * attrib_elem_size + offsets[i]]; + w[j] = Vector2(v[0], v[1]); } ret[i] = arr; } break; + case RS::ARRAY_CUSTOM0: + case RS::ARRAY_CUSTOM1: + case RS::ARRAY_CUSTOM2: + case RS::ARRAY_CUSTOM3: { + uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (RS::ARRAY_CUSTOM0 - i))) & ARRAY_FORMAT_CUSTOM_MASK; + switch (type) { + case ARRAY_CUSTOM_RGBA8_UNORM: + case ARRAY_CUSTOM_RGBA8_SNORM: + case ARRAY_CUSTOM_RG_HALF: + case ARRAY_CUSTOM_RGBA_HALF: { + //size 4 + int s = type == ARRAY_CUSTOM_RGBA_HALF ? 8 : 4; + Vector<uint8_t> arr; + arr.resize(p_vertex_len * s); + + uint8_t *w = arr.ptrw(); + + for (int j = 0; j < p_vertex_len; j++) { + const uint8_t *v = (const uint8_t *)&ar[j * attrib_elem_size + offsets[i]]; + copymem(&w[j * s], v, s); + } + + ret[i] = arr; + + } break; + case ARRAY_CUSTOM_R_FLOAT: + case ARRAY_CUSTOM_RG_FLOAT: + case ARRAY_CUSTOM_RGB_FLOAT: + case ARRAY_CUSTOM_RGBA_FLOAT: { + uint32_t s = type - ARRAY_CUSTOM_R_FLOAT + 1; + + Vector<float> arr; + float *w = arr.ptrw(); + + for (int j = 0; j < p_vertex_len; j++) { + const float *v = (const float *)&ar[j * attrib_elem_size + offsets[i]]; + copymem(&w[j * s], v, s * sizeof(float)); + } + ret[i] = arr; + + } break; + default: { + } + } + + } break; case RS::ARRAY_WEIGHTS: { + uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4; + Vector<float> arr; - arr.resize(p_vertex_len * 4); + arr.resize(p_vertex_len * bone_count); { float *w = arr.ptrw(); for (int j = 0; j < p_vertex_len; j++) { - const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]]; - for (int k = 0; k < 4; k++) { - w[j * 4 + k] = float(v[k] / 65535.0); + const uint16_t *v = (const uint16_t *)&sr[j * skin_elem_size + offsets[i]]; + for (uint32_t k = 0; k < bone_count; k++) { + w[j * bone_count + k] = float(v[k] / 65535.0); } } } @@ -1303,15 +1217,17 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t } break; case RS::ARRAY_BONES: { + uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4; + Vector<int> arr; - arr.resize(p_vertex_len * 4); + arr.resize(p_vertex_len * bone_count); int *w = arr.ptrw(); for (int j = 0; j < p_vertex_len; j++) { - const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]]; - for (int k = 0; k < 4; k++) { - w[j * 4 + k] = v[k]; + const uint16_t *v = (const uint16_t *)&sr[j * skin_elem_size + offsets[i]]; + for (uint32_t k = 0; k < bone_count; k++) { + w[j * bone_count + k] = v[k]; } } @@ -1394,20 +1310,30 @@ Array RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_sur SurfaceData sd = mesh_get_surface(p_mesh, p_surface); ERR_FAIL_COND_V(sd.vertex_count == 0, Array()); - Vector<Vector<uint8_t>> blend_shape_data = sd.blend_shapes; + Vector<uint8_t> blend_shape_data = sd.blend_shape_data; if (blend_shape_data.size() > 0) { - int vertex_len = sd.vertex_count; + uint32_t bs_offsets[RS::ARRAY_MAX]; + uint32_t bs_format = (sd.format & RS::ARRAY_FORMAT_BLEND_SHAPE_MASK); + uint32_t vertex_elem_size; + uint32_t attrib_elem_size; + uint32_t skin_elem_size; - Vector<uint8_t> index_data = sd.index_data; - int index_len = sd.index_count; + mesh_surface_make_offsets_from_format(bs_format, sd.vertex_count, 0, bs_offsets, vertex_elem_size, attrib_elem_size, skin_elem_size); - uint32_t format = sd.format; + int divisor = vertex_elem_size * sd.vertex_count; + ERR_FAIL_COND_V((blend_shape_data.size() % divisor) != 0, Array()); + + uint32_t blend_shape_count = blend_shape_data.size() / divisor; + + ERR_FAIL_COND_V(blend_shape_count != (uint32_t)mesh_get_blend_shape_count(p_mesh), Array()); Array blend_shape_array; - blend_shape_array.resize(blend_shape_data.size()); - for (int i = 0; i < blend_shape_data.size(); i++) { - blend_shape_array.set(i, _get_array_from_surface(format, blend_shape_data[i], vertex_len, index_data, index_len)); + blend_shape_array.resize(mesh_get_blend_shape_count(p_mesh)); + for (uint32_t i = 0; i < blend_shape_count; i++) { + Vector<uint8_t> bs_data = blend_shape_data.subarray(i * divisor, (i + 1) * divisor - 1); + Vector<uint8_t> unused; + blend_shape_array.set(i, _get_array_from_surface(bs_format, bs_data, unused, unused, sd.vertex_count, unused, 0)); } return blend_shape_array; @@ -1418,6 +1344,8 @@ Array RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_sur Array RenderingServer::mesh_create_arrays_from_surface_data(const SurfaceData &p_data) const { Vector<uint8_t> vertex_data = p_data.vertex_data; + Vector<uint8_t> attrib_data = p_data.attribute_data; + Vector<uint8_t> skin_data = p_data.skin_data; ERR_FAIL_COND_V(vertex_data.size() == 0, Array()); int vertex_len = p_data.vertex_count; @@ -1427,11 +1355,10 @@ Array RenderingServer::mesh_create_arrays_from_surface_data(const SurfaceData &p uint32_t format = p_data.format; - return _get_array_from_surface(format, vertex_data, vertex_len, index_data, index_len); + return _get_array_from_surface(format, vertex_data, attrib_data, skin_data, vertex_len, index_data, index_len); } #if 0 Array RenderingServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_surface) const { - Vector<AABB> vec = RS::get_singleton()->mesh_surface_get_skeleton_aabb(p_mesh, p_surface); Array arr; for (int i = 0; i < vec.size(); i++) { @@ -1541,9 +1468,11 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("material_set_next_pass", "material", "next_material"), &RenderingServer::material_set_next_pass); ClassDB::bind_method(D_METHOD("mesh_create"), &RenderingServer::mesh_create); - ClassDB::bind_method(D_METHOD("mesh_surface_get_format_offset", "format", "vertex_len", "index_len", "array_index"), &RenderingServer::mesh_surface_get_format_offset); - ClassDB::bind_method(D_METHOD("mesh_surface_get_format_stride", "format", "vertex_len", "index_len"), &RenderingServer::mesh_surface_get_format_stride); - ClassDB::bind_method(D_METHOD("mesh_add_surface_from_arrays", "mesh", "primitive", "arrays", "blend_shapes", "lods", "compress_format"), &RenderingServer::mesh_add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(ARRAY_COMPRESS_DEFAULT)); + ClassDB::bind_method(D_METHOD("mesh_surface_get_format_offset", "format", "vertex_count", "array_index"), &RenderingServer::mesh_surface_get_format_offset); + ClassDB::bind_method(D_METHOD("mesh_surface_get_format_vertex_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_vertex_stride); + ClassDB::bind_method(D_METHOD("mesh_surface_get_format_attribute_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_attribute_stride); + ClassDB::bind_method(D_METHOD("mesh_surface_get_format_skin_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_skin_stride); + //ClassDB::bind_method(D_METHOD("mesh_add_surface_from_arrays", "mesh", "primitive", "arrays", "blend_shapes", "lods", "compress_format"), &RenderingServer::mesh_add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(ARRAY_COMPRESS_DEFAULT)); ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_count", "mesh"), &RenderingServer::mesh_get_blend_shape_count); ClassDB::bind_method(D_METHOD("mesh_set_blend_shape_mode", "mesh", "mode"), &RenderingServer::mesh_set_blend_shape_mode); ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_mode", "mesh"), &RenderingServer::mesh_get_blend_shape_mode); @@ -1618,6 +1547,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("light_directional_set_shadow_mode", "light", "mode"), &RenderingServer::light_directional_set_shadow_mode); ClassDB::bind_method(D_METHOD("light_directional_set_blend_splits", "light", "enable"), &RenderingServer::light_directional_set_blend_splits); + ClassDB::bind_method(D_METHOD("light_directional_set_sky_only", "light", "enable"), &RenderingServer::light_directional_set_sky_only); ClassDB::bind_method(D_METHOD("light_directional_set_shadow_depth_range_mode", "light", "range_mode"), &RenderingServer::light_directional_set_shadow_depth_range_mode); ClassDB::bind_method(D_METHOD("reflection_probe_create"), &RenderingServer::reflection_probe_create); @@ -1731,7 +1661,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_set_transparent_background", "viewport", "enabled"), &RenderingServer::viewport_set_transparent_background); ClassDB::bind_method(D_METHOD("viewport_set_global_canvas_transform", "viewport", "transform"), &RenderingServer::viewport_set_global_canvas_transform); ClassDB::bind_method(D_METHOD("viewport_set_canvas_stacking", "viewport", "canvas", "layer", "sublayer"), &RenderingServer::viewport_set_canvas_stacking); - ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_size", "viewport", "size"), &RenderingServer::viewport_set_shadow_atlas_size); + ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_size", "viewport", "size", "use_16_bits"), &RenderingServer::viewport_set_shadow_atlas_size, DEFVAL(false)); ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_quadrant_subdivision", "viewport", "quadrant", "subdivision"), &RenderingServer::viewport_set_shadow_atlas_quadrant_subdivision); ClassDB::bind_method(D_METHOD("viewport_set_msaa", "viewport", "msaa"), &RenderingServer::viewport_set_msaa); ClassDB::bind_method(D_METHOD("viewport_set_use_debanding", "viewport", "enable"), &RenderingServer::viewport_set_use_debanding); @@ -1739,6 +1669,10 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_get_render_info", "viewport", "info"), &RenderingServer::viewport_get_render_info); ClassDB::bind_method(D_METHOD("viewport_set_debug_draw", "viewport", "draw"), &RenderingServer::viewport_set_debug_draw); + ClassDB::bind_method(D_METHOD("viewport_set_measure_render_time", "viewport", "enable"), &RenderingServer::viewport_set_measure_render_time); + ClassDB::bind_method(D_METHOD("viewport_get_measured_render_time_cpu", "viewport"), &RenderingServer::viewport_get_measured_render_time_cpu); + ClassDB::bind_method(D_METHOD("viewport_get_measured_render_time_gpu", "viewport"), &RenderingServer::viewport_get_measured_render_time_gpu); + ClassDB::bind_method(D_METHOD("environment_create"), &RenderingServer::environment_create); ClassDB::bind_method(D_METHOD("environment_set_background", "env", "bg"), &RenderingServer::environment_set_background); ClassDB::bind_method(D_METHOD("environment_set_sky", "env", "sky"), &RenderingServer::environment_set_sky); @@ -1750,9 +1684,9 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("environment_set_ambient_light", "env", "color", "ambient", "energy", "sky_contibution", "reflection_source", "ao_color"), &RenderingServer::environment_set_ambient_light, DEFVAL(RS::ENV_AMBIENT_SOURCE_BG), DEFVAL(1.0), DEFVAL(0.0), DEFVAL(RS::ENV_REFLECTION_SOURCE_BG), DEFVAL(Color())); ClassDB::bind_method(D_METHOD("environment_set_glow", "env", "enable", "levels", "intensity", "strength", "mix", "bloom_threshold", "blend_mode", "hdr_bleed_threshold", "hdr_bleed_scale", "hdr_luminance_cap"), &RenderingServer::environment_set_glow); ClassDB::bind_method(D_METHOD("environment_set_tonemap", "env", "tone_mapper", "exposure", "white", "auto_exposure", "min_luminance", "max_luminance", "auto_exp_speed", "auto_exp_grey"), &RenderingServer::environment_set_tonemap); - ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "ramp"), &RenderingServer::environment_set_adjustment); + ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "use_1d_color_correction", "color_correction"), &RenderingServer::environment_set_adjustment); ClassDB::bind_method(D_METHOD("environment_set_ssr", "env", "enable", "max_steps", "fade_in", "fade_out", "depth_tolerance"), &RenderingServer::environment_set_ssr); - ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "bias", "light_affect", "ao_channel_affect", "blur", "bilateral_sharpness"), &RenderingServer::environment_set_ssao); + ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "power", "detail", "horizon", "sharpness", "light_affect", "ao_channel_affect"), &RenderingServer::environment_set_ssao); ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "light_color", "light_energy", "sun_scatter", "density", "height", "height_density", "aerial_perspective"), &RenderingServer::environment_set_fog); ClassDB::bind_method(D_METHOD("scenario_create"), &RenderingServer::scenario_create); @@ -1833,7 +1767,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_light_create"), &RenderingServer::canvas_light_create); ClassDB::bind_method(D_METHOD("canvas_light_attach_to_canvas", "light", "canvas"), &RenderingServer::canvas_light_attach_to_canvas); ClassDB::bind_method(D_METHOD("canvas_light_set_enabled", "light", "enabled"), &RenderingServer::canvas_light_set_enabled); - ClassDB::bind_method(D_METHOD("canvas_light_set_scale", "light", "scale"), &RenderingServer::canvas_light_set_scale); + ClassDB::bind_method(D_METHOD("canvas_light_set_texture_scale", "light", "scale"), &RenderingServer::canvas_light_set_texture_scale); ClassDB::bind_method(D_METHOD("canvas_light_set_transform", "light", "transform"), &RenderingServer::canvas_light_set_transform); ClassDB::bind_method(D_METHOD("canvas_light_set_texture", "light", "texture"), &RenderingServer::canvas_light_set_texture); ClassDB::bind_method(D_METHOD("canvas_light_set_texture_offset", "light", "offset"), &RenderingServer::canvas_light_set_texture_offset); @@ -1859,7 +1793,6 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_create"), &RenderingServer::canvas_occluder_polygon_create); ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_shape", "occluder_polygon", "shape", "closed"), &RenderingServer::canvas_occluder_polygon_set_shape); - ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_shape_as_lines", "occluder_polygon", "shape"), &RenderingServer::canvas_occluder_polygon_set_shape_as_lines); ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_cull_mode", "occluder_polygon", "mode"), &RenderingServer::canvas_occluder_polygon_set_cull_mode); ClassDB::bind_method(D_METHOD("global_variable_add", "name", "type", "default_value"), &RenderingServer::global_variable_add); @@ -1898,6 +1831,9 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("is_render_loop_enabled"), &RenderingServer::is_render_loop_enabled); ClassDB::bind_method(D_METHOD("set_render_loop_enabled", "enabled"), &RenderingServer::set_render_loop_enabled); + + ClassDB::bind_method(D_METHOD("get_frame_setup_time_cpu"), &RenderingServer::get_frame_setup_time_cpu); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_loop_enabled"), "set_render_loop_enabled", "is_render_loop_enabled"); BIND_CONSTANT(NO_INDEX_ARRAY); @@ -1933,6 +1869,10 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(ARRAY_COLOR); BIND_ENUM_CONSTANT(ARRAY_TEX_UV); BIND_ENUM_CONSTANT(ARRAY_TEX_UV2); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM0); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM1); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM2); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM3); BIND_ENUM_CONSTANT(ARRAY_BONES); BIND_ENUM_CONSTANT(ARRAY_WEIGHTS); BIND_ENUM_CONSTANT(ARRAY_INDEX); @@ -1944,20 +1884,28 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(ARRAY_FORMAT_COLOR); BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV); BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV2); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM0); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM1); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM2); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM3); BIND_ENUM_CONSTANT(ARRAY_FORMAT_BONES); BIND_ENUM_CONSTANT(ARRAY_FORMAT_WEIGHTS); BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_NORMAL); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TANGENT); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_COLOR); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV2); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_INDEX); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_DEFAULT); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_BLEND_SHAPE_MASK); + + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_BASE); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM0_SHIFT); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM1_SHIFT); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM2_SHIFT); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM3_SHIFT); + + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_MASK); + BIND_ENUM_CONSTANT(ARRAY_COMPRESS_FLAGS_BASE); BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES); BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_DYNAMIC_UPDATE); + BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_8_BONE_WEIGHTS); BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); BIND_ENUM_CONSTANT(PRIMITIVE_LINES); @@ -2111,11 +2059,7 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(ENV_SSR_ROUGNESS_QUALITY_MEDIUM); BIND_ENUM_CONSTANT(ENV_SSR_ROUGNESS_QUALITY_HIGH); - BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_DISABLED); - BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_1x1); - BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_2x2); - BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_3x3); - + BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_VERY_LOW); BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_LOW); BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_MEDIUM); BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_HIGH); @@ -2190,10 +2134,16 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_REPEAT_MIRROR); BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_REPEAT_MAX); - BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_ADD); - BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_SUB); - BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_MIX); - BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_MASK); + BIND_ENUM_CONSTANT(CANVAS_GROUP_MODE_DISABLED); + BIND_ENUM_CONSTANT(CANVAS_GROUP_MODE_OPAQUE); + BIND_ENUM_CONSTANT(CANVAS_GROUP_MODE_TRANSPARENT); + + BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_POINT); + BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_DIRECTIONAL); + + BIND_ENUM_CONSTANT(CANVAS_LIGHT_BLEND_MODE_ADD); + BIND_ENUM_CONSTANT(CANVAS_LIGHT_BLEND_MODE_SUB); + BIND_ENUM_CONSTANT(CANVAS_LIGHT_BLEND_MODE_MIX); BIND_ENUM_CONSTANT(CANVAS_LIGHT_FILTER_NONE); BIND_ENUM_CONSTANT(CANVAS_LIGHT_FILTER_PCF5); @@ -2252,15 +2202,6 @@ void RenderingServer::_bind_methods() { ADD_SIGNAL(MethodInfo("frame_post_draw")); } -void RenderingServer::_canvas_item_add_style_box(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector<float> &p_margins, const Color &p_modulate) { - ERR_FAIL_COND(p_margins.size() != 4); - //canvas_item_add_style_box(p_item,p_rect,p_source,p_texture,Vector2(p_margins[0],p_margins[1]),Vector2(p_margins[2],p_margins[3]),true,p_modulate); -} - -void RenderingServer::_camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) { - camera_set_orthogonal(p_camera, p_size, p_z_near, p_z_far); -} - void RenderingServer::mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry3D::MeshData &p_mesh_data) { Vector<Vector3> vertices; Vector<Vector3> normals; @@ -2312,6 +2253,8 @@ void RenderingServer::set_render_loop_enabled(bool p_enabled) { RenderingServer::RenderingServer() { //ERR_FAIL_COND(singleton); + + thread_pool = memnew(RendererThreadPool); singleton = this; GLOBAL_DEF_RST("rendering/vram_compression/import_bptc", false); @@ -2329,6 +2272,7 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/quality/directional_shadow/soft_shadow_quality", 2); GLOBAL_DEF("rendering/quality/directional_shadow/soft_shadow_quality.mobile", 0); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/directional_shadow/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/quality/directional_shadow/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)")); + GLOBAL_DEF("rendering/quality/directional_shadow/16_bits", true); GLOBAL_DEF("rendering/quality/shadows/soft_shadow_quality", 2); GLOBAL_DEF("rendering/quality/shadows/soft_shadow_quality.mobile", 0); @@ -2336,17 +2280,8 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/quality/2d_shadow_atlas/size", 2048); - GLOBAL_DEF("rendering/quality/shadow_atlas/size", 4096); - GLOBAL_DEF("rendering/quality/shadow_atlas/size.mobile", 2048); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/size", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/size", PROPERTY_HINT_RANGE, "256,16384")); - GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_0_subdiv", 1); - GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_1_subdiv", 2); - GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_2_subdiv", 3); - GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_3_subdiv", 4); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_0_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_0_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_1_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_1_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_2_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_2_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_3_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_3_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + GLOBAL_DEF("rendering/quality/rd_renderer/use_low_end_renderer", false); + GLOBAL_DEF("rendering/quality/rd_renderer/use_low_end_renderer.mobile", true); GLOBAL_DEF("rendering/quality/reflections/roughness_layers", 8); GLOBAL_DEF("rendering/quality/reflections/texture_array_reflections", true); @@ -2358,6 +2293,8 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_size.mobile", 128); GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_count", 64); + GLOBAL_DEF("rendering/quality/gi/use_half_resolution", false); + GLOBAL_DEF("rendering/quality/gi_probes/anisotropic", false); GLOBAL_DEF("rendering/quality/gi_probes/quality", 1); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/gi_probes/quality", PropertyInfo(Variant::INT, "rendering/quality/gi_probes/quality", PROPERTY_HINT_ENUM, "Low (4 Cones - Fast),High (6 Cones - Slow)")); @@ -2382,9 +2319,18 @@ RenderingServer::RenderingServer() { ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/depth_of_field/depth_of_field_bokeh_quality", PropertyInfo(Variant::INT, "rendering/quality/depth_of_field/depth_of_field_bokeh_quality", PROPERTY_HINT_ENUM, "Very Low (Fastest),Low (Fast),Medium (Average),High (Slow)")); GLOBAL_DEF("rendering/quality/depth_of_field/depth_of_field_use_jitter", false); - GLOBAL_DEF("rendering/quality/ssao/quality", 1); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/ssao/quality", PropertyInfo(Variant::INT, "rendering/quality/ssao/quality", PROPERTY_HINT_ENUM, "Low (Fast),Medium (Average),High (Slow),Ultra (Slower)")); + GLOBAL_DEF("rendering/quality/ssao/quality", 2); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/ssao/quality", PropertyInfo(Variant::INT, "rendering/quality/ssao/quality", PROPERTY_HINT_ENUM, "Very Low (Fast),Low (Fast),Medium (Average),High (Slow),Ultra (Custom)")); GLOBAL_DEF("rendering/quality/ssao/half_size", false); + GLOBAL_DEF("rendering/quality/ssao/half_size.mobile", true); + GLOBAL_DEF("rendering/quality/ssao/adaptive_target", 0.5); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/ssao/adaptive_target", PropertyInfo(Variant::FLOAT, "rendering/quality/ssao/adaptive_target", PROPERTY_HINT_RANGE, "0.0,1.0,0.01")); + GLOBAL_DEF("rendering/quality/ssao/blur_passes", 2); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/ssao/blur_passes", PropertyInfo(Variant::INT, "rendering/quality/ssao/blur_passes", PROPERTY_HINT_RANGE, "0,6")); + GLOBAL_DEF("rendering/quality/ssao/fadeout_from", 50.0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/ssao/fadeout_from", PropertyInfo(Variant::FLOAT, "rendering/quality/ssao/fadeout_from", PROPERTY_HINT_RANGE, "0.0,512,0.1,or_greater")); + GLOBAL_DEF("rendering/quality/ssao/fadeout_to", 300.0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/ssao/fadeout_to", PropertyInfo(Variant::FLOAT, "rendering/quality/ssao/fadeout_to", PROPERTY_HINT_RANGE, "64,65536,0.1,or_greater")); GLOBAL_DEF("rendering/quality/screen_filters/screen_space_roughness_limiter_enabled", true); GLOBAL_DEF("rendering/quality/screen_filters/screen_space_roughness_limiter_amount", 0.25); @@ -2412,10 +2358,12 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/lightmapper/probe_capture_update_speed", 15); ProjectSettings::get_singleton()->set_custom_property_info("rendering/lightmapper/probe_capture_update_speed", PropertyInfo(Variant::FLOAT, "rendering/lightmapper/probe_capture_update_speed", PROPERTY_HINT_RANGE, "0.001,256,0.001")); - GLOBAL_DEF("rendering/sdfgi/probe_ray_count", 2); + GLOBAL_DEF("rendering/sdfgi/probe_ray_count", 1); ProjectSettings::get_singleton()->set_custom_property_info("rendering/sdfgi/probe_ray_count", PropertyInfo(Variant::INT, "rendering/sdfgi/probe_ray_count", PROPERTY_HINT_ENUM, "8 (Fastest),16,32,64,96,128 (Slowest)")); - GLOBAL_DEF("rendering/sdfgi/frames_to_converge", 1); + GLOBAL_DEF("rendering/sdfgi/frames_to_converge", 4); ProjectSettings::get_singleton()->set_custom_property_info("rendering/sdfgi/frames_to_converge", PropertyInfo(Variant::INT, "rendering/sdfgi/frames_to_converge", PROPERTY_HINT_ENUM, "5 (Less Latency but Lower Quality),10,15,20,25,30 (More Latency but Higher Quality)")); + GLOBAL_DEF("rendering/sdfgi/frames_to_update_lights", 2); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/sdfgi/frames_to_update_lights", PropertyInfo(Variant::INT, "rendering/sdfgi/frames_to_update_lights", PROPERTY_HINT_ENUM, "1 (Slower),2,4,8,16 (Faster)")); GLOBAL_DEF("rendering/volumetric_fog/volume_size", 64); ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/volume_size", PropertyInfo(Variant::INT, "rendering/volumetric_fog/volume_size", PROPERTY_HINT_RANGE, "16,512,1")); @@ -2427,8 +2375,19 @@ RenderingServer::RenderingServer() { ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/directional_shadow_shrink", PropertyInfo(Variant::INT, "rendering/volumetric_fog/directional_shadow_shrink", PROPERTY_HINT_RANGE, "32,2048,1")); GLOBAL_DEF("rendering/volumetric_fog/positional_shadow_shrink", 512); ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/positional_shadow_shrink", PropertyInfo(Variant::INT, "rendering/volumetric_fog/positional_shadow_shrink", PROPERTY_HINT_RANGE, "32,2048,1")); + + GLOBAL_DEF("rendering/spatial_indexer/update_iterations_per_frame", 10); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/spatial_indexer/update_iterations_per_frame", PropertyInfo(Variant::INT, "rendering/spatial_indexer/update_iterations_per_frame", PROPERTY_HINT_RANGE, "0,1024,1")); + GLOBAL_DEF("rendering/spatial_indexer/threaded_cull_minimum_instances", 1000); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/spatial_indexer/threaded_cull_minimum_instances", PropertyInfo(Variant::INT, "rendering/spatial_indexer/threaded_cull_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1")); + GLOBAL_DEF("rendering/forward_renderer/threaded_render_minimum_instances", 500); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/forward_renderer/threaded_render_minimum_instances", PropertyInfo(Variant::INT, "rendering/forward_renderer/threaded_render_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1")); + + GLOBAL_DEF("rendering/cluster_builder/max_clustered_elements", 512); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/cluster_builder/max_clustered_elements", PropertyInfo(Variant::FLOAT, "rendering/cluster_builder/max_clustered_elements", PROPERTY_HINT_RANGE, "32,8192,1")); } RenderingServer::~RenderingServer() { + memdelete(thread_pool); singleton = nullptr; } diff --git a/servers/rendering_server.h b/servers/rendering_server.h index a33215a882..fd8d8cd21d 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,14 +31,15 @@ #ifndef RENDERING_SERVER_H #define RENDERING_SERVER_H -#include "core/class_db.h" -#include "core/image.h" +#include "core/io/image.h" #include "core/math/geometry_3d.h" #include "core/math/transform_2d.h" -#include "core/rid.h" -#include "core/typed_array.h" -#include "core/variant.h" +#include "core/object/class_db.h" +#include "core/templates/rid.h" +#include "core/variant/typed_array.h" +#include "core/variant/variant.h" #include "servers/display_server.h" +#include "servers/rendering/renderer_thread_pool.h" #include "servers/rendering/rendering_device.h" #include "servers/rendering/shader_language.h" @@ -50,9 +51,9 @@ class RenderingServer : public Object { int mm_policy; bool render_loop_enabled = true; - void _camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far); - void _canvas_item_add_style_box(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector<float> &p_margins, const Color &p_modulate = Color(1, 1, 1)); - Array _get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const; + Array _get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, Vector<uint8_t> p_attrib_data, Vector<uint8_t> p_skin_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const; + + RendererThreadPool *thread_pool = nullptr; protected: RID _make_test_cube(); @@ -61,7 +62,7 @@ protected: RID white_texture; RID test_material; - Error _surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_stride, Vector<uint8_t> &r_vertex_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb); + Error _surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_vertex_stride, uint32_t p_attrib_stride, uint32_t p_skin_stride, Vector<uint8_t> &r_vertex_array, Vector<uint8_t> &r_attrib_array, Vector<uint8_t> &r_skin_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb); static RenderingServer *(*create_func)(); static void _bind_methods(); @@ -77,6 +78,7 @@ public: CANVAS_ITEM_Z_MAX = 4096, MAX_GLOW_LEVELS = 7, MAX_CURSORS = 8, + MAX_2D_DIRECTIONAL_LIGHTS = 8 }; /* TEXTURE API */ @@ -131,11 +133,11 @@ public: virtual void texture_set_detect_normal_callback(RID p_texture, TextureDetectCallback p_callback, void *p_userdata) = 0; enum TextureDetectRoughnessChannel { - TEXTURE_DETECT_ROUGNHESS_R, - TEXTURE_DETECT_ROUGNHESS_G, - TEXTURE_DETECT_ROUGNHESS_B, - TEXTURE_DETECT_ROUGNHESS_A, - TEXTURE_DETECT_ROUGNHESS_GRAY, + TEXTURE_DETECT_ROUGHNESS_R, + TEXTURE_DETECT_ROUGHNESS_G, + TEXTURE_DETECT_ROUGHNESS_B, + TEXTURE_DETECT_ROUGHNESS_A, + TEXTURE_DETECT_ROUGHNESS_GRAY, }; typedef void (*TextureDetectRoughnessCallback)(void *, const String &, TextureDetectRoughnessChannel); @@ -177,6 +179,19 @@ public: virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) = 0; virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const = 0; + struct ShaderNativeSourceCode { + struct Version { + struct Stage { + String name; + String code; + }; + Vector<Stage> stages; + }; + Vector<Version> versions; + }; + + virtual ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const = 0; + /* COMMON MATERIAL API */ enum { @@ -198,16 +213,36 @@ public: /* MESH API */ enum ArrayType { - ARRAY_VERTEX = 0, - ARRAY_NORMAL = 1, - ARRAY_TANGENT = 2, - ARRAY_COLOR = 3, - ARRAY_TEX_UV = 4, - ARRAY_TEX_UV2 = 5, - ARRAY_BONES = 6, - ARRAY_WEIGHTS = 7, - ARRAY_INDEX = 8, - ARRAY_MAX = 9 + ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit) + ARRAY_NORMAL = 1, // A2B10G10R10 + ARRAY_TANGENT = 2, // A2B10G10R10, A flips sign of binormal + ARRAY_COLOR = 3, // RGBA16F + ARRAY_TEX_UV = 4, // RG32F + ARRAY_TEX_UV2 = 5, // RG32F + ARRAY_CUSTOM0 = 6, // depends on ArrayCustomFormat + ARRAY_CUSTOM1 = 7, + ARRAY_CUSTOM2 = 8, + ARRAY_CUSTOM3 = 9, + ARRAY_BONES = 10, // RGBA16UI (x2 if 8 weights) + ARRAY_WEIGHTS = 11, // RGBA16UNORM (x2 if 8 weights) + ARRAY_INDEX = 12, // 16 or 32 bits depending on length > 0xFFFF + ARRAY_MAX = 13 + }; + + enum { + ARRAY_CUSTOM_COUNT = ARRAY_BONES - ARRAY_CUSTOM0 + }; + + enum ArrayCustomFormat { + ARRAY_CUSTOM_RGBA8_UNORM, + ARRAY_CUSTOM_RGBA8_SNORM, + ARRAY_CUSTOM_RG_HALF, + ARRAY_CUSTOM_RGBA_HALF, + ARRAY_CUSTOM_R_FLOAT, + ARRAY_CUSTOM_RG_FLOAT, + ARRAY_CUSTOM_RGB_FLOAT, + ARRAY_CUSTOM_RGBA_FLOAT, + ARRAY_CUSTOM_MAX }; enum ArrayFormat { @@ -218,21 +253,29 @@ public: ARRAY_FORMAT_COLOR = 1 << ARRAY_COLOR, ARRAY_FORMAT_TEX_UV = 1 << ARRAY_TEX_UV, ARRAY_FORMAT_TEX_UV2 = 1 << ARRAY_TEX_UV2, + ARRAY_FORMAT_CUSTOM0 = 1 << ARRAY_CUSTOM0, + ARRAY_FORMAT_CUSTOM1 = 1 << ARRAY_CUSTOM1, + ARRAY_FORMAT_CUSTOM2 = 1 << ARRAY_CUSTOM2, + ARRAY_FORMAT_CUSTOM3 = 1 << ARRAY_CUSTOM3, ARRAY_FORMAT_BONES = 1 << ARRAY_BONES, ARRAY_FORMAT_WEIGHTS = 1 << ARRAY_WEIGHTS, ARRAY_FORMAT_INDEX = 1 << ARRAY_INDEX, - ARRAY_COMPRESS_BASE = (ARRAY_INDEX + 1), - ARRAY_COMPRESS_NORMAL = 1 << (ARRAY_NORMAL + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_TANGENT = 1 << (ARRAY_TANGENT + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_COLOR = 1 << (ARRAY_COLOR + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_TEX_UV = 1 << (ARRAY_TEX_UV + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_TEX_UV2 = 1 << (ARRAY_TEX_UV2 + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_INDEX = 1 << (ARRAY_INDEX + ARRAY_COMPRESS_BASE), - ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2, + ARRAY_FORMAT_BLEND_SHAPE_MASK = (~(ARRAY_FORMAT_COLOR | ARRAY_FORMAT_TEX_UV | ARRAY_FORMAT_TEX_UV2 | ARRAY_FORMAT_BONES | ARRAY_FORMAT_WEIGHTS | ARRAY_FORMAT_CUSTOM0 | ARRAY_FORMAT_CUSTOM1 | ARRAY_FORMAT_CUSTOM2 | ARRAY_FORMAT_CUSTOM3 | ARRAY_FORMAT_INDEX)) & 0x7FFFFFFF, + + ARRAY_FORMAT_CUSTOM_BASE = (ARRAY_INDEX + 1), + ARRAY_FORMAT_CUSTOM_BITS = 3, + ARRAY_FORMAT_CUSTOM0_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + 0), + ARRAY_FORMAT_CUSTOM1_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS), + ARRAY_FORMAT_CUSTOM2_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * 2), + ARRAY_FORMAT_CUSTOM3_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * 3), - ARRAY_FLAG_USE_2D_VERTICES = ARRAY_COMPRESS_INDEX << 1, - ARRAY_FLAG_USE_DYNAMIC_UPDATE = ARRAY_COMPRESS_INDEX << 3, + ARRAY_FORMAT_CUSTOM_MASK = 0x7, + ARRAY_COMPRESS_FLAGS_BASE = (ARRAY_INDEX + 1 + 12), + + ARRAY_FLAG_USE_2D_VERTICES = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 0), + ARRAY_FLAG_USE_DYNAMIC_UPDATE = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 1), + ARRAY_FLAG_USE_8_BONE_WEIGHTS = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 2), }; enum PrimitiveType { @@ -248,7 +291,9 @@ public: PrimitiveType primitive = PRIMITIVE_MAX; uint32_t format = 0; - Vector<uint8_t> vertex_data; + Vector<uint8_t> vertex_data; // vertex, normal, tangent (change with skinning, blendshape) + Vector<uint8_t> attribute_data; // color,uv, uv2, custom0-3 + Vector<uint8_t> skin_data; // bone index, bone weight uint32_t vertex_count = 0; Vector<uint8_t> index_data; uint32_t index_count = 0; @@ -261,25 +306,30 @@ public: Vector<LOD> lods; Vector<AABB> bone_aabbs; - Vector<Vector<uint8_t>> blend_shapes; + Vector<uint8_t> blend_shape_data; RID material; }; - virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces) = 0; + virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces, int p_blend_shape_count = 0) = 0; virtual RID mesh_create() = 0; - virtual uint32_t mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_index_len, int p_array_index) const; - virtual uint32_t mesh_surface_get_format_stride(uint32_t p_format, int p_vertex_len, int p_index_len) const; + virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) = 0; + + virtual uint32_t mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_array_index) const; + virtual uint32_t mesh_surface_get_format_vertex_stride(uint32_t p_format, int p_vertex_len) const; + virtual uint32_t mesh_surface_get_format_attribute_stride(uint32_t p_format, int p_vertex_len) const; + virtual uint32_t mesh_surface_get_format_skin_stride(uint32_t p_format, int p_vertex_len) const; + /// Returns stride - virtual uint32_t mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets) const; - virtual Error mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT); + virtual void mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets, uint32_t &r_vertex_element_size, uint32_t &r_attrib_element_size, uint32_t &r_skin_element_size) const; + virtual Error mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = 0); Array mesh_create_arrays_from_surface_data(const SurfaceData &p_data) const; Array mesh_surface_get_arrays(RID p_mesh, int p_surface) const; Array mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const; Dictionary mesh_surface_get_lods(RID p_mesh, int p_surface) const; - virtual void mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT); + virtual void mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = 0); virtual void mesh_add_surface(RID p_mesh, const SurfaceData &p_surface) = 0; virtual int mesh_get_blend_shape_count(RID p_mesh) const = 0; @@ -304,6 +354,8 @@ public: virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0; virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0; + virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) = 0; + virtual void mesh_clear(RID p_mesh) = 0; /* MULTIMESH API */ @@ -435,6 +487,7 @@ public: virtual void light_directional_set_shadow_mode(RID p_light, LightDirectionalShadowMode p_mode) = 0; virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0; + virtual void light_directional_set_sky_only(RID p_light, bool p_sky_only) = 0; enum LightDirectionalShadowDepthRangeMode { LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE, @@ -472,6 +525,7 @@ public: virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) = 0; virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0; virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0; + virtual void reflection_probe_set_lod_threshold(RID p_probe, float p_pixels) = 0; /* DECAL API */ @@ -729,7 +783,24 @@ public: virtual void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform) = 0; virtual void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) = 0; - virtual void viewport_set_shadow_atlas_size(RID p_viewport, int p_size) = 0; + enum ViewportSDFOversize { + VIEWPORT_SDF_OVERSIZE_100_PERCENT, + VIEWPORT_SDF_OVERSIZE_120_PERCENT, + VIEWPORT_SDF_OVERSIZE_150_PERCENT, + VIEWPORT_SDF_OVERSIZE_200_PERCENT, + VIEWPORT_SDF_OVERSIZE_MAX + }; + + enum ViewportSDFScale { + VIEWPORT_SDF_SCALE_100_PERCENT, + VIEWPORT_SDF_SCALE_50_PERCENT, + VIEWPORT_SDF_SCALE_25_PERCENT, + VIEWPORT_SDF_SCALE_MAX + }; + + virtual void viewport_set_sdf_oversize_and_scale(RID p_viewport, ViewportSDFOversize p_oversize, ViewportSDFScale p_scale) = 0; + + virtual void viewport_set_shadow_atlas_size(RID p_viewport, int p_size, bool p_16_bits = false) = 0; virtual void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) = 0; enum ViewportMSAA { @@ -753,6 +824,8 @@ public: virtual void viewport_set_use_debanding(RID p_viewport, bool p_use_debanding) = 0; + virtual void viewport_set_lod_threshold(RID p_viewport, float p_pixels) = 0; + enum ViewportRenderInfo { VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME, VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME, @@ -784,7 +857,11 @@ public: VIEWPORT_DEBUG_DRAW_SDFGI, VIEWPORT_DEBUG_DRAW_SDFGI_PROBES, VIEWPORT_DEBUG_DRAW_GI_BUFFER, - + VIEWPORT_DEBUG_DRAW_DISABLE_LOD, + VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS, + VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS, + VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS, + VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES, }; virtual void viewport_set_debug_draw(RID p_viewport, ViewportDebugDraw p_draw) = 0; @@ -793,7 +870,7 @@ public: virtual float viewport_get_measured_render_time_cpu(RID p_viewport) const = 0; virtual float viewport_get_measured_render_time_gpu(RID p_viewport) const = 0; - virtual void directional_shadow_atlas_set_size(int p_size) = 0; + virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) = 0; /* SKY API */ @@ -871,7 +948,7 @@ public: }; virtual void environment_set_tonemap(RID p_env, EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_grey) = 0; - virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) = 0; + virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) = 0; virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance) = 0; @@ -884,23 +961,17 @@ public: virtual void environment_set_ssr_roughness_quality(EnvironmentSSRRoughnessQuality p_quality) = 0; - enum EnvironmentSSAOBlur { - ENV_SSAO_BLUR_DISABLED, - ENV_SSAO_BLUR_1x1, - ENV_SSAO_BLUR_2x2, - ENV_SSAO_BLUR_3x3, - }; - - virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) = 0; + virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) = 0; enum EnvironmentSSAOQuality { + ENV_SSAO_QUALITY_VERY_LOW, ENV_SSAO_QUALITY_LOW, ENV_SSAO_QUALITY_MEDIUM, ENV_SSAO_QUALITY_HIGH, ENV_SSAO_QUALITY_ULTRA, }; - virtual void environment_set_ssao_quality(EnvironmentSSAOQuality p_quality, bool p_half_size) = 0; + virtual void environment_set_ssao_quality(EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; enum EnvironmentSDFGICascades { ENV_SDFGI_CASCADES_4, @@ -917,6 +988,7 @@ public: virtual void environment_set_sdfgi(RID p_env, bool p_enable, EnvironmentSDFGICascades p_cascades, float p_min_cell_size, EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0; enum EnvironmentSDFGIRayCount { + ENV_SDFGI_RAY_COUNT_4, ENV_SDFGI_RAY_COUNT_8, ENV_SDFGI_RAY_COUNT_16, ENV_SDFGI_RAY_COUNT_32, @@ -940,6 +1012,17 @@ public: virtual void environment_set_sdfgi_frames_to_converge(EnvironmentSDFGIFramesToConverge p_frames) = 0; + enum EnvironmentSDFGIFramesToUpdateLight { + ENV_SDFGI_UPDATE_LIGHT_IN_1_FRAME, + ENV_SDFGI_UPDATE_LIGHT_IN_2_FRAMES, + ENV_SDFGI_UPDATE_LIGHT_IN_4_FRAMES, + ENV_SDFGI_UPDATE_LIGHT_IN_8_FRAMES, + ENV_SDFGI_UPDATE_LIGHT_IN_16_FRAMES, + ENV_SDFGI_UPDATE_LIGHT_MAX, + }; + + virtual void environment_set_sdfgi_frames_to_update_light(EnvironmentSDFGIFramesToUpdateLight p_update) = 0; + virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) = 0; enum EnvVolumetricFogShadowFilter { @@ -1090,6 +1173,7 @@ public: virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0; virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) = 0; virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice) = 0; + virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) = 0; virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &, const Variant &p_value) = 0; virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &) const = 0; @@ -1157,7 +1241,7 @@ public: }; virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0) = 0; - virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0) = 0; + virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0; virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0) = 0; virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0; virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0; @@ -1195,12 +1279,17 @@ public: virtual void canvas_item_set_canvas_group_mode(RID p_item, CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false) = 0; virtual RID canvas_light_create() = 0; + + enum CanvasLightMode { + CANVAS_LIGHT_MODE_POINT, + CANVAS_LIGHT_MODE_DIRECTIONAL, + }; + + virtual void canvas_light_set_mode(RID p_light, CanvasLightMode p_mode) = 0; + virtual void canvas_light_attach_to_canvas(RID p_light, RID p_canvas) = 0; virtual void canvas_light_set_enabled(RID p_light, bool p_enabled) = 0; - virtual void canvas_light_set_scale(RID p_light, float p_scale) = 0; virtual void canvas_light_set_transform(RID p_light, const Transform2D &p_transform) = 0; - virtual void canvas_light_set_texture(RID p_light, RID p_texture) = 0; - virtual void canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) = 0; virtual void canvas_light_set_color(RID p_light, const Color &p_color) = 0; virtual void canvas_light_set_height(RID p_light, float p_height) = 0; virtual void canvas_light_set_energy(RID p_light, float p_energy) = 0; @@ -1209,14 +1298,19 @@ public: virtual void canvas_light_set_item_cull_mask(RID p_light, int p_mask) = 0; virtual void canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask) = 0; - enum CanvasLightMode { - CANVAS_LIGHT_MODE_ADD, - CANVAS_LIGHT_MODE_SUB, - CANVAS_LIGHT_MODE_MIX, - CANVAS_LIGHT_MODE_MASK, + virtual void canvas_light_set_directional_distance(RID p_light, float p_distance) = 0; + + virtual void canvas_light_set_texture_scale(RID p_light, float p_scale) = 0; + virtual void canvas_light_set_texture(RID p_light, RID p_texture) = 0; + virtual void canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) = 0; + + enum CanvasLightBlendMode { + CANVAS_LIGHT_BLEND_MODE_ADD, + CANVAS_LIGHT_BLEND_MODE_SUB, + CANVAS_LIGHT_BLEND_MODE_MIX, }; - virtual void canvas_light_set_mode(RID p_light, CanvasLightMode p_mode) = 0; + virtual void canvas_light_set_blend_mode(RID p_light, CanvasLightBlendMode p_mode) = 0; enum CanvasLightShadowFilter { CANVAS_LIGHT_FILTER_NONE, @@ -1234,12 +1328,12 @@ public: virtual void canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) = 0; virtual void canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled) = 0; virtual void canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon) = 0; + virtual void canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable) = 0; virtual void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) = 0; virtual void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) = 0; virtual RID canvas_occluder_polygon_create() = 0; virtual void canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) = 0; - virtual void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon, const Vector<Vector2> &p_shape) = 0; enum CanvasOccluderPolygonCullMode { CANVAS_OCCLUDER_POLYGON_CULL_DISABLED, @@ -1348,6 +1442,10 @@ public: virtual Vector<FrameProfileArea> get_frame_profile() = 0; virtual uint64_t get_frame_profile_frame() = 0; + virtual float get_frame_setup_time_cpu() const = 0; + + virtual void gi_set_use_half_resolution(bool p_enable) = 0; + /* TESTING */ virtual RID get_test_cube() = 0; @@ -1380,6 +1478,8 @@ public: virtual bool is_low_end() const = 0; + virtual void set_print_gpu_profile(bool p_enable) = 0; + RenderingDevice *create_local_rendering_device() const; bool is_render_loop_enabled() const; @@ -1421,7 +1521,6 @@ VARIANT_ENUM_CAST(RenderingServer::EnvironmentReflectionSource); VARIANT_ENUM_CAST(RenderingServer::EnvironmentGlowBlendMode); VARIANT_ENUM_CAST(RenderingServer::EnvironmentToneMapper); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSRRoughnessQuality); -VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSAOBlur); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSAOQuality); VARIANT_ENUM_CAST(RenderingServer::SubSurfaceScatteringQuality); VARIANT_ENUM_CAST(RenderingServer::DOFBlurQuality); @@ -1434,7 +1533,9 @@ VARIANT_ENUM_CAST(RenderingServer::ShadowCastingSetting); VARIANT_ENUM_CAST(RenderingServer::NinePatchAxisMode); VARIANT_ENUM_CAST(RenderingServer::CanvasItemTextureFilter); VARIANT_ENUM_CAST(RenderingServer::CanvasItemTextureRepeat); +VARIANT_ENUM_CAST(RenderingServer::CanvasGroupMode); VARIANT_ENUM_CAST(RenderingServer::CanvasLightMode); +VARIANT_ENUM_CAST(RenderingServer::CanvasLightBlendMode); VARIANT_ENUM_CAST(RenderingServer::CanvasLightShadowFilter); VARIANT_ENUM_CAST(RenderingServer::CanvasOccluderPolygonCullMode); VARIANT_ENUM_CAST(RenderingServer::GlobalVariableType); diff --git a/servers/server_wrap_mt_common.h b/servers/server_wrap_mt_common.h index 4481b296c6..5e18dc1e6d 100644 --- a/servers/server_wrap_mt_common.h +++ b/servers/server_wrap_mt_common.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/text_server.cpp b/servers/text_server.cpp new file mode 100644 index 0000000000..da68ceb128 --- /dev/null +++ b/servers/text_server.cpp @@ -0,0 +1,1299 @@ +/*************************************************************************/ +/* text_server.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "servers/text_server.h" +#include "scene/main/canvas_item.h" + +TextServerManager *TextServerManager::singleton = nullptr; +TextServer *TextServerManager::server = nullptr; +TextServerManager::TextServerCreate TextServerManager::server_create_functions[TextServerManager::MAX_SERVERS]; +int TextServerManager::server_create_count = 0; + +void TextServerManager::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_interface_count"), &TextServerManager::_get_interface_count); + ClassDB::bind_method(D_METHOD("get_interface_name", "index"), &TextServerManager::_get_interface_name); + ClassDB::bind_method(D_METHOD("get_interface_features", "index"), &TextServerManager::_get_interface_features); + ClassDB::bind_method(D_METHOD("get_interface", "index"), &TextServerManager::_get_interface); + ClassDB::bind_method(D_METHOD("get_interfaces"), &TextServerManager::_get_interfaces); + ClassDB::bind_method(D_METHOD("find_interface", "name"), &TextServerManager::_find_interface); + + ClassDB::bind_method(D_METHOD("set_primary_interface", "index"), &TextServerManager::_set_primary_interface); + ClassDB::bind_method(D_METHOD("get_primary_interface"), &TextServerManager::_get_primary_interface); +} + +void TextServerManager::register_create_function(const String &p_name, uint32_t p_features, TextServerManager::CreateFunction p_function, void *p_user_data) { + ERR_FAIL_COND(server_create_count == MAX_SERVERS); + server_create_functions[server_create_count].name = p_name; + server_create_functions[server_create_count].create_function = p_function; + server_create_functions[server_create_count].user_data = p_user_data; + server_create_functions[server_create_count].features = p_features; + server_create_count++; +} + +int TextServerManager::get_interface_count() { + return server_create_count; +} + +String TextServerManager::get_interface_name(int p_index) { + ERR_FAIL_INDEX_V(p_index, server_create_count, String()); + return server_create_functions[p_index].name; +} + +uint32_t TextServerManager::get_interface_features(int p_index) { + ERR_FAIL_INDEX_V(p_index, server_create_count, 0); + return server_create_functions[p_index].features; +} + +TextServer *TextServerManager::initialize(int p_index, Error &r_error) { + ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr); + if (server_create_functions[p_index].instance == nullptr) { + server_create_functions[p_index].instance = server_create_functions[p_index].create_function(r_error, server_create_functions[p_index].user_data); + if (server_create_functions[p_index].instance != nullptr) { + server_create_functions[p_index].instance->load_support_data(""); // Try loading default data. + } + } + if (server_create_functions[p_index].instance != nullptr) { + server = server_create_functions[p_index].instance; + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TEXT_SERVER_CHANGED); + } + } + return server_create_functions[p_index].instance; +} + +TextServer *TextServerManager::get_primary_interface() { + return server; +} + +int TextServerManager::_get_interface_count() const { + return server_create_count; +} + +String TextServerManager::_get_interface_name(int p_index) const { + return get_interface_name(p_index); +} + +uint32_t TextServerManager::_get_interface_features(int p_index) const { + return get_interface_features(p_index); +} + +TextServer *TextServerManager::_get_interface(int p_index) const { + ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr); + if (server_create_functions[p_index].instance == nullptr) { + Error error; + server_create_functions[p_index].instance = server_create_functions[p_index].create_function(error, server_create_functions[p_index].user_data); + if (server_create_functions[p_index].instance != nullptr) { + server_create_functions[p_index].instance->load_support_data(""); // Try loading default data. + } + } + return server_create_functions[p_index].instance; +} + +TextServer *TextServerManager::_find_interface(const String &p_name) const { + for (int i = 0; i < server_create_count; i++) { + if (server_create_functions[i].name == p_name) { + return _get_interface(i); + } + } + return nullptr; +} + +Array TextServerManager::_get_interfaces() const { + Array ret; + + for (int i = 0; i < server_create_count; i++) { + Dictionary iface_info; + + iface_info["id"] = i; + iface_info["name"] = server_create_functions[i].name; + + ret.push_back(iface_info); + }; + + return ret; +}; + +bool TextServerManager::_set_primary_interface(int p_index) { + Error error; + TextServerManager::initialize(p_index, error); + return (error == OK); +} + +TextServer *TextServerManager::_get_primary_interface() const { + return server; +} + +TextServerManager::TextServerManager() { + singleton = this; +} + +TextServerManager::~TextServerManager() { + singleton = nullptr; + for (int i = 0; i < server_create_count; i++) { + if (server_create_functions[i].instance != nullptr) { + memdelete(server_create_functions[i].instance); + server_create_functions[i].instance = nullptr; + } + } +} + +/*************************************************************************/ + +bool TextServer::Glyph::operator==(const Glyph &p_a) const { + return (p_a.index == index) && (p_a.font_rid == font_rid) && (p_a.font_size == font_size) && (p_a.start == start); +} + +bool TextServer::Glyph::operator!=(const Glyph &p_a) const { + return (p_a.index != index) || (p_a.font_rid != font_rid) || (p_a.font_size != font_size) || (p_a.start != start); +} + +bool TextServer::Glyph::operator<(const Glyph &p_a) const { + if (p_a.start == start) { + if (p_a.count == count) { + if ((p_a.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { + return true; + } else { + return false; + } + } + return p_a.count > count; + } + return p_a.start < start; +} + +bool TextServer::Glyph::operator>(const Glyph &p_a) const { + if (p_a.start == start) { + if (p_a.count == count) { + if ((p_a.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { + return false; + } else { + return true; + } + } + return p_a.count < count; + } + return p_a.start > start; +} + +void TextServer::_bind_methods() { + ClassDB::bind_method(D_METHOD("has_feature", "feature"), &TextServer::has_feature); + ClassDB::bind_method(D_METHOD("get_name"), &TextServer::get_name); + ClassDB::bind_method(D_METHOD("load_support_data", "filename"), &TextServer::load_support_data); + + ClassDB::bind_method(D_METHOD("is_locale_right_to_left", "locale"), &TextServer::is_locale_right_to_left); + + ClassDB::bind_method(D_METHOD("name_to_tag", "name"), &TextServer::name_to_tag); + ClassDB::bind_method(D_METHOD("tag_to_name", "tag"), &TextServer::tag_to_name); + + ClassDB::bind_method(D_METHOD("has", "rid"), &TextServer::has); + ClassDB::bind_method(D_METHOD("free_rid", "rid"), &TextServer::free); // shouldn't conflict with Object::free() + + /* Font Interface */ + ClassDB::bind_method(D_METHOD("create_font_system", "name", "base_size"), &TextServer::create_font_system, DEFVAL(16)); + ClassDB::bind_method(D_METHOD("create_font_resource", "filename", "base_size"), &TextServer::create_font_resource, DEFVAL(16)); + ClassDB::bind_method(D_METHOD("create_font_memory", "data", "type", "base_size"), &TextServer::_create_font_memory, DEFVAL(16)); + + ClassDB::bind_method(D_METHOD("font_get_height", "font", "size"), &TextServer::font_get_height); + ClassDB::bind_method(D_METHOD("font_get_ascent", "font", "size"), &TextServer::font_get_ascent); + ClassDB::bind_method(D_METHOD("font_get_descent", "font", "size"), &TextServer::font_get_descent); + + ClassDB::bind_method(D_METHOD("font_get_underline_position", "font", "size"), &TextServer::font_get_underline_position); + ClassDB::bind_method(D_METHOD("font_get_underline_thickness", "font", "size"), &TextServer::font_get_underline_thickness); + + ClassDB::bind_method(D_METHOD("font_set_antialiased", "font", "antialiased"), &TextServer::font_set_antialiased); + ClassDB::bind_method(D_METHOD("font_get_antialiased", "font"), &TextServer::font_get_antialiased); + + ClassDB::bind_method(D_METHOD("font_get_feature_list", "font"), &TextServer::font_get_feature_list); + ClassDB::bind_method(D_METHOD("font_get_variation_list", "font"), &TextServer::font_get_variation_list); + + ClassDB::bind_method(D_METHOD("font_set_variation", "font", "tag", "value"), &TextServer::font_set_variation); + ClassDB::bind_method(D_METHOD("font_get_variation", "font", "tag"), &TextServer::font_get_variation); + + ClassDB::bind_method(D_METHOD("font_set_hinting", "font", "hinting"), &TextServer::font_set_hinting); + ClassDB::bind_method(D_METHOD("font_get_hinting", "font"), &TextServer::font_get_hinting); + + ClassDB::bind_method(D_METHOD("font_set_distance_field_hint", "font", "distance_field"), &TextServer::font_set_distance_field_hint); + ClassDB::bind_method(D_METHOD("font_get_distance_field_hint", "font"), &TextServer::font_get_distance_field_hint); + + ClassDB::bind_method(D_METHOD("font_set_force_autohinter", "font", "enabeld"), &TextServer::font_set_force_autohinter); + ClassDB::bind_method(D_METHOD("font_get_force_autohinter", "font"), &TextServer::font_get_force_autohinter); + + ClassDB::bind_method(D_METHOD("font_has_char", "font", "char"), &TextServer::font_has_char); + ClassDB::bind_method(D_METHOD("font_get_supported_chars", "font"), &TextServer::font_get_supported_chars); + + ClassDB::bind_method(D_METHOD("font_has_outline", "font"), &TextServer::font_has_outline); + ClassDB::bind_method(D_METHOD("font_get_base_size", "font"), &TextServer::font_get_base_size); + + ClassDB::bind_method(D_METHOD("font_is_language_supported", "font", "language"), &TextServer::font_is_language_supported); + ClassDB::bind_method(D_METHOD("font_set_language_support_override", "font", "language", "supported"), &TextServer::font_set_language_support_override); + + ClassDB::bind_method(D_METHOD("font_get_language_support_override", "font", "language"), &TextServer::font_get_language_support_override); + ClassDB::bind_method(D_METHOD("font_remove_language_support_override", "font", "language"), &TextServer::font_remove_language_support_override); + ClassDB::bind_method(D_METHOD("font_get_language_support_overrides", "font"), &TextServer::font_get_language_support_overrides); + + ClassDB::bind_method(D_METHOD("font_is_script_supported", "font", "script"), &TextServer::font_is_script_supported); + ClassDB::bind_method(D_METHOD("font_set_script_support_override", "font", "script", "supported"), &TextServer::font_set_script_support_override); + + ClassDB::bind_method(D_METHOD("font_get_script_support_override", "font", "script"), &TextServer::font_get_script_support_override); + ClassDB::bind_method(D_METHOD("font_remove_script_support_override", "font", "script"), &TextServer::font_remove_script_support_override); + ClassDB::bind_method(D_METHOD("font_get_script_support_overrides", "font"), &TextServer::font_get_script_support_overrides); + + ClassDB::bind_method(D_METHOD("font_get_glyph_index", "font", "char", "variation_selector"), &TextServer::font_get_glyph_index, DEFVAL(0x0000)); + ClassDB::bind_method(D_METHOD("font_get_glyph_advance", "font", "index", "size"), &TextServer::font_get_glyph_advance); + ClassDB::bind_method(D_METHOD("font_get_glyph_kerning", "font", "index_a", "index_b", "size"), &TextServer::font_get_glyph_kerning); + + ClassDB::bind_method(D_METHOD("font_draw_glyph", "font", "canvas", "size", "pos", "index", "color"), &TextServer::font_draw_glyph, DEFVAL(Color(1, 1, 1))); + ClassDB::bind_method(D_METHOD("font_draw_glyph_outline", "font", "canvas", "size", "outline_size", "pos", "index", "color"), &TextServer::font_draw_glyph_outline, DEFVAL(Color(1, 1, 1))); + + ClassDB::bind_method(D_METHOD("font_get_oversampling"), &TextServer::font_get_oversampling); + ClassDB::bind_method(D_METHOD("font_set_oversampling", "oversampling"), &TextServer::font_set_oversampling); + + ClassDB::bind_method(D_METHOD("get_system_fonts"), &TextServer::get_system_fonts); + + ClassDB::bind_method(D_METHOD("get_hex_code_box_size", "size", "index"), &TextServer::get_hex_code_box_size); + ClassDB::bind_method(D_METHOD("draw_hex_code_box", "canvas", "size", "pos", "index", "color"), &TextServer::draw_hex_code_box); + + /* Shaped text buffer interface */ + + ClassDB::bind_method(D_METHOD("create_shaped_text", "direction", "orientation"), &TextServer::create_shaped_text, DEFVAL(DIRECTION_AUTO), DEFVAL(ORIENTATION_HORIZONTAL)); + + ClassDB::bind_method(D_METHOD("shaped_text_clear"), &TextServer::shaped_text_clear); + + ClassDB::bind_method(D_METHOD("shaped_text_set_direction", "shaped", "direction"), &TextServer::shaped_text_set_direction, DEFVAL(DIRECTION_AUTO)); + ClassDB::bind_method(D_METHOD("shaped_text_get_direction", "shaped"), &TextServer::shaped_text_get_direction); + + ClassDB::bind_method(D_METHOD("shaped_text_set_bidi_override", "shaped", "override"), &TextServer::_shaped_text_set_bidi_override); + + ClassDB::bind_method(D_METHOD("shaped_text_set_orientation", "shaped", "orientation"), &TextServer::shaped_text_set_orientation, DEFVAL(ORIENTATION_HORIZONTAL)); + ClassDB::bind_method(D_METHOD("shaped_text_get_orientation", "shaped"), &TextServer::shaped_text_get_orientation); + + ClassDB::bind_method(D_METHOD("shaped_text_set_preserve_invalid", "shaped", "enabled"), &TextServer::shaped_text_set_preserve_invalid); + ClassDB::bind_method(D_METHOD("shaped_text_get_preserve_invalid", "shaped"), &TextServer::shaped_text_get_preserve_invalid); + + ClassDB::bind_method(D_METHOD("shaped_text_set_preserve_control", "shaped", "enabled"), &TextServer::shaped_text_set_preserve_control); + ClassDB::bind_method(D_METHOD("shaped_text_get_preserve_control", "shaped"), &TextServer::shaped_text_get_preserve_control); + + ClassDB::bind_method(D_METHOD("shaped_text_add_string", "shaped", "text", "fonts", "size", "opentype_features", "language"), &TextServer::shaped_text_add_string, DEFVAL(Dictionary()), DEFVAL("")); + ClassDB::bind_method(D_METHOD("shaped_text_add_object", "shaped", "key", "size", "inline_align", "length"), &TextServer::shaped_text_add_object, DEFVAL(VALIGN_CENTER), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("shaped_text_resize_object", "shaped", "key", "size", "inline_align"), &TextServer::shaped_text_resize_object, DEFVAL(VALIGN_CENTER)); + + ClassDB::bind_method(D_METHOD("shaped_text_substr", "shaped", "start", "length"), &TextServer::shaped_text_substr); + ClassDB::bind_method(D_METHOD("shaped_text_get_parent", "shaped"), &TextServer::shaped_text_get_parent); + ClassDB::bind_method(D_METHOD("shaped_text_fit_to_width", "shaped", "width", "jst_flags"), &TextServer::shaped_text_fit_to_width, DEFVAL(JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA)); + ClassDB::bind_method(D_METHOD("shaped_text_tab_align", "shaped", "tab_stops"), &TextServer::shaped_text_tab_align); + + ClassDB::bind_method(D_METHOD("shaped_text_shape", "shaped"), &TextServer::shaped_text_shape); + ClassDB::bind_method(D_METHOD("shaped_text_is_ready", "shaped"), &TextServer::shaped_text_is_ready); + + ClassDB::bind_method(D_METHOD("shaped_text_get_glyphs", "shaped"), &TextServer::_shaped_text_get_glyphs); + + ClassDB::bind_method(D_METHOD("shaped_text_get_range", "shaped"), &TextServer::shaped_text_get_range); + ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks_adv", "shaped", "width", "start", "once", "break_flags"), &TextServer::_shaped_text_get_line_breaks_adv, DEFVAL(0), DEFVAL(true), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND)); + ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks", "shaped", "width", "start", "break_flags"), &TextServer::_shaped_text_get_line_breaks, DEFVAL(0), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND)); + ClassDB::bind_method(D_METHOD("shaped_text_get_word_breaks", "shaped"), &TextServer::_shaped_text_get_word_breaks); + ClassDB::bind_method(D_METHOD("shaped_text_get_objects", "shaped"), &TextServer::shaped_text_get_objects); + ClassDB::bind_method(D_METHOD("shaped_text_get_object_rect", "shaped", "key"), &TextServer::shaped_text_get_object_rect); + + ClassDB::bind_method(D_METHOD("shaped_text_get_size", "shaped"), &TextServer::shaped_text_get_size); + ClassDB::bind_method(D_METHOD("shaped_text_get_ascent", "shaped"), &TextServer::shaped_text_get_ascent); + ClassDB::bind_method(D_METHOD("shaped_text_get_descent", "shaped"), &TextServer::shaped_text_get_descent); + ClassDB::bind_method(D_METHOD("shaped_text_get_width", "shaped"), &TextServer::shaped_text_get_width); + ClassDB::bind_method(D_METHOD("shaped_text_get_underline_position", "shaped"), &TextServer::shaped_text_get_underline_position); + ClassDB::bind_method(D_METHOD("shaped_text_get_underline_thickness", "shaped"), &TextServer::shaped_text_get_underline_thickness); + + ClassDB::bind_method(D_METHOD("shaped_text_get_carets", "shaped", "position"), &TextServer::_shaped_text_get_carets); + ClassDB::bind_method(D_METHOD("shaped_text_get_selection", "shaped", "start", "end"), &TextServer::_shaped_text_get_selection); + + ClassDB::bind_method(D_METHOD("shaped_text_hit_test_grapheme", "shaped", "coords"), &TextServer::shaped_text_hit_test_grapheme); + ClassDB::bind_method(D_METHOD("shaped_text_hit_test_position", "shaped", "coords"), &TextServer::shaped_text_hit_test_position); + + ClassDB::bind_method(D_METHOD("shaped_text_next_grapheme_pos", "shaped", "pos"), &TextServer::shaped_text_next_grapheme_pos); + ClassDB::bind_method(D_METHOD("shaped_text_prev_grapheme_pos", "shaped", "pos"), &TextServer::shaped_text_prev_grapheme_pos); + + ClassDB::bind_method(D_METHOD("shaped_text_draw", "shaped", "canvas", "pos", "clip_l", "clip_r", "color"), &TextServer::shaped_text_draw, DEFVAL(-1), DEFVAL(-1), DEFVAL(Color(1, 1, 1))); + ClassDB::bind_method(D_METHOD("shaped_text_draw_outline", "shaped", "canvas", "pos", "clip_l", "clip_r", "outline_size", "color"), &TextServer::shaped_text_draw_outline, DEFVAL(-1), DEFVAL(-1), DEFVAL(1), DEFVAL(Color(1, 1, 1))); + + ClassDB::bind_method(D_METHOD("shaped_text_get_dominant_direciton_in_range", "shaped", "start", "end"), &TextServer::shaped_text_get_dominant_direciton_in_range); + + ClassDB::bind_method(D_METHOD("format_number", "number", "language"), &TextServer::format_number, DEFVAL("")); + ClassDB::bind_method(D_METHOD("parse_number", "number", "language"), &TextServer::parse_number, DEFVAL("")); + ClassDB::bind_method(D_METHOD("percent_sign", "language"), &TextServer::percent_sign, DEFVAL("")); + + /* Direction */ + BIND_ENUM_CONSTANT(DIRECTION_AUTO); + BIND_ENUM_CONSTANT(DIRECTION_LTR); + BIND_ENUM_CONSTANT(DIRECTION_RTL); + + /* Orientation */ + BIND_ENUM_CONSTANT(ORIENTATION_HORIZONTAL); + BIND_ENUM_CONSTANT(ORIENTATION_VERTICAL); + + /* JustificationFlag */ + BIND_ENUM_CONSTANT(JUSTIFICATION_NONE); + BIND_ENUM_CONSTANT(JUSTIFICATION_KASHIDA); + BIND_ENUM_CONSTANT(JUSTIFICATION_WORD_BOUND); + BIND_ENUM_CONSTANT(JUSTIFICATION_TRIM_EDGE_SPACES); + BIND_ENUM_CONSTANT(JUSTIFICATION_AFTER_LAST_TAB); + + /* LineBreakFlag */ + BIND_ENUM_CONSTANT(BREAK_NONE); + BIND_ENUM_CONSTANT(BREAK_MANDATORY); + BIND_ENUM_CONSTANT(BREAK_WORD_BOUND); + BIND_ENUM_CONSTANT(BREAK_GRAPHEME_BOUND); + + /* GraphemeFlag */ + BIND_ENUM_CONSTANT(GRAPHEME_IS_RTL); + BIND_ENUM_CONSTANT(GRAPHEME_IS_VIRTUAL); + BIND_ENUM_CONSTANT(GRAPHEME_IS_SPACE); + BIND_ENUM_CONSTANT(GRAPHEME_IS_BREAK_HARD); + BIND_ENUM_CONSTANT(GRAPHEME_IS_BREAK_SOFT); + BIND_ENUM_CONSTANT(GRAPHEME_IS_TAB); + BIND_ENUM_CONSTANT(GRAPHEME_IS_ELONGATION); + BIND_ENUM_CONSTANT(GRAPHEME_IS_PUNCTUATION); + + /* Hinting */ + BIND_ENUM_CONSTANT(HINTING_NONE); + BIND_ENUM_CONSTANT(HINTING_LIGHT); + BIND_ENUM_CONSTANT(HINTING_NORMAL); + + /* Feature */ + BIND_ENUM_CONSTANT(FEATURE_BIDI_LAYOUT); + BIND_ENUM_CONSTANT(FEATURE_VERTICAL_LAYOUT); + BIND_ENUM_CONSTANT(FEATURE_SHAPING); + BIND_ENUM_CONSTANT(FEATURE_KASHIDA_JUSTIFICATION); + BIND_ENUM_CONSTANT(FEATURE_BREAK_ITERATORS); + BIND_ENUM_CONSTANT(FEATURE_FONT_SYSTEM); + BIND_ENUM_CONSTANT(FEATURE_FONT_VARIABLE); + BIND_ENUM_CONSTANT(FEATURE_USE_SUPPORT_DATA); +} + +Vector3 TextServer::hex_code_box_font_size[2] = { Vector3(5, 5, 1), Vector3(10, 10, 2) }; +Ref<CanvasTexture> TextServer::hex_code_box_font_tex[2] = { nullptr, nullptr }; + +void TextServer::initialize_hex_code_box_fonts() { + static unsigned int tamsyn5x9_png_len = 175; + static unsigned char tamsyn5x9_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x05, + 0x04, 0x03, 0x00, 0x00, 0x00, 0x20, 0x7c, 0x76, 0xda, 0x00, 0x00, 0x00, + 0x0f, 0x50, 0x4c, 0x54, 0x45, 0xfd, 0x07, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x7e, 0x74, 0x00, 0x40, 0xc6, 0xff, 0xff, 0xff, 0x47, 0x9a, 0xd4, 0xc7, + 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, + 0x66, 0x00, 0x00, 0x00, 0x4e, 0x49, 0x44, 0x41, 0x54, 0x08, 0x1d, 0x05, + 0xc1, 0x21, 0x01, 0x00, 0x00, 0x00, 0x83, 0x30, 0x04, 0xc1, 0x10, 0xef, + 0x9f, 0xe9, 0x1b, 0x86, 0x2c, 0x17, 0xb9, 0xcc, 0x65, 0x0c, 0x73, 0x38, + 0xc7, 0xe6, 0x22, 0x19, 0x88, 0x98, 0x10, 0x48, 0x4a, 0x29, 0x85, 0x14, + 0x02, 0x89, 0x10, 0xa3, 0x1c, 0x0b, 0x31, 0xd6, 0xe6, 0x08, 0x69, 0x39, + 0x48, 0x44, 0xa0, 0x0d, 0x4a, 0x22, 0xa1, 0x94, 0x42, 0x0a, 0x01, 0x63, + 0x6d, 0x0e, 0x72, 0x18, 0x61, 0x8c, 0x74, 0x38, 0xc7, 0x26, 0x1c, 0xf3, + 0x71, 0x16, 0x15, 0x27, 0x6a, 0xc2, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + }; + + static unsigned int tamsyn10x20_png_len = 270; + static unsigned char tamsyn10x20_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x0a, + 0x04, 0x03, 0x00, 0x00, 0x00, 0xc1, 0x66, 0x48, 0x96, 0x00, 0x00, 0x00, + 0x0f, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0x00, 0xf9, 0x07, 0x00, 0x5d, + 0x71, 0xa5, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x49, 0xdb, 0xcb, 0x7f, + 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, + 0x66, 0x00, 0x00, 0x00, 0xad, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0xa5, + 0x92, 0x4b, 0x0e, 0x03, 0x31, 0x08, 0x43, 0xdf, 0x82, 0x83, 0x79, 0xe1, + 0xfb, 0x9f, 0xa9, 0x0b, 0x3e, 0x61, 0xa6, 0x1f, 0x55, 0xad, 0x14, 0x31, + 0x66, 0x42, 0x1c, 0x70, 0x0c, 0xb6, 0x00, 0x01, 0xb6, 0x08, 0xdb, 0x00, + 0x8d, 0xc2, 0x14, 0xb2, 0x55, 0xa1, 0xfe, 0x09, 0xc2, 0x26, 0xdc, 0x25, + 0x75, 0x22, 0x97, 0x1a, 0x25, 0x77, 0x28, 0x31, 0x02, 0x80, 0xc8, 0xdd, + 0x2c, 0x11, 0x1a, 0x54, 0x9f, 0xc8, 0xa2, 0x8a, 0x06, 0xa9, 0x93, 0x22, + 0xbd, 0xd4, 0xd0, 0x0c, 0xcf, 0x81, 0x2b, 0xca, 0xbb, 0x83, 0xe0, 0x10, + 0xe6, 0xad, 0xff, 0x10, 0x2a, 0x66, 0x34, 0x41, 0x58, 0x35, 0x54, 0x49, + 0x5a, 0x63, 0xa5, 0xc2, 0x87, 0xab, 0x52, 0x76, 0x9a, 0xba, 0xc6, 0xf4, + 0x75, 0x7a, 0x9e, 0x3c, 0x46, 0x86, 0x5c, 0xa3, 0xfd, 0x87, 0x0e, 0x75, + 0x08, 0x7b, 0xee, 0x7e, 0xea, 0x21, 0x5c, 0x4f, 0xf6, 0xc5, 0xc8, 0x4b, + 0xb9, 0x11, 0xf2, 0xd6, 0xe1, 0x8f, 0x84, 0x62, 0x7b, 0x67, 0xf9, 0x24, + 0xde, 0x6d, 0xbc, 0xb2, 0xcd, 0xb1, 0xf3, 0xf2, 0x2f, 0xe8, 0xe2, 0xe4, + 0xae, 0x4b, 0x4f, 0xcf, 0x2b, 0xdc, 0x8d, 0x0d, 0xf0, 0x00, 0x8f, 0x22, + 0x26, 0x65, 0x75, 0x8a, 0xe6, 0x84, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, + 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + }; + + if (RenderingServer::get_singleton() != nullptr) { + Vector<uint8_t> hex_box_data; + + Ref<Image> image; + image.instance(); + + Ref<ImageTexture> hex_code_image_tex[2]; + + hex_box_data.resize(tamsyn5x9_png_len); + memcpy(hex_box_data.ptrw(), tamsyn5x9_png, tamsyn5x9_png_len); + image->load_png_from_buffer(hex_box_data); + hex_code_image_tex[0].instance(); + hex_code_image_tex[0]->create_from_image(image); + hex_code_box_font_tex[0].instance(); + hex_code_box_font_tex[0]->set_diffuse_texture(hex_code_image_tex[0]); + hex_code_box_font_tex[0]->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); + hex_box_data.clear(); + + hex_box_data.resize(tamsyn10x20_png_len); + memcpy(hex_box_data.ptrw(), tamsyn10x20_png, tamsyn10x20_png_len); + image->load_png_from_buffer(hex_box_data); + hex_code_image_tex[1].instance(); + hex_code_image_tex[1]->create_from_image(image); + hex_code_box_font_tex[1].instance(); + hex_code_box_font_tex[1]->set_diffuse_texture(hex_code_image_tex[1]); + hex_code_box_font_tex[1]->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); + hex_box_data.clear(); + } +} + +void TextServer::finish_hex_code_box_fonts() { + if (hex_code_box_font_tex[0].is_valid()) { + hex_code_box_font_tex[0].unref(); + } + if (hex_code_box_font_tex[1].is_valid()) { + hex_code_box_font_tex[1].unref(); + } +} + +Vector2 TextServer::get_hex_code_box_size(int p_size, char32_t p_index) const { + int fnt = (p_size < 20) ? 0 : 1; + + float w = ((p_index <= 0xFF) ? 1 : ((p_index <= 0xFFFF) ? 2 : 3)) * hex_code_box_font_size[fnt].x; + float h = 2 * hex_code_box_font_size[fnt].y; + return Vector2(w + 4, h + 3 + 2 * hex_code_box_font_size[fnt].z); +} + +void TextServer::draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_pos, char32_t p_index, const Color &p_color) const { + int fnt = (p_size < 20) ? 0 : 1; + + ERR_FAIL_COND(hex_code_box_font_tex[fnt].is_null()); + + uint8_t a = p_index & 0x0F; + uint8_t b = (p_index >> 4) & 0x0F; + uint8_t c = (p_index >> 8) & 0x0F; + uint8_t d = (p_index >> 12) & 0x0F; + uint8_t e = (p_index >> 16) & 0x0F; + uint8_t f = (p_index >> 20) & 0x0F; + + Vector2 pos = p_pos; + Rect2 dest = Rect2(Vector2(), Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y)); + + float w = ((p_index <= 0xFF) ? 1 : ((p_index <= 0xFFFF) ? 2 : 3)) * hex_code_box_font_size[fnt].x; + float h = 2 * hex_code_box_font_size[fnt].y; + + pos.y -= Math::floor((h + 3 + hex_code_box_font_size[fnt].z) * 0.75); + + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, 0), Size2(1, h + 2 + 2 * hex_code_box_font_size[fnt].z)), p_color); + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(w + 2, 0), Size2(1, h + 2 + 2 * hex_code_box_font_size[fnt].z)), p_color); + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, 0), Size2(w + 2, 1)), p_color); + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, h + 2 + 2 * hex_code_box_font_size[fnt].z), Size2(w + 2, 1)), p_color); + + pos += Point2(2, 2); + if (p_index <= 0xFF) { + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 0); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(b * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 1) + Point2(0, hex_code_box_font_size[fnt].z); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(a * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + } else if (p_index <= 0xFFFF) { + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 0); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(d * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(1, 0); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(c * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 1) + Point2(0, hex_code_box_font_size[fnt].z); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(b * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(1, 1) + Point2(0, hex_code_box_font_size[fnt].z); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(a * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + } else { + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 0); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(f * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(1, 0); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(e * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(2, 0); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(d * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 1) + Point2(0, hex_code_box_font_size[fnt].z); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(c * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(1, 1) + Point2(0, hex_code_box_font_size[fnt].z); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(b * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(2, 1) + Point2(0, hex_code_box_font_size[fnt].z); + RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(a * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + } +} + +Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<float> &p_width, int p_start, bool p_once, uint8_t /*TextBreakFlag*/ p_break_flags) const { + Vector<Vector2i> lines; + + ERR_FAIL_COND_V(p_width.is_empty(), lines); + + const_cast<TextServer *>(this)->shaped_text_update_breaks(p_shaped); + const Vector<Glyph> &logical = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); + const Vector2i &range = shaped_text_get_range(p_shaped); + + float width = 0.f; + int line_start = MAX(p_start, range.x); + int last_safe_break = -1; + int chunk = 0; + + int l_size = logical.size(); + const Glyph *l_gl = logical.ptr(); + + for (int i = 0; i < l_size; i++) { + if (l_gl[i].start < p_start) { + continue; + } + if (l_gl[i].count > 0) { + if ((p_width[chunk] > 0) && (width + l_gl[i].advance > p_width[chunk]) && (last_safe_break >= 0)) { + lines.push_back(Vector2i(line_start, l_gl[last_safe_break].end)); + line_start = l_gl[last_safe_break].end; + i = last_safe_break; + last_safe_break = -1; + width = 0; + chunk++; + if (chunk >= p_width.size()) { + chunk = 0; + if (p_once) { + return lines; + } + } + continue; + } + if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) { + if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) { + lines.push_back(Vector2i(line_start, l_gl[i].end)); + line_start = l_gl[i].end; + last_safe_break = -1; + width = 0; + chunk = 0; + if (p_once) { + return lines; + } + continue; + } + } + if ((p_break_flags & BREAK_WORD_BOUND) == BREAK_WORD_BOUND) { + if ((l_gl[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) { + last_safe_break = i; + } + } + if ((p_break_flags & BREAK_GRAPHEME_BOUND) == BREAK_GRAPHEME_BOUND) { + last_safe_break = i; + } + } + width += l_gl[i].advance; + } + + if (l_size > 0) { + lines.push_back(Vector2i(line_start, range.y)); + } else { + lines.push_back(Vector2i(0, 0)); + } + + return lines; +} + +Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start, uint8_t /*TextBreakFlag*/ p_break_flags) const { + Vector<Vector2i> lines; + + const_cast<TextServer *>(this)->shaped_text_update_breaks(p_shaped); + const Vector<Glyph> &logical = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); + const Vector2i &range = shaped_text_get_range(p_shaped); + + float width = 0.f; + int line_start = MAX(p_start, range.x); + int last_safe_break = -1; + + int l_size = logical.size(); + const Glyph *l_gl = logical.ptr(); + + for (int i = 0; i < l_size; i++) { + if (l_gl[i].start < p_start) { + continue; + } + if (l_gl[i].count > 0) { + if ((p_width > 0) && (width + l_gl[i].advance > p_width) && (last_safe_break >= 0)) { + lines.push_back(Vector2i(line_start, l_gl[last_safe_break].end)); + line_start = l_gl[last_safe_break].end; + i = last_safe_break; + last_safe_break = -1; + width = 0; + continue; + } + if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) { + if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) { + lines.push_back(Vector2i(line_start, l_gl[i].end)); + line_start = l_gl[i].end; + last_safe_break = -1; + width = 0; + continue; + } + } + if ((p_break_flags & BREAK_WORD_BOUND) == BREAK_WORD_BOUND) { + if ((l_gl[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) { + last_safe_break = i; + } + } + if ((p_break_flags & BREAK_GRAPHEME_BOUND) == BREAK_GRAPHEME_BOUND) { + last_safe_break = i; + } + } + width += l_gl[i].advance; + } + + if (l_size > 0) { + if (lines.size() == 0 || lines[lines.size() - 1].y < range.y) { + lines.push_back(Vector2i(line_start, range.y)); + } + } else { + lines.push_back(Vector2i(0, 0)); + } + + return lines; +} + +Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped) const { + Vector<Vector2i> words; + + const_cast<TextServer *>(this)->shaped_text_update_justification_ops(p_shaped); + const Vector<Glyph> &logical = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); + const Vector2i &range = shaped_text_get_range(p_shaped); + + int word_start = range.x; + + int l_size = logical.size(); + const Glyph *l_gl = logical.ptr(); + + for (int i = 0; i < l_size; i++) { + if (l_gl[i].count > 0) { + if (((l_gl[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) || ((l_gl[i].flags & GRAPHEME_IS_PUNCTUATION) == GRAPHEME_IS_PUNCTUATION)) { + words.push_back(Vector2i(word_start, l_gl[i].start)); + word_start = l_gl[i].end; + } + } + } + if (l_size > 0) { + words.push_back(Vector2i(word_start, range.y)); + } + + return words; +} + +void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_leading_caret, Direction &p_leading_dir, Rect2 &p_trailing_caret, Direction &p_trailing_dir) const { + Vector<Rect2> carets; + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped); + const Vector2 &range = shaped_text_get_range(p_shaped); + float ascent = shaped_text_get_ascent(p_shaped); + float descent = shaped_text_get_descent(p_shaped); + float height = (ascent + descent) / 2; + + float off = 0.0f; + p_leading_dir = DIRECTION_AUTO; + p_trailing_dir = DIRECTION_AUTO; + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + + for (int i = 0; i < v_size; i++) { + if (glyphs[i].count > 0) { + // Caret before grapheme (top / left). + if (p_position == glyphs[i].start && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) { + Rect2 cr; + if (orientation == ORIENTATION_HORIZONTAL) { + if (glyphs[i].start == range.x) { + cr.size.y = height * 2; + } else { + cr.size.y = height; + } + cr.position.y = -ascent; + cr.position.x = off; + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + p_trailing_dir = DIRECTION_RTL; + for (int j = 0; j < glyphs[i].count; j++) { + cr.position.x += glyphs[i + j].advance * glyphs[i + j].repeat; + cr.size.x -= glyphs[i + j].advance * glyphs[i + j].repeat; + } + } else { + p_trailing_dir = DIRECTION_LTR; + for (int j = 0; j < glyphs[i].count; j++) { + cr.size.x += glyphs[i + j].advance * glyphs[i + j].repeat; + } + } + } else { + if (glyphs[i].start == range.x) { + cr.size.x = height * 2; + } else { + cr.size.x = height; + } + cr.position.x = -ascent; + cr.position.y = off; + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + p_trailing_dir = DIRECTION_RTL; + for (int j = 0; j < glyphs[i].count; j++) { + cr.position.y += glyphs[i + j].advance * glyphs[i + j].repeat; + cr.size.y -= glyphs[i + j].advance * glyphs[i + j].repeat; + } + } else { + p_trailing_dir = DIRECTION_LTR; + for (int j = 0; j < glyphs[i].count; j++) { + cr.size.y += glyphs[i + j].advance * glyphs[i + j].repeat; + } + } + } + p_trailing_caret = cr; + } + // Caret after grapheme (bottom / right). + if (p_position == glyphs[i].end && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) { + Rect2 cr; + if (orientation == ORIENTATION_HORIZONTAL) { + if (glyphs[i].end == range.y) { + cr.size.y = height * 2; + cr.position.y = -ascent; + } else { + cr.size.y = height; + cr.position.y = -ascent + height; + } + cr.position.x = off; + if ((glyphs[i].flags & GRAPHEME_IS_RTL) != GRAPHEME_IS_RTL) { + p_leading_dir = DIRECTION_LTR; + for (int j = 0; j < glyphs[i].count; j++) { + cr.position.x += glyphs[i + j].advance * glyphs[i + j].repeat; + cr.size.x -= glyphs[i + j].advance * glyphs[i + j].repeat; + } + } else { + p_leading_dir = DIRECTION_RTL; + for (int j = 0; j < glyphs[i].count; j++) { + cr.size.x += glyphs[i + j].advance * glyphs[i + j].repeat; + } + } + } else { + cr.size.y = 1.0f; + if (glyphs[i].end == range.y) { + cr.size.x = height * 2; + cr.position.x = -ascent; + } else { + cr.size.x = height; + cr.position.x = -ascent + height; + } + cr.position.y = off; + if ((glyphs[i].flags & GRAPHEME_IS_RTL) != GRAPHEME_IS_RTL) { + p_leading_dir = DIRECTION_LTR; + for (int j = 0; j < glyphs[i].count; j++) { + cr.position.y += glyphs[i + j].advance * glyphs[i + j].repeat; + cr.size.y -= glyphs[i + j].advance * glyphs[i + j].repeat; + } + } else { + p_leading_dir = DIRECTION_RTL; + for (int j = 0; j < glyphs[i].count; j++) { + cr.size.y += glyphs[i + j].advance * glyphs[i + j].repeat; + } + } + } + p_leading_caret = cr; + } + // Caret inside grapheme (middle). + if (p_position > glyphs[i].start && p_position < glyphs[i].end && (glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL) { + float advance = 0.f; + for (int j = 0; j < glyphs[i].count; j++) { + advance += glyphs[i + j].advance * glyphs[i + j].repeat; + } + float char_adv = advance / (float)(glyphs[i].end - glyphs[i].start); + Rect2 cr; + if (orientation == ORIENTATION_HORIZONTAL) { + cr.size.x = 1.0f; + cr.size.y = height * 2; + cr.position.y = -ascent; + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + cr.position.x = off + char_adv * (glyphs[i].end - p_position); + } else { + cr.position.x = off + char_adv * (p_position - glyphs[i].start); + } + } else { + cr.size.y = 1.0f; + cr.size.x = height * 2; + cr.position.x = -ascent; + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + cr.position.y = off + char_adv * (glyphs[i].end - p_position); + } else { + cr.position.y = off + char_adv * (p_position - glyphs[i].start); + } + } + p_trailing_caret = cr; + p_leading_caret = cr; + } + } + off += glyphs[i].advance * glyphs[i].repeat; + } +} + +TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RID p_shaped, int p_start, int p_end) const { + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + + if (p_start == p_end) { + return DIRECTION_AUTO; + } + + int start = MIN(p_start, p_end); + int end = MAX(p_start, p_end); + + int rtl = 0; + int ltr = 0; + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + + for (int i = 0; i < v_size; i++) { + if ((glyphs[i].end > start) && (glyphs[i].start < end)) { + if (glyphs[i].count > 0) { + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + rtl++; + } else { + ltr++; + } + } + } + } + if (ltr == rtl) { + return DIRECTION_AUTO; + } else if (ltr > rtl) { + return DIRECTION_LTR; + } else { + return DIRECTION_RTL; + } +} + +Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const { + Vector<Vector2> ranges; + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + + if (p_start == p_end) { + return ranges; + } + + int start = MIN(p_start, p_end); + int end = MAX(p_start, p_end); + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + + float off = 0.0f; + for (int i = 0; i < v_size; i++) { + for (int k = 0; k < glyphs[i].repeat; k++) { + if ((glyphs[i].count > 0) && ((glyphs[i].index != 0) || ((glyphs[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE))) { + if (glyphs[i].start < end && glyphs[i].end > start) { + // Grapheme fully in selection range. + if (glyphs[i].start >= start && glyphs[i].end <= end) { + float advance = 0.f; + for (int j = 0; j < glyphs[i].count; j++) { + advance += glyphs[i + j].advance; + } + ranges.push_back(Vector2(off, off + advance)); + } + // Only start of grapheme is in selection range. + if (glyphs[i].start >= start && glyphs[i].end > end) { + float advance = 0.f; + for (int j = 0; j < glyphs[i].count; j++) { + advance += glyphs[i + j].advance; + } + float char_adv = advance / (float)(glyphs[i].end - glyphs[i].start); + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + ranges.push_back(Vector2(off + char_adv * (glyphs[i].end - end), off + advance)); + } else { + ranges.push_back(Vector2(off, off + char_adv * (end - glyphs[i].start))); + } + } + // Only end of grapheme is in selection range. + if (glyphs[i].start < start && glyphs[i].end <= end) { + float advance = 0.f; + for (int j = 0; j < glyphs[i].count; j++) { + advance += glyphs[i + j].advance; + } + float char_adv = advance / (float)(glyphs[i].end - glyphs[i].start); + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + ranges.push_back(Vector2(off, off + char_adv * (start - glyphs[i].start))); + } else { + ranges.push_back(Vector2(off + char_adv * (glyphs[i].end - start), off + advance)); + } + } + // Selection range is within grapheme + if (glyphs[i].start < start && glyphs[i].end > end) { + float advance = 0.f; + for (int j = 0; j < glyphs[i].count; j++) { + advance += glyphs[i + j].advance; + } + float char_adv = advance / (float)(glyphs[i].end - glyphs[i].start); + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + ranges.push_back(Vector2(off + char_adv * (glyphs[i].end - end), off + char_adv * (glyphs[i].end - start))); + } else { + ranges.push_back(Vector2(off + char_adv * (start - glyphs[i].start), off + char_adv * (end - glyphs[i].start))); + } + } + } + } + off += glyphs[i].advance; + } + } + + // Merge intersecting ranges. + int i = 0; + while (i < ranges.size()) { + i++; + } + i = 0; + while (i < ranges.size()) { + int j = i + 1; + while (j < ranges.size()) { + if (Math::is_equal_approx(ranges[i].y, ranges[j].x, UNIT_EPSILON)) { + ranges.write[i].y = ranges[j].y; + ranges.remove(j); + continue; + } + j++; + } + i++; + } + + return ranges; +} + +int TextServer::shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const { + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + + // Exact grapheme hit test, return -1 if missed. + float off = 0.0f; + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + + for (int i = 0; i < v_size; i++) { + for (int j = 0; j < glyphs[i].repeat; j++) { + if (p_coords >= off && p_coords < off + glyphs[i].advance) { + return i; + } + off += glyphs[i].advance; + } + } + return -1; +} + +int TextServer::shaped_text_hit_test_position(RID p_shaped, float p_coords) const { + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + + // Cursor placement hit test. + + // Place caret to the left of the leftmost grapheme, or to position 0 if string is empty. + if (p_coords <= 0) { + if (v_size > 0) { + if ((glyphs[0].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + return glyphs[0].end; + } else { + return glyphs[0].start; + } + } else { + return 0; + } + } + + // Place caret to the right of the rightmost grapheme, or to position 0 if string is empty. + if (p_coords >= shaped_text_get_width(p_shaped)) { + if (v_size > 0) { + if ((glyphs[v_size - 1].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + return glyphs[v_size - 1].start; + } else { + return glyphs[v_size - 1].end; + } + } else { + return 0; + } + } + + float off = 0.0f; + for (int i = 0; i < v_size; i++) { + if (glyphs[i].count > 0) { + float advance = 0.f; + for (int j = 0; j < glyphs[i].count; j++) { + advance += glyphs[i + j].advance * glyphs[i + j].repeat; + } + if (((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) && (p_coords >= off && p_coords < off + advance)) { + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + return glyphs[i].end; + } else { + return glyphs[i].start; + } + } + // Place caret to the left of clicked grapheme. + if (p_coords >= off && p_coords < off + advance / 2) { + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + return glyphs[i].end; + } else { + return glyphs[i].start; + } + } + // Place caret to the right of clicked grapheme. + if (p_coords >= off + advance / 2 && p_coords < off + advance) { + if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { + return glyphs[i].start; + } else { + return glyphs[i].end; + } + } + } + off += glyphs[i].advance * glyphs[i].repeat; + } + return 0; +} + +int TextServer::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) { + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + for (int i = 0; i < v_size; i++) { + if (p_pos >= glyphs[i].start && p_pos < glyphs[i].end) { + return glyphs[i].end; + } + } + return p_pos; +} + +int TextServer::shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) { + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + for (int i = 0; i < v_size; i++) { + if (p_pos > glyphs[i].start && p_pos <= glyphs[i].end) { + return glyphs[i].start; + } + } + + return p_pos; +} + +void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, const Color &p_color) const { + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped); + bool hex_codes = shaped_text_get_preserve_control(p_shaped) || shaped_text_get_preserve_invalid(p_shaped); + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + + Vector2 ofs = p_pos; + // Draw at the baseline. + for (int i = 0; i < v_size; i++) { + for (int j = 0; j < glyphs[i].repeat; j++) { + if (p_clip_r > 0) { + // Clip right / bottom. + if (orientation == ORIENTATION_HORIZONTAL) { + if (ofs.x - p_pos.x > p_clip_r) { + return; + } + } else { + if (ofs.y - p_pos.y > p_clip_r) { + return; + } + } + } + if (p_clip_l > 0) { + // Clip left / top. + if (orientation == ORIENTATION_HORIZONTAL) { + if (ofs.x - p_pos.x < p_clip_l) { + ofs.x += glyphs[i].advance; + continue; + } + } else { + if (ofs.y - p_pos.y < p_clip_l) { + ofs.y += glyphs[i].advance; + continue; + } + } + } + if (glyphs[i].font_rid != RID()) { + font_draw_glyph(glyphs[i].font_rid, p_canvas, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color); + } else if (hex_codes && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) { + TextServer::draw_hex_code_box(p_canvas, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color); + } + if (orientation == ORIENTATION_HORIZONTAL) { + ofs.x += glyphs[i].advance; + } else { + ofs.y += glyphs[i].advance; + } + } + } +} + +void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, int p_outline_size, const Color &p_color) const { + const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped); + + int v_size = visual.size(); + const Glyph *glyphs = visual.ptr(); + Vector2 ofs = p_pos; + // Draw at the baseline. + for (int i = 0; i < v_size; i++) { + for (int j = 0; j < glyphs[i].repeat; j++) { + if (p_clip_r > 0) { + // Clip right / bottom. + if (orientation == ORIENTATION_HORIZONTAL) { + if (ofs.x - p_pos.x > p_clip_r) { + return; + } + } else { + if (ofs.y - p_pos.y > p_clip_r) { + return; + } + } + } + if (p_clip_l > 0) { + // Clip left / top. + if (orientation == ORIENTATION_HORIZONTAL) { + if (ofs.x - p_pos.x < p_clip_l) { + ofs.x += glyphs[i].advance; + continue; + } + } else { + if (ofs.y - p_pos.y < p_clip_l) { + ofs.y += glyphs[i].advance; + continue; + } + } + } + if (glyphs[i].font_rid != RID()) { + font_draw_glyph_outline(glyphs[i].font_rid, p_canvas, glyphs[i].font_size, p_outline_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color); + } + if (orientation == ORIENTATION_HORIZONTAL) { + ofs.x += glyphs[i].advance; + } else { + ofs.y += glyphs[i].advance; + } + } + } +} + +RID TextServer::_create_font_memory(const PackedByteArray &p_data, const String &p_type, int p_base_size) { + return create_font_memory(p_data.ptr(), p_data.size(), p_type, p_base_size); +} + +void TextServer::_shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) { + Vector<Vector2i> overrides; + for (int i = 0; i < p_override.size(); i++) { + overrides.push_back(p_override[i]); + } + shaped_text_set_bidi_override(p_shaped, overrides); +} + +Array TextServer::_shaped_text_get_glyphs(RID p_shaped) const { + Array ret; + + Vector<Glyph> glyphs = shaped_text_get_glyphs(p_shaped); + for (int i = 0; i < glyphs.size(); i++) { + Dictionary glyph; + + glyph["start"] = glyphs[i].start; + glyph["end"] = glyphs[i].end; + glyph["repeat"] = glyphs[i].repeat; + glyph["count"] = glyphs[i].count; + glyph["flags"] = glyphs[i].flags; + glyph["offset"] = Vector2(glyphs[i].x_off, glyphs[i].y_off); + glyph["advance"] = glyphs[i].advance; + glyph["font_rid"] = glyphs[i].font_rid; + glyph["font_size"] = glyphs[i].font_size; + glyph["index"] = glyphs[i].index; + + ret.push_back(glyph); + } + + return ret; +} + +Array TextServer::_shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start, bool p_once, uint8_t p_break_flags) const { + Array ret; + + Vector<Vector2i> lines = shaped_text_get_line_breaks_adv(p_shaped, p_width, p_start, p_once, p_break_flags); + for (int i = 0; i < lines.size(); i++) { + ret.push_back(lines[i]); + } + + return ret; +} + +Array TextServer::_shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start, uint8_t p_break_flags) const { + Array ret; + + Vector<Vector2i> lines = shaped_text_get_line_breaks(p_shaped, p_width, p_start, p_break_flags); + for (int i = 0; i < lines.size(); i++) { + ret.push_back(lines[i]); + } + + return ret; +} + +Array TextServer::_shaped_text_get_word_breaks(RID p_shaped) const { + Array ret; + + Vector<Vector2i> words = shaped_text_get_word_breaks(p_shaped); + for (int i = 0; i < words.size(); i++) { + ret.push_back(words[i]); + } + + return ret; +} + +Dictionary TextServer::_shaped_text_get_carets(RID p_shaped, int p_position) const { + Dictionary ret; + + Rect2 l_caret, t_caret; + Direction l_dir, t_dir; + shaped_text_get_carets(p_shaped, p_position, l_caret, l_dir, t_caret, t_dir); + + ret["leading_rect"] = l_caret; + ret["leading_direction"] = l_dir; + ret["trailing_rect"] = t_caret; + ret["trailing_direction"] = t_dir; + + return ret; +} + +Array TextServer::_shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const { + Array ret; + + Vector<Vector2> ranges = shaped_text_get_selection(p_shaped, p_start, p_end); + for (int i = 0; i < ranges.size(); i++) { + ret.push_back(ranges[i]); + } + + return ret; +} + +TextServer::TextServer() { +} + +TextServer::~TextServer() { +} diff --git a/servers/text_server.h b/servers/text_server.h index e69de29bb2..23367de4c8 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -0,0 +1,459 @@ +/*************************************************************************/ +/* text_server.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEXT_SERVER_H +#define TEXT_SERVER_H + +#include "core/object/reference.h" +#include "core/os/os.h" +#include "core/templates/rid.h" +#include "core/variant/variant.h" +#include "scene/resources/texture.h" + +class CanvasTexture; + +class TextServer : public Object { + GDCLASS(TextServer, Object); + +public: + enum Direction { + DIRECTION_AUTO, + DIRECTION_LTR, + DIRECTION_RTL + }; + + enum Orientation { + ORIENTATION_HORIZONTAL, + ORIENTATION_VERTICAL + }; + + enum JustificationFlag { + JUSTIFICATION_NONE = 0, + JUSTIFICATION_KASHIDA = 1 << 0, + JUSTIFICATION_WORD_BOUND = 1 << 1, + JUSTIFICATION_TRIM_EDGE_SPACES = 1 << 2, + JUSTIFICATION_AFTER_LAST_TAB = 1 << 3 + }; + + enum LineBreakFlag { + BREAK_NONE = 0, + BREAK_MANDATORY = 1 << 4, + BREAK_WORD_BOUND = 1 << 5, + BREAK_GRAPHEME_BOUND = 1 << 6 + //RESERVED = 1 << 7 + }; + + enum GraphemeFlag { + GRAPHEME_IS_VALID = 1 << 0, // Glyph is valid. + GRAPHEME_IS_RTL = 1 << 1, // Glyph is right-to-left. + GRAPHEME_IS_VIRTUAL = 1 << 2, // Glyph is not part of source string (added by fit_to_width function, do not affect caret movement). + GRAPHEME_IS_SPACE = 1 << 3, // Is whitespace (for justification and word breaks). + GRAPHEME_IS_BREAK_HARD = 1 << 4, // Is line break (mandatory break, e.g. "\n"). + GRAPHEME_IS_BREAK_SOFT = 1 << 5, // Is line break (optional break, e.g. space). + GRAPHEME_IS_TAB = 1 << 6, // Is tab or vertical tab. + GRAPHEME_IS_ELONGATION = 1 << 7, // Elongation (e.g. kashida), glyph can be duplicated or truncated to fit line to width. + GRAPHEME_IS_PUNCTUATION = 1 << 8 // Punctuation (can be used as word break, but not line break or justifiction). + }; + + enum Hinting { + HINTING_NONE, + HINTING_LIGHT, + HINTING_NORMAL + }; + + enum Feature { + FEATURE_BIDI_LAYOUT = 1 << 0, + FEATURE_VERTICAL_LAYOUT = 1 << 1, + FEATURE_SHAPING = 1 << 2, + FEATURE_KASHIDA_JUSTIFICATION = 1 << 3, + FEATURE_BREAK_ITERATORS = 1 << 4, + FEATURE_FONT_SYSTEM = 1 << 5, + FEATURE_FONT_VARIABLE = 1 << 6, + FEATURE_USE_SUPPORT_DATA = 1 << 7 + }; + + struct Glyph { + int start = -1; // Start offset in the source string. + int end = -1; // End offset in the source string. + + uint8_t count = 0; // Number of glyphs in the grapheme, set in the first glyph only. + uint8_t repeat = 1; // Draw multiple times in the row. + uint16_t flags = 0; // Grapheme flags (valid, rtl, virtual), set in the first glyph only. + + float x_off = 0.f; // Offset from the origin of the glyph on baseline. + float y_off = 0.f; + float advance = 0.f; // Advance to the next glyph along baseline(x for horizontal layout, y for vertical). + + RID font_rid; // Font resource. + int font_size = 0; // Font size; + uint32_t index = 0; // Glyph index (font specific) or UTF-32 codepoint (for the invalid glyphs). + + bool operator==(const Glyph &p_a) const; + bool operator!=(const Glyph &p_a) const; + + bool operator<(const Glyph &p_a) const; + bool operator>(const Glyph &p_a) const; + }; + + struct GlyphCompare { // For line breaking reordering. + _FORCE_INLINE_ bool operator()(const Glyph &l, const Glyph &r) const { + if (l.start == r.start) { + if (l.count == r.count) { + if ((l.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { + return false; + } else { + return true; + } + } + return l.count > r.count; // Sort first glyoh with count & flags, order of the rest are irrelevant. + } else { + return l.start < r.start; + } + } + }; + + struct ShapedTextData { + /* Source data */ + RID parent; // Substring parent ShapedTextData. + + int start = 0; // Substring start offset in the parent string. + int end = 0; // Substring end offset in the parent string. + + String text; + TextServer::Direction direction = DIRECTION_LTR; // Desired text direction. + TextServer::Orientation orientation = ORIENTATION_HORIZONTAL; + + struct Span { + int start = -1; + int end = -1; + + Vector<RID> fonts; + int font_size = 0; + + Variant embedded_key; + + String language; + Dictionary features; + }; + Vector<Span> spans; + + struct EmbeddedObject { + int pos = 0; + VAlign inline_align = VALIGN_TOP; + Rect2 rect; + }; + Map<Variant, EmbeddedObject> objects; + + /* Shaped data */ + TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction. + bool valid = false; // String is shaped. + bool line_breaks_valid = false; // Line and word break flags are populated (and virtual zero width spaces inserted). + bool justification_ops_valid = false; // Virtual elongation glyphs are added to the string. + bool sort_valid = false; + + bool preserve_invalid = true; // Draw hex code box instead of missing characters. + bool preserve_control = false; // Draw control characters. + + float ascent = 0.f; // Ascent for horizontal layout, 1/2 of width for vertical. + float descent = 0.f; // Descent for horizontal layout, 1/2 of width for vertical. + float width = 0.f; // Width for horizontal layout, height for vertical. + + float upos = 0.f; + float uthk = 0.f; + + Vector<TextServer::Glyph> glyphs; + Vector<TextServer::Glyph> glyphs_logical; + }; + + struct BitmapFontData { + int height = 0; + int ascent = 0; + int charcount = 0; + const int *char_rects = nullptr; + int kerning_count = 0; + const int *kernings = nullptr; + int w = 0; + int h = 0; + const unsigned char *img = nullptr; + }; + +protected: + static void _bind_methods(); + + static Vector3 hex_code_box_font_size[2]; + static Ref<CanvasTexture> hex_code_box_font_tex[2]; + +public: + static void initialize_hex_code_box_fonts(); + static void finish_hex_code_box_fonts(); + + virtual bool has_feature(Feature p_feature) = 0; + virtual String get_name() const = 0; + + virtual void free(RID p_rid) = 0; + virtual bool has(RID p_rid) = 0; + virtual bool load_support_data(const String &p_filename) = 0; + +#ifdef TOOLS_ENABLED + virtual String get_support_data_filename() = 0; + virtual String get_support_data_info() = 0; + virtual bool save_support_data(const String &p_filename) = 0; +#endif + + virtual bool is_locale_right_to_left(const String &p_locale) = 0; + + virtual int32_t name_to_tag(const String &p_name) { return 0; }; + virtual String tag_to_name(int32_t p_tag) { return ""; }; + + /* Font interface */ + virtual RID create_font_system(const String &p_name, int p_base_size = 16) = 0; + virtual RID create_font_resource(const String &p_filename, int p_base_size = 16) = 0; + virtual RID create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size = 16) = 0; + + virtual float font_get_height(RID p_font, int p_size) const = 0; + virtual float font_get_ascent(RID p_font, int p_size) const = 0; + virtual float font_get_descent(RID p_font, int p_size) const = 0; + + virtual float font_get_underline_position(RID p_font, int p_size) const = 0; + virtual float font_get_underline_thickness(RID p_font, int p_size) const = 0; + + virtual void font_set_antialiased(RID p_font, bool p_antialiased) = 0; + virtual bool font_get_antialiased(RID p_font) const = 0; + + virtual Dictionary font_get_feature_list(RID p_font) const { return Dictionary(); }; + virtual Dictionary font_get_variation_list(RID p_font) const { return Dictionary(); }; + + virtual void font_set_variation(RID p_font, const String &p_name, double p_value){}; + virtual double font_get_variation(RID p_font, const String &p_name) const { return 0; }; + + virtual void font_set_distance_field_hint(RID p_font, bool p_distance_field) = 0; + virtual bool font_get_distance_field_hint(RID p_font) const = 0; + + virtual void font_set_hinting(RID p_font, Hinting p_hinting) = 0; + virtual Hinting font_get_hinting(RID p_font) const = 0; + + virtual void font_set_force_autohinter(RID p_font, bool p_enabeld) = 0; + virtual bool font_get_force_autohinter(RID p_font) const = 0; + + virtual bool font_has_char(RID p_font, char32_t p_char) const = 0; + virtual String font_get_supported_chars(RID p_font) const = 0; + + virtual bool font_has_outline(RID p_font) const = 0; + virtual float font_get_base_size(RID p_font) const = 0; + + virtual bool font_is_language_supported(RID p_font, const String &p_language) const = 0; + virtual void font_set_language_support_override(RID p_font, const String &p_language, bool p_supported) = 0; + virtual bool font_get_language_support_override(RID p_font, const String &p_language) = 0; + virtual void font_remove_language_support_override(RID p_font, const String &p_language) = 0; + virtual Vector<String> font_get_language_support_overrides(RID p_font) = 0; + + virtual bool font_is_script_supported(RID p_font, const String &p_script) const = 0; + virtual void font_set_script_support_override(RID p_font, const String &p_script, bool p_supported) = 0; + virtual bool font_get_script_support_override(RID p_font, const String &p_script) = 0; + virtual void font_remove_script_support_override(RID p_font, const String &p_script) = 0; + virtual Vector<String> font_get_script_support_overrides(RID p_font) = 0; + + virtual uint32_t font_get_glyph_index(RID p_font, char32_t p_char, char32_t p_variation_selector = 0x0000) const = 0; + virtual Vector2 font_get_glyph_advance(RID p_font, uint32_t p_index, int p_size) const = 0; + virtual Vector2 font_get_glyph_kerning(RID p_font, uint32_t p_index_a, uint32_t p_index_b, int p_size) const = 0; + + virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const = 0; + virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const = 0; + + virtual float font_get_oversampling() const = 0; + virtual void font_set_oversampling(float p_oversampling) = 0; + + Vector2 get_hex_code_box_size(int p_size, char32_t p_index) const; + void draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_pos, char32_t p_index, const Color &p_color) const; + + virtual Vector<String> get_system_fonts() const = 0; + + /* Shaped text buffer interface */ + + virtual RID create_shaped_text(Direction p_direction = DIRECTION_AUTO, Orientation p_orientation = ORIENTATION_HORIZONTAL) = 0; + + virtual void shaped_text_clear(RID p_shaped) = 0; + + virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) = 0; + virtual Direction shaped_text_get_direction(RID p_shaped) const = 0; + + virtual void shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) = 0; + + virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) = 0; + virtual Orientation shaped_text_get_orientation(RID p_shaped) const = 0; + + virtual void shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) = 0; + virtual bool shaped_text_get_preserve_invalid(RID p_shaped) const = 0; + + virtual void shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) = 0; + virtual bool shaped_text_get_preserve_control(RID p_shaped) const = 0; + + virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") = 0; + virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) = 0; + virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) = 0; + + virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const = 0; // Copy shaped substring (e.g. line break) without reshaping, but correctly reordered, preservers range. + virtual RID shaped_text_get_parent(RID p_shaped) const = 0; + + virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint8_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) = 0; + virtual float shaped_text_tab_align(RID p_shaped, const Vector<float> &p_tab_stops) = 0; + + virtual bool shaped_text_shape(RID p_shaped) = 0; + virtual bool shaped_text_update_breaks(RID p_shaped) = 0; + virtual bool shaped_text_update_justification_ops(RID p_shaped) = 0; + + virtual bool shaped_text_is_ready(RID p_shaped) const = 0; + + virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const = 0; + + virtual Vector2i shaped_text_get_range(RID p_shaped) const = 0; + + virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) = 0; + + virtual Vector<Vector2i> shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<float> &p_width, int p_start = 0, bool p_once = true, uint8_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const; + virtual Vector<Vector2i> shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start = 0, uint8_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const; + virtual Vector<Vector2i> shaped_text_get_word_breaks(RID p_shaped) const; + virtual Array shaped_text_get_objects(RID p_shaped) const = 0; + virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const = 0; + + virtual Size2 shaped_text_get_size(RID p_shaped) const = 0; + virtual float shaped_text_get_ascent(RID p_shaped) const = 0; + virtual float shaped_text_get_descent(RID p_shaped) const = 0; + virtual float shaped_text_get_width(RID p_shaped) const = 0; + virtual float shaped_text_get_underline_position(RID p_shaped) const = 0; + virtual float shaped_text_get_underline_thickness(RID p_shaped) const = 0; + + virtual Direction shaped_text_get_dominant_direciton_in_range(RID p_shaped, int p_start, int p_end) const; + + virtual void shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_leading_caret, Direction &p_leading_dir, Rect2 &p_trailing_caret, Direction &p_trailing_dir) const; + virtual Vector<Vector2> shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const; + + virtual int shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const; // Return grapheme index. + virtual int shaped_text_hit_test_position(RID p_shaped, float p_coords) const; // Return caret/selection position. + + virtual int shaped_text_next_grapheme_pos(RID p_shaped, int p_pos); + virtual int shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos); + + // The pen position is always placed on the baseline and moveing left to right. + virtual void shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l = -1.f, float p_clip_r = -1.f, const Color &p_color = Color(1, 1, 1)) const; + virtual void shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l = -1.f, float p_clip_r = -1.f, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1)) const; + + // Number conversion. + virtual String format_number(const String &p_string, const String &p_language = "") const { return p_string; }; + virtual String parse_number(const String &p_string, const String &p_language = "") const { return p_string; }; + virtual String percent_sign(const String &p_language = "") const { return "%"; }; + + /* GDScript wrappers */ + RID _create_font_memory(const PackedByteArray &p_data, const String &p_type, int p_base_size = 16); + + Array _shaped_text_get_glyphs(RID p_shaped) const; + Dictionary _shaped_text_get_carets(RID p_shaped, int p_position) const; + + void _shaped_text_set_bidi_override(RID p_shaped, const Array &p_override); + + Array _shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start, bool p_once, uint8_t p_break_flags) const; + Array _shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start, uint8_t p_break_flags) const; + Array _shaped_text_get_word_breaks(RID p_shaped) const; + + Array _shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const; + + TextServer(); + ~TextServer(); +}; + +/*************************************************************************/ + +class TextServerManager : public Object { + GDCLASS(TextServerManager, Object); + +public: + typedef TextServer *(*CreateFunction)(Error &r_error, void *p_user_data); + +protected: + static void _bind_methods(); + +private: + static TextServerManager *singleton; + static TextServer *server; + enum { + MAX_SERVERS = 64 + }; + + struct TextServerCreate { + String name; + CreateFunction create_function = nullptr; + uint32_t features = 0; + TextServer *instance = nullptr; + void *user_data = nullptr; + }; + + static TextServerCreate server_create_functions[MAX_SERVERS]; + static int server_create_count; + +public: + _FORCE_INLINE_ static TextServerManager *get_singleton() { + return singleton; + } + + static void register_create_function(const String &p_name, uint32_t p_features, CreateFunction p_function, void *p_user_data); + static int get_interface_count(); + static String get_interface_name(int p_index); + static uint32_t get_interface_features(int p_index); + static TextServer *initialize(int p_index, Error &r_error); + static TextServer *get_primary_interface(); + + /* GDScript wrappers */ + int _get_interface_count() const; + String _get_interface_name(int p_index) const; + uint32_t _get_interface_features(int p_index) const; + TextServer *_get_interface(int p_index) const; + Array _get_interfaces() const; + TextServer *_find_interface(const String &p_name) const; + + bool _set_primary_interface(int p_index); + TextServer *_get_primary_interface() const; + + TextServerManager(); + ~TextServerManager(); +}; + +/*************************************************************************/ + +#define TS TextServerManager::get_primary_interface() + +VARIANT_ENUM_CAST(TextServer::Direction); +VARIANT_ENUM_CAST(TextServer::Orientation); +VARIANT_ENUM_CAST(TextServer::JustificationFlag); +VARIANT_ENUM_CAST(TextServer::LineBreakFlag); +VARIANT_ENUM_CAST(TextServer::GraphemeFlag); +VARIANT_ENUM_CAST(TextServer::Hinting); +VARIANT_ENUM_CAST(TextServer::Feature); + +#endif // TEXT_SERVER_H diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp index e9858416ec..9148631899 100644 --- a/servers/xr/xr_interface.cpp +++ b/servers/xr/xr_interface.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h index 99fcef7925..8039018f35 100644 --- a/servers/xr/xr_interface.h +++ b/servers/xr/xr_interface.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,7 +33,6 @@ #include "core/math/camera_matrix.h" #include "core/os/thread_safe.h" -#include "scene/main/window.h" #include "servers/xr_server.h" /** diff --git a/servers/xr/xr_positional_tracker.cpp b/servers/xr/xr_positional_tracker.cpp index ad5cee92ea..5341390045 100644 --- a/servers/xr/xr_positional_tracker.cpp +++ b/servers/xr/xr_positional_tracker.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -34,25 +34,25 @@ void XRPositionalTracker::_bind_methods() { BIND_ENUM_CONSTANT(TRACKER_HAND_UNKNOWN); - BIND_ENUM_CONSTANT(TRACKER_LEFT_HAND); - BIND_ENUM_CONSTANT(TRACKER_RIGHT_HAND); + BIND_ENUM_CONSTANT(TRACKER_HAND_LEFT); + BIND_ENUM_CONSTANT(TRACKER_HAND_RIGHT); // this class is read only from GDScript, so we only have access to getters.. - ClassDB::bind_method(D_METHOD("get_type"), &XRPositionalTracker::get_type); + ClassDB::bind_method(D_METHOD("get_tracker_type"), &XRPositionalTracker::get_tracker_type); ClassDB::bind_method(D_METHOD("get_tracker_id"), &XRPositionalTracker::get_tracker_id); - ClassDB::bind_method(D_METHOD("get_name"), &XRPositionalTracker::get_name); + ClassDB::bind_method(D_METHOD("get_tracker_name"), &XRPositionalTracker::get_tracker_name); ClassDB::bind_method(D_METHOD("get_joy_id"), &XRPositionalTracker::get_joy_id); - ClassDB::bind_method(D_METHOD("get_tracks_orientation"), &XRPositionalTracker::get_tracks_orientation); + ClassDB::bind_method(D_METHOD("is_tracking_orientation"), &XRPositionalTracker::is_tracking_orientation); ClassDB::bind_method(D_METHOD("get_orientation"), &XRPositionalTracker::get_orientation); - ClassDB::bind_method(D_METHOD("get_tracks_position"), &XRPositionalTracker::get_tracks_position); + ClassDB::bind_method(D_METHOD("is_tracking_position"), &XRPositionalTracker::is_tracking_position); ClassDB::bind_method(D_METHOD("get_position"), &XRPositionalTracker::get_position); - ClassDB::bind_method(D_METHOD("get_hand"), &XRPositionalTracker::get_hand); + ClassDB::bind_method(D_METHOD("get_tracker_hand"), &XRPositionalTracker::get_tracker_hand); ClassDB::bind_method(D_METHOD("get_transform", "adjust_by_reference_frame"), &XRPositionalTracker::get_transform); ClassDB::bind_method(D_METHOD("get_mesh"), &XRPositionalTracker::get_mesh); // these functions we don't want to expose to normal users but do need to be callable from GDNative - ClassDB::bind_method(D_METHOD("_set_type", "type"), &XRPositionalTracker::set_type); - ClassDB::bind_method(D_METHOD("_set_name", "name"), &XRPositionalTracker::set_name); + ClassDB::bind_method(D_METHOD("_set_tracker_type", "type"), &XRPositionalTracker::set_tracker_type); + ClassDB::bind_method(D_METHOD("_set_tracker_name", "name"), &XRPositionalTracker::set_tracker_name); ClassDB::bind_method(D_METHOD("_set_joy_id", "joy_id"), &XRPositionalTracker::set_joy_id); ClassDB::bind_method(D_METHOD("_set_orientation", "orientation"), &XRPositionalTracker::set_orientation); ClassDB::bind_method(D_METHOD("_set_rw_position", "rw_position"), &XRPositionalTracker::set_rw_position); @@ -63,7 +63,7 @@ void XRPositionalTracker::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble"), "set_rumble", "get_rumble"); }; -void XRPositionalTracker::set_type(XRServer::TrackerType p_type) { +void XRPositionalTracker::set_tracker_type(XRServer::TrackerType p_type) { if (type != p_type) { type = p_type; hand = XRPositionalTracker::TRACKER_HAND_UNKNOWN; @@ -77,15 +77,15 @@ void XRPositionalTracker::set_type(XRServer::TrackerType p_type) { }; }; -XRServer::TrackerType XRPositionalTracker::get_type() const { +XRServer::TrackerType XRPositionalTracker::get_tracker_type() const { return type; }; -void XRPositionalTracker::set_name(const String &p_name) { +void XRPositionalTracker::set_tracker_name(const String &p_name) { name = p_name; }; -StringName XRPositionalTracker::get_name() const { +StringName XRPositionalTracker::get_tracker_name() const { return name; }; @@ -101,14 +101,14 @@ int XRPositionalTracker::get_joy_id() const { return joy_id; }; -bool XRPositionalTracker::get_tracks_orientation() const { - return tracks_orientation; +bool XRPositionalTracker::is_tracking_orientation() const { + return tracking_orientation; }; void XRPositionalTracker::set_orientation(const Basis &p_orientation) { _THREAD_SAFE_METHOD_ - tracks_orientation = true; // obviously we have this + tracking_orientation = true; // obviously we have this orientation = p_orientation; }; @@ -118,8 +118,8 @@ Basis XRPositionalTracker::get_orientation() const { return orientation; }; -bool XRPositionalTracker::get_tracks_position() const { - return tracks_position; +bool XRPositionalTracker::is_tracking_position() const { + return tracking_position; }; void XRPositionalTracker::set_position(const Vector3 &p_position) { @@ -130,7 +130,7 @@ void XRPositionalTracker::set_position(const Vector3 &p_position) { real_t world_scale = xr_server->get_world_scale(); ERR_FAIL_COND(world_scale == 0); - tracks_position = true; // obviously we have this + tracking_position = true; // obviously we have this rw_position = p_position / world_scale; }; @@ -147,7 +147,7 @@ Vector3 XRPositionalTracker::get_position() const { void XRPositionalTracker::set_rw_position(const Vector3 &p_rw_position) { _THREAD_SAFE_METHOD_ - tracks_position = true; // obviously we have this + tracking_position = true; // obviously we have this rw_position = p_rw_position; }; @@ -169,11 +169,11 @@ Ref<Mesh> XRPositionalTracker::get_mesh() const { return mesh; }; -XRPositionalTracker::TrackerHand XRPositionalTracker::get_hand() const { +XRPositionalTracker::TrackerHand XRPositionalTracker::get_tracker_hand() const { return hand; }; -void XRPositionalTracker::set_hand(const XRPositionalTracker::TrackerHand p_hand) { +void XRPositionalTracker::set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand) { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL(xr_server); @@ -182,11 +182,11 @@ void XRPositionalTracker::set_hand(const XRPositionalTracker::TrackerHand p_hand ERR_FAIL_COND((type != XRServer::TRACKER_CONTROLLER) && (p_hand != XRPositionalTracker::TRACKER_HAND_UNKNOWN)); hand = p_hand; - if (hand == XRPositionalTracker::TRACKER_LEFT_HAND) { + if (hand == XRPositionalTracker::TRACKER_HAND_LEFT) { if (!xr_server->is_tracker_id_in_use_for_type(type, 1)) { tracker_id = 1; }; - } else if (hand == XRPositionalTracker::TRACKER_RIGHT_HAND) { + } else if (hand == XRPositionalTracker::TRACKER_HAND_RIGHT) { if (!xr_server->is_tracker_id_in_use_for_type(type, 2)) { tracker_id = 2; }; @@ -227,8 +227,8 @@ XRPositionalTracker::XRPositionalTracker() { name = "Unknown"; joy_id = -1; tracker_id = 0; - tracks_orientation = false; - tracks_position = false; + tracking_orientation = false; + tracking_position = false; hand = TRACKER_HAND_UNKNOWN; rumble = 0.0; }; diff --git a/servers/xr/xr_positional_tracker.h b/servers/xr/xr_positional_tracker.h index 515359e9b1..420d818342 100644 --- a/servers/xr/xr_positional_tracker.h +++ b/servers/xr/xr_positional_tracker.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -50,8 +50,8 @@ class XRPositionalTracker : public Object { public: enum TrackerHand { TRACKER_HAND_UNKNOWN, /* unknown or not applicable */ - TRACKER_LEFT_HAND, /* controller is the left hand controller */ - TRACKER_RIGHT_HAND /* controller is the right hand controller */ + TRACKER_HAND_LEFT, /* controller is the left hand controller */ + TRACKER_HAND_RIGHT /* controller is the right hand controller */ }; private: @@ -59,9 +59,9 @@ private: StringName name; // (unique) name of the tracker int tracker_id; // tracker index id that is unique per type int joy_id; // if we also have a related joystick entity, the id of the joystick - bool tracks_orientation; // do we track orientation? + bool tracking_orientation; // do we track orientation? Basis orientation; // our orientation - bool tracks_position; // do we track position? + bool tracking_position; // do we track position? Vector3 rw_position; // our position "in the real world, so without world_scale applied" Ref<Mesh> mesh; // when available, a mesh that can be used to render this tracker TrackerHand hand; // if known, the hand this tracker is held in @@ -71,23 +71,23 @@ protected: static void _bind_methods(); public: - void set_type(XRServer::TrackerType p_type); - XRServer::TrackerType get_type() const; - void set_name(const String &p_name); - StringName get_name() const; + void set_tracker_type(XRServer::TrackerType p_type); + XRServer::TrackerType get_tracker_type() const; + void set_tracker_name(const String &p_name); + StringName get_tracker_name() const; int get_tracker_id() const; void set_joy_id(int p_joy_id); int get_joy_id() const; - bool get_tracks_orientation() const; + bool is_tracking_orientation() const; void set_orientation(const Basis &p_orientation); Basis get_orientation() const; - bool get_tracks_position() const; + bool is_tracking_position() const; void set_position(const Vector3 &p_position); // set position with world_scale applied Vector3 get_position() const; // get position with world_scale applied void set_rw_position(const Vector3 &p_rw_position); Vector3 get_rw_position() const; - XRPositionalTracker::TrackerHand get_hand() const; - void set_hand(const XRPositionalTracker::TrackerHand p_hand); + XRPositionalTracker::TrackerHand get_tracker_hand() const; + void set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand); real_t get_rumble() const; void set_rumble(real_t p_rumble); void set_mesh(const Ref<Mesh> &p_mesh); diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index 09800443b7..2acc2e398c 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,7 +29,7 @@ /*************************************************************************/ #include "xr_server.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h" #include "xr/xr_interface.h" #include "xr/xr_positional_tracker.h" @@ -235,7 +235,7 @@ Array XRServer::get_interfaces() const { bool XRServer::is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const { for (int i = 0; i < trackers.size(); i++) { - if (trackers[i]->get_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { + if (trackers[i]->get_tracker_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { return true; }; }; @@ -264,7 +264,7 @@ void XRServer::add_tracker(XRPositionalTracker *p_tracker) { ERR_FAIL_NULL(p_tracker); trackers.push_back(p_tracker); - emit_signal("tracker_added", p_tracker->get_name(), p_tracker->get_type(), p_tracker->get_tracker_id()); + emit_signal("tracker_added", p_tracker->get_tracker_name(), p_tracker->get_tracker_type(), p_tracker->get_tracker_id()); }; void XRServer::remove_tracker(XRPositionalTracker *p_tracker) { @@ -280,7 +280,7 @@ void XRServer::remove_tracker(XRPositionalTracker *p_tracker) { ERR_FAIL_COND(idx == -1); - emit_signal("tracker_removed", p_tracker->get_name(), p_tracker->get_type(), p_tracker->get_tracker_id()); + emit_signal("tracker_removed", p_tracker->get_tracker_name(), p_tracker->get_tracker_type(), p_tracker->get_tracker_id()); trackers.remove(idx); }; @@ -298,7 +298,7 @@ XRPositionalTracker *XRServer::find_by_type_and_id(TrackerType p_tracker_type, i ERR_FAIL_COND_V(p_tracker_id == 0, nullptr); for (int i = 0; i < trackers.size(); i++) { - if (trackers[i]->get_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { + if (trackers[i]->get_tracker_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { return trackers[i]; }; }; @@ -336,7 +336,7 @@ uint64_t XRServer::get_last_frame_usec() { }; void XRServer::_process() { - /* called from rendering_server_viewport.draw_viewports right before we start drawing our viewports */ + /* called from renderer_viewport.draw_viewports right before we start drawing our viewports */ /* mark for our frame timing */ last_process_usec = OS::get_singleton()->get_ticks_usec(); diff --git a/servers/xr_server.h b/servers/xr_server.h index e04c7b3592..d3972be838 100644 --- a/servers/xr_server.h +++ b/servers/xr_server.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,11 +31,11 @@ #ifndef XR_SERVER_H #define XR_SERVER_H +#include "core/object/reference.h" #include "core/os/os.h" #include "core/os/thread_safe.h" -#include "core/reference.h" -#include "core/rid.h" -#include "core/variant.h" +#include "core/templates/rid.h" +#include "core/variant/variant.h" class XRInterface; class XRPositionalTracker; |