diff options
Diffstat (limited to 'drivers')
93 files changed, 2377 insertions, 26304 deletions
diff --git a/drivers/SCsub b/drivers/SCsub index cc7bcbc640..e2ac9ee01e 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -24,9 +24,7 @@ SConscript("winmidi/SCsub") # Graphics drivers if env["platform"] != "server" and env["platform"] != "javascript": - # SConscript('gles2/SCsub') SConscript("vulkan/SCsub") - SConscript("gl_context/SCsub") else: SConscript("dummy/SCsub") @@ -34,15 +32,6 @@ else: SConscript("png/SCsub") SConscript("spirv-reflect/SCsub") -if env["vsproj"]: - import os - - path = os.getcwd() - # Change directory so the path resolves correctly in the function call. - os.chdir("..") - env.AddToVSProject(env.drivers_sources) - os.chdir(path) - env.add_source_files(env.drivers_sources, "*.cpp") lib = env.add_library("drivers", env.drivers_sources) diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp index 48e694dd3a..5b0d2233e0 100644 --- a/drivers/alsa/audio_driver_alsa.cpp +++ b/drivers/alsa/audio_driver_alsa.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,13 +32,13 @@ #ifdef ALSA_ENABLED +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" #include <errno.h> Error AudioDriverALSA::init_device() { - mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE); + mix_rate = GLOBAL_GET("audio/mix_rate"); speaker_mode = SPEAKER_MODE_STEREO; channels = 2; @@ -104,7 +104,7 @@ Error AudioDriverALSA::init_device() { // In ALSA the period size seems to be the one that will determine the actual latency // Ref: https://www.alsa-project.org/main/index.php/FramesPeriods unsigned int periods = 2; - int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY); + int latency = GLOBAL_GET("audio/output_latency"); buffer_frames = closest_power_of_2(latency * mix_rate / 1000); buffer_size = buffer_frames * periods; period_size = buffer_frames; @@ -147,7 +147,6 @@ Error AudioDriverALSA::init_device() { } Error AudioDriverALSA::init() { - active = false; thread_exited = false; exit_thread = false; @@ -161,11 +160,9 @@ Error AudioDriverALSA::init() { } void AudioDriverALSA::thread_func(void *p_udata) { - AudioDriverALSA *ad = (AudioDriverALSA *)p_udata; while (!ad->exit_thread) { - ad->lock(); ad->start_counting_ticks(); @@ -186,7 +183,7 @@ void AudioDriverALSA::thread_func(void *p_udata) { int total = 0; while (todo && !ad->exit_thread) { - uint8_t *src = (uint8_t *)ad->samples_out.ptr(); + int16_t *src = (int16_t *)ad->samples_out.ptr(); int wrote = snd_pcm_writei(ad->pcm_handle, (void *)(src + (total * ad->channels)), todo); if (wrote > 0) { @@ -237,30 +234,27 @@ void AudioDriverALSA::thread_func(void *p_udata) { } void AudioDriverALSA::start() { - active = true; } int AudioDriverALSA::get_mix_rate() const { - return mix_rate; } AudioDriver::SpeakerMode AudioDriverALSA::get_speaker_mode() const { - return speaker_mode; } Array AudioDriverALSA::get_device_list() { - Array list; list.push_back("Default"); void **hints; - if (snd_device_name_hint(-1, "pcm", &hints) < 0) + if (snd_device_name_hint(-1, "pcm", &hints) < 0) { return list; + } for (void **n = hints; *n != nullptr; n++) { char *name = snd_device_name_get_hint(*n, "NAME"); @@ -274,10 +268,12 @@ Array AudioDriverALSA::get_device_list() { } } - if (desc != nullptr) + if (desc != nullptr) { free(desc); - if (name != nullptr) + } + if (name != nullptr) { free(name); + } } snd_device_name_free_hint(hints); @@ -285,33 +281,30 @@ Array AudioDriverALSA::get_device_list() { } String AudioDriverALSA::get_device() { - return device_name; } void AudioDriverALSA::set_device(String device) { - lock(); new_device = device; unlock(); } void AudioDriverALSA::lock() { - - if (!thread) + if (!thread) { return; + } mutex.lock(); } void AudioDriverALSA::unlock() { - - if (!thread) + if (!thread) { return; + } mutex.unlock(); } void AudioDriverALSA::finish_device() { - if (pcm_handle) { snd_pcm_close(pcm_handle); pcm_handle = nullptr; @@ -319,7 +312,6 @@ void AudioDriverALSA::finish_device() { } void AudioDriverALSA::finish() { - if (thread) { exit_thread = true; Thread::wait_to_finish(thread); @@ -331,14 +323,4 @@ void AudioDriverALSA::finish() { finish_device(); } -AudioDriverALSA::AudioDriverALSA() : - thread(nullptr), - pcm_handle(nullptr), - device_name("Default"), - new_device("Default") { -} - -AudioDriverALSA::~AudioDriverALSA() { -} - -#endif +#endif // ALSA_ENABLED diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h index 50bd9e853d..7441229704 100644 --- a/drivers/alsa/audio_driver_alsa.h +++ b/drivers/alsa/audio_driver_alsa.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 */ @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef ALSA_ENABLED - #ifndef AUDIO_DRIVER_ALSA_H #define AUDIO_DRIVER_ALSA_H +#ifdef ALSA_ENABLED + #include "core/os/mutex.h" #include "core/os/thread.h" #include "servers/audio_server.h" @@ -40,14 +40,13 @@ #include <alsa/asoundlib.h> class AudioDriverALSA : public AudioDriver { - - Thread *thread; + Thread *thread = nullptr; Mutex mutex; - snd_pcm_t *pcm_handle; + snd_pcm_t *pcm_handle = nullptr; - String device_name; - String new_device; + String device_name = "Default"; + String new_device = "Default"; Vector<int32_t> samples_in; Vector<int16_t> samples_out; @@ -57,17 +56,17 @@ class AudioDriverALSA : public AudioDriver { static void thread_func(void *p_udata); - unsigned int mix_rate; + unsigned int mix_rate = 0; SpeakerMode speaker_mode; snd_pcm_uframes_t buffer_frames; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; - int channels; + int channels = 0; - bool active; - bool thread_exited; - mutable bool exit_thread; + bool active = false; + bool thread_exited = false; + mutable bool exit_thread = false; public: const char *get_name() const { @@ -85,10 +84,10 @@ public: virtual void unlock(); virtual void finish(); - AudioDriverALSA(); - ~AudioDriverALSA(); + AudioDriverALSA() {} + ~AudioDriverALSA() {} }; -#endif // AUDIO_DRIVER_ALSA_H - #endif // ALSA_ENABLED + +#endif // AUDIO_DRIVER_ALSA_H diff --git a/drivers/alsamidi/midi_driver_alsamidi.cpp b/drivers/alsamidi/midi_driver_alsamidi.cpp index e3e54ea267..2e1034fc66 100644 --- a/drivers/alsamidi/midi_driver_alsamidi.cpp +++ b/drivers/alsamidi/midi_driver_alsamidi.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,7 +33,7 @@ #include "midi_driver_alsamidi.h" #include "core/os/os.h" -#include "core/print_string.h" +#include "core/string/print_string.h" #include <errno.h> @@ -125,11 +125,11 @@ void MIDIDriverALSAMidi::thread_func(void *p_udata) { } Error MIDIDriverALSAMidi::open() { - void **hints; - if (snd_device_name_hint(-1, "rawmidi", &hints) < 0) + if (snd_device_name_hint(-1, "rawmidi", &hints) < 0) { return ERR_CANT_OPEN; + } int i = 0; for (void **n = hints; *n != nullptr; n++) { @@ -143,8 +143,9 @@ Error MIDIDriverALSAMidi::open() { } } - if (name != nullptr) + if (name != nullptr) { free(name); + } } snd_device_name_free_hint(hints); @@ -155,7 +156,6 @@ Error MIDIDriverALSAMidi::open() { } void MIDIDriverALSAMidi::close() { - if (thread) { exit_thread = true; Thread::wait_to_finish(thread); @@ -172,17 +172,14 @@ void MIDIDriverALSAMidi::close() { } void MIDIDriverALSAMidi::lock() const { - mutex.lock(); } void MIDIDriverALSAMidi::unlock() const { - mutex.unlock(); } PackedStringArray MIDIDriverALSAMidi::get_connected_inputs() { - PackedStringArray list; lock(); @@ -201,14 +198,12 @@ PackedStringArray MIDIDriverALSAMidi::get_connected_inputs() { } MIDIDriverALSAMidi::MIDIDriverALSAMidi() { - thread = nullptr; exit_thread = false; } MIDIDriverALSAMidi::~MIDIDriverALSAMidi() { - close(); } diff --git a/drivers/alsamidi/midi_driver_alsamidi.h b/drivers/alsamidi/midi_driver_alsamidi.h index 6797c7c138..1ce0d397df 100644 --- a/drivers/alsamidi/midi_driver_alsamidi.h +++ b/drivers/alsamidi/midi_driver_alsamidi.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 */ @@ -28,21 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef ALSAMIDI_ENABLED - #ifndef MIDI_DRIVER_ALSAMIDI_H #define MIDI_DRIVER_ALSAMIDI_H +#ifdef ALSAMIDI_ENABLED + #include "core/os/midi_driver.h" #include "core/os/mutex.h" #include "core/os/thread.h" -#include "core/vector.h" +#include "core/templates/vector.h" #include <alsa/asoundlib.h> #include <stdio.h> class MIDIDriverALSAMidi : public MIDIDriver { - Thread *thread; Mutex mutex; @@ -65,5 +64,6 @@ public: virtual ~MIDIDriverALSAMidi(); }; -#endif // MIDI_DRIVER_ALSAMIDI_H #endif // ALSAMIDI_ENABLED + +#endif // MIDI_DRIVER_ALSAMIDI_H diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp index 21c3649445..6f88107086 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.cpp +++ b/drivers/coreaudio/audio_driver_coreaudio.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,8 +32,8 @@ #include "audio_driver_coreaudio.h" +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" #define kOutputBus 0 #define kInputBus 1 @@ -116,7 +116,7 @@ Error AudioDriverCoreAudio::init() { break; } - mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); + mix_rate = GLOBAL_GET("audio/mix_rate"); zeromem(&strdesc, sizeof(strdesc)); strdesc.mFormatID = kAudioFormatLinearPCM; @@ -131,7 +131,7 @@ Error AudioDriverCoreAudio::init() { result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc)); ERR_FAIL_COND_V(result != noErr, FAILED); - int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY); + int latency = GLOBAL_GET("audio/output_latency"); // Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels) buffer_frames = closest_power_of_2(latency * mix_rate / 1000); @@ -168,7 +168,6 @@ OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { - AudioDriverCoreAudio *ad = (AudioDriverCoreAudio *)inRefCon; if (!ad->active || !ad->try_lock()) { @@ -182,18 +181,15 @@ OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon, ad->start_counting_ticks(); for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) { - AudioBuffer *abuf = &ioData->mBuffers[i]; unsigned int frames_left = inNumberFrames; int16_t *out = (int16_t *)abuf->mData; while (frames_left) { - unsigned int frames = MIN(frames_left, ad->buffer_frames); ad->audio_server_process(frames, ad->samples_in.ptrw()); for (unsigned int j = 0; j < frames * ad->channels; j++) { - out[j] = ad->samples_in[j] >> 16; } @@ -213,7 +209,6 @@ OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { - AudioDriverCoreAudio *ad = (AudioDriverCoreAudio *)inRefCon; if (!ad->active) { return 0; @@ -408,7 +403,7 @@ Error AudioDriverCoreAudio::capture_init() { break; } - mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); + mix_rate = GLOBAL_GET("audio/mix_rate"); zeromem(&strdesc, sizeof(strdesc)); strdesc.mFormatID = kAudioFormatLinearPCM; @@ -475,7 +470,6 @@ void AudioDriverCoreAudio::capture_finish() { } Error AudioDriverCoreAudio::capture_start() { - input_buffer_init(buffer_frames); OSStatus result = AudioOutputUnitStart(input_unit); @@ -487,7 +481,6 @@ Error AudioDriverCoreAudio::capture_start() { } Error AudioDriverCoreAudio::capture_stop() { - if (input_unit) { OSStatus result = AudioOutputUnitStop(input_unit); if (result != noErr) { @@ -501,7 +494,6 @@ Error AudioDriverCoreAudio::capture_stop() { #ifdef OSX_ENABLED Array AudioDriverCoreAudio::_get_device_list(bool capture) { - Array list; list.push_back("Default"); @@ -558,7 +550,6 @@ Array AudioDriverCoreAudio::_get_device_list(bool capture) { } void AudioDriverCoreAudio::_set_device(const String &device, bool capture) { - AudioDeviceID deviceId; bool found = false; if (device != "Default") { @@ -639,17 +630,14 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) { } Array AudioDriverCoreAudio::get_device_list() { - return _get_device_list(); } String AudioDriverCoreAudio::get_device() { - return device_name; } void AudioDriverCoreAudio::set_device(String device) { - device_name = device; if (active) { _set_device(device_name); @@ -657,7 +645,6 @@ void AudioDriverCoreAudio::set_device(String device) { } void AudioDriverCoreAudio::capture_set_device(const String &p_name) { - capture_device_name = p_name; if (active) { _set_device(capture_device_name, true); @@ -665,30 +652,17 @@ void AudioDriverCoreAudio::capture_set_device(const String &p_name) { } Array AudioDriverCoreAudio::capture_get_device_list() { - return _get_device_list(true); } String AudioDriverCoreAudio::capture_get_device() { - return capture_device_name; } #endif -AudioDriverCoreAudio::AudioDriverCoreAudio() : - audio_unit(nullptr), - input_unit(nullptr), - active(false), - device_name("Default"), - capture_device_name("Default"), - mix_rate(0), - channels(2), - capture_channels(2), - buffer_frames(0) { +AudioDriverCoreAudio::AudioDriverCoreAudio() { samples_in.clear(); } -AudioDriverCoreAudio::~AudioDriverCoreAudio(){}; - -#endif +#endif // COREAUDIO_ENABLED diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h index fb9473e230..b31835760e 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.h +++ b/drivers/coreaudio/audio_driver_coreaudio.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,20 +41,19 @@ #endif class AudioDriverCoreAudio : public AudioDriver { + AudioComponentInstance audio_unit = nullptr; + AudioComponentInstance input_unit = nullptr; - AudioComponentInstance audio_unit; - AudioComponentInstance input_unit; - - bool active; + bool active = false; Mutex mutex; - String device_name; - String capture_device_name; + String device_name = "Default"; + String capture_device_name = "Default"; - int mix_rate; - unsigned int channels; - unsigned int capture_channels; - unsigned int buffer_frames; + int mix_rate = 0; + unsigned int channels = 2; + unsigned int capture_channels = 2; + unsigned int buffer_frames = 0; Vector<int32_t> samples_in; Vector<int16_t> input_buf; @@ -118,7 +117,7 @@ public: #endif AudioDriverCoreAudio(); - ~AudioDriverCoreAudio(); + ~AudioDriverCoreAudio() {} }; #endif diff --git a/drivers/coremidi/midi_driver_coremidi.cpp b/drivers/coremidi/midi_driver_coremidi.cpp index 2cd322813b..87764d9b10 100644 --- a/drivers/coremidi/midi_driver_coremidi.cpp +++ b/drivers/coremidi/midi_driver_coremidi.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 "midi_driver_coremidi.h" -#include "core/print_string.h" +#include "core/string/print_string.h" #include <CoreAudio/HostTime.h> #include <CoreServices/CoreServices.h> @@ -46,7 +46,6 @@ void MIDIDriverCoreMidi::read(const MIDIPacketList *packet_list, void *read_proc } Error MIDIDriverCoreMidi::open() { - CFStringRef name = CFStringCreateWithCString(nullptr, "Godot", kCFStringEncodingASCII); OSStatus result = MIDIClientCreate(name, nullptr, nullptr, &client); CFRelease(name); @@ -63,7 +62,6 @@ Error MIDIDriverCoreMidi::open() { int sources = MIDIGetNumberOfSources(); for (int i = 0; i < sources; i++) { - MIDIEndpointRef source = MIDIGetSource(i); if (source) { MIDIPortConnectSource(port_in, source, (void *)this); @@ -75,7 +73,6 @@ Error MIDIDriverCoreMidi::open() { } void MIDIDriverCoreMidi::close() { - for (int i = 0; i < connected_sources.size(); i++) { MIDIEndpointRef source = connected_sources[i]; MIDIPortDisconnectSource(port_in, source); @@ -94,7 +91,6 @@ void MIDIDriverCoreMidi::close() { } PackedStringArray MIDIDriverCoreMidi::get_connected_inputs() { - PackedStringArray list; for (int i = 0; i < connected_sources.size(); i++) { @@ -112,9 +108,7 @@ PackedStringArray MIDIDriverCoreMidi::get_connected_inputs() { return list; } -MIDIDriverCoreMidi::MIDIDriverCoreMidi() : - client(0) { -} +MIDIDriverCoreMidi::MIDIDriverCoreMidi() {} MIDIDriverCoreMidi::~MIDIDriverCoreMidi() { close(); diff --git a/drivers/coremidi/midi_driver_coremidi.h b/drivers/coremidi/midi_driver_coremidi.h index e8b4481c20..41a7c760ac 100644 --- a/drivers/coremidi/midi_driver_coremidi.h +++ b/drivers/coremidi/midi_driver_coremidi.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -34,14 +34,13 @@ #define MIDI_DRIVER_COREMIDI_H #include "core/os/midi_driver.h" -#include "core/vector.h" +#include "core/templates/vector.h" #include <CoreMIDI/CoreMIDI.h> #include <stdio.h> class MIDIDriverCoreMidi : public MIDIDriver { - - MIDIClientRef client; + MIDIClientRef client = 0; MIDIPortRef port_in; Vector<MIDIEndpointRef> connected_sources; diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index 0bcfed2dcf..2507add506 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_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 */ @@ -32,141 +32,201 @@ #define RASTERIZER_DUMMY_H #include "core/math/camera_matrix.h" -#include "core/rid_owner.h" -#include "core/self_list.h" +#include "core/templates/rid_owner.h" +#include "core/templates/self_list.h" #include "scene/resources/mesh.h" -#include "servers/rendering/rasterizer.h" +#include "servers/rendering/renderer_compositor.h" #include "servers/rendering_server.h" -class RasterizerSceneDummy : public RasterizerScene { +class RasterizerSceneDummy : public RendererSceneRender { public: + GeometryInstance *geometry_instance_create(RID p_base) override { return nullptr; } + void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override {} + void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override {} + void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_material) override {} + void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) override {} + void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) override {} + void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) override {} + void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) override {} + void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) override {} + void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) override {} + 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) override {} + void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) override {} + void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) override {} + void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) override {} + + uint32_t geometry_instance_get_pair_mask() override { return 0; } + void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) override {} + void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {} + void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) override {} + void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) override {} + + void geometry_instance_free(GeometryInstance *p_geometry_instance) override {} + /* SHADOW ATLAS API */ - RID shadow_atlas_create() { return RID(); } - void shadow_atlas_set_size(RID p_atlas, int p_size) {} - 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) { return false; } + RID shadow_atlas_create() override { return RID(); } + void shadow_atlas_set_size(RID p_atlas, int p_size) override {} + void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override {} + bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override { return false; } + + void directional_shadow_atlas_set_size(int p_size) override {} + int get_directional_light_shadow_size(RID p_light_intance) override { return 0; } + void set_directional_shadow_count(int p_count) override {} - void directional_shadow_atlas_set_size(int p_size) {} - int get_directional_light_shadow_size(RID p_light_intance) { return 0; } - void set_directional_shadow_count(int p_count) {} + /* SDFGI UPDATE */ + + void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) override {} + int sdfgi_get_pending_region_count(RID p_render_buffers) const override { return 0; } + AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const override { return AABB(); } + uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const override { return 0; } + 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) override {} /* SKY API */ - RID sky_create() { return RID(); } - void sky_set_radiance_size(RID p_sky, int p_radiance_size) {} - void sky_set_mode(RID p_sky, RS::SkyMode p_samples) {} - void sky_set_texture(RID p_sky, RID p_panorama) {} - void sky_set_texture(RID p_sky, RID p_cube_map, int p_radiance_size) {} - void sky_set_material(RID p_sky, RID p_material) {} + RID sky_create() override { return RID(); } + void sky_set_radiance_size(RID p_sky, int p_radiance_size) override {} + void sky_set_mode(RID p_sky, RS::SkyMode p_samples) override {} + void sky_set_material(RID p_sky, RID p_material) override {} + Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) override { return Ref<Image>(); } /* ENVIRONMENT API */ - RID environment_create() { return RID(); } + RID environment_create() override { return RID(); } - void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) {} - void environment_set_sky(RID p_env, RID p_sky) {} - void environment_set_sky_custom_fov(RID p_env, float p_scale) {} - void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) {} - void environment_set_bg_color(RID p_env, const Color &p_color) {} - void environment_set_bg_energy(RID p_env, float p_energy) {} - void environment_set_canvas_max_layer(RID p_env, int p_max_layer) {} - void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) {} -// FIXME: Disabled during Vulkan refactoring, should be ported. -#if 0 - void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) {} -#endif + void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) override {} + void environment_set_sky(RID p_env, RID p_sky) override {} + void environment_set_sky_custom_fov(RID p_env, float p_scale) override {} + void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) override {} + void environment_set_bg_color(RID p_env, const Color &p_color) override {} + void environment_set_bg_energy(RID p_env, float p_energy) override {} + void environment_set_canvas_max_layer(RID p_env, int p_max_layer) override {} + 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()) override {} + + 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) override {} + void environment_glow_set_use_bicubic_upscale(bool p_enable) override {} + void environment_glow_set_use_high_quality(bool p_enable) override {} + + 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) override {} + void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override {} + 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) override {} + 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) override {} + + 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) override {} + + void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) override {} + void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) override {} + + 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) override {} + + 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) override {} + + 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) override {} + 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) override {} + void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) override {} + void environment_set_volumetric_fog_filter_active(bool p_enable) override {} + void environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size) override {} + void environment_set_volumetric_fog_positional_shadow_shrink_size(int p_shrink_size) override {} + + Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) override { return Ref<Image>(); } + + bool is_environment(RID p_env) const override { return false; } + RS::EnvironmentBG environment_get_background(RID p_env) const override { return RS::ENV_BG_KEEP; } + int environment_get_canvas_max_layer(RID p_env) const override { return 0; } - void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, 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) {} + RID camera_effects_create() override { return RID(); } - void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {} + void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) override {} + void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) override {} - 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, bool p_roughness) {} - 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) {} - virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size) {} + 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) override {} + void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) override {} - 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 shadows_quality_set(RS::ShadowQuality p_quality) override {} + void directional_shadow_quality_set(RS::ShadowQuality p_quality) override {} - void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) {} + RID light_instance_create(RID p_light) override { return RID(); } + void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) override {} + void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override {} + 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()) override {} + void light_instance_mark_visible(RID p_light_instance) override {} - void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) {} - void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) {} - void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) {} + RID reflection_atlas_create() override { return RID(); } + int reflection_atlas_get_size(RID p_ref_atlas) const override { return 0; } + void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override {} - bool is_environment(RID p_env) const { return false; } - RS::EnvironmentBG environment_get_background(RID p_env) const { return RS::ENV_BG_KEEP; } - int environment_get_canvas_max_layer(RID p_env) const { return 0; } + RID reflection_probe_instance_create(RID p_probe) override { return RID(); } + void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) override {} + void reflection_probe_release_atlas_index(RID p_instance) override {} + bool reflection_probe_instance_needs_redraw(RID p_instance) override { return false; } + bool reflection_probe_instance_has_reflection(RID p_instance) override { return false; } + bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override { return false; } + bool reflection_probe_instance_postprocess_step(RID p_instance) override { return true; } - virtual RID camera_effects_create() { return RID(); } + RID decal_instance_create(RID p_decal) override { return RID(); } + void decal_instance_set_transform(RID p_decal, const Transform &p_transform) override {} - virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) {} - virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) {} + RID lightmap_instance_create(RID p_lightmap) override { return RID(); } + void lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform) override {} - 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) {} - virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) {} + RID gi_probe_instance_create(RID p_gi_probe) override { return RID(); } + void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) override {} + bool gi_probe_needs_update(RID p_probe) const override { return false; } + 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) override {} - RID light_instance_create(RID p_light) { return RID(); } - void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) {} - 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_bias_scale = 1.0) {} - void light_instance_mark_visible(RID p_light_instance) {} + void gi_probe_set_quality(RS::GIProbeQuality) override {} - RID reflection_atlas_create() { return RID(); } - virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) {} + void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold) override {} + 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) override {} + 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) override {} + void render_sdfgi(RID p_render_buffers, int p_region, const PagedArray<GeometryInstance *> &p_instances) override {} + 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) override {} + void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) override {} - RID reflection_probe_instance_create(RID p_probe) { return RID(); } - void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) {} - void reflection_probe_release_atlas_index(RID p_instance) {} - bool reflection_probe_instance_needs_redraw(RID p_instance) { return false; } - bool reflection_probe_instance_has_reflection(RID p_instance) { return false; } - bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { return false; } - bool reflection_probe_instance_postprocess_step(RID p_instance) { return true; } + void set_scene_pass(uint64_t p_pass) override {} + void set_time(double p_time, double p_step) override {} + void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) override {} - virtual RID gi_probe_instance_create(RID p_gi_probe) { return RID(); } - void gi_probe_instance_set_light_data(RID p_probe, RID p_base, RID p_data) {} - void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) {} - virtual bool gi_probe_needs_update(RID p_probe) const { return false; } - 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) {} + RID render_buffers_create() override { return RID(); } + 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) override {} - 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_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {} - void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) {} - 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) {} + void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override {} + bool screen_space_roughness_limiter_is_active() const override { return false; } - void set_scene_pass(uint64_t p_pass) {} - virtual void set_time(double p_time, double p_step) {} - void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) {} + void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override {} + void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override {} - virtual RID render_buffers_create() { return RID(); } - virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa) {} + TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) override { return TypedArray<Image>(); } - virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_curve) {} - virtual bool screen_space_roughness_limiter_is_active() const { return false; } + bool free(RID p_rid) override { return true; } + void update() override {} + void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override {} - bool free(RID p_rid) { return true; } - virtual void update() {} + bool is_low_end() const override { return true; } RasterizerSceneDummy() {} ~RasterizerSceneDummy() {} }; -class RasterizerStorageDummy : public RasterizerStorage { +class RasterizerStorageDummy : public RendererStorage { public: /* TEXTURE API */ struct DummyTexture { - int width; - int height; - uint32_t flags; - Image::Format format; + int width = 0; + int height = 0; + uint32_t flags = 0; + Image::Format format = Image::Format::FORMAT_MAX; Ref<Image> image; String path; }; struct DummySurface { - uint32_t format; - RS::PrimitiveType primitive; + uint32_t format = 0; + RS::PrimitiveType primitive = RS::PrimitiveType::PRIMITIVE_MAX; Vector<uint8_t> array; - int vertex_count; + int vertex_count = 0; Vector<uint8_t> index_array; - int index_count; + int index_count = 0; AABB aabb; Vector<Vector<uint8_t>> blend_shapes; Vector<AABB> bone_aabbs; @@ -174,58 +234,69 @@ public: struct DummyMesh { Vector<DummySurface> surfaces; - int blend_shape_count; - RS::BlendShapeMode blend_shape_mode; + int blend_shape_count = 0; + RS::BlendShapeMode blend_shape_mode = RS::BlendShapeMode::BLEND_SHAPE_MODE_NORMALIZED; }; mutable RID_PtrOwner<DummyTexture> texture_owner; mutable RID_PtrOwner<DummyMesh> mesh_owner; - virtual RID texture_2d_create(const Ref<Image> &p_image) { return RID(); } - virtual RID texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) { return RID(); } - virtual RID texture_3d_create(const Vector<Ref<Image>> &p_slices) { return RID(); } - virtual RID texture_proxy_create(RID p_base) { return RID(); } + RID texture_2d_create(const Ref<Image> &p_image) override { return RID(); } + RID texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) override { return RID(); } + RID texture_3d_create(Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) override { return RID(); } + RID texture_proxy_create(RID p_base) override { return RID(); } - virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) {} - virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) {} - virtual void texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap) {} - virtual void texture_proxy_update(RID p_proxy, RID p_base) {} + void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override {} + void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override {} + void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override {} + void texture_proxy_update(RID p_proxy, RID p_base) override {} - virtual RID texture_2d_placeholder_create() { return RID(); } - virtual RID texture_2d_layered_placeholder_create() { return RID(); } - virtual RID texture_3d_placeholder_create() { return RID(); } + RID texture_2d_placeholder_create() override { return RID(); } + RID texture_2d_layered_placeholder_create(RenderingServer::TextureLayeredType p_layered_type) override { return RID(); } + RID texture_3d_placeholder_create() override { return RID(); } - virtual Ref<Image> texture_2d_get(RID p_texture) const { return Ref<Image>(); } - virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const { return Ref<Image>(); } - virtual Ref<Image> texture_3d_slice_get(RID p_texture, int p_depth, int p_mipmap) const { return Ref<Image>(); } + Ref<Image> texture_2d_get(RID p_texture) const override { return Ref<Image>(); } + Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const override { return Ref<Image>(); } + Vector<Ref<Image>> texture_3d_get(RID p_texture) const override { return Vector<Ref<Image>>(); } - virtual void texture_replace(RID p_texture, RID p_by_texture) {} - virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) {} + void texture_replace(RID p_texture, RID p_by_texture) override {} + void texture_set_size_override(RID p_texture, int p_width, int p_height) override {} // FIXME: Disabled during Vulkan refactoring, should be ported. #if 0 - virtual void texture_bind(RID p_texture, uint32_t p_texture_no) = 0; + void texture_bind(RID p_texture, uint32_t p_texture_no) = 0; #endif - virtual void texture_set_path(RID p_texture, const String &p_path) {} - virtual String texture_get_path(RID p_texture) const { return String(); } + void texture_set_path(RID p_texture, const String &p_path) override {} + String texture_get_path(RID p_texture) const override { return String(); } - virtual void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {} - virtual void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {} - virtual void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) {} + void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override {} + void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override {} + void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) override {} - virtual void texture_debug_usage(List<RS::TextureInfo> *r_info) {} - virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) {} - virtual Size2 texture_size_with_proxy(RID p_proxy) { return Size2(); } + void texture_debug_usage(List<RS::TextureInfo> *r_info) override {} + void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) override {} + Size2 texture_size_with_proxy(RID p_proxy) override { return Size2(); } -#if 0 - RID texture_create() { + void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {} + void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {} + + /* CANVAS TEXTURE API */ + + RID canvas_texture_create() override { return RID(); } + void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) override {} + void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) override {} + + void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override {} + void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override {} +#if 0 + RID texture_create() override { DummyTexture *texture = memnew(DummyTexture); ERR_FAIL_COND_V(!texture, RID()); return texture_owner.make_rid(texture); } - void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, RenderingServer::TextureType p_type = RS::TEXTURE_TYPE_2D, uint32_t p_flags = RS::TEXTURE_FLAGS_DEFAULT) { + void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, RenderingServer::TextureType p_type = RS::TEXTURE_TYPE_2D, uint32_t p_flags = RS::TEXTURE_FLAGS_DEFAULT) override { DummyTexture *t = texture_owner.getornull(p_texture); ERR_FAIL_COND(!t); t->width = p_width; @@ -235,7 +306,7 @@ public: t->image = Ref<Image>(memnew(Image)); t->image->create(p_width, p_height, false, p_format); } - void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_level) { + void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_level) override { DummyTexture *t = texture_owner.getornull(p_texture); ERR_FAIL_COND(!t); t->width = p_image->get_width(); @@ -244,7 +315,7 @@ public: t->image->create(t->width, t->height, false, t->format, p_image->get_data()); } - void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_level) { + void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_level) override { DummyTexture *t = texture_owner.getornull(p_texture); ERR_FAIL_COND(!t); @@ -257,99 +328,97 @@ public: t->image->blit_rect(p_image, Rect2(src_x, src_y, src_w, src_h), Vector2(dst_x, dst_y)); } - Ref<Image> texture_get_data(RID p_texture, int p_level) const { + Ref<Image> texture_get_data(RID p_texture, int p_level) const override { DummyTexture *t = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!t, Ref<Image>()); return t->image; } - void texture_set_flags(RID p_texture, uint32_t p_flags) { + void texture_set_flags(RID p_texture, uint32_t p_flags) override { DummyTexture *t = texture_owner.getornull(p_texture); ERR_FAIL_COND(!t); t->flags = p_flags; } - uint32_t texture_get_flags(RID p_texture) const { + uint32_t texture_get_flags(RID p_texture) const override { DummyTexture *t = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!t, 0); return t->flags; } - Image::Format texture_get_format(RID p_texture) const { + Image::Format texture_get_format(RID p_texture) const override { DummyTexture *t = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!t, Image::FORMAT_RGB8); return t->format; } - RenderingServer::TextureType texture_get_type(RID p_texture) const { return RS::TEXTURE_TYPE_2D; } - uint32_t texture_get_texid(RID p_texture) const { return 0; } - uint32_t texture_get_width(RID p_texture) const { return 0; } - uint32_t texture_get_height(RID p_texture) const { return 0; } - uint32_t texture_get_depth(RID p_texture) const { return 0; } - void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth_3d) {} - void texture_bind(RID p_texture, uint32_t p_texture_no) {} + RenderingServer::TextureType texture_get_type(RID p_texture) const override { return RS::TEXTURE_TYPE_2D; } + uint32_t texture_get_texid(RID p_texture) const override { return 0; } + uint32_t texture_get_width(RID p_texture) const override { return 0; } + uint32_t texture_get_height(RID p_texture) const override { return 0; } + uint32_t texture_get_depth(RID p_texture) const override { return 0; } + void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth_3d) override {} + void texture_bind(RID p_texture, uint32_t p_texture_no) override {} - void texture_set_path(RID p_texture, const String &p_path) { + void texture_set_path(RID p_texture, const String &p_path) override { DummyTexture *t = texture_owner.getornull(p_texture); ERR_FAIL_COND(!t); t->path = p_path; } - String texture_get_path(RID p_texture) const { + String texture_get_path(RID p_texture) const override { DummyTexture *t = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!t, String()); return t->path; } - void texture_set_shrink_all_x2_on_set_data(bool p_enable) {} + void texture_set_shrink_all_x2_on_set_data(bool p_enable) override {} - void texture_debug_usage(List<RS::TextureInfo> *r_info) {} + void texture_debug_usage(List<RS::TextureInfo> *r_info) override {} - RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const { return RID(); } + RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const override { return RID(); } - void texture_set_detect_3d_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) {} - void texture_set_detect_srgb_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) {} - void texture_set_detect_normal_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) {} + void texture_set_detect_3d_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) override {} + void texture_set_detect_srgb_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) override {} + void texture_set_detect_normal_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) override {} - void textures_keep_original(bool p_enable) {} + void textures_keep_original(bool p_enable) override {} - void texture_set_proxy(RID p_proxy, RID p_base) {} - virtual Size2 texture_size_with_proxy(RID p_texture) const { return Size2(); } - void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) {} + void texture_set_proxy(RID p_proxy, RID p_base) override {} + Size2 texture_size_with_proxy(RID p_texture) const override { return Size2(); } + void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) override {} #endif - /* SKY API */ - - RID sky_create() { return RID(); } - void sky_set_texture(RID p_sky, RID p_cube_map, int p_radiance_size) {} - /* SHADER API */ - RID shader_create() { return RID(); } + RID shader_create() override { return RID(); } + + void shader_set_code(RID p_shader, const String &p_code) override {} + String shader_get_code(RID p_shader) const override { return ""; } + void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const override {} - void shader_set_code(RID p_shader, const String &p_code) {} - String shader_get_code(RID p_shader) const { return ""; } - void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const {} + void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) override {} + RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const override { return RID(); } + Variant shader_get_param_default(RID p_material, const StringName &p_param) const override { return Variant(); } - void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) {} - RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const { return RID(); } - virtual Variant shader_get_param_default(RID p_material, const StringName &p_param) const { return Variant(); } + RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override { return RS::ShaderNativeSourceCode(); }; /* COMMON MATERIAL API */ - RID material_create() { return RID(); } + RID material_create() override { return RID(); } - void material_set_render_priority(RID p_material, int priority) {} - void material_set_shader(RID p_shader_material, RID p_shader) {} + void material_set_render_priority(RID p_material, int priority) override {} + void material_set_shader(RID p_shader_material, RID p_shader) override {} - void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) {} - Variant material_get_param(RID p_material, const StringName &p_param) const { return Variant(); } + void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) override {} + Variant material_get_param(RID p_material, const StringName &p_param) const override { return Variant(); } - void material_set_next_pass(RID p_material, RID p_next_material) {} + void material_set_next_pass(RID p_material, RID p_next_material) override {} - bool material_is_animated(RID p_material) { return false; } - bool material_casts_shadows(RID p_material) { return false; } - void material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) {} + bool material_is_animated(RID p_material) override { return false; } + bool material_casts_shadows(RID p_material) override { return false; } + void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) override {} + void material_update_dependency(RID p_material, DependencyTracker *p_instance) override {} /* MESH API */ - RID mesh_create() { + RID mesh_create() override { DummyMesh *mesh = memnew(DummyMesh); ERR_FAIL_COND_V(!mesh, RID()); mesh->blend_shape_count = 0; @@ -357,10 +426,20 @@ public: return mesh_owner.make_rid(mesh); } - void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) {} + void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override {} + bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override { return false; } + RID mesh_instance_create(RID p_base) override { return RID(); } + void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override {} + void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) override {} + void mesh_instance_check_for_update(RID p_mesh_instance) override {} + void update_mesh_instances() override {} + void reflection_probe_set_lod_threshold(RID p_probe, float p_ratio) override {} + float reflection_probe_get_lod_threshold(RID p_probe) const override { return 0.0; } + + void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override {} #if 0 - void mesh_add_surface(RID p_mesh, uint32_t p_format, RS::PrimitiveType p_primitive, const Vector<uint8_t> &p_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<Vector<uint8_t> > &p_blend_shapes = Vector<Vector<uint8_t> >(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>()) { + void mesh_add_surface(RID p_mesh, uint32_t p_format, RS::PrimitiveType p_primitive, const Vector<uint8_t> &p_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<Vector<uint8_t> > &p_blend_shapes = Vector<Vector<uint8_t> >(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>()) override { DummyMesh *m = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!m); @@ -377,95 +456,95 @@ public: s->bone_aabbs = p_bone_aabbs; } - void mesh_set_blend_shape_count(RID p_mesh, int p_amount) { + void mesh_set_blend_shape_count(RID p_mesh, int p_amount) override { DummyMesh *m = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!m); m->blend_shape_count = p_amount; } #endif - int mesh_get_blend_shape_count(RID p_mesh) const { + int mesh_get_blend_shape_count(RID p_mesh) const override { DummyMesh *m = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!m, 0); return m->blend_shape_count; } - void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) { + void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override { DummyMesh *m = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!m); m->blend_shape_mode = p_mode; } - RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const { + RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override { DummyMesh *m = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!m, RS::BLEND_SHAPE_MODE_NORMALIZED); return m->blend_shape_mode; } - void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {} + void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {} - void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) {} - RID mesh_surface_get_material(RID p_mesh, int p_surface) const { return RID(); } + void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override {} + RID mesh_surface_get_material(RID p_mesh, int p_surface) const override { return RID(); } #if 0 - int mesh_surface_get_array_len(RID p_mesh, int p_surface) const { + int mesh_surface_get_array_len(RID p_mesh, int p_surface) const override { DummyMesh *m = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!m, 0); return m->surfaces[p_surface].vertex_count; } - int mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const { + int mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const override { DummyMesh *m = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!m, 0); return m->surfaces[p_surface].index_count; } - Vector<uint8_t> mesh_surface_get_array(RID p_mesh, int p_surface) const { + Vector<uint8_t> mesh_surface_get_array(RID p_mesh, int p_surface) const override { DummyMesh *m = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!m, Vector<uint8_t>()); return m->surfaces[p_surface].array; } - Vector<uint8_t> mesh_surface_get_index_array(RID p_mesh, int p_surface) const { + Vector<uint8_t> mesh_surface_get_index_array(RID p_mesh, int p_surface) const override { DummyMesh *m = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!m, Vector<uint8_t>()); return m->surfaces[p_surface].index_array; } - uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const { + uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const override { DummyMesh *m = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!m, 0); return m->surfaces[p_surface].format; } - RS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const { + RS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const override { DummyMesh *m = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!m, RS::PRIMITIVE_POINTS); return m->surfaces[p_surface].primitive; } - AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const { + AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const override { DummyMesh *m = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!m, AABB()); return m->surfaces[p_surface].aabb; } - Vector<Vector<uint8_t> > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const { + Vector<Vector<uint8_t> > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const override { DummyMesh *m = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!m, Vector<Vector<uint8_t> >()); return m->surfaces[p_surface].blend_shapes; } - Vector<AABB> mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const { + Vector<AABB> mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const override { DummyMesh *m = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!m, Vector<AABB>()); return m->surfaces[p_surface].bone_aabbs; } - void mesh_remove_surface(RID p_mesh, int p_index) { + void mesh_remove_surface(RID p_mesh, int p_index) override { DummyMesh *m = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!m); ERR_FAIL_COND(p_index >= m->surfaces.size()); @@ -474,309 +553,387 @@ public: } #endif - RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const { return RS::SurfaceData(); } - int mesh_get_surface_count(RID p_mesh) const { + RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override { return RS::SurfaceData(); } + int mesh_get_surface_count(RID p_mesh) const override { DummyMesh *m = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!m, 0); return m->surfaces.size(); } - void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) {} - AABB mesh_get_custom_aabb(RID p_mesh) const { return AABB(); } + void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override {} + AABB mesh_get_custom_aabb(RID p_mesh) const override { return AABB(); } - AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) { return AABB(); } - void mesh_clear(RID p_mesh) {} + AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override { return AABB(); } + void mesh_clear(RID p_mesh) override {} /* MULTIMESH API */ - virtual RID multimesh_create() { return RID(); } + RID multimesh_create() override { return RID(); } - 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) {} - int multimesh_get_instance_count(RID p_multimesh) const { return 0; } + 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) override {} + int multimesh_get_instance_count(RID p_multimesh) const override { return 0; } - void multimesh_set_mesh(RID p_multimesh, RID p_mesh) {} - void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) {} - void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) {} - void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) {} - void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) {} + void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override {} + void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) override {} + void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override {} + void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override {} + void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override {} - RID multimesh_get_mesh(RID p_multimesh) const { return RID(); } - AABB multimesh_get_aabb(RID p_multimesh) const { return AABB(); } + RID multimesh_get_mesh(RID p_multimesh) const override { return RID(); } + AABB multimesh_get_aabb(RID p_multimesh) const override { return AABB(); } - Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const { return Transform(); } - Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const { return Transform2D(); } - Color multimesh_instance_get_color(RID p_multimesh, int p_index) const { return Color(); } - Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const { return Color(); } - virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {} - virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const { return Vector<float>(); } + Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const override { return Transform(); } + Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override { return Transform2D(); } + Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override { return Color(); } + Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override { return Color(); } + void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override {} + Vector<float> multimesh_get_buffer(RID p_multimesh) const override { return Vector<float>(); } - void multimesh_set_visible_instances(RID p_multimesh, int p_visible) {} - int multimesh_get_visible_instances(RID p_multimesh) const { return 0; } + void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override {} + int multimesh_get_visible_instances(RID p_multimesh) const override { return 0; } /* IMMEDIATE API */ - RID immediate_create() { return RID(); } - void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) {} - void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) {} - void immediate_normal(RID p_immediate, const Vector3 &p_normal) {} - void immediate_tangent(RID p_immediate, const Plane &p_tangent) {} - void immediate_color(RID p_immediate, const Color &p_color) {} - void immediate_uv(RID p_immediate, const Vector2 &tex_uv) {} - void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) {} - void immediate_end(RID p_immediate) {} - void immediate_clear(RID p_immediate) {} - void immediate_set_material(RID p_immediate, RID p_material) {} - RID immediate_get_material(RID p_immediate) const { return RID(); } - AABB immediate_get_aabb(RID p_immediate) const { return AABB(); } + RID immediate_create() override { return RID(); } + void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) override {} + void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) override {} + void immediate_normal(RID p_immediate, const Vector3 &p_normal) override {} + void immediate_tangent(RID p_immediate, const Plane &p_tangent) override {} + void immediate_color(RID p_immediate, const Color &p_color) override {} + void immediate_uv(RID p_immediate, const Vector2 &tex_uv) override {} + void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) override {} + void immediate_end(RID p_immediate) override {} + void immediate_clear(RID p_immediate) override {} + void immediate_set_material(RID p_immediate, RID p_material) override {} + RID immediate_get_material(RID p_immediate) const override { return RID(); } + AABB immediate_get_aabb(RID p_immediate) const override { return AABB(); } /* SKELETON API */ - RID skeleton_create() { return RID(); } - void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) {} - void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) {} - void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_world_transform) {} - int skeleton_get_bone_count(RID p_skeleton) const { return 0; } - void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) {} - Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { return Transform(); } - 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 { return Transform2D(); } + RID skeleton_create() override { return RID(); } + void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) override {} + void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) override {} + int skeleton_get_bone_count(RID p_skeleton) const override { return 0; } + void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) override {} + Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override { return Transform(); } + void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) override {} + Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const override { return Transform2D(); } /* Light API */ - RID light_create(RS::LightType p_type) { return RID(); } - - 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); } - - void light_set_color(RID p_light, const Color &p_color) {} - void light_set_param(RID p_light, RS::LightParam p_param, float p_value) {} - void light_set_shadow(RID p_light, bool p_enabled) {} - void light_set_shadow_color(RID p_light, const Color &p_color) {} - void light_set_projector(RID p_light, RID p_texture) {} - void light_set_negative(RID p_light, bool p_enable) {} - void light_set_cull_mask(RID p_light, uint32_t p_mask) {} - void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) {} - void light_set_use_gi(RID p_light, bool p_enabled) {} - - void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) {} - - 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 { return false; } - 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 { return RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE; } - - RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) { return RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; } - RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) { return RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; } - - bool light_has_shadow(RID p_light) const { return false; } - - RS::LightType light_get_type(RID p_light) const { return RS::LIGHT_OMNI; } - AABB light_get_aabb(RID p_light) const { return AABB(); } - float light_get_param(RID p_light, RS::LightParam p_param) { return 0.0; } - Color light_get_color(RID p_light) { return Color(); } - bool light_get_use_gi(RID p_light) { return false; } - uint64_t light_get_version(RID p_light) const { return 0; } + RID light_create(RS::LightType p_type) override { return RID(); } + + void light_set_color(RID p_light, const Color &p_color) override {} + void light_set_param(RID p_light, RS::LightParam p_param, float p_value) override {} + void light_set_shadow(RID p_light, bool p_enabled) override {} + void light_set_shadow_color(RID p_light, const Color &p_color) override {} + void light_set_projector(RID p_light, RID p_texture) override {} + void light_set_negative(RID p_light, bool p_enable) override {} + void light_set_cull_mask(RID p_light, uint32_t p_mask) override {} + void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) override {} + void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) override {} + void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) override {} + + void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) override {} + + void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) override {} + void light_directional_set_blend_splits(RID p_light, bool p_enable) override {} + bool light_directional_get_blend_splits(RID p_light) const override { return false; } + void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) override {} + void light_directional_set_sky_only(RID p_light, bool p_sky_only) override {} + bool light_directional_is_sky_only(RID p_light) const override { return false; } + RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const override { return RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE; } + + RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) override { return RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; } + RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) override { return RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; } + + bool light_has_shadow(RID p_light) const override { return false; } + + RS::LightType light_get_type(RID p_light) const override { return RS::LIGHT_OMNI; } + AABB light_get_aabb(RID p_light) const override { return AABB(); } + float light_get_param(RID p_light, RS::LightParam p_param) override { return 0.0; } + Color light_get_color(RID p_light) override { return Color(); } + RS::LightBakeMode light_get_bake_mode(RID p_light) override { return RS::LIGHT_BAKE_DISABLED; } + uint32_t light_get_max_sdfgi_cascade(RID p_light) override { return 0; } + uint64_t light_get_version(RID p_light) const override { return 0; } /* PROBE API */ - RID reflection_probe_create() { return RID(); } - - void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) {} - void reflection_probe_set_intensity(RID p_probe, float p_intensity) {} - void reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient) {} - void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) {} - void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) {} - void reflection_probe_set_max_distance(RID p_probe, float p_distance) {} - void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) {} - void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) {} - void reflection_probe_set_as_interior(RID p_probe, bool p_enable) {} - void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {} - 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) {} - - AABB reflection_probe_get_aabb(RID p_probe) const { return AABB(); } - RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const { return RenderingServer::REFLECTION_PROBE_UPDATE_ONCE; } - uint32_t reflection_probe_get_cull_mask(RID p_probe) const { return 0; } - Vector3 reflection_probe_get_extents(RID p_probe) const { return Vector3(); } - Vector3 reflection_probe_get_origin_offset(RID p_probe) const { return Vector3(); } - float reflection_probe_get_origin_max_distance(RID p_probe) const { return 0.0; } - bool reflection_probe_renders_shadows(RID p_probe) const { return false; } - - virtual void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {} - virtual void skeleton_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {} + RID reflection_probe_create() override { return RID(); } + + void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) override {} + void reflection_probe_set_intensity(RID p_probe, float p_intensity) override {} + void reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) override {} + void reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) override {} + void reflection_probe_set_ambient_energy(RID p_probe, float p_energy) override {} + void reflection_probe_set_max_distance(RID p_probe, float p_distance) override {} + void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) override {} + void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) override {} + void reflection_probe_set_as_interior(RID p_probe, bool p_enable) override {} + void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) override {} + void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) override {} + void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) override {} + void reflection_probe_set_resolution(RID p_probe, int p_resolution) override {} + + AABB reflection_probe_get_aabb(RID p_probe) const override { return AABB(); } + RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const override { return RenderingServer::REFLECTION_PROBE_UPDATE_ONCE; } + uint32_t reflection_probe_get_cull_mask(RID p_probe) const override { return 0; } + Vector3 reflection_probe_get_extents(RID p_probe) const override { return Vector3(); } + Vector3 reflection_probe_get_origin_offset(RID p_probe) const override { return Vector3(); } + float reflection_probe_get_origin_max_distance(RID p_probe) const override { return 0.0; } + bool reflection_probe_renders_shadows(RID p_probe) const override { return false; } + + void base_update_dependency(RID p_base, DependencyTracker *p_instance) override {} + void skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) override {} + + /* DECAL API */ + + RID decal_create() override { return RID(); } + void decal_set_extents(RID p_decal, const Vector3 &p_extents) override {} + void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) override {} + void decal_set_emission_energy(RID p_decal, float p_energy) override {} + void decal_set_albedo_mix(RID p_decal, float p_mix) override {} + void decal_set_modulate(RID p_decal, const Color &p_modulate) override {} + void decal_set_cull_mask(RID p_decal, uint32_t p_layers) override {} + void decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) override {} + void decal_set_fade(RID p_decal, float p_above, float p_below) override {} + void decal_set_normal_fade(RID p_decal, float p_fade) override {} + + AABB decal_get_aabb(RID p_decal) const override { return AABB(); } /* GI PROBE API */ - RID gi_probe_create() { return RID(); } + RID gi_probe_create() override { return RID(); } - 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) {} + 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) override {} - virtual AABB gi_probe_get_bounds(RID p_gi_probe) const { return AABB(); } - virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const { return Vector3i(); } - virtual Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const { return Vector<uint8_t>(); } - virtual Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const { return Vector<uint8_t>(); } - virtual Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const { return Vector<uint8_t>(); } + AABB gi_probe_get_bounds(RID p_gi_probe) const override { return AABB(); } + Vector3i gi_probe_get_octree_size(RID p_gi_probe) const override { return Vector3i(); } + Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const override { return Vector<uint8_t>(); } + Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const override { return Vector<uint8_t>(); } + Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const override { return Vector<uint8_t>(); } - virtual Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const { return Vector<int>(); } - virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const { return Transform(); } + Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const override { return Vector<int>(); } + Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const override { return Transform(); } - virtual void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) {} - virtual float gi_probe_get_dynamic_range(RID p_gi_probe) const { return 0; } + void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) override {} + float gi_probe_get_dynamic_range(RID p_gi_probe) const override { return 0; } - virtual void gi_probe_set_propagation(RID p_gi_probe, float p_range) {} - virtual float gi_probe_get_propagation(RID p_gi_probe) const { return 0; } + void gi_probe_set_propagation(RID p_gi_probe, float p_range) override {} + float gi_probe_get_propagation(RID p_gi_probe) const override { return 0; } - void gi_probe_set_energy(RID p_gi_probe, float p_range) {} - float gi_probe_get_energy(RID p_gi_probe) const { return 0.0; } + void gi_probe_set_energy(RID p_gi_probe, float p_range) override {} + float gi_probe_get_energy(RID p_gi_probe) const override { return 0.0; } - virtual void gi_probe_set_ao(RID p_gi_probe, float p_ao) {} - virtual float gi_probe_get_ao(RID p_gi_probe) const { return 0; } + void gi_probe_set_ao(RID p_gi_probe, float p_ao) override {} + float gi_probe_get_ao(RID p_gi_probe) const override { return 0; } - virtual void gi_probe_set_ao_size(RID p_gi_probe, float p_strength) {} - virtual float gi_probe_get_ao_size(RID p_gi_probe) const { return 0; } + void gi_probe_set_ao_size(RID p_gi_probe, float p_strength) override {} + float gi_probe_get_ao_size(RID p_gi_probe) const override { return 0; } - void gi_probe_set_bias(RID p_gi_probe, float p_range) {} - float gi_probe_get_bias(RID p_gi_probe) const { return 0.0; } + void gi_probe_set_bias(RID p_gi_probe, float p_range) override {} + float gi_probe_get_bias(RID p_gi_probe) const override { return 0.0; } - void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) {} - float gi_probe_get_normal_bias(RID p_gi_probe) const { return 0.0; } + void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) override {} + float gi_probe_get_normal_bias(RID p_gi_probe) const override { return 0.0; } - void gi_probe_set_interior(RID p_gi_probe, bool p_enable) {} - bool gi_probe_is_interior(RID p_gi_probe) const { return false; } + void gi_probe_set_interior(RID p_gi_probe, bool p_enable) override {} + bool gi_probe_is_interior(RID p_gi_probe) const override { return false; } - virtual void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) {} - virtual bool gi_probe_is_using_two_bounces(RID p_gi_probe) const { return false; } + void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) override {} + bool gi_probe_is_using_two_bounces(RID p_gi_probe) const override { return false; } - virtual void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) {} - virtual float gi_probe_get_anisotropy_strength(RID p_gi_probe) const { return 0; } + void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) override {} + float gi_probe_get_anisotropy_strength(RID p_gi_probe) const override { return 0; } - uint32_t gi_probe_get_version(RID p_gi_probe) { return 0; } + uint32_t gi_probe_get_version(RID p_gi_probe) override { return 0; } /* LIGHTMAP CAPTURE */ +#if 0 struct Instantiable { + SelfList<RendererSceneRender::GeometryInstance>::List instance_list; - SelfList<RasterizerScene::InstanceBase>::List instance_list; - - _FORCE_INLINE_ void instance_change_notify(bool p_aabb = true, bool p_materials = true) { - - SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); - while (instances) { - + _FORCE_INLINE_ void instance_change_notify(bool p_aabb = true, bool p_materials = true) override { + SelfList<RendererSceneRender::GeometryInstance> *instances = instance_list.first(); + while (instances) override { //instances->self()->base_changed(p_aabb, p_materials); instances = instances->next(); } } - _FORCE_INLINE_ void instance_remove_deps() { - SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); - while (instances) { - - SelfList<RasterizerScene::InstanceBase> *next = instances->next(); + _FORCE_INLINE_ void instance_remove_deps() override { + SelfList<RendererSceneRender::GeometryInstance> *instances = instance_list.first(); + while (instances) override { + SelfList<RendererSceneRender::GeometryInstance> *next = instances->next(); //instances->self()->base_removed(); instances = next; } } - Instantiable() {} - virtual ~Instantiable() { + Instantiable() override {} + ~Instantiable() override { } }; struct LightmapCapture : public Instantiable { - Vector<LightmapCaptureOctree> octree; AABB bounds; Transform cell_xform; int cell_subdiv; float energy; - LightmapCapture() { + LightmapCapture() override { energy = 1.0; cell_subdiv = 1; } }; mutable RID_PtrOwner<LightmapCapture> lightmap_capture_data_owner; - void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) {} - AABB lightmap_capture_get_bounds(RID p_capture) const { return AABB(); } - void lightmap_capture_set_octree(RID p_capture, const Vector<uint8_t> &p_octree) {} - RID lightmap_capture_create() { + void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) override {} + AABB lightmap_capture_get_bounds(RID p_capture) const override { return AABB(); } + void lightmap_capture_set_octree(RID p_capture, const Vector<uint8_t> &p_octree) override {} + RID lightmap_capture_create() override { LightmapCapture *capture = memnew(LightmapCapture); return lightmap_capture_data_owner.make_rid(capture); } - Vector<uint8_t> lightmap_capture_get_octree(RID p_capture) const { + Vector<uint8_t> lightmap_capture_get_octree(RID p_capture) const override { const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); ERR_FAIL_COND_V(!capture, Vector<uint8_t>()); return Vector<uint8_t>(); } - void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) {} - Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const { return Transform(); } - void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) {} - int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const { return 0; } - void lightmap_capture_set_energy(RID p_capture, float p_energy) {} - float lightmap_capture_get_energy(RID p_capture) const { return 0.0; } - const Vector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const { + void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) override {} + Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const override { return Transform(); } + void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) override {} + int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const override { return 0; } + void lightmap_capture_set_energy(RID p_capture, float p_energy) override {} + float lightmap_capture_get_energy(RID p_capture) const override { return 0.0; } + const Vector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const override { const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); ERR_FAIL_COND_V(!capture, nullptr); return &capture->octree; } +#endif - /* PARTICLES */ - - RID particles_create() { return RID(); } - - void particles_set_emitting(RID p_particles, bool p_emitting) {} - void particles_set_amount(RID p_particles, int p_amount) {} - void particles_set_lifetime(RID p_particles, float p_lifetime) {} - void particles_set_one_shot(RID p_particles, bool p_one_shot) {} - void particles_set_pre_process_time(RID p_particles, float p_time) {} - void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) {} - void particles_set_randomness_ratio(RID p_particles, float p_ratio) {} - void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) {} - void particles_set_speed_scale(RID p_particles, float p_scale) {} - void particles_set_use_local_coordinates(RID p_particles, bool p_enable) {} - void particles_set_process_material(RID p_particles, RID p_material) {} - void particles_set_fixed_fps(RID p_particles, int p_fps) {} - void particles_set_fractional_delta(RID p_particles, bool p_enable) {} - void particles_restart(RID p_particles) {} - - void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) {} - - void particles_set_draw_passes(RID p_particles, int p_count) {} - void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {} - - void particles_request_process(RID p_particles) {} - AABB particles_get_current_aabb(RID p_particles) { return AABB(); } - AABB particles_get_aabb(RID p_particles) const { return AABB(); } - - void particles_set_emission_transform(RID p_particles, const Transform &p_transform) {} + RID lightmap_create() override { return RID(); } + + void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) override {} + void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) override {} + void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) override {} + 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) override {} + PackedVector3Array lightmap_get_probe_capture_points(RID p_lightmap) const override { return PackedVector3Array(); } + PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const override { return PackedColorArray(); } + PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const override { return PackedInt32Array(); } + PackedInt32Array lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const override { return PackedInt32Array(); } + AABB lightmap_get_aabb(RID p_lightmap) const override { return AABB(); } + void lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) override {} + bool lightmap_is_interior(RID p_lightmap) const override { return false; } + void lightmap_set_probe_capture_update_speed(float p_speed) override {} + float lightmap_get_probe_capture_update_speed() const override { return 0; } - bool particles_get_emitting(RID p_particles) { return false; } - int particles_get_draw_passes(RID p_particles) const { return 0; } - RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { return RID(); } + /* PARTICLES */ - virtual bool particles_is_inactive(RID p_particles) const { return false; } + RID particles_create() override { return RID(); } + + 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) override {} + void particles_set_emitting(RID p_particles, bool p_emitting) override {} + void particles_set_amount(RID p_particles, int p_amount) override {} + void particles_set_lifetime(RID p_particles, float p_lifetime) override {} + void particles_set_one_shot(RID p_particles, bool p_one_shot) override {} + void particles_set_pre_process_time(RID p_particles, float p_time) override {} + void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) override {} + void particles_set_randomness_ratio(RID p_particles, float p_ratio) override {} + void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) override {} + void particles_set_speed_scale(RID p_particles, float p_scale) override {} + void particles_set_use_local_coordinates(RID p_particles, bool p_enable) override {} + void particles_set_process_material(RID p_particles, RID p_material) override {} + void particles_set_fixed_fps(RID p_particles, int p_fps) override {} + void particles_set_fractional_delta(RID p_particles, bool p_enable) override {} + void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) override {} + void particles_set_view_axis(RID p_particles, const Vector3 &p_axis) override {} + void particles_set_collision_base_size(RID p_particles, float p_size) override {} + void particles_restart(RID p_particles) override {} + + void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) override {} + + void particles_set_draw_passes(RID p_particles, int p_count) override {} + void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) override {} + + void particles_request_process(RID p_particles) override {} + AABB particles_get_current_aabb(RID p_particles) override { return AABB(); } + AABB particles_get_aabb(RID p_particles) const override { return AABB(); } + + void particles_set_emission_transform(RID p_particles, const Transform &p_transform) override {} + + bool particles_get_emitting(RID p_particles) override { return false; } + int particles_get_draw_passes(RID p_particles) const override { return 0; } + RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const override { return RID(); } + + void particles_add_collision(RID p_particles, RID p_instance) override {} + void particles_remove_collision(RID p_particles, RID p_instance) override {} + + void update_particles() override {} + + /* PARTICLES COLLISION */ + + RID particles_collision_create() override { return RID(); } + void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) override {} + void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) override {} + void particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius) override {} + void particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) override {} + void particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength) override {} + void particles_collision_set_attractor_directionality(RID p_particles_collision, float p_directionality) override {} + void particles_collision_set_attractor_attenuation(RID p_particles_collision, float p_curve) override {} + void particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) override {} + void particles_collision_height_field_update(RID p_particles_collision) override {} + void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) override {} + AABB particles_collision_get_aabb(RID p_particles_collision) const override { return AABB(); } + bool particles_collision_is_heightfield(RID p_particles_collision) const override { return false; } + RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const override { return RID(); } + + RID particles_collision_instance_create(RID p_collision) override { return RID(); }; + void particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform) override{}; + void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override{}; + + /* GLOBAL VARIABLES */ + + void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) override {} + void global_variable_remove(const StringName &p_name) override {} + Vector<StringName> global_variable_get_list() const override { return Vector<StringName>(); } + + void global_variable_set(const StringName &p_name, const Variant &p_value) override {} + void global_variable_set_override(const StringName &p_name, const Variant &p_value) override {} + Variant global_variable_get(const StringName &p_name) const override { return Variant(); } + RS::GlobalVariableType global_variable_get_type(const StringName &p_name) const override { return RS::GLOBAL_VAR_TYPE_MAX; } + + void global_variables_load_settings(bool p_load_textures = true) override {} + void global_variables_clear() override {} + + int32_t global_variables_instance_allocate(RID p_instance) override { return 0; } + void global_variables_instance_free(RID p_instance) override {} + void global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) override {} + + bool particles_is_inactive(RID p_particles) const override { return false; } /* RENDER TARGET */ - RID render_target_create() { return RID(); } - void render_target_set_position(RID p_render_target, int p_x, int p_y) {} - void render_target_set_size(RID p_render_target, int p_width, int p_height) {} - RID render_target_get_texture(RID p_render_target) { return RID(); } - void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {} - void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {} - bool render_target_was_used(RID p_render_target) { return false; } - void render_target_set_as_unused(RID p_render_target) {} - - virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) {} - virtual bool render_target_is_clear_requested(RID p_render_target) { return false; } - virtual Color render_target_get_clear_request_color(RID p_render_target) { return Color(); } - virtual void render_target_disable_clear_request(RID p_render_target) {} - virtual void render_target_do_clear_request(RID p_render_target) {} - - RS::InstanceType get_base_type(RID p_rid) const { + RID render_target_create() override { return RID(); } + void render_target_set_position(RID p_render_target, int p_x, int p_y) override {} + void render_target_set_size(RID p_render_target, int p_width, int p_height) override {} + RID render_target_get_texture(RID p_render_target) override { return RID(); } + void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override {} + void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) override {} + bool render_target_was_used(RID p_render_target) override { return false; } + void render_target_set_as_unused(RID p_render_target) override {} + + void render_target_request_clear(RID p_render_target, const Color &p_clear_color) override {} + bool render_target_is_clear_requested(RID p_render_target) override { return false; } + Color render_target_get_clear_request_color(RID p_render_target) override { return Color(); } + void render_target_disable_clear_request(RID p_render_target) override {} + void render_target_do_clear_request(RID p_render_target) override {} + + void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override {} + Rect2i render_target_get_sdf_rect(RID p_render_target) const override { return Rect2i(); } + + RS::InstanceType get_base_type(RID p_rid) const override { if (mesh_owner.owns(p_rid)) { return RS::INSTANCE_MESH; } @@ -784,101 +941,115 @@ public: return RS::INSTANCE_NONE; } - bool free(RID p_rid) { - + bool free(RID p_rid) override { if (texture_owner.owns(p_rid)) { // delete the texture DummyTexture *texture = texture_owner.getornull(p_rid); texture_owner.free(p_rid); memdelete(texture); } + + if (mesh_owner.owns(p_rid)) { + // delete the mesh + DummyMesh *mesh = mesh_owner.getornull(p_rid); + mesh_owner.free(p_rid); + memdelete(mesh); + } return true; } - bool has_os_feature(const String &p_feature) const { return false; } + bool has_os_feature(const String &p_feature) const override { return false; } - void update_dirty_resources() {} + void update_dirty_resources() override {} - void set_debug_generate_wireframes(bool p_generate) {} + void set_debug_generate_wireframes(bool p_generate) override {} - void render_info_begin_capture() {} - void render_info_end_capture() {} - int get_captured_render_info(RS::RenderInfo p_info) { return 0; } + void render_info_begin_capture() override {} + void render_info_end_capture() override {} + int get_captured_render_info(RS::RenderInfo p_info) override { return 0; } - int get_render_info(RS::RenderInfo p_info) { return 0; } - String get_video_adapter_name() const { return String(); } - String get_video_adapter_vendor() const { return String(); } + int get_render_info(RS::RenderInfo p_info) override { return 0; } + String get_video_adapter_name() const override { return String(); } + String get_video_adapter_vendor() const override { return String(); } - static RasterizerStorage *base_singleton; + static RendererStorage *base_singleton; - virtual void capture_timestamps_begin() {} - virtual void capture_timestamp(const String &p_name) {} - virtual uint32_t get_captured_timestamps_count() const { return 0; } - virtual uint64_t get_captured_timestamps_frame() const { return 0; } - virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const { return 0; } - virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const { return 0; } - virtual String get_captured_timestamp_name(uint32_t p_index) const { return String(); } + void capture_timestamps_begin() override {} + void capture_timestamp(const String &p_name) override {} + uint32_t get_captured_timestamps_count() const override { return 0; } + uint64_t get_captured_timestamps_frame() const override { return 0; } + uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const override { return 0; } + uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const override { return 0; } + String get_captured_timestamp_name(uint32_t p_index) const override { return String(); } RasterizerStorageDummy() {} ~RasterizerStorageDummy() {} }; -class RasterizerCanvasDummy : public RasterizerCanvas { +class RasterizerCanvasDummy : public RendererCanvasRender { public: - virtual TextureBindingID request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat, RID p_multimesh) { return 0; } - virtual void free_texture_binding(TextureBindingID p_binding) {} - - 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>()) { return 0; } - virtual void free_polygon(PolygonID p_polygon) {} + 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>()) override { return 0; } + void free_polygon(PolygonID p_polygon) override {} - 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) {} - virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) {} + 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) override {} + void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) override {} - virtual RID light_create() { return RID(); } - virtual void light_set_texture(RID p_rid, RID p_texture) {} - virtual void light_set_use_shadow(RID p_rid, bool p_enable, int p_resolution) {} - virtual void light_update_shadow(RID p_rid, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) {} + RID light_create() override { return RID(); } + void light_set_texture(RID p_rid, RID p_texture) override {} + void light_set_use_shadow(RID p_rid, bool p_enable) override {} + 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) override {} + 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) override {} - virtual RID occluder_polygon_create() { return RID(); } - virtual void occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines) {} - virtual void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) {} + void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) override {} + RID occluder_polygon_create() override { return RID(); } + void occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) override {} + void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) override {} + void set_shadow_texture_size(int p_size) override {} - void draw_window_margins(int *p_margins, RID *p_margin_textures) {} + void draw_window_margins(int *p_margins, RID *p_margin_textures) override {} - virtual bool free(RID p_rid) { return true; } - virtual void update() {} + bool free(RID p_rid) override { return true; } + void update() override {} RasterizerCanvasDummy() {} ~RasterizerCanvasDummy() {} }; -class RasterizerDummy : public Rasterizer { +class RasterizerDummy : public RendererCompositor { +private: + uint64_t frame = 1; + float delta = 0; + protected: RasterizerCanvasDummy canvas; RasterizerStorageDummy storage; RasterizerSceneDummy scene; public: - RasterizerStorage *get_storage() { return &storage; } - RasterizerCanvas *get_canvas() { return &canvas; } - RasterizerScene *get_scene() { return &scene; } - - void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) {} + RendererStorage *get_storage() override { return &storage; } + RendererCanvasRender *get_canvas() override { return &canvas; } + RendererSceneRender *get_scene() override { return &scene; } - void initialize() {} - void begin_frame(double frame_step) {} + void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) override {} - virtual void prepare_for_blitting_render_targets() {} - virtual void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) {} + void initialize() override {} + void begin_frame(double frame_step) override { + frame++; + delta = frame_step; + } - void end_frame(bool p_swap_buffers) { OS::get_singleton()->swap_buffers(); } - void finalize() {} + void prepare_for_blitting_render_targets() override {} + void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) override {} - static Error is_viable() { - return OK; + void end_frame(bool p_swap_buffers) override { + if (p_swap_buffers) { + DisplayServer::get_singleton()->swap_buffers(); + } } - static Rasterizer *_create_current() { + void finalize() override {} + + static RendererCompositor *_create_current() { return memnew(RasterizerDummy); } @@ -886,7 +1057,9 @@ public: _create_func = _create_current; } - virtual bool is_low_end() const { return true; } + bool is_low_end() const override { return true; } + uint64_t get_frame_number() const override { return frame; } + float get_frame_delta_time() const override { return delta; } RasterizerDummy() {} ~RasterizerDummy() {} diff --git a/drivers/dummy/texture_loader_dummy.cpp b/drivers/dummy/texture_loader_dummy.cpp index ddd2943720..2484e6d140 100644 --- a/drivers/dummy/texture_loader_dummy.cpp +++ b/drivers/dummy/texture_loader_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 */ @@ -31,7 +31,7 @@ #include "texture_loader_dummy.h" #include "core/os/file_access.h" -#include "core/print_string.h" +#include "core/string/print_string.h" #include <string.h> diff --git a/drivers/dummy/texture_loader_dummy.h b/drivers/dummy/texture_loader_dummy.h index ef9f3b13b6..3b71b5824f 100644 --- a/drivers/dummy/texture_loader_dummy.h +++ b/drivers/dummy/texture_loader_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/drivers/gl_context/SCsub b/drivers/gl_context/SCsub deleted file mode 100644 index ddeec6f4c6..0000000000 --- a/drivers/gl_context/SCsub +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python - -Import("env") - -if env["platform"] in ["haiku", "osx", "windows", "linuxbsd"]: - # Thirdparty source files - thirdparty_dir = "#thirdparty/glad/" - thirdparty_sources = [ - "glad.c", - ] - thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - - env.Prepend(CPPPATH=[thirdparty_dir]) - - env.Append(CPPDEFINES=["GLAD_ENABLED"]) - env.Append(CPPDEFINES=["GLES_OVER_GL"]) - - env_thirdparty = env.Clone() - env_thirdparty.disable_warnings() - env_thirdparty.add_source_files(env.drivers_sources, thirdparty_sources) - -# Godot source files -env.add_source_files(env.drivers_sources, "*.cpp") diff --git a/drivers/gles2/SCsub b/drivers/gles2/SCsub deleted file mode 100644 index 987ddcd16e..0000000000 --- a/drivers/gles2/SCsub +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python - -Import("env") - -env.add_source_files(env.drivers_sources, "*.cpp") - -SConscript("shaders/SCsub") diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp deleted file mode 100644 index 069eeaba6c..0000000000 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ /dev/null @@ -1,2228 +0,0 @@ -/*************************************************************************/ -/* rasterizer_canvas_gles2.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 "rasterizer_canvas_gles2.h" - -#include "core/os/os.h" -#include "core/project_settings.h" -#include "rasterizer_scene_gles2.h" -#include "servers/rendering/rendering_server_raster.h" - -#ifndef GLES_OVER_GL -#define glClearDepth glClearDepthf -#endif - -RID RasterizerCanvasGLES2::light_internal_create() { - - return RID(); -} - -void RasterizerCanvasGLES2::light_internal_update(RID p_rid, Light *p_light) { -} - -void RasterizerCanvasGLES2::light_internal_free(RID p_rid) { -} - -void RasterizerCanvasGLES2::_set_uniforms() { - - state.canvas_shader.set_uniform(CanvasShaderGLES2::PROJECTION_MATRIX, state.uniforms.projection_matrix); - state.canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); - state.canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX, state.uniforms.extra_matrix); - - state.canvas_shader.set_uniform(CanvasShaderGLES2::FINAL_MODULATE, state.uniforms.final_modulate); - - state.canvas_shader.set_uniform(CanvasShaderGLES2::TIME, storage->frame.time[0]); - - if (storage->frame.current_rt) { - Vector2 screen_pixel_size; - screen_pixel_size.x = 1.0 / storage->frame.current_rt->width; - screen_pixel_size.y = 1.0 / storage->frame.current_rt->height; - - state.canvas_shader.set_uniform(CanvasShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); - } - - if (state.using_skeleton) { - state.canvas_shader.set_uniform(CanvasShaderGLES2::SKELETON_TRANSFORM, state.skeleton_transform); - state.canvas_shader.set_uniform(CanvasShaderGLES2::SKELETON_TRANSFORM_INVERSE, state.skeleton_transform_inverse); - state.canvas_shader.set_uniform(CanvasShaderGLES2::SKELETON_TEXTURE_SIZE, state.skeleton_texture_size); - } - - if (state.using_light) { - - Light *light = state.using_light; - state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_MATRIX, light->light_shader_xform); - Transform2D basis_inverse = light->light_shader_xform.affine_inverse().orthonormalized(); - basis_inverse[2] = Vector2(); - state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_MATRIX_INVERSE, basis_inverse); - state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_LOCAL_MATRIX, light->xform_cache.affine_inverse()); - state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_COLOR, light->color * light->energy); - state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_POS, light->light_shader_pos); - state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_HEIGHT, light->height); - state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_OUTSIDE_ALPHA, light->mode == RS::CANVAS_LIGHT_MODE_MASK ? 1.0 : 0.0); - - if (state.using_shadow) { - RasterizerStorageGLES2::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.getornull(light->shadow_buffer); - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 5); - glBindTexture(GL_TEXTURE_2D, cls->distance); - state.canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_MATRIX, light->shadow_matrix_cache); - state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_SHADOW_COLOR, light->shadow_color); - - state.canvas_shader.set_uniform(CanvasShaderGLES2::SHADOWPIXEL_SIZE, (1.0 / light->shadow_buffer_size) * (1.0 + light->shadow_smooth)); - if (light->radius_cache == 0) { - state.canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_GRADIENT, 0.0); - } else { - state.canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_GRADIENT, light->shadow_gradient_length / (light->radius_cache * 1.1)); - } - state.canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_DISTANCE_MULT, light->radius_cache * 1.1); - - /*canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_MATRIX,light->shadow_matrix_cache); - canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_ESM_MULTIPLIER,light->shadow_esm_mult); - canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_SHADOW_COLOR,light->shadow_color);*/ - } - } -} - -void RasterizerCanvasGLES2::canvas_begin() { - - state.canvas_shader.bind(); - state.using_transparent_rt = false; - int viewport_x, viewport_y, viewport_width, viewport_height; - - if (storage->frame.current_rt) { - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); - state.using_transparent_rt = storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]; - - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { - // set Viewport and Scissor when rendering directly to screen - viewport_width = storage->frame.current_rt->width; - viewport_height = storage->frame.current_rt->height; - viewport_x = storage->frame.current_rt->x; - viewport_y = DisplayServer::get_singleton()->window_get_size().height - viewport_height - storage->frame.current_rt->y; - glScissor(viewport_x, viewport_y, viewport_width, viewport_height); - glViewport(viewport_x, viewport_y, viewport_width, viewport_height); - glEnable(GL_SCISSOR_TEST); - } - } - - if (storage->frame.clear_request) { - glClearColor(storage->frame.clear_request_color.r, - storage->frame.clear_request_color.g, - storage->frame.clear_request_color.b, - state.using_transparent_rt ? storage->frame.clear_request_color.a : 1.0); - glClear(GL_COLOR_BUFFER_BIT); - storage->frame.clear_request = false; - } - - /* - if (storage->frame.current_rt) { - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); - glColorMask(1, 1, 1, 1); - } - */ - - reset_canvas(); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - glDisableVertexAttribArray(RS::ARRAY_COLOR); - - // set up default uniforms - - Transform canvas_transform; - - if (storage->frame.current_rt) { - - float csy = 1.0; - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { - csy = -1.0; - } - canvas_transform.translate(-(storage->frame.current_rt->width / 2.0f), -(storage->frame.current_rt->height / 2.0f), 0.0f); - canvas_transform.scale(Vector3(2.0f / storage->frame.current_rt->width, csy * -2.0f / storage->frame.current_rt->height, 1.0f)); - } else { - Vector2 ssize = DisplayServer::get_singleton()->window_get_size(); - canvas_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f); - canvas_transform.scale(Vector3(2.0f / ssize.width, -2.0f / ssize.height, 1.0f)); - } - - state.uniforms.projection_matrix = canvas_transform; - - state.uniforms.final_modulate = Color(1, 1, 1, 1); - - state.uniforms.modelview_matrix = Transform2D(); - state.uniforms.extra_matrix = Transform2D(); - - _set_uniforms(); - _bind_quad_buffer(); -} - -void RasterizerCanvasGLES2::canvas_end() { - - glBindBuffer(GL_ARRAY_BUFFER, 0); - - for (int i = 0; i < RS::ARRAY_MAX; i++) { - glDisableVertexAttribArray(i); - } - - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { - //reset viewport to full window size - int viewport_width = DisplayServer::get_singleton()->window_get_size().width; - int viewport_height = DisplayServer::get_singleton()->window_get_size().height; - glViewport(0, 0, viewport_width, viewport_height); - glScissor(0, 0, viewport_width, viewport_height); - } - - state.using_texture_rect = false; - state.using_skeleton = false; - state.using_ninepatch = false; - state.using_transparent_rt = false; -} - -RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map) { - - RasterizerStorageGLES2::Texture *tex_return = nullptr; - - if (p_texture.is_valid()) { - - RasterizerStorageGLES2::Texture *texture = storage->texture_owner.getornull(p_texture); - - if (!texture) { - state.current_tex = RID(); - state.current_tex_ptr = nullptr; - - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - - } else { - - if (texture->redraw_if_visible) { - RenderingServerRaster::redraw_request(); - } - - texture = texture->get_ptr(); - - if (texture->render_target) { - texture->render_target->used_in_frame = true; - } - - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); - glBindTexture(GL_TEXTURE_2D, texture->tex_id); - - state.current_tex = p_texture; - state.current_tex_ptr = texture; - - tex_return = texture; - } - } else { - state.current_tex = RID(); - state.current_tex_ptr = nullptr; - - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - } - - if (p_normal_map == state.current_normal) { - //do none - state.canvas_shader.set_uniform(CanvasShaderGLES2::USE_DEFAULT_NORMAL, state.current_normal.is_valid()); - - } else if (p_normal_map.is_valid()) { - - RasterizerStorageGLES2::Texture *normal_map = storage->texture_owner.getornull(p_normal_map); - - if (!normal_map) { - state.current_normal = RID(); - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); - glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex); - state.canvas_shader.set_uniform(CanvasShaderGLES2::USE_DEFAULT_NORMAL, false); - - } else { - - if (normal_map->redraw_if_visible) { //check before proxy, because this is usually used with proxies - RenderingServerRaster::redraw_request(); - } - - normal_map = normal_map->get_ptr(); - - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); - glBindTexture(GL_TEXTURE_2D, normal_map->tex_id); - state.current_normal = p_normal_map; - state.canvas_shader.set_uniform(CanvasShaderGLES2::USE_DEFAULT_NORMAL, true); - } - - } else { - - state.current_normal = RID(); - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); - glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex); - state.canvas_shader.set_uniform(CanvasShaderGLES2::USE_DEFAULT_NORMAL, false); - } - - return tex_return; -} - -void RasterizerCanvasGLES2::_draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const float *p_weights, const int *p_bones) { - - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); -#ifndef GLES_OVER_GL - // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData - glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, nullptr, GL_DYNAMIC_DRAW); -#endif - - uint32_t buffer_ofs = 0; - - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector2) * p_vertex_count, p_vertices); - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), nullptr); - buffer_ofs += sizeof(Vector2) * p_vertex_count; - - if (p_singlecolor) { - glDisableVertexAttribArray(RS::ARRAY_COLOR); - Color m = *p_colors; - glVertexAttrib4f(RS::ARRAY_COLOR, m.r, m.g, m.b, m.a); - } else if (!p_colors) { - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - } else { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); - glEnableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(Color) * p_vertex_count; - } - - if (p_uvs) { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); - glEnableVertexAttribArray(RS::ARRAY_TEX_UV); - glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(Vector2) * p_vertex_count; - } else { - glDisableVertexAttribArray(RS::ARRAY_TEX_UV); - } - - if (p_weights && p_bones) { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(float) * 4 * p_vertex_count, p_weights); - glEnableVertexAttribArray(RS::ARRAY_WEIGHTS); - glVertexAttribPointer(RS::ARRAY_WEIGHTS, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(float) * 4 * p_vertex_count; - - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(int) * 4 * p_vertex_count, p_bones); - glEnableVertexAttribArray(RS::ARRAY_BONES); - glVertexAttribPointer(RS::ARRAY_BONES, 4, GL_UNSIGNED_INT, GL_FALSE, sizeof(int) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(int) * 4 * p_vertex_count; - - } else { - glDisableVertexAttribArray(RS::ARRAY_WEIGHTS); - glDisableVertexAttribArray(RS::ARRAY_BONES); - } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); -#ifndef GLES_OVER_GL - // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData - glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer_size, nullptr, GL_DYNAMIC_DRAW); -#endif - - if (storage->config.support_32_bits_indices) { //should check for - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * p_index_count, p_indices); - glDrawElements(GL_TRIANGLES, p_index_count, GL_UNSIGNED_INT, 0); - } else { - uint16_t *index16 = (uint16_t *)alloca(sizeof(uint16_t) * p_index_count); - for (int i = 0; i < p_index_count; i++) { - index16[i] = uint16_t(p_indices[i]); - } - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(uint16_t) * p_index_count, index16); - glDrawElements(GL_TRIANGLES, p_index_count, GL_UNSIGNED_SHORT, 0); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} - -void RasterizerCanvasGLES2::_draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) { - - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); -#ifndef GLES_OVER_GL - // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData - glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, nullptr, GL_DYNAMIC_DRAW); -#endif - - uint32_t buffer_ofs = 0; - - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector2) * p_vertex_count, p_vertices); - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), nullptr); - buffer_ofs += sizeof(Vector2) * p_vertex_count; - - if (p_singlecolor) { - glDisableVertexAttribArray(RS::ARRAY_COLOR); - Color m = *p_colors; - glVertexAttrib4f(RS::ARRAY_COLOR, m.r, m.g, m.b, m.a); - } else if (!p_colors) { - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - } else { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); - glEnableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(Color) * p_vertex_count; - } - - if (p_uvs) { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); - glEnableVertexAttribArray(RS::ARRAY_TEX_UV); - glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - } else { - glDisableVertexAttribArray(RS::ARRAY_TEX_UV); - } - - glDrawArrays(p_primitive, 0, p_vertex_count); - - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void RasterizerCanvasGLES2::_draw_generic_indices(GLuint p_primitive, const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) { - - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); -#ifndef GLES_OVER_GL - // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData - glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, nullptr, GL_DYNAMIC_DRAW); -#endif - - uint32_t buffer_ofs = 0; - - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector2) * p_vertex_count, p_vertices); - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), nullptr); - buffer_ofs += sizeof(Vector2) * p_vertex_count; - - if (p_singlecolor) { - glDisableVertexAttribArray(RS::ARRAY_COLOR); - Color m = *p_colors; - glVertexAttrib4f(RS::ARRAY_COLOR, m.r, m.g, m.b, m.a); - } else if (!p_colors) { - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - } else { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); - glEnableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(Color) * p_vertex_count; - } - - if (p_uvs) { - glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); - glEnableVertexAttribArray(RS::ARRAY_TEX_UV); - glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs += sizeof(Vector2) * p_vertex_count; - } else { - glDisableVertexAttribArray(RS::ARRAY_TEX_UV); - } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); -#ifndef GLES_OVER_GL - // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData - glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer_size, nullptr, GL_DYNAMIC_DRAW); -#endif - - if (storage->config.support_32_bits_indices) { //should check for - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * p_index_count, p_indices); - glDrawElements(p_primitive, p_index_count, GL_UNSIGNED_INT, 0); - } else { - uint16_t *index16 = (uint16_t *)alloca(sizeof(uint16_t) * p_index_count); - for (int i = 0; i < p_index_count; i++) { - index16[i] = uint16_t(p_indices[i]); - } - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(uint16_t) * p_index_count, index16); - glDrawElements(p_primitive, p_index_count, GL_UNSIGNED_SHORT, 0); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} - -void RasterizerCanvasGLES2::_draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs) { - - static const GLenum prim[5] = { GL_POINTS, GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_FAN }; - - int color_offset = 0; - int uv_offset = 0; - int stride = 2; - - if (p_colors) { - color_offset = stride; - stride += 4; - } - - if (p_uvs) { - uv_offset = stride; - stride += 2; - } - - float buffer_data[(2 + 2 + 4) * 4]; - - for (int i = 0; i < p_points; i++) { - buffer_data[stride * i + 0] = p_vertices[i].x; - buffer_data[stride * i + 1] = p_vertices[i].y; - } - - if (p_colors) { - for (int i = 0; i < p_points; i++) { - buffer_data[stride * i + color_offset + 0] = p_colors[i].r; - buffer_data[stride * i + color_offset + 1] = p_colors[i].g; - buffer_data[stride * i + color_offset + 2] = p_colors[i].b; - buffer_data[stride * i + color_offset + 3] = p_colors[i].a; - } - } - - if (p_uvs) { - for (int i = 0; i < p_points; i++) { - buffer_data[stride * i + uv_offset + 0] = p_uvs[i].x; - buffer_data[stride * i + uv_offset + 1] = p_uvs[i].y; - } - } - - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); -#ifndef GLES_OVER_GL - // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData - glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, nullptr, GL_DYNAMIC_DRAW); -#endif - glBufferSubData(GL_ARRAY_BUFFER, 0, p_points * stride * 4 * sizeof(float), buffer_data); - - glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), nullptr); - - if (p_colors) { - glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(color_offset * sizeof(float))); - glEnableVertexAttribArray(RS::ARRAY_COLOR); - } - - if (p_uvs) { - glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(uv_offset * sizeof(float))); - glEnableVertexAttribArray(RS::ARRAY_TEX_UV); - } - - glDrawArrays(prim[p_points], 0, p_points); - - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -static const GLenum gl_primitive[] = { - GL_POINTS, - GL_LINES, - GL_LINE_STRIP, - GL_LINE_LOOP, - GL_TRIANGLES, - GL_TRIANGLE_STRIP, - GL_TRIANGLE_FAN -}; - -void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip, RasterizerStorageGLES2::Material *p_material) { - - int command_count = p_item->commands.size(); - Item::Command **commands = p_item->commands.ptrw(); - - for (int i = 0; i < command_count; i++) { - - Item::Command *command = commands[i]; - - switch (command->type) { - - case Item::Command::TYPE_LINE: { - - Item::CommandLine *line = static_cast<Item::CommandLine *>(command); - - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - _bind_canvas_texture(RID(), RID()); - - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4fv(RS::ARRAY_COLOR, line->color.components); - - state.canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); - - if (line->width <= 1) { - Vector2 verts[2] = { - Vector2(line->from.x, line->from.y), - Vector2(line->to.x, line->to.y) - }; - -#ifdef GLES_OVER_GL - if (line->antialiased) - glEnable(GL_LINE_SMOOTH); -#endif - _draw_gui_primitive(2, verts, nullptr, nullptr); - -#ifdef GLES_OVER_GL - if (line->antialiased) - glDisable(GL_LINE_SMOOTH); -#endif - } else { - Vector2 t = (line->from - line->to).normalized().tangent() * line->width * 0.5; - - Vector2 verts[4] = { - line->from - t, - line->from + t, - line->to + t, - line->to - t - }; - - _draw_gui_primitive(4, verts, nullptr, nullptr); -#ifdef GLES_OVER_GL - if (line->antialiased) { - glEnable(GL_LINE_SMOOTH); - for (int j = 0; j < 4; j++) { - Vector2 vertsl[2] = { - verts[j], - verts[(j + 1) % 4], - }; - _draw_gui_primitive(2, vertsl, nullptr, nullptr); - } - glDisable(GL_LINE_SMOOTH); - } -#endif - } - } break; - - case Item::Command::TYPE_RECT: { - - Item::CommandRect *r = static_cast<Item::CommandRect *>(command); - - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4fv(RS::ARRAY_COLOR, r->modulate.components); - - bool can_tile = true; - if (r->texture.is_valid() && r->flags & CANVAS_RECT_TILE && !storage->config.support_npot_repeat_mipmap) { - // workaround for when setting tiling does not work due to hardware limitation - - RasterizerStorageGLES2::Texture *texture = storage->texture_owner.getornull(r->texture); - - if (texture) { - - texture = texture->get_ptr(); - - if (next_power_of_2(texture->alloc_width) != (unsigned int)texture->alloc_width && next_power_of_2(texture->alloc_height) != (unsigned int)texture->alloc_height) { - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_FORCE_REPEAT, true); - can_tile = false; - } - } - } - - // On some widespread Nvidia cards, the normal draw method can produce some - // flickering in draw_rect and especially TileMap rendering (tiles randomly flicker). - // See GH-9913. - // To work it around, we use a simpler draw method which does not flicker, but gives - // a non negligible performance hit, so it's opt-in (GH-24466). - if (use_nvidia_rect_workaround) { - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - Vector2 points[4] = { - r->rect.position, - r->rect.position + Vector2(r->rect.size.x, 0.0), - r->rect.position + r->rect.size, - r->rect.position + Vector2(0.0, r->rect.size.y), - }; - - if (r->rect.size.x < 0) { - SWAP(points[0], points[1]); - SWAP(points[2], points[3]); - } - if (r->rect.size.y < 0) { - SWAP(points[0], points[3]); - SWAP(points[1], points[2]); - } - - RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(r->texture, r->normal_map); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - - Rect2 src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1); - - Vector2 uvs[4] = { - src_rect.position, - src_rect.position + Vector2(src_rect.size.x, 0.0), - src_rect.position + src_rect.size, - src_rect.position + Vector2(0.0, src_rect.size.y), - }; - - if (r->flags & CANVAS_RECT_TRANSPOSE) { - SWAP(uvs[1], uvs[3]); - } - - if (r->flags & CANVAS_RECT_FLIP_H) { - SWAP(uvs[0], uvs[1]); - SWAP(uvs[2], uvs[3]); - } - if (r->flags & CANVAS_RECT_FLIP_V) { - SWAP(uvs[0], uvs[3]); - SWAP(uvs[1], uvs[2]); - } - - state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); - - bool untile = false; - - if (can_tile && r->flags & CANVAS_RECT_TILE && !(texture->flags & RS::TEXTURE_FLAG_REPEAT)) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - untile = true; - } - - _draw_gui_primitive(4, points, nullptr, uvs); - - if (untile) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - } else { - static const Vector2 uvs[4] = { - Vector2(0.0, 0.0), - Vector2(0.0, 1.0), - Vector2(1.0, 1.0), - Vector2(1.0, 0.0), - }; - - state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, Vector2()); - _draw_gui_primitive(4, points, nullptr, uvs); - } - - } else { - // This branch is better for performance, but can produce flicker on Nvidia, see above comment. - _bind_quad_buffer(); - - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - RasterizerStorageGLES2::Texture *tex = _bind_canvas_texture(r->texture, r->normal_map); - - if (!tex) { - Rect2 dst_rect = Rect2(r->rect.position, r->rect.size); - - if (dst_rect.size.width < 0) { - dst_rect.position.x += dst_rect.size.width; - dst_rect.size.width *= -1; - } - if (dst_rect.size.height < 0) { - dst_rect.position.y += dst_rect.size.height; - dst_rect.size.height *= -1; - } - - state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y)); - state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(0, 0, 1, 1)); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } else { - - bool untile = false; - - if (can_tile && r->flags & CANVAS_RECT_TILE && !(tex->flags & RS::TEXTURE_FLAG_REPEAT)) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - untile = true; - } - - Size2 texpixel_size(1.0 / tex->width, 1.0 / tex->height); - Rect2 src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1); - - Rect2 dst_rect = Rect2(r->rect.position, r->rect.size); - - if (dst_rect.size.width < 0) { - dst_rect.position.x += dst_rect.size.width; - dst_rect.size.width *= -1; - } - if (dst_rect.size.height < 0) { - dst_rect.position.y += dst_rect.size.height; - dst_rect.size.height *= -1; - } - - if (r->flags & CANVAS_RECT_FLIP_H) { - src_rect.size.x *= -1; - } - - if (r->flags & CANVAS_RECT_FLIP_V) { - src_rect.size.y *= -1; - } - - if (r->flags & CANVAS_RECT_TRANSPOSE) { - dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform - } - - state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); - - state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y)); - state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y)); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - if (untile) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_FORCE_REPEAT, false); - - } break; - - case Item::Command::TYPE_NINEPATCH: { - - Item::CommandNinePatch *np = static_cast<Item::CommandNinePatch *>(command); - - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4fv(RS::ARRAY_COLOR, np->color.components); - - RasterizerStorageGLES2::Texture *tex = _bind_canvas_texture(np->texture, np->normal_map); - - if (!tex) { - // FIXME: Handle textureless ninepatch gracefully - WARN_PRINT("NinePatch without texture not supported yet in GLES2 backend, skipping."); - continue; - } - if (tex->width == 0 || tex->height == 0) { - WARN_PRINT("Cannot set empty texture to NinePatch."); - continue; - } - - Size2 texpixel_size(1.0 / tex->width, 1.0 / tex->height); - - // state.canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); - state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); - - Rect2 source = np->source; - if (source.size.x == 0 && source.size.y == 0) { - source.size.x = tex->width; - source.size.y = tex->height; - } - - float screen_scale = 1.0; - - if (source.size.x != 0 && source.size.y != 0) { - - screen_scale = MIN(np->rect.size.x / source.size.x, np->rect.size.y / source.size.y); - screen_scale = MIN(1.0, screen_scale); - } - - // prepare vertex buffer - - // this buffer contains [ POS POS UV UV ] * - - float buffer[16 * 2 + 16 * 2]; - - { - - // first row - - buffer[(0 * 4 * 4) + 0] = np->rect.position.x; - buffer[(0 * 4 * 4) + 1] = np->rect.position.y; - - buffer[(0 * 4 * 4) + 2] = source.position.x * texpixel_size.x; - buffer[(0 * 4 * 4) + 3] = source.position.y * texpixel_size.y; - - buffer[(0 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT] * screen_scale; - buffer[(0 * 4 * 4) + 5] = np->rect.position.y; - - buffer[(0 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x; - buffer[(0 * 4 * 4) + 7] = source.position.y * texpixel_size.y; - - buffer[(0 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT] * screen_scale; - buffer[(0 * 4 * 4) + 9] = np->rect.position.y; - - buffer[(0 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x; - buffer[(0 * 4 * 4) + 11] = source.position.y * texpixel_size.y; - - buffer[(0 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x; - buffer[(0 * 4 * 4) + 13] = np->rect.position.y; - - buffer[(0 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x; - buffer[(0 * 4 * 4) + 15] = source.position.y * texpixel_size.y; - - // second row - - buffer[(1 * 4 * 4) + 0] = np->rect.position.x; - buffer[(1 * 4 * 4) + 1] = np->rect.position.y + np->margin[MARGIN_TOP] * screen_scale; - - buffer[(1 * 4 * 4) + 2] = source.position.x * texpixel_size.x; - buffer[(1 * 4 * 4) + 3] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y; - - buffer[(1 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT] * screen_scale; - buffer[(1 * 4 * 4) + 5] = np->rect.position.y + np->margin[MARGIN_TOP] * screen_scale; - - buffer[(1 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x; - buffer[(1 * 4 * 4) + 7] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y; - - buffer[(1 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT] * screen_scale; - buffer[(1 * 4 * 4) + 9] = np->rect.position.y + np->margin[MARGIN_TOP] * screen_scale; - - buffer[(1 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x; - buffer[(1 * 4 * 4) + 11] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y; - - buffer[(1 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x; - buffer[(1 * 4 * 4) + 13] = np->rect.position.y + np->margin[MARGIN_TOP] * screen_scale; - - buffer[(1 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x; - buffer[(1 * 4 * 4) + 15] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y; - - // third row - - buffer[(2 * 4 * 4) + 0] = np->rect.position.x; - buffer[(2 * 4 * 4) + 1] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM] * screen_scale; - - buffer[(2 * 4 * 4) + 2] = source.position.x * texpixel_size.x; - buffer[(2 * 4 * 4) + 3] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y; - - buffer[(2 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT] * screen_scale; - buffer[(2 * 4 * 4) + 5] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM] * screen_scale; - - buffer[(2 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x; - buffer[(2 * 4 * 4) + 7] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y; - - buffer[(2 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT] * screen_scale; - buffer[(2 * 4 * 4) + 9] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM] * screen_scale; - - buffer[(2 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x; - buffer[(2 * 4 * 4) + 11] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y; - - buffer[(2 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x; - buffer[(2 * 4 * 4) + 13] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM] * screen_scale; - - buffer[(2 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x; - buffer[(2 * 4 * 4) + 15] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y; - - // fourth row - - buffer[(3 * 4 * 4) + 0] = np->rect.position.x; - buffer[(3 * 4 * 4) + 1] = np->rect.position.y + np->rect.size.y; - - buffer[(3 * 4 * 4) + 2] = source.position.x * texpixel_size.x; - buffer[(3 * 4 * 4) + 3] = (source.position.y + source.size.y) * texpixel_size.y; - - buffer[(3 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT] * screen_scale; - buffer[(3 * 4 * 4) + 5] = np->rect.position.y + np->rect.size.y; - - buffer[(3 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x; - buffer[(3 * 4 * 4) + 7] = (source.position.y + source.size.y) * texpixel_size.y; - - buffer[(3 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT] * screen_scale; - buffer[(3 * 4 * 4) + 9] = np->rect.position.y + np->rect.size.y; - - buffer[(3 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x; - buffer[(3 * 4 * 4) + 11] = (source.position.y + source.size.y) * texpixel_size.y; - - buffer[(3 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x; - buffer[(3 * 4 * 4) + 13] = np->rect.position.y + np->rect.size.y; - - buffer[(3 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x; - buffer[(3 * 4 * 4) + 15] = (source.position.y + source.size.y) * texpixel_size.y; - } - - glBindBuffer(GL_ARRAY_BUFFER, data.ninepatch_vertices); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * (16 + 16) * 2, buffer, GL_DYNAMIC_DRAW); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ninepatch_elements); - - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glEnableVertexAttribArray(RS::ARRAY_TEX_UV); - - glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), nullptr); - glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), CAST_INT_TO_UCHAR_PTR((sizeof(float) * 2))); - - glDrawElements(GL_TRIANGLES, 18 * 3 - (np->draw_center ? 0 : 6), GL_UNSIGNED_BYTE, nullptr); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - } break; - - case Item::Command::TYPE_CIRCLE: { - - Item::CommandCircle *circle = static_cast<Item::CommandCircle *>(command); - - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - static const int num_points = 32; - - Vector2 points[num_points + 1]; - points[num_points] = circle->pos; - - int indices[num_points * 3]; - - for (int j = 0; j < num_points; j++) { - points[j] = circle->pos + Vector2(Math::sin(j * Math_PI * 2.0 / num_points), Math::cos(j * Math_PI * 2.0 / num_points)) * circle->radius; - indices[j * 3 + 0] = j; - indices[j * 3 + 1] = (j + 1) % num_points; - indices[j * 3 + 2] = num_points; - } - - _bind_canvas_texture(RID(), RID()); - - _draw_polygon(indices, num_points * 3, num_points + 1, points, nullptr, &circle->color, true); - } break; - - case Item::Command::TYPE_POLYGON: { - - Item::CommandPolygon *polygon = static_cast<Item::CommandPolygon *>(command); - - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->normal_map); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); - } - - _draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1, polygon->weights.ptr(), polygon->bones.ptr()); -#ifdef GLES_OVER_GL - if (polygon->antialiased) { - glEnable(GL_LINE_SMOOTH); - // FIXME: Removed during Vulkan rebase. - //if (polygon->antialiasing_use_indices) { - // _draw_generic_indices(GL_LINE_STRIP, polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); - //} else - _draw_generic(GL_LINE_LOOP, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); - glDisable(GL_LINE_SMOOTH); - } -#endif - } break; - case Item::Command::TYPE_MESH: { - - Item::CommandMesh *mesh = static_cast<Item::CommandMesh *>(command); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(mesh->texture, mesh->normal_map); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); - } - - RasterizerStorageGLES2::Mesh *mesh_data = storage->mesh_owner.getornull(mesh->mesh); - if (mesh_data) { - - for (int j = 0; j < mesh_data->surfaces.size(); j++) { - RasterizerStorageGLES2::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 - - glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); - - if (s->index_array_len > 0) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id); - } - - for (int k = 0; k < RS::ARRAY_MAX - 1; k++) { - if (s->attribs[k].enabled) { - glEnableVertexAttribArray(k); - glVertexAttribPointer(s->attribs[k].index, s->attribs[k].size, s->attribs[k].type, s->attribs[k].normalized, s->attribs[k].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[k].offset)); - } else { - glDisableVertexAttribArray(k); - switch (k) { - case RS::ARRAY_NORMAL: { - glVertexAttrib4f(RS::ARRAY_NORMAL, 0.0, 0.0, 1, 1); - } break; - case RS::ARRAY_COLOR: { - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - - } break; - default: { - } - } - } - } - - if (s->index_array_len > 0) { - glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); - } else { - glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); - } - } - - for (int j = 1; j < RS::ARRAY_MAX - 1; j++) { - glDisableVertexAttribArray(j); - } - } - - } break; - case Item::Command::TYPE_MULTIMESH: { - Item::CommandMultiMesh *mmesh = static_cast<Item::CommandMultiMesh *>(command); - - RasterizerStorageGLES2::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(mmesh->multimesh); - - if (!multi_mesh) - break; - - RasterizerStorageGLES2::Mesh *mesh_data = storage->mesh_owner.getornull(multi_mesh->mesh); - - if (!mesh_data) - break; - - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_INSTANCE_CUSTOM, multi_mesh->custom_data_format != RS::MULTIMESH_CUSTOM_DATA_NONE); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_INSTANCING, true); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(mmesh->texture, mmesh->normal_map); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); - } - - //reset shader and force rebind - - int amount = MIN(multi_mesh->size, multi_mesh->visible_instances); - - if (amount == -1) { - amount = multi_mesh->size; - } - - int stride = multi_mesh->color_floats + multi_mesh->custom_data_floats + multi_mesh->xform_floats; - - int color_ofs = multi_mesh->xform_floats; - int custom_data_ofs = color_ofs + multi_mesh->color_floats; - - // drawing - - const float *base_buffer = multi_mesh->data.ptr(); - - for (int j = 0; j < mesh_data->surfaces.size(); j++) { - RasterizerStorageGLES2::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 - - //bind buffers for mesh surface - glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); - - if (s->index_array_len > 0) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id); - } - - for (int k = 0; k < RS::ARRAY_MAX - 1; k++) { - if (s->attribs[k].enabled) { - glEnableVertexAttribArray(k); - glVertexAttribPointer(s->attribs[k].index, s->attribs[k].size, s->attribs[k].type, s->attribs[k].normalized, s->attribs[k].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[k].offset)); - } else { - glDisableVertexAttribArray(k); - switch (k) { - case RS::ARRAY_NORMAL: { - glVertexAttrib4f(RS::ARRAY_NORMAL, 0.0, 0.0, 1, 1); - } break; - case RS::ARRAY_COLOR: { - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - - } break; - default: { - } - } - } - } - - for (int k = 0; k < amount; k++) { - const float *buffer = base_buffer + k * stride; - - { - - glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 0, &buffer[0]); - glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 1, &buffer[4]); - if (multi_mesh->transform_format == RS::MULTIMESH_TRANSFORM_3D) { - glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 2, &buffer[8]); - } else { - glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 2, 0.0, 0.0, 1.0, 0.0); - } - } - - if (multi_mesh->color_floats) { - if (multi_mesh->color_format == RS::MULTIMESH_COLOR_8BIT) { - uint8_t *color_data = (uint8_t *)(buffer + color_ofs); - glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, color_data[0] / 255.0, color_data[1] / 255.0, color_data[2] / 255.0, color_data[3] / 255.0); - } else { - glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 3, buffer + color_ofs); - } - } else { - glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, 1.0, 1.0, 1.0, 1.0); - } - - if (multi_mesh->custom_data_floats) { - if (multi_mesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_8BIT) { - uint8_t *custom_data = (uint8_t *)(buffer + custom_data_ofs); - glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 4, custom_data[0] / 255.0, custom_data[1] / 255.0, custom_data[2] / 255.0, custom_data[3] / 255.0); - } else { - glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 4, buffer + custom_data_ofs); - } - } - - if (s->index_array_len > 0) { - glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); - } else { - glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); - } - } - } - - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_INSTANCE_CUSTOM, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_INSTANCING, false); - - } break; - case Item::Command::TYPE_POLYLINE: { - Item::CommandPolyLine *pline = static_cast<Item::CommandPolyLine *>(command); - - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - _bind_canvas_texture(RID(), RID()); - - if (pline->triangles.size()) { - _draw_generic(GL_TRIANGLE_STRIP, pline->triangles.size(), pline->triangles.ptr(), nullptr, pline->triangle_colors.ptr(), pline->triangle_colors.size() == 1); -#ifdef GLES_OVER_GL - glEnable(GL_LINE_SMOOTH); - if (pline->multiline) { - //needs to be different - } else { - _draw_generic(GL_LINE_LOOP, pline->lines.size(), pline->lines.ptr(), nullptr, pline->line_colors.ptr(), pline->line_colors.size() == 1); - } - glDisable(GL_LINE_SMOOTH); -#endif - } else { - -#ifdef GLES_OVER_GL - if (pline->antialiased) - glEnable(GL_LINE_SMOOTH); -#endif - - if (pline->multiline) { - int todo = pline->lines.size() / 2; - int max_per_call = data.polygon_buffer_size / (sizeof(real_t) * 4); - int offset = 0; - - while (todo) { - int to_draw = MIN(max_per_call, todo); - _draw_generic(GL_LINES, to_draw * 2, &pline->lines.ptr()[offset], nullptr, pline->line_colors.size() == 1 ? pline->line_colors.ptr() : &pline->line_colors.ptr()[offset], pline->line_colors.size() == 1); - todo -= to_draw; - offset += to_draw * 2; - } - } else { - _draw_generic(GL_LINES, pline->lines.size(), pline->lines.ptr(), nullptr, pline->line_colors.ptr(), pline->line_colors.size() == 1); - } - -#ifdef GLES_OVER_GL - if (pline->antialiased) - glDisable(GL_LINE_SMOOTH); -#endif - } - } break; - - case Item::Command::TYPE_PRIMITIVE: { - - Item::CommandPrimitive *primitive = static_cast<Item::CommandPrimitive *>(command); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - ERR_CONTINUE(primitive->points.size() < 1); - - RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(primitive->texture, primitive->normal_map); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); - } - - if (primitive->colors.size() == 1 && primitive->points.size() > 1) { - Color c = primitive->colors[0]; - glVertexAttrib4f(RS::ARRAY_COLOR, c.r, c.g, c.b, c.a); - } else if (primitive->colors.empty()) { - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - } - - _draw_gui_primitive(primitive->points.size(), primitive->points.ptr(), primitive->colors.ptr(), primitive->uvs.ptr()); - } break; - - case Item::Command::TYPE_TRANSFORM: { - Item::CommandTransform *transform = static_cast<Item::CommandTransform *>(command); - state.uniforms.extra_matrix = transform->xform; - state.canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX, state.uniforms.extra_matrix); - } break; - - case Item::Command::TYPE_PARTICLES: { - - } break; - - case Item::Command::TYPE_CLIP_IGNORE: { - - Item::CommandClipIgnore *ci = static_cast<Item::CommandClipIgnore *>(command); - if (current_clip) { - if (ci->ignore != reclip) { - if (ci->ignore) { - glDisable(GL_SCISSOR_TEST); - reclip = true; - } else { - glEnable(GL_SCISSOR_TEST); - - int x = current_clip->final_clip_rect.position.x; - int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y); - int w = current_clip->final_clip_rect.size.x; - int h = current_clip->final_clip_rect.size.y; - - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) - y = current_clip->final_clip_rect.position.y; - - glScissor(x, y, w, h); - - reclip = false; - } - } - } - - } break; - - default: { - // FIXME: Proper error handling if relevant - //print_line("other"); - } break; - } - } -} - -void RasterizerCanvasGLES2::_copy_screen(const Rect2 &p_rect) { - - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { - ERR_PRINT_ONCE("Cannot use screen texture copying in render target set to render direct to screen."); - return; - } - - ERR_FAIL_COND_MSG(storage->frame.current_rt->copy_screen_effect.color == 0, "Can't use screen texture copying in a render target configured without copy buffers."); - - glDisable(GL_BLEND); - - Vector2 wh(storage->frame.current_rt->width, storage->frame.current_rt->height); - - Color copy_section(p_rect.position.x / wh.x, p_rect.position.y / wh.y, p_rect.size.x / wh.x, p_rect.size.y / wh.y); - - if (p_rect != Rect2()) { - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, true); - } - - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_NO_ALPHA, !state.using_transparent_rt); - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->copy_screen_effect.fbo); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); - - storage->shaders.copy.bind(); - storage->shaders.copy.set_uniform(CopyShaderGLES2::COPY_SECTION, copy_section); - - const Vector2 vertpos[4] = { - Vector2(-1, -1), - Vector2(-1, 1), - Vector2(1, 1), - Vector2(1, -1), - }; - - const Vector2 uvpos[4] = { - Vector2(0, 0), - Vector2(0, 1), - Vector2(1, 1), - Vector2(1, 0) - }; - - const int indexpos[6] = { - 0, 1, 2, - 2, 3, 0 - }; - - _draw_polygon(indexpos, 6, 4, vertpos, uvpos, nullptr, false); - - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_NO_ALPHA, false); - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); //back to front - glEnable(GL_BLEND); -} - -void RasterizerCanvasGLES2::_copy_texscreen(const Rect2 &p_rect) { - - state.canvas_texscreen_used = true; - - _copy_screen(p_rect); - - // back to canvas, force rebind - state.using_texture_rect = false; - state.canvas_shader.bind(); - _bind_canvas_texture(state.current_tex, state.current_normal); - _set_uniforms(); -} - -void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) { - - Item *current_clip = nullptr; - - RasterizerStorageGLES2::Shader *shader_cache = nullptr; - - bool rebind_shader = true; - bool prev_use_skeleton = false; - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_SKELETON, false); - - state.current_tex = RID(); - state.current_tex_ptr = nullptr; - state.current_normal = RID(); - state.canvas_texscreen_used = false; - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - - int last_blend_mode = -1; - - RID canvas_last_material = RID(); - - while (p_item_list) { - - Item *ci = p_item_list; - - if (current_clip != ci->final_clip_owner) { - - current_clip = ci->final_clip_owner; - - if (current_clip) { - glEnable(GL_SCISSOR_TEST); - int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) - y = current_clip->final_clip_rect.position.y; - glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height); - } else { - glDisable(GL_SCISSOR_TEST); - } - } - - // TODO: copy back buffer - - if (ci->copy_back_buffer) { - if (ci->copy_back_buffer->full) { - _copy_texscreen(Rect2()); - } else { - _copy_texscreen(ci->copy_back_buffer->rect); - } - } - - RasterizerStorageGLES2::Skeleton *skeleton = nullptr; - - { - //skeleton handling - if (ci->skeleton.is_valid() && storage->skeleton_owner.owns(ci->skeleton)) { - skeleton = storage->skeleton_owner.getornull(ci->skeleton); - if (!skeleton->use_2d) { - skeleton = nullptr; - } else { - state.skeleton_transform = p_base_transform * skeleton->base_transform_2d; - state.skeleton_transform_inverse = state.skeleton_transform.affine_inverse(); - state.skeleton_texture_size = Vector2(skeleton->size * 2, 0); - } - } - - bool use_skeleton = skeleton != nullptr; - if (prev_use_skeleton != use_skeleton) { - rebind_shader = true; - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_SKELETON, use_skeleton); - prev_use_skeleton = use_skeleton; - } - - if (skeleton) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); - glBindTexture(GL_TEXTURE_2D, skeleton->tex_id); - state.using_skeleton = true; - } else { - state.using_skeleton = false; - } - } - - Item *material_owner = ci->material_owner ? ci->material_owner : ci; - - RID material = material_owner->material; - RasterizerStorageGLES2::Material *material_ptr = storage->material_owner.getornull(material); - - if (material != canvas_last_material || rebind_shader) { - - RasterizerStorageGLES2::Shader *shader_ptr = nullptr; - - if (material_ptr) { - shader_ptr = material_ptr->shader; - - if (shader_ptr && shader_ptr->mode != RS::SHADER_CANVAS_ITEM) { - shader_ptr = nullptr; // not a canvas item shader, don't use. - } - } - - if (shader_ptr) { - if (shader_ptr->canvas_item.uses_screen_texture) { - if (!state.canvas_texscreen_used) { - //copy if not copied before - _copy_texscreen(Rect2()); - - // blend mode will have been enabled so make sure we disable it again later on - //last_blend_mode = last_blend_mode != RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_DISABLED ? last_blend_mode : -1; - } - - if (storage->frame.current_rt->copy_screen_effect.color) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->copy_screen_effect.color); - } - } - - if (shader_ptr != shader_cache) { - - if (shader_ptr->canvas_item.uses_time) { - RenderingServerRaster::redraw_request(); - } - - state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id); - state.canvas_shader.bind(); - } - - int tc = material_ptr->textures.size(); - Pair<StringName, RID> *textures = material_ptr->textures.ptrw(); - - ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = shader_ptr->texture_hints.ptrw(); - - for (int i = 0; i < tc; i++) { - - glActiveTexture(GL_TEXTURE0 + i); - - RasterizerStorageGLES2::Texture *t = storage->texture_owner.getornull(textures[i].second); - - if (!t) { - - switch (texture_hints[i]) { - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: { - glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); - } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: { - glBindTexture(GL_TEXTURE_2D, storage->resources.aniso_tex); - } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: { - glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex); - } break; - default: { - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - } break; - } - - continue; - } - - if (t->redraw_if_visible) { - RenderingServerRaster::redraw_request(); - } - - t = t->get_ptr(); - -#ifdef TOOLS_ENABLED - if (t->detect_normal && texture_hints[i] == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL) { - t->detect_normal(t->detect_normal_ud); - } -#endif - if (t->render_target) - t->render_target->used_in_frame = true; - - glBindTexture(t->target, t->tex_id); - } - - } else { - state.canvas_shader.set_custom_shader(0); - state.canvas_shader.bind(); - } - state.canvas_shader.use_material((void *)material_ptr); - - shader_cache = shader_ptr; - - canvas_last_material = material; - - rebind_shader = false; - } - - int blend_mode = shader_cache ? shader_cache->canvas_item.blend_mode : RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MIX; - bool unshaded = shader_cache && (shader_cache->canvas_item.light_mode == RasterizerStorageGLES2::Shader::CanvasItem::LIGHT_MODE_UNSHADED || (blend_mode != RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MIX && blend_mode != RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_PMALPHA)); - bool reclip = false; - - if (last_blend_mode != blend_mode) { - - switch (blend_mode) { - - case RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MIX: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); - } - - } break; - case RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_ADD: { - - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE); - } else { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); - } - - } break; - case RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_SUB: { - - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE); - } else { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); - } - } break; - case RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MUL: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO); - } else { - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE); - } - } break; - case RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_PMALPHA: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); - } - } break; - } - } - - state.uniforms.final_modulate = unshaded ? ci->final_modulate : Color(ci->final_modulate.r * p_modulate.r, ci->final_modulate.g * p_modulate.g, ci->final_modulate.b * p_modulate.b, ci->final_modulate.a * p_modulate.a); - - state.uniforms.modelview_matrix = ci->final_transform; - state.uniforms.extra_matrix = Transform2D(); - - _set_uniforms(); - - if (unshaded || (state.uniforms.final_modulate.a > 0.001 && (!shader_cache || shader_cache->canvas_item.light_mode != RasterizerStorageGLES2::Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY) && !ci->light_masked)) - _canvas_item_render_commands(p_item_list, nullptr, reclip, material_ptr); - - rebind_shader = true; // hacked in for now. - - if ((blend_mode == RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MIX || blend_mode == RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_PMALPHA) && p_light && !unshaded) { - - Light *light = p_light; - bool light_used = false; - RS::CanvasLightMode mode = RS::CANVAS_LIGHT_MODE_ADD; - state.uniforms.final_modulate = ci->final_modulate; // remove the canvas modulate - - 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)) { - - //intersects this light - - if (!light_used || mode != light->mode) { - - mode = light->mode; - - switch (mode) { - - case RS::CANVAS_LIGHT_MODE_ADD: { - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - - } break; - case RS::CANVAS_LIGHT_MODE_SUB: { - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - } break; - case RS::CANVAS_LIGHT_MODE_MIX: - case RS::CANVAS_LIGHT_MODE_MASK: { - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - } break; - } - } - - if (!light_used) { - - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHTING, true); - light_used = true; - } - - bool has_shadow = light->shadow_buffer.is_valid() && ci->light_mask & light->item_shadow_mask; - - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_SHADOWS, has_shadow); - if (has_shadow) { - state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_USE_GRADIENT, light->shadow_gradient_length > 0); - state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_NEAREST, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_NONE); - state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF3, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF3); - state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF5, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF5); - state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF7, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF7); - state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF9, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF9); - state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF13, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF13); - } - - state.canvas_shader.bind(); - state.using_light = light; - state.using_shadow = has_shadow; - - //always re-set uniforms, since light parameters changed - _set_uniforms(); - state.canvas_shader.use_material((void *)material_ptr); - - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); - RasterizerStorageGLES2::Texture *t = storage->texture_owner.getornull(light->texture); - if (!t) { - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - } else { - t = t->get_ptr(); - - glBindTexture(t->target, t->tex_id); - } - - glActiveTexture(GL_TEXTURE0); - _canvas_item_render_commands(p_item_list, nullptr, reclip, material_ptr); //redraw using light - - state.using_light = nullptr; - } - - light = light->next_ptr; - } - - if (light_used) { - - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHTING, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_SHADOWS, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_NEAREST, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF3, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF5, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF7, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF9, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF13, false); - - state.canvas_shader.bind(); - - last_blend_mode = -1; - - /* - //this is set again, so it should not be needed anyway? - state.canvas_item_modulate = unshaded ? ci->final_modulate : Color( - ci->final_modulate.r * p_modulate.r, - ci->final_modulate.g * p_modulate.g, - ci->final_modulate.b * p_modulate.b, - ci->final_modulate.a * p_modulate.a ); - - - state.canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,state.final_transform); - state.canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX,Transform2D()); - state.canvas_shader.set_uniform(CanvasShaderGLES2::FINAL_MODULATE,state.canvas_item_modulate); - - glBlendEquation(GL_FUNC_ADD); - - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - - //@TODO RESET canvas_blend_mode - */ - } - } - - if (reclip) { - glEnable(GL_SCISSOR_TEST); - int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) - y = current_clip->final_clip_rect.position.y; - glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height); - } - - p_item_list = p_item_list->next; - } - - if (current_clip) { - glDisable(GL_SCISSOR_TEST); - } - - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_SKELETON, false); -} - -void RasterizerCanvasGLES2::canvas_debug_viewport_shadows(Light *p_lights_with_shadow) { -} - -void RasterizerCanvasGLES2::canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache) { - - RasterizerStorageGLES2::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.getornull(p_buffer); - ERR_FAIL_COND(!cls); - - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_DITHER); - glDisable(GL_CULL_FACE); - glDepthFunc(GL_LEQUAL); - glEnable(GL_DEPTH_TEST); - glDepthMask(true); - - glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); - - state.canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES2::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows); - state.canvas_shadow_shader.bind(); - - glViewport(0, 0, cls->size, cls->height); - glClearDepth(1.0f); - glClearColor(1, 1, 1, 1); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - RS::CanvasOccluderPolygonCullMode cull = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; - - for (int i = 0; i < 4; i++) { - - //make sure it remains orthogonal, makes easy to read angle later - - Transform light; - light.origin[0] = p_light_xform[2][0]; - light.origin[1] = p_light_xform[2][1]; - light.basis[0][0] = p_light_xform[0][0]; - light.basis[0][1] = p_light_xform[1][0]; - light.basis[1][0] = p_light_xform[0][1]; - light.basis[1][1] = p_light_xform[1][1]; - - //light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1)); - - //p_near=1; - CameraMatrix projection; - { - real_t fov = 90; - real_t nearp = p_near; - real_t farp = p_far; - real_t aspect = 1.0; - - real_t ymax = nearp * Math::tan(Math::deg2rad(fov * 0.5)); - real_t ymin = -ymax; - real_t xmin = ymin * aspect; - real_t xmax = ymax * aspect; - - projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp); - } - - Vector3 cam_target = Basis(Vector3(0, 0, Math_PI * 2 * (i / 4.0))).xform(Vector3(0, 1, 0)); - projection = projection * CameraMatrix(Transform().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse()); - - state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::PROJECTION_MATRIX, projection); - state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::LIGHT_MATRIX, light); - state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::DISTANCE_NORM, 1.0 / p_far); - - if (i == 0) - *p_xform_cache = projection; - - glViewport(0, (cls->height / 4) * i, cls->size, cls->height / 4); - - LightOccluderInstance *instance = p_occluders; - - while (instance) { - - RasterizerStorageGLES2::CanvasOccluder *cc = storage->canvas_occluder_owner.getornull(instance->polygon_buffer); - if (!cc || cc->len == 0 || !(p_light_mask & instance->light_mask)) { - - instance = instance->next; - continue; - } - - state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::WORLD_MATRIX, instance->xform_cache); - - RS::CanvasOccluderPolygonCullMode transformed_cull_cache = instance->cull_cache; - - if (transformed_cull_cache != RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED && - (p_light_xform.basis_determinant() * instance->xform_cache.basis_determinant()) < 0) { - transformed_cull_cache = - transformed_cull_cache == RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE ? - RS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE : - RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE; - } - - if (cull != transformed_cull_cache) { - - cull = transformed_cull_cache; - switch (cull) { - case RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED: { - - glDisable(GL_CULL_FACE); - - } break; - case RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE: { - - glEnable(GL_CULL_FACE); - glCullFace(GL_FRONT); - } break; - case RS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE: { - - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - - } break; - } - } - - glBindBuffer(GL_ARRAY_BUFFER, cc->vertex_id); - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glVertexAttribPointer(RS::ARRAY_VERTEX, 3, GL_FLOAT, false, 0, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cc->index_id); - - glDrawElements(GL_TRIANGLES, cc->len * 3, GL_UNSIGNED_SHORT, 0); - - instance = instance->next; - } - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} -void RasterizerCanvasGLES2::reset_canvas() { - - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_DITHER); - glEnable(GL_BLEND); - - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - - // bind the back buffer to a texture so shaders can use it. - // It should probably use texture unit -3 (as GLES2 does as well) but currently that's buggy. - // keeping this for now as there's nothing else that uses texture unit 2 - // TODO ^ - if (storage->frame.current_rt) { - // glActiveTexture(GL_TEXTURE0 + 2); - // glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->copy_screen_effect.color); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} - -void RasterizerCanvasGLES2::_bind_quad_buffer() { - glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices); - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, nullptr); -} -void RasterizerCanvasGLES2::draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src) { - - state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y)); - state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(p_src.position.x, p_src.position.y, p_src.size.x, p_src.size.y)); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); -} - -void RasterizerCanvasGLES2::draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) { - Vector2 half_size; - if (storage->frame.current_rt) { - half_size = Vector2(storage->frame.current_rt->width, storage->frame.current_rt->height); - } else { - half_size = DisplayServer::get_singleton()->window_get_size(); - } - half_size *= 0.5; - Vector2 offset((p_rect.position.x - half_size.x) / half_size.x, (p_rect.position.y - half_size.y) / half_size.y); - Vector2 scale(p_rect.size.x / half_size.x, p_rect.size.y / half_size.y); - - float aspect_ratio = p_rect.size.x / p_rect.size.y; - - // setup our lens shader - state.lens_shader.bind(); - state.lens_shader.set_uniform(LensDistortedShaderGLES2::OFFSET, offset); - state.lens_shader.set_uniform(LensDistortedShaderGLES2::SCALE, scale); - state.lens_shader.set_uniform(LensDistortedShaderGLES2::K1, p_k1); - state.lens_shader.set_uniform(LensDistortedShaderGLES2::K2, p_k2); - state.lens_shader.set_uniform(LensDistortedShaderGLES2::EYE_CENTER, p_eye_center); - state.lens_shader.set_uniform(LensDistortedShaderGLES2::UPSCALE, p_oversample); - state.lens_shader.set_uniform(LensDistortedShaderGLES2::ASPECT_RATIO, aspect_ratio); - - // bind our quad buffer - _bind_quad_buffer(); - - // and draw - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - // and cleanup - glBindBuffer(GL_ARRAY_BUFFER, 0); - - for (int i = 0; i < RS::ARRAY_MAX; i++) { - glDisableVertexAttribArray(i); - } -} - -void RasterizerCanvasGLES2::draw_window_margins(int *black_margin, RID *black_image) { - - Vector2 window_size = DisplayServer::get_singleton()->window_get_size(); - int window_h = window_size.height; - int window_w = window_size.width; - - glBindFramebuffer(GL_FRAMEBUFFER, storage->system_fbo); - glViewport(0, 0, window_size.width, window_size.height); - canvas_begin(); - - if (black_image[MARGIN_LEFT].is_valid()) { - _bind_canvas_texture(black_image[MARGIN_LEFT], RID()); - Size2 sz(storage->texture_get_width(black_image[MARGIN_LEFT]), storage->texture_get_height(black_image[MARGIN_LEFT])); - draw_generic_textured_rect(Rect2(0, 0, black_margin[MARGIN_LEFT], window_h), Rect2(0, 0, sz.x, sz.y)); - } else if (black_margin[MARGIN_LEFT]) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); - - draw_generic_textured_rect(Rect2(0, 0, black_margin[MARGIN_LEFT], window_h), Rect2(0, 0, 1, 1)); - } - - if (black_image[MARGIN_RIGHT].is_valid()) { - _bind_canvas_texture(black_image[MARGIN_RIGHT], RID()); - Size2 sz(storage->texture_get_width(black_image[MARGIN_RIGHT]), storage->texture_get_height(black_image[MARGIN_RIGHT])); - draw_generic_textured_rect(Rect2(window_w - black_margin[MARGIN_RIGHT], 0, black_margin[MARGIN_RIGHT], window_h), Rect2(0, 0, sz.x, sz.y)); - } else if (black_margin[MARGIN_RIGHT]) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); - - draw_generic_textured_rect(Rect2(window_w - black_margin[MARGIN_RIGHT], 0, black_margin[MARGIN_RIGHT], window_h), Rect2(0, 0, 1, 1)); - } - - if (black_image[MARGIN_TOP].is_valid()) { - _bind_canvas_texture(black_image[MARGIN_TOP], RID()); - - Size2 sz(storage->texture_get_width(black_image[MARGIN_TOP]), storage->texture_get_height(black_image[MARGIN_TOP])); - draw_generic_textured_rect(Rect2(0, 0, window_w, black_margin[MARGIN_TOP]), Rect2(0, 0, sz.x, sz.y)); - - } else if (black_margin[MARGIN_TOP]) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); - - draw_generic_textured_rect(Rect2(0, 0, window_w, black_margin[MARGIN_TOP]), Rect2(0, 0, 1, 1)); - } - - if (black_image[MARGIN_BOTTOM].is_valid()) { - - _bind_canvas_texture(black_image[MARGIN_BOTTOM], RID()); - - Size2 sz(storage->texture_get_width(black_image[MARGIN_BOTTOM]), storage->texture_get_height(black_image[MARGIN_BOTTOM])); - draw_generic_textured_rect(Rect2(0, window_h - black_margin[MARGIN_BOTTOM], window_w, black_margin[MARGIN_BOTTOM]), Rect2(0, 0, sz.x, sz.y)); - - } else if (black_margin[MARGIN_BOTTOM]) { - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); - - draw_generic_textured_rect(Rect2(0, window_h - black_margin[MARGIN_BOTTOM], window_w, black_margin[MARGIN_BOTTOM]), Rect2(0, 0, 1, 1)); - } - - canvas_end(); -} - -void RasterizerCanvasGLES2::initialize() { - - // quad buffer - { - glGenBuffers(1, &data.canvas_quad_vertices); - glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices); - - const float qv[8] = { - 0, 0, - 0, 1, - 1, 1, - 1, 0 - }; - - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, qv, GL_STATIC_DRAW); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - // polygon buffer - { - uint32_t poly_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater")); - poly_size *= 1024; - poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float)); - glGenBuffers(1, &data.polygon_buffer); - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); - glBufferData(GL_ARRAY_BUFFER, poly_size, nullptr, GL_DYNAMIC_DRAW); - - data.polygon_buffer_size = poly_size; - - glBindBuffer(GL_ARRAY_BUFFER, 0); - - uint32_t index_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", 128); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater")); - index_size *= 1024; // kb - glGenBuffers(1, &data.polygon_index_buffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_size, nullptr, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - data.polygon_index_buffer_size = index_size; - } - - // ninepatch buffers - { - // array buffer - glGenBuffers(1, &data.ninepatch_vertices); - glBindBuffer(GL_ARRAY_BUFFER, data.ninepatch_vertices); - - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * (16 + 16) * 2, nullptr, GL_DYNAMIC_DRAW); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - - // element buffer - glGenBuffers(1, &data.ninepatch_elements); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ninepatch_elements); - -#define _EIDX(y, x) (y * 4 + x) - uint8_t elems[3 * 2 * 9] = { - - // first row - - _EIDX(0, 0), _EIDX(0, 1), _EIDX(1, 1), - _EIDX(1, 1), _EIDX(1, 0), _EIDX(0, 0), - - _EIDX(0, 1), _EIDX(0, 2), _EIDX(1, 2), - _EIDX(1, 2), _EIDX(1, 1), _EIDX(0, 1), - - _EIDX(0, 2), _EIDX(0, 3), _EIDX(1, 3), - _EIDX(1, 3), _EIDX(1, 2), _EIDX(0, 2), - - // second row - - _EIDX(1, 0), _EIDX(1, 1), _EIDX(2, 1), - _EIDX(2, 1), _EIDX(2, 0), _EIDX(1, 0), - - // the center one would be here, but we'll put it at the end - // so it's easier to disable the center and be able to use - // one draw call for both - - _EIDX(1, 2), _EIDX(1, 3), _EIDX(2, 3), - _EIDX(2, 3), _EIDX(2, 2), _EIDX(1, 2), - - // third row - - _EIDX(2, 0), _EIDX(2, 1), _EIDX(3, 1), - _EIDX(3, 1), _EIDX(3, 0), _EIDX(2, 0), - - _EIDX(2, 1), _EIDX(2, 2), _EIDX(3, 2), - _EIDX(3, 2), _EIDX(3, 1), _EIDX(2, 1), - - _EIDX(2, 2), _EIDX(2, 3), _EIDX(3, 3), - _EIDX(3, 3), _EIDX(3, 2), _EIDX(2, 2), - - // center field - - _EIDX(1, 1), _EIDX(1, 2), _EIDX(2, 2), - _EIDX(2, 2), _EIDX(2, 1), _EIDX(1, 1) - }; -#undef _EIDX - - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elems), elems, GL_STATIC_DRAW); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - state.canvas_shadow_shader.init(); - - state.canvas_shader.init(); - - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows); - - state.canvas_shader.bind(); - - state.lens_shader.init(); - - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP, GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false)); - - state.using_light = nullptr; - state.using_transparent_rt = false; - state.using_skeleton = false; -} - -void RasterizerCanvasGLES2::finalize() { -} - -RasterizerCanvasGLES2::RasterizerCanvasGLES2() { -#ifdef GLES_OVER_GL - use_nvidia_rect_workaround = GLOBAL_GET("rendering/quality/2d/gles2_use_nvidia_rect_flicker_workaround"); -#else - // Not needed (a priori) on GLES devices - use_nvidia_rect_workaround = false; -#endif -} diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h deleted file mode 100644 index 2d6355e948..0000000000 --- a/drivers/gles2/rasterizer_canvas_gles2.h +++ /dev/null @@ -1,148 +0,0 @@ -/*************************************************************************/ -/* rasterizer_canvas_gles2.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 RASTERIZERCANVASGLES2_H -#define RASTERIZERCANVASGLES2_H - -#include "rasterizer_storage_gles2.h" -#include "servers/rendering/rasterizer.h" - -#include "shaders/canvas.glsl.gen.h" -#include "shaders/lens_distorted.glsl.gen.h" - -#include "shaders/canvas_shadow.glsl.gen.h" - -class RasterizerSceneGLES2; - -class RasterizerCanvasGLES2 : public RasterizerCanvas { -public: - enum { - INSTANCE_ATTRIB_BASE = 8, - }; - - struct Uniforms { - Transform projection_matrix; - - Transform2D modelview_matrix; - Transform2D extra_matrix; - - Color final_modulate; - - float time; - }; - - struct Data { - - GLuint canvas_quad_vertices; - GLuint polygon_buffer; - GLuint polygon_index_buffer; - - uint32_t polygon_buffer_size; - uint32_t polygon_index_buffer_size; - - GLuint ninepatch_vertices; - GLuint ninepatch_elements; - - } data; - - struct State { - Uniforms uniforms; - bool canvas_texscreen_used; - CanvasShaderGLES2 canvas_shader; - CanvasShadowShaderGLES2 canvas_shadow_shader; - LensDistortedShaderGLES2 lens_shader; - - bool using_texture_rect; - bool using_ninepatch; - bool using_skeleton; - - Transform2D skeleton_transform; - Transform2D skeleton_transform_inverse; - Size2i skeleton_texture_size; - - RID current_tex; - RID current_normal; - RasterizerStorageGLES2::Texture *current_tex_ptr; - - Transform vp; - Light *using_light; - bool using_shadow; - bool using_transparent_rt; - - } state; - - typedef void Texture; - - RasterizerSceneGLES2 *scene_render; - - RasterizerStorageGLES2 *storage; - - bool use_nvidia_rect_workaround; - - virtual RID light_internal_create(); - virtual void light_internal_update(RID p_rid, Light *p_light); - virtual void light_internal_free(RID p_rid); - - void _set_uniforms(); - - virtual void canvas_begin(); - virtual void canvas_end(); - - _FORCE_INLINE_ void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs); - _FORCE_INLINE_ void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const float *p_weights = nullptr, const int *p_bones = nullptr); - _FORCE_INLINE_ void _draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); - _FORCE_INLINE_ void _draw_generic_indices(GLuint p_primitive, const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); - - _FORCE_INLINE_ void _canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip, RasterizerStorageGLES2::Material *p_material); - void _copy_screen(const Rect2 &p_rect); - _FORCE_INLINE_ void _copy_texscreen(const Rect2 &p_rect); - - virtual void canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform); - virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow); - - virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache); - - virtual void reset_canvas(); - - RasterizerStorageGLES2::Texture *_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map); - - void _bind_quad_buffer(); - void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src); - void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample); - - void initialize(); - void finalize(); - - virtual void draw_window_margins(int *black_margin, RID *black_image); - - RasterizerCanvasGLES2(); -}; - -#endif // RASTERIZERCANVASGLES2_H diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp deleted file mode 100644 index 28f06f939c..0000000000 --- a/drivers/gles2/rasterizer_gles2.cpp +++ /dev/null @@ -1,510 +0,0 @@ -/*************************************************************************/ -/* rasterizer_gles2.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 "rasterizer_gles2.h" - -#include "core/os/os.h" -#include "core/project_settings.h" - -#define _EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 -#define _EXT_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 -#define _EXT_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 -#define _EXT_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 -#define _EXT_DEBUG_SOURCE_API_ARB 0x8246 -#define _EXT_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 -#define _EXT_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 -#define _EXT_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 -#define _EXT_DEBUG_SOURCE_APPLICATION_ARB 0x824A -#define _EXT_DEBUG_SOURCE_OTHER_ARB 0x824B -#define _EXT_DEBUG_TYPE_ERROR_ARB 0x824C -#define _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D -#define _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E -#define _EXT_DEBUG_TYPE_PORTABILITY_ARB 0x824F -#define _EXT_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 -#define _EXT_DEBUG_TYPE_OTHER_ARB 0x8251 -#define _EXT_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 -#define _EXT_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 -#define _EXT_DEBUG_LOGGED_MESSAGES_ARB 0x9145 -#define _EXT_DEBUG_SEVERITY_HIGH_ARB 0x9146 -#define _EXT_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 -#define _EXT_DEBUG_SEVERITY_LOW_ARB 0x9148 -#define _EXT_DEBUG_OUTPUT 0x92E0 - -#ifndef GLAPIENTRY -#if defined(WINDOWS_ENABLED) && !defined(UWP_ENABLED) -#define GLAPIENTRY APIENTRY -#else -#define GLAPIENTRY -#endif -#endif - -#ifndef IPHONE_ENABLED -// We include EGL below to get debug callback on GLES2 platforms, -// but EGL is not available on iOS. -#define CAN_DEBUG -#endif - -#if !defined(GLES_OVER_GL) && defined(CAN_DEBUG) -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#include <GLES2/gl2platform.h> - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#endif - -#if defined(MINGW_ENABLED) || defined(_MSC_VER) -#define strcpy strcpy_s -#endif - -#ifdef CAN_DEBUG -static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const GLvoid *userParam) { - - if (type == _EXT_DEBUG_TYPE_OTHER_ARB) - return; - - if (type == _EXT_DEBUG_TYPE_PERFORMANCE_ARB) - return; //these are ultimately annoying, so removing for now - - char debSource[256], debType[256], debSev[256]; - - if (source == _EXT_DEBUG_SOURCE_API_ARB) - strcpy(debSource, "OpenGL"); - else if (source == _EXT_DEBUG_SOURCE_WINDOW_SYSTEM_ARB) - strcpy(debSource, "Windows"); - else if (source == _EXT_DEBUG_SOURCE_SHADER_COMPILER_ARB) - strcpy(debSource, "Shader Compiler"); - else if (source == _EXT_DEBUG_SOURCE_THIRD_PARTY_ARB) - strcpy(debSource, "Third Party"); - else if (source == _EXT_DEBUG_SOURCE_APPLICATION_ARB) - strcpy(debSource, "Application"); - else if (source == _EXT_DEBUG_SOURCE_OTHER_ARB) - strcpy(debSource, "Other"); - - if (type == _EXT_DEBUG_TYPE_ERROR_ARB) - strcpy(debType, "Error"); - else if (type == _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB) - strcpy(debType, "Deprecated behavior"); - else if (type == _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB) - strcpy(debType, "Undefined behavior"); - else if (type == _EXT_DEBUG_TYPE_PORTABILITY_ARB) - strcpy(debType, "Portability"); - else if (type == _EXT_DEBUG_TYPE_PERFORMANCE_ARB) - strcpy(debType, "Performance"); - else if (type == _EXT_DEBUG_TYPE_OTHER_ARB) - strcpy(debType, "Other"); - - if (severity == _EXT_DEBUG_SEVERITY_HIGH_ARB) - strcpy(debSev, "High"); - else if (severity == _EXT_DEBUG_SEVERITY_MEDIUM_ARB) - strcpy(debSev, "Medium"); - else if (severity == _EXT_DEBUG_SEVERITY_LOW_ARB) - strcpy(debSev, "Low"); - - String output = String() + "GL ERROR: Source: " + debSource + "\tType: " + debType + "\tID: " + itos(id) + "\tSeverity: " + debSev + "\tMessage: " + message; - - ERR_PRINT(output); -} -#endif // CAN_DEBUG - -typedef void (*DEBUGPROCARB)(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const char *message, - const void *userParam); - -typedef void (*DebugMessageCallbackARB)(DEBUGPROCARB callback, const void *userParam); - -RasterizerStorage *RasterizerGLES2::get_storage() { - - return storage; -} - -RasterizerCanvas *RasterizerGLES2::get_canvas() { - - return canvas; -} - -RasterizerScene *RasterizerGLES2::get_scene() { - - return scene; -} - -Error RasterizerGLES2::is_viable() { - -#ifdef GLAD_ENABLED - if (!gladLoadGL()) { - ERR_PRINT("Error initializing GLAD"); - return ERR_UNAVAILABLE; - } - -// GLVersion seems to be used for both GL and GL ES, so we need different version checks for them -#ifdef OPENGL_ENABLED // OpenGL 2.1 Profile required - if (GLVersion.major < 2 || (GLVersion.major == 2 && GLVersion.minor < 1)) { -#else // OpenGL ES 2.0 - if (GLVersion.major < 2) { -#endif - return ERR_UNAVAILABLE; - } - -#ifdef GLES_OVER_GL - //Test GL_ARB_framebuffer_object extension - if (!GLAD_GL_ARB_framebuffer_object) { - //Try older GL_EXT_framebuffer_object extension - if (GLAD_GL_EXT_framebuffer_object) { - glIsRenderbuffer = glIsRenderbufferEXT; - glBindRenderbuffer = glBindRenderbufferEXT; - glDeleteRenderbuffers = glDeleteRenderbuffersEXT; - glGenRenderbuffers = glGenRenderbuffersEXT; - glRenderbufferStorage = glRenderbufferStorageEXT; - glGetRenderbufferParameteriv = glGetRenderbufferParameterivEXT; - glIsFramebuffer = glIsFramebufferEXT; - glBindFramebuffer = glBindFramebufferEXT; - glDeleteFramebuffers = glDeleteFramebuffersEXT; - glGenFramebuffers = glGenFramebuffersEXT; - glCheckFramebufferStatus = glCheckFramebufferStatusEXT; - glFramebufferTexture1D = glFramebufferTexture1DEXT; - glFramebufferTexture2D = glFramebufferTexture2DEXT; - glFramebufferTexture3D = glFramebufferTexture3DEXT; - glFramebufferRenderbuffer = glFramebufferRenderbufferEXT; - glGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameterivEXT; - glGenerateMipmap = glGenerateMipmapEXT; - } else { - return ERR_UNAVAILABLE; - } - } - - if (GLAD_GL_EXT_framebuffer_multisample) { - glRenderbufferStorageMultisample = glRenderbufferStorageMultisampleEXT; - } -#endif // GLES_OVER_GL - -#endif // GLAD_ENABLED - - return OK; -} - -void RasterizerGLES2::initialize() { - - print_verbose("Using GLES2 video driver"); - -#ifdef GLAD_ENABLED - if (OS::get_singleton()->is_stdout_verbose()) { - if (GLAD_GL_ARB_debug_output) { - glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); - glDebugMessageCallbackARB(_gl_debug_print, nullptr); - glEnable(_EXT_DEBUG_OUTPUT); - } else { - print_line("OpenGL debugging not supported!"); - } - } -#endif // GLAD_ENABLED - - // For debugging -#ifdef CAN_DEBUG -#ifdef GLES_OVER_GL - if (OS::get_singleton()->is_stdout_verbose() && GLAD_GL_ARB_debug_output) { - glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_ERROR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE); - glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE); - glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE); - glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_PORTABILITY_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE); - glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_PERFORMANCE_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE); - glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_OTHER_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE); - /* glDebugMessageInsertARB( - GL_DEBUG_SOURCE_API_ARB, - GL_DEBUG_TYPE_OTHER_ARB, 1, - GL_DEBUG_SEVERITY_HIGH_ARB, 5, "hello"); - */ - } -#else - if (OS::get_singleton()->is_stdout_verbose()) { - DebugMessageCallbackARB callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallback"); - if (!callback) { - callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallbackKHR"); - } - - if (callback) { - - print_line("godot: ENABLING GL DEBUG"); - glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); - callback(_gl_debug_print, nullptr); - glEnable(_EXT_DEBUG_OUTPUT); - } - } -#endif // GLES_OVER_GL -#endif // CAN_DEBUG - - print_line("OpenGL ES 2.0 Renderer: " + RenderingServer::get_singleton()->get_video_adapter_name()); - storage->initialize(); - canvas->initialize(); - scene->initialize(); -} - -void RasterizerGLES2::begin_frame(double frame_step) { - time_total += frame_step; - - if (frame_step == 0) { - //to avoid hiccups - frame_step = 0.001; - } - - double time_roll_over = GLOBAL_GET("rendering/limits/time/time_rollover_secs"); - time_total = Math::fmod(time_total, time_roll_over); - - storage->frame.time[0] = time_total; - storage->frame.time[1] = Math::fmod(time_total, 3600); - storage->frame.time[2] = Math::fmod(time_total, 900); - storage->frame.time[3] = Math::fmod(time_total, 60); - storage->frame.count++; - storage->frame.delta = frame_step; - - storage->update_dirty_resources(); - - storage->info.render_final = storage->info.render; - storage->info.render.reset(); - - scene->iteration(); -} - -void RasterizerGLES2::set_current_render_target(RID p_render_target) { - - if (!p_render_target.is_valid() && storage->frame.current_rt && storage->frame.clear_request) { - // pending clear request. Do that first. - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); - glClearColor(storage->frame.clear_request_color.r, - storage->frame.clear_request_color.g, - storage->frame.clear_request_color.b, - storage->frame.clear_request_color.a); - glClear(GL_COLOR_BUFFER_BIT); - } - - if (p_render_target.is_valid()) { - RasterizerStorageGLES2::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target); - storage->frame.current_rt = rt; - ERR_FAIL_COND(!rt); - storage->frame.clear_request = false; - - glViewport(0, 0, rt->width, rt->height); - } else { - storage->frame.current_rt = nullptr; - storage->frame.clear_request = false; - glViewport(0, 0, DisplayServer::get_singleton()->window_get_size().width, DisplayServer::get_singleton()->window_get_size().height); - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); - } -} - -void RasterizerGLES2::restore_render_target(bool p_3d_was_drawn) { - ERR_FAIL_COND(storage->frame.current_rt == nullptr); - RasterizerStorageGLES2::RenderTarget *rt = storage->frame.current_rt; - glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo); - glViewport(0, 0, rt->width, rt->height); -} - -void RasterizerGLES2::clear_render_target(const Color &p_color) { - ERR_FAIL_COND(!storage->frame.current_rt); - - storage->frame.clear_request = true; - storage->frame.clear_request_color = p_color; -} - -void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) { - - if (p_image.is_null() || p_image->empty()) - return; - - int window_w = OS::get_singleton()->get_video_mode(0).width; - int window_h = OS::get_singleton()->get_video_mode(0).height; - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glViewport(0, 0, window_w, window_h); - glDisable(GL_BLEND); - glDepthMask(GL_FALSE); - if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { - glClearColor(0.0, 0.0, 0.0, 0.0); - } else { - glClearColor(p_color.r, p_color.g, p_color.b, 1.0); - } - glClear(GL_COLOR_BUFFER_BIT); - - canvas->canvas_begin(); - - RID texture = storage->texture_create(); - storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), RS::TEXTURE_TYPE_2D, p_use_filter ? RS::TEXTURE_FLAG_FILTER : 0); - storage->texture_set_data(texture, p_image); - - Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height()); - Rect2 screenrect; - if (p_scale) { - - if (window_w > window_h) { - //scale horizontally - screenrect.size.y = window_h; - screenrect.size.x = imgrect.size.x * window_h / imgrect.size.y; - screenrect.position.x = (window_w - screenrect.size.x) / 2; - - } else { - //scale vertically - screenrect.size.x = window_w; - screenrect.size.y = imgrect.size.y * window_w / imgrect.size.x; - screenrect.position.y = (window_h - screenrect.size.y) / 2; - } - } else { - - screenrect = imgrect; - screenrect.position += ((Size2(window_w, window_h) - screenrect.size) / 2.0).floor(); - } - - RasterizerStorageGLES2::Texture *t = storage->texture_owner.getornull(texture); - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); - glBindTexture(GL_TEXTURE_2D, t->tex_id); - canvas->draw_generic_textured_rect(screenrect, Rect2(0, 0, 1, 1)); - glBindTexture(GL_TEXTURE_2D, 0); - canvas->canvas_end(); - - storage->free(texture); - - end_frame(true); -} - -void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen) { - - ERR_FAIL_COND(storage->frame.current_rt); - - RasterizerStorageGLES2::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target); - ERR_FAIL_COND(!rt); - - canvas->state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true); - - canvas->state.canvas_shader.set_custom_shader(0); - canvas->state.canvas_shader.bind(); - - canvas->canvas_begin(); - glDisable(GL_BLEND); - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); - if (rt->external.fbo != 0) { - glBindTexture(GL_TEXTURE_2D, rt->external.color); - } else { - glBindTexture(GL_TEXTURE_2D, rt->color); - } - - // TODO normals - - canvas->draw_generic_textured_rect(p_screen_rect, Rect2(0, 0, 1, -1)); - - glBindTexture(GL_TEXTURE_2D, 0); - canvas->canvas_end(); -} - -void RasterizerGLES2::output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) { - ERR_FAIL_COND(storage->frame.current_rt); - - RasterizerStorageGLES2::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target); - ERR_FAIL_COND(!rt); - - glDisable(GL_BLEND); - - // render to our framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); - - // output our texture - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, rt->color); - - canvas->draw_lens_distortion_rect(p_screen_rect, p_k1, p_k2, p_eye_center, p_oversample); - - glBindTexture(GL_TEXTURE_2D, 0); -} - -void RasterizerGLES2::end_frame(bool p_swap_buffers) { - - if (OS::get_singleton()->is_layered_allowed()) { - if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { -#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED) - Size2 wndsize = OS::get_singleton()->get_layered_buffer_size(); - uint8_t *data = OS::get_singleton()->get_layered_buffer_data(); - if (data) { - glReadPixels(0, 0, wndsize.x, wndsize.y, GL_BGRA, GL_UNSIGNED_BYTE, data); - OS::get_singleton()->swap_layered_buffer(); - - return; - } -#endif - } else { - //clear alpha - glColorMask(false, false, false, true); - glClearColor(0, 0, 0, 1); - glClear(GL_COLOR_BUFFER_BIT); - glColorMask(true, true, true, true); - } - } - - if (p_swap_buffers) - OS::get_singleton()->swap_buffers(); - else - glFinish(); -} - -void RasterizerGLES2::finalize() { -} - -Rasterizer *RasterizerGLES2::_create_current() { - - return memnew(RasterizerGLES2); -} - -void RasterizerGLES2::make_current() { - _create_func = _create_current; -} - -void RasterizerGLES2::register_config() { -} - -RasterizerGLES2::RasterizerGLES2() { - - storage = memnew(RasterizerStorageGLES2); - canvas = memnew(RasterizerCanvasGLES2); - scene = memnew(RasterizerSceneGLES2); - canvas->storage = storage; - canvas->scene_render = scene; - storage->canvas = canvas; - scene->storage = storage; - storage->scene = scene; - - time_total = 0; -} - -RasterizerGLES2::~RasterizerGLES2() { - - memdelete(storage); - memdelete(canvas); -} diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h deleted file mode 100644 index 027a634ae8..0000000000 --- a/drivers/gles2/rasterizer_gles2.h +++ /dev/null @@ -1,76 +0,0 @@ -/*************************************************************************/ -/* rasterizer_gles2.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 RASTERIZERGLES2_H -#define RASTERIZERGLES2_H - -#include "rasterizer_canvas_gles2.h" -#include "rasterizer_scene_gles2.h" -#include "rasterizer_storage_gles2.h" -#include "servers/rendering/rasterizer.h" - -class RasterizerGLES2 : public Rasterizer { - - static Rasterizer *_create_current(); - - RasterizerStorageGLES2 *storage; - RasterizerCanvasGLES2 *canvas; - RasterizerSceneGLES2 *scene; - - double time_total; - -public: - virtual RasterizerStorage *get_storage(); - virtual RasterizerCanvas *get_canvas(); - virtual RasterizerScene *get_scene(); - - virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true); - - virtual void initialize(); - virtual void begin_frame(double frame_step); - virtual void set_current_render_target(RID p_render_target); - virtual void restore_render_target(bool p_3d_was_drawn); - virtual void clear_render_target(const Color &p_color); - virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0); - virtual void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample); - virtual void end_frame(bool p_swap_buffers); - virtual void finalize(); - - static Error is_viable(); - static void make_current(); - static void register_config(); - - virtual bool is_low_end() const { return true; } - - RasterizerGLES2(); - ~RasterizerGLES2(); -}; - -#endif // RASTERIZERGLES2_H diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp deleted file mode 100644 index bdf0559f58..0000000000 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ /dev/null @@ -1,4093 +0,0 @@ -/*************************************************************************/ -/* rasterizer_scene_gles2.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 "rasterizer_scene_gles2.h" - -#include "core/math/math_funcs.h" -#include "core/math/transform.h" -#include "core/os/os.h" -#include "core/project_settings.h" -#include "core/vmap.h" -#include "rasterizer_canvas_gles2.h" -#include "servers/camera/camera_feed.h" -#include "servers/rendering/rendering_server_raster.h" - -#ifndef GLES_OVER_GL -#define glClearDepth glClearDepthf -#endif - -#ifndef GLES_OVER_GL -#ifdef IPHONE_ENABLED -#include <OpenGLES/ES2/glext.h> -//void *glResolveMultisampleFramebufferAPPLE; - -#define GL_READ_FRAMEBUFFER 0x8CA8 -#define GL_DRAW_FRAMEBUFFER 0x8CA9 -#endif -#endif - -#if !defined(GLES_OVER_GL) -#define GL_TEXTURE_2D_ARRAY 0x8C1A -#define GL_TEXTURE_3D 0x806F -#endif - -static const GLenum _cube_side_enum[6] = { - - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_X, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - -}; - -/* SHADOW ATLAS API */ - -RID RasterizerSceneGLES2::shadow_atlas_create() { - - ShadowAtlas *shadow_atlas = memnew(ShadowAtlas); - shadow_atlas->fbo = 0; - shadow_atlas->depth = 0; - shadow_atlas->color = 0; - shadow_atlas->size = 0; - shadow_atlas->smallest_subdiv = 0; - - for (int i = 0; i < 4; i++) { - shadow_atlas->size_order[i] = i; - } - - return shadow_atlas_owner.make_rid(shadow_atlas); -} - -void RasterizerSceneGLES2::shadow_atlas_set_size(RID p_atlas, int p_size) { - 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) - return; - - // erase the old atlast - if (shadow_atlas->fbo) { - if (storage->config.use_rgba_3d_shadows) { - glDeleteRenderbuffers(1, &shadow_atlas->depth); - } else { - glDeleteTextures(1, &shadow_atlas->depth); - } - glDeleteFramebuffers(1, &shadow_atlas->fbo); - if (shadow_atlas->color) { - glDeleteTextures(1, &shadow_atlas->color); - } - - shadow_atlas->fbo = 0; - shadow_atlas->depth = 0; - shadow_atlas->color = 0; - } - - // erase shadow atlast references from lights - for (Map<RID, uint32_t>::Element *E = shadow_atlas->shadow_owners.front(); E; E = E->next()) { - LightInstance *li = light_instance_owner.getornull(E->key()); - ERR_CONTINUE(!li); - li->shadow_atlases.erase(p_atlas); - } - - shadow_atlas->shadow_owners.clear(); - - shadow_atlas->size = p_size; - - if (shadow_atlas->size) { - glGenFramebuffers(1, &shadow_atlas->fbo); - glBindFramebuffer(GL_FRAMEBUFFER, shadow_atlas->fbo); - - // create a depth texture - glActiveTexture(GL_TEXTURE0); - - if (storage->config.use_rgba_3d_shadows) { - - //maximum compatibility, renderbuffer and RGBA shadow - glGenRenderbuffers(1, &shadow_atlas->depth); - glBindRenderbuffer(GL_RENDERBUFFER, shadow_atlas->depth); - glRenderbufferStorage(GL_RENDERBUFFER, storage->config.depth_internalformat, shadow_atlas->size, shadow_atlas->size); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, shadow_atlas->depth); - - glGenTextures(1, &shadow_atlas->color); - glBindTexture(GL_TEXTURE_2D, shadow_atlas->color); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shadow_atlas->size, shadow_atlas->size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, shadow_atlas->color, 0); - } else { - //just depth texture - glGenTextures(1, &shadow_atlas->depth); - glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); - glTexImage2D(GL_TEXTURE_2D, 0, storage->config.depth_internalformat, shadow_atlas->size, shadow_atlas->size, 0, GL_DEPTH_COMPONENT, storage->config.depth_type, nullptr); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadow_atlas->depth, 0); - } - glViewport(0, 0, shadow_atlas->size, shadow_atlas->size); - - glDepthMask(GL_TRUE); - - glClearDepth(0.0f); - glClear(GL_DEPTH_BUFFER_BIT); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - } -} - -void RasterizerSceneGLES2::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); - ERR_FAIL_INDEX(p_subdivision, 16384); - - uint32_t subdiv = next_power_of_2(p_subdivision); - if (subdiv & 0xaaaaaaaa) { // sqrt(subdiv) must be integer - subdiv <<= 1; - } - - subdiv = int(Math::sqrt((float)subdiv)); - - if (shadow_atlas->quadrants[p_quadrant].shadows.size() == (int)subdiv) - return; - - // erase all data from the quadrant - for (int i = 0; i < shadow_atlas->quadrants[p_quadrant].shadows.size(); i++) { - if (shadow_atlas->quadrants[p_quadrant].shadows[i].owner.is_valid()) { - shadow_atlas->shadow_owners.erase(shadow_atlas->quadrants[p_quadrant].shadows[i].owner); - - LightInstance *li = light_instance_owner.getornull(shadow_atlas->quadrants[p_quadrant].shadows[i].owner); - ERR_CONTINUE(!li); - li->shadow_atlases.erase(p_atlas); - } - } - - shadow_atlas->quadrants[p_quadrant].shadows.resize(0); - shadow_atlas->quadrants[p_quadrant].shadows.resize(subdiv); - shadow_atlas->quadrants[p_quadrant].subdivision = subdiv; - - // cache the smallest subdivision for faster allocations - - shadow_atlas->smallest_subdiv = 1 << 30; - - for (int i = 0; i < 4; i++) { - if (shadow_atlas->quadrants[i].subdivision) { - shadow_atlas->smallest_subdiv = MIN(shadow_atlas->smallest_subdiv, shadow_atlas->quadrants[i].subdivision); - } - } - - if (shadow_atlas->smallest_subdiv == 1 << 30) { - shadow_atlas->smallest_subdiv = 0; - } - - // re-sort the quadrants - - int swaps = 0; - do { - swaps = 0; - - for (int i = 0; i < 3; i++) { - if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision < shadow_atlas->quadrants[shadow_atlas->size_order[i + 1]].subdivision) { - SWAP(shadow_atlas->size_order[i], shadow_atlas->size_order[i + 1]); - swaps++; - } - } - - } while (swaps > 0); -} - -bool RasterizerSceneGLES2::_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]; - - if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) { - return false; - } - - // look for an empty space - - int sc = shadow_atlas->quadrants[qidx].shadows.size(); - - ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptrw(); - - int found_free_idx = -1; // found a free one - int found_used_idx = -1; // found an existing one, must steal it - uint64_t min_pass = 0; // pass of the existing one, try to use the least recently - - for (int j = 0; j < sc; j++) { - if (!sarr[j].owner.is_valid()) { - found_free_idx = j; - break; - } - - LightInstance *sli = light_instance_owner.getornull(sarr[j].owner); - ERR_CONTINUE(!sli); - - if (sli->last_scene_pass != scene_pass) { - - // was just allocated, don't kill it so soon, wait a bit... - - if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) { - continue; - } - - if (found_used_idx == -1 || sli->last_scene_pass < min_pass) { - found_used_idx = j; - min_pass = sli->last_scene_pass; - } - } - } - - if (found_free_idx == -1 && found_used_idx == -1) { - continue; // nothing found - } - - if (found_free_idx == -1 && found_used_idx != -1) { - found_free_idx = found_used_idx; - } - - r_quadrant = qidx; - r_shadow = found_free_idx; - - return true; - } - - return false; -} - -bool RasterizerSceneGLES2::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); - - LightInstance *li = light_instance_owner.getornull(p_light_intance); - ERR_FAIL_COND_V(!li, false); - - if (shadow_atlas->size == 0 || shadow_atlas->smallest_subdiv == 0) { - return false; - } - - uint32_t quad_size = shadow_atlas->size >> 1; - int desired_fit = MIN(quad_size / shadow_atlas->smallest_subdiv, next_power_of_2(quad_size * p_coverage)); - - int valid_quadrants[4]; - int valid_quadrant_count = 0; - int best_size = -1; - int best_subdiv = -1; - - for (int i = 0; i < 4; i++) { - int q = shadow_atlas->size_order[i]; - int sd = shadow_atlas->quadrants[q].subdivision; - - if (sd == 0) { - continue; - } - - int max_fit = quad_size / sd; - - if (best_size != -1 && max_fit > best_size) { - break; // what we asked for is bigger than this. - } - - valid_quadrants[valid_quadrant_count] = q; - valid_quadrant_count++; - - best_subdiv = sd; - - if (max_fit >= desired_fit) { - best_size = max_fit; - } - } - - ERR_FAIL_COND_V(valid_quadrant_count == 0, false); // no suitable block available - - uint64_t tick = OS::get_singleton()->get_ticks_msec(); - - if (shadow_atlas->shadow_owners.has(p_light_intance)) { - // light was already known! - - uint32_t key = shadow_atlas->shadow_owners[p_light_intance]; - uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; - uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK; - - bool should_realloc = shadow_atlas->quadrants[q].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[q].shadows[s].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec); - - bool should_redraw = shadow_atlas->quadrants[q].shadows[s].version != p_light_version; - - if (!should_realloc) { - shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version; - return should_redraw; - } - - int new_quadrant; - int new_shadow; - - // find a better place - - if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, shadow_atlas->quadrants[q].subdivision, tick, new_quadrant, new_shadow)) { - // found a better place - - ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow]; - if (sh->owner.is_valid()) { - // it is take but invalid, so we can take it - - shadow_atlas->shadow_owners.erase(sh->owner); - LightInstance *sli = light_instance_owner.getornull(sh->owner); - sli->shadow_atlases.erase(p_atlas); - } - - // erase previous - shadow_atlas->quadrants[q].shadows.write[s].version = 0; - shadow_atlas->quadrants[q].shadows.write[s].owner = RID(); - - sh->owner = p_light_intance; - sh->alloc_tick = tick; - sh->version = p_light_version; - li->shadow_atlases.insert(p_atlas); - - // make a new key - key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT; - key |= new_shadow; - - // update it in the map - shadow_atlas->shadow_owners[p_light_intance] = key; - - // make it dirty, so we redraw - return true; - } - - // no better place found, so we keep the current place - - shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version; - - return should_redraw; - } - - int new_quadrant; - int new_shadow; - - if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, -1, tick, new_quadrant, new_shadow)) { - // found a better place - - ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow]; - if (sh->owner.is_valid()) { - // it is take but invalid, so we can take it - - shadow_atlas->shadow_owners.erase(sh->owner); - LightInstance *sli = light_instance_owner.getornull(sh->owner); - sli->shadow_atlases.erase(p_atlas); - } - - sh->owner = p_light_intance; - sh->alloc_tick = tick; - sh->version = p_light_version; - li->shadow_atlases.insert(p_atlas); - - // make a new key - uint32_t key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT; - key |= new_shadow; - - // update it in the map - shadow_atlas->shadow_owners[p_light_intance] = key; - - // make it dirty, so we redraw - return true; - } - - return false; -} - -void RasterizerSceneGLES2::set_directional_shadow_count(int p_count) { - directional_shadow.light_count = p_count; - directional_shadow.current_light = 0; -} - -int RasterizerSceneGLES2::get_directional_light_shadow_size(RID p_light_intance) { - - ERR_FAIL_COND_V(directional_shadow.light_count == 0, 0); - - int shadow_size; - - if (directional_shadow.light_count == 1) { - shadow_size = directional_shadow.size; - } else { - shadow_size = directional_shadow.size / 2; //more than 4 not supported anyway - } - - LightInstance *light_instance = light_instance_owner.getornull(p_light_intance); - ERR_FAIL_COND_V(!light_instance, 0); - - switch (light_instance->light_ptr->directional_shadow_mode) { - case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: - break; //none - case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: - case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: - shadow_size /= 2; - break; - } - - return shadow_size; -} -////////////////////////////////////////////////////// - -RID RasterizerSceneGLES2::reflection_atlas_create() { - return RID(); -} - -void RasterizerSceneGLES2::reflection_atlas_set_size(RID p_ref_atlas, int p_size) { -} - -void RasterizerSceneGLES2::reflection_atlas_set_subdivision(RID p_ref_atlas, int p_subdiv) { -} - -//////////////////////////////////////////////////// - -RID RasterizerSceneGLES2::reflection_probe_instance_create(RID p_probe) { - - RasterizerStorageGLES2::ReflectionProbe *probe = storage->reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND_V(!probe, RID()); - - ReflectionProbeInstance *rpi = memnew(ReflectionProbeInstance); - - rpi->probe_ptr = probe; - rpi->self = reflection_probe_instance_owner.make_rid(rpi); - rpi->probe = p_probe; - rpi->reflection_atlas_index = -1; - rpi->render_step = -1; - rpi->last_pass = 0; - rpi->current_resolution = 0; - rpi->dirty = true; - - rpi->index = 0; - - for (int i = 0; i < 6; i++) { - glGenFramebuffers(1, &rpi->fbo[i]); - glGenTextures(1, &rpi->color[i]); - } - - glGenRenderbuffers(1, &rpi->depth); - - rpi->cubemap = 0; - //glGenTextures(1, &rpi->cubemap); - - return rpi->self; -} - -void RasterizerSceneGLES2::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); - rpi->transform = p_transform; -} - -void RasterizerSceneGLES2::reflection_probe_release_atlas_index(RID p_instance) { -} - -bool RasterizerSceneGLES2::reflection_probe_instance_needs_redraw(RID p_instance) { - const ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); - ERR_FAIL_COND_V(!rpi, false); - - bool need_redraw = rpi->probe_ptr->resolution != rpi->current_resolution || rpi->dirty || rpi->probe_ptr->update_mode == RS::REFLECTION_PROBE_UPDATE_ALWAYS; - rpi->dirty = false; - return need_redraw; -} - -bool RasterizerSceneGLES2::reflection_probe_instance_has_reflection(RID p_instance) { - return true; -} - -bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { - - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); - ERR_FAIL_COND_V(!rpi, false); - - rpi->render_step = 0; - - if (rpi->probe_ptr->resolution != rpi->current_resolution) { - - //update cubemap if resolution changed - int size = rpi->probe_ptr->resolution; - rpi->current_resolution = size; - - GLenum internal_format = GL_RGB; - GLenum format = GL_RGB; - GLenum type = GL_UNSIGNED_BYTE; - - glActiveTexture(GL_TEXTURE0); - - glBindRenderbuffer(GL_RENDERBUFFER, rpi->depth); - glRenderbufferStorage(GL_RENDERBUFFER, storage->config.depth_internalformat, size, size); - - if (rpi->cubemap != 0) { - glDeleteTextures(1, &rpi->cubemap); - } - - glGenTextures(1, &rpi->cubemap); - glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap); - - // Mobile hardware (PowerVR specially) prefers this approach, - // the previous approach with manual lod levels kills the game. - for (int i = 0; i < 6; i++) { - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, size, size, 0, format, type, nullptr); - } - - glGenerateMipmap(GL_TEXTURE_CUBE_MAP); - - // Generate framebuffers for rendering - for (int i = 0; i < 6; i++) { - glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]); - glBindTexture(GL_TEXTURE_2D, rpi->color[i]); - glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size, size, 0, format, type, nullptr); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rpi->color[i], 0); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rpi->depth); - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE); - } - - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); - } - - return true; -} - -bool RasterizerSceneGLES2::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->current_resolution == 0, false); - - int size = rpi->probe_ptr->resolution; - - { - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - glDepthMask(GL_FALSE); - - for (int i = 0; i < RS::ARRAY_MAX - 1; i++) { - glDisableVertexAttribArray(i); - } - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //use linear, no mipmaps so it does not read from what is being written to - - //first of all, copy rendered textures to cubemap - for (int i = 0; i < 6; i++) { - glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]); - glViewport(0, 0, size, size); - glCopyTexSubImage2D(_cube_side_enum[i], 0, 0, 0, 0, 0, size, size); - } - //do filtering - //vdc cache - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->resources.radical_inverse_vdc_cache_tex); - - // now render to the framebuffer, mipmap level for mipmap level - int lod = 1; - - size >>= 1; - int mipmaps = 6; - - storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false); - storage->shaders.cubemap_filter.bind(); - - glBindFramebuffer(GL_FRAMEBUFFER, storage->resources.mipmap_blur_fbo); - - //blur - while (size >= 1) { - - glActiveTexture(GL_TEXTURE3); - glBindTexture(GL_TEXTURE_2D, storage->resources.mipmap_blur_color); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, storage->resources.mipmap_blur_color, 0); - glViewport(0, 0, size, size); - glActiveTexture(GL_TEXTURE0); - - for (int i = 0; i < 6; i++) { - - storage->bind_quad_array(); - storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::FACE_ID, i); - float roughness = CLAMP(lod / (float)(mipmaps - 1), 0, 1); - storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::ROUGHNESS, roughness); - storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::Z_FLIP, false); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glCopyTexSubImage2D(_cube_side_enum[i], lod, 0, 0, 0, 0, size, size); - } - - size >>= 1; - - lod++; - } - - // restore ranges - glActiveTexture(GL_TEXTURE0); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE3); //back to panorama - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); - - return true; -} - -/* ENVIRONMENT API */ - -RID RasterizerSceneGLES2::environment_create() { - - Environment *env = memnew(Environment); - - return environment_owner.make_rid(env); -} - -void RasterizerSceneGLES2::environment_set_background(RID p_env, RS::EnvironmentBG p_bg) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - env->bg_mode = p_bg; -} - -void RasterizerSceneGLES2::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 RasterizerSceneGLES2::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 RasterizerSceneGLES2::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 RasterizerSceneGLES2::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 RasterizerSceneGLES2::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 RasterizerSceneGLES2::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 RasterizerSceneGLES2::environment_set_ambient_light(RID p_env, const Color &p_color, float p_energy, float p_sky_contribution) { - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->ambient_color = p_color; - env->ambient_energy = p_energy; - env->ambient_sky_contribution = p_sky_contribution; -} - -void RasterizerSceneGLES2::environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) { - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->camera_feed_id = p_camera_feed_id; -} - -void RasterizerSceneGLES2::environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, RS::EnvironmentDOFBlurQuality p_quality) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->dof_blur_far_enabled = p_enable; - env->dof_blur_far_distance = p_distance; - env->dof_blur_far_transition = p_transition; - env->dof_blur_far_amount = p_amount; - env->dof_blur_far_quality = p_quality; -} - -void RasterizerSceneGLES2::environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, RS::EnvironmentDOFBlurQuality p_quality) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->dof_blur_near_enabled = p_enable; - env->dof_blur_near_distance = p_distance; - env->dof_blur_near_transition = p_transition; - env->dof_blur_near_amount = p_amount; - env->dof_blur_near_quality = p_quality; -} - -void RasterizerSceneGLES2::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->glow_enabled = p_enable; - env->glow_levels = p_level_flags; - env->glow_intensity = p_intensity; - env->glow_strength = p_strength; - env->glow_bloom = p_bloom_threshold; - env->glow_blend_mode = p_blend_mode; - env->glow_hdr_bleed_threshold = p_hdr_bleed_threshold; - env->glow_hdr_bleed_scale = p_hdr_bleed_scale; - env->glow_hdr_luminance_cap = p_hdr_luminance_cap; - env->glow_bicubic_upscale = p_bicubic_upscale; -} - -void RasterizerSceneGLES2::environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) { - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); -} - -void RasterizerSceneGLES2::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, bool p_roughness) { - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); -} - -void RasterizerSceneGLES2::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, float p_ao_channel_affect, const Color &p_color, RS::EnvironmentSSAOQuality p_quality, RenderingServer::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) { - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); -} - -void RasterizerSceneGLES2::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); -} - -void RasterizerSceneGLES2::environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) { - - 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->color_correction = p_ramp; -} - -void RasterizerSceneGLES2::environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->fog_enabled = p_enable; - env->fog_color = p_color; - env->fog_sun_color = p_sun_color; - env->fog_sun_amount = p_sun_amount; -} - -void RasterizerSceneGLES2::environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->fog_depth_enabled = p_enable; - env->fog_depth_begin = p_depth_begin; - env->fog_depth_end = p_depth_end; - env->fog_depth_curve = p_depth_curve; - env->fog_transmit_enabled = p_transmit; - env->fog_transmit_curve = p_transmit_curve; -} - -void RasterizerSceneGLES2::environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) { - - Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND(!env); - - env->fog_height_enabled = p_enable; - env->fog_height_min = p_min_height; - env->fog_height_max = p_max_height; - env->fog_height_curve = p_height_curve; -} -bool RasterizerSceneGLES2::is_environment(RID p_env) { - return environment_owner.owns(p_env); -} - -RS::EnvironmentBG RasterizerSceneGLES2::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->bg_mode; -} - -int RasterizerSceneGLES2::environment_get_canvas_max_layer(RID p_env) { - const Environment *env = environment_owner.getornull(p_env); - ERR_FAIL_COND_V(!env, -1); - - return env->canvas_max_layer; -} - -RID RasterizerSceneGLES2::light_instance_create(RID p_light) { - - LightInstance *light_instance = memnew(LightInstance); - - light_instance->last_scene_pass = 0; - - light_instance->light = p_light; - light_instance->light_ptr = storage->light_owner.getornull(p_light); - - light_instance->light_index = 0xFFFF; - - if (!light_instance->light_ptr) { - memdelete(light_instance); - ERR_FAIL_V_MSG(RID(), "Condition ' !light_instance->light_ptr ' is true."); - } - - light_instance->self = light_instance_owner.make_rid(light_instance); - - return light_instance->self; -} - -void RasterizerSceneGLES2::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 RasterizerSceneGLES2::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_bias_scale) { - - LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); - ERR_FAIL_COND(!light_instance); - - if (light_instance->light_ptr->type != RS::LIGHT_DIRECTIONAL) { - p_pass = 0; - } - - ERR_FAIL_INDEX(p_pass, 4); - - light_instance->shadow_transform[p_pass].camera = p_projection; - light_instance->shadow_transform[p_pass].transform = p_transform; - light_instance->shadow_transform[p_pass].farplane = p_far; - light_instance->shadow_transform[p_pass].split = p_split; - light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale; -} - -void RasterizerSceneGLES2::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; -} - -////////////////////// - -RID RasterizerSceneGLES2::gi_probe_instance_create() { - - return RID(); -} - -void RasterizerSceneGLES2::gi_probe_instance_set_light_data(RID p_probe, RID p_base, RID p_data) { -} -void RasterizerSceneGLES2::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) { -} - -void RasterizerSceneGLES2::gi_probe_instance_set_bounds(RID p_probe, const Vector3 &p_bounds) { -} - -//////////////////////////// -//////////////////////////// -//////////////////////////// - -void RasterizerSceneGLES2::_add_geometry(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, int p_material, bool p_depth_pass, bool p_shadow_pass) { - - RasterizerStorageGLES2::Material *material = nullptr; - RID material_src; - - if (p_instance->material_override.is_valid()) { - material_src = p_instance->material_override; - } else if (p_material >= 0) { - material_src = p_instance->materials[p_material]; - } else { - material_src = p_geometry->material; - } - - if (material_src.is_valid()) { - material = storage->material_owner.getornull(material_src); - - if (!material->shader || !material->shader->valid) { - material = nullptr; - } - } - - if (!material) { - material = storage->material_owner.getornull(default_material); - } - - ERR_FAIL_COND(!material); - - _add_geometry_with_material(p_geometry, p_instance, p_owner, material, p_depth_pass, p_shadow_pass); - - while (material->next_pass.is_valid()) { - material = storage->material_owner.getornull(material->next_pass); - - if (!material || !material->shader || !material->shader->valid) { - break; - } - - _add_geometry_with_material(p_geometry, p_instance, p_owner, material, p_depth_pass, p_shadow_pass); - } -} -void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, RasterizerStorageGLES2::Material *p_material, bool p_depth_pass, bool p_shadow_pass) { - - bool has_base_alpha = (p_material->shader->spatial.uses_alpha && !p_material->shader->spatial.uses_alpha_scissor) || p_material->shader->spatial.uses_screen_texture || p_material->shader->spatial.uses_depth_texture; - bool has_blend_alpha = p_material->shader->spatial.blend_mode != RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_MIX; - bool has_alpha = has_base_alpha || has_blend_alpha; - - bool mirror = p_instance->mirror; - - if (p_material->shader->spatial.cull_mode == RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_DISABLED) { - mirror = false; - } else if (p_material->shader->spatial.cull_mode == RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_FRONT) { - mirror = !mirror; - } - - //if (p_material->shader->spatial.uses_sss) { - // state.used_sss = true; - //} - - if (p_material->shader->spatial.uses_screen_texture) { - state.used_screen_texture = true; - } - - if (p_depth_pass) { - - if (has_blend_alpha || p_material->shader->spatial.uses_depth_texture || (has_base_alpha && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) - return; //bye - - if (!p_material->shader->spatial.uses_alpha_scissor && !p_material->shader->spatial.writes_modelview_or_projection && !p_material->shader->spatial.uses_vertex && !p_material->shader->spatial.uses_discard && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { - //shader does not use discard and does not write a vertex position, use generic material - if (p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) { - p_material = storage->material_owner.getornull(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material_twosided : default_material_twosided); - mirror = false; - } else { - p_material = storage->material_owner.getornull(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material : default_material); - } - } - - has_alpha = false; - } - - RenderList::Element *e = (has_alpha || p_material->shader->spatial.no_depth_test) ? render_list.add_alpha_element() : render_list.add_element(); - - if (!e) { - return; - } - - e->geometry = p_geometry; - e->material = p_material; - e->instance = p_instance; - e->owner = p_owner; - e->sort_key = 0; - e->depth_key = 0; - e->use_accum = false; - e->light_index = RenderList::MAX_LIGHTS; - e->use_accum_ptr = &e->use_accum; - e->instancing = (e->instance->base_type == RS::INSTANCE_MULTIMESH) ? 1 : 0; - e->front_facing = false; - - if (e->geometry->last_pass != render_pass) { - e->geometry->last_pass = render_pass; - e->geometry->index = current_geometry_index++; - } - - e->geometry_index = e->geometry->index; - - if (e->material->last_pass != render_pass) { - e->material->last_pass = render_pass; - e->material->index = current_material_index++; - - if (e->material->shader->last_pass != render_pass) { - e->material->shader->index = current_shader_index++; - } - } - - e->material_index = e->material->index; - - if (mirror) { - e->front_facing = true; - } - - e->refprobe_0_index = RenderList::MAX_REFLECTION_PROBES; //refprobe disabled by default - e->refprobe_1_index = RenderList::MAX_REFLECTION_PROBES; //refprobe disabled by default - - if (!p_depth_pass) { - - e->depth_layer = e->instance->depth_layer; - e->priority = p_material->render_priority; - - if (has_alpha && p_material->shader->spatial.depth_draw_mode == RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { - //add element to opaque - RenderList::Element *eo = render_list.add_element(); - *eo = *e; - eo->use_accum_ptr = &eo->use_accum; - } - - int rpsize = e->instance->reflection_probe_instances.size(); - if (rpsize > 0) { - bool first = true; - rpsize = MIN(rpsize, 2); //more than 2 per object are not supported, this keeps it stable - - for (int i = 0; i < rpsize; i++) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(e->instance->reflection_probe_instances[i]); - if (rpi->last_pass != render_pass) { - continue; - } - if (first) { - e->refprobe_0_index = rpi->index; - first = false; - } else { - e->refprobe_1_index = rpi->index; - break; - } - } - - /* if (e->refprobe_0_index > e->refprobe_1_index) { //if both are valid, swap them to keep order as best as possible - uint64_t tmp = e->refprobe_0_index; - e->refprobe_0_index = e->refprobe_1_index; - e->refprobe_1_index = tmp; - }*/ - } - - //add directional lights - - if (p_material->shader->spatial.unshaded) { - e->light_mode = LIGHTMODE_UNSHADED; - } else { - - bool copy = false; - - for (int i = 0; i < render_directional_lights; i++) { - - if (copy) { - RenderList::Element *e2 = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); - if (!e2) { - break; - } - *e2 = *e; //this includes accum ptr :) - e = e2; - } - - //directional sort key - e->light_type1 = 0; - e->light_type2 = 1; - e->light_index = i; - - copy = true; - } - - //add omni / spots - - for (int i = 0; i < e->instance->light_instances.size(); i++) { - - LightInstance *li = light_instance_owner.getornull(e->instance->light_instances[i]); - - if (!li || li->light_index >= render_light_instance_count || render_light_instances[li->light_index] != li) { - continue; // too many or light_index did not correspond to the light instances to be rendered - } - - if (copy) { - RenderList::Element *e2 = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); - if (!e2) { - break; - } - *e2 = *e; //this includes accum ptr :) - e = e2; - } - - //directional sort key - e->light_type1 = 1; - e->light_type2 = li->light_ptr->type == RenderingServer::LIGHT_OMNI ? 0 : 1; - e->light_index = li->light_index; - - copy = true; - } - - if (e->instance->lightmap.is_valid()) { - e->light_mode = LIGHTMODE_LIGHTMAP; - } else if (!e->instance->lightmap_capture_data.empty()) { - e->light_mode = LIGHTMODE_LIGHTMAP_CAPTURE; - } else { - e->light_mode = LIGHTMODE_NORMAL; - } - } - } - - // do not add anything here, as lights are duplicated elements.. - - if (p_material->shader->spatial.uses_time) { - RenderingServerRaster::redraw_request(); - } -} - -void RasterizerSceneGLES2::_copy_texture_to_buffer(GLuint p_texture, GLuint p_buffer) { - - //copy to front buffer - glBindFramebuffer(GL_FRAMEBUFFER, p_buffer); - - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glDepthFunc(GL_LEQUAL); - glColorMask(1, 1, 1, 1); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, p_texture); - - glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); - - storage->shaders.copy.bind(); - - storage->bind_quad_array(); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass) { - - render_pass++; - current_material_index = 0; - current_geometry_index = 0; - current_light_index = 0; - current_refprobe_index = 0; - current_shader_index = 0; - - for (int i = 0; i < p_cull_count; i++) { - - InstanceBase *instance = p_cull_result[i]; - - switch (instance->base_type) { - - case RS::INSTANCE_MESH: { - - RasterizerStorageGLES2::Mesh *mesh = storage->mesh_owner.getornull(instance->base); - ERR_CONTINUE(!mesh); - - int num_surfaces = mesh->surfaces.size(); - - for (int j = 0; j < num_surfaces; j++) { - int material_index = instance->materials[j].is_valid() ? j : -1; - - RasterizerStorageGLES2::Surface *surface = mesh->surfaces[j]; - - _add_geometry(surface, instance, nullptr, material_index, p_depth_pass, p_shadow_pass); - } - - } break; - - case RS::INSTANCE_MULTIMESH: { - RasterizerStorageGLES2::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(instance->base); - ERR_CONTINUE(!multi_mesh); - - if (multi_mesh->size == 0 || multi_mesh->visible_instances == 0) - continue; - - RasterizerStorageGLES2::Mesh *mesh = storage->mesh_owner.getornull(multi_mesh->mesh); - if (!mesh) - continue; - - int ssize = mesh->surfaces.size(); - - for (int j = 0; j < ssize; j++) { - RasterizerStorageGLES2::Surface *s = mesh->surfaces[j]; - _add_geometry(s, instance, multi_mesh, -1, p_depth_pass, p_shadow_pass); - } - } break; - - case RS::INSTANCE_IMMEDIATE: { - RasterizerStorageGLES2::Immediate *im = storage->immediate_owner.getornull(instance->base); - ERR_CONTINUE(!im); - - _add_geometry(im, instance, nullptr, -1, p_depth_pass, p_shadow_pass); - - } break; - - default: { - } - } - } -} - -static const GLenum gl_primitive[] = { - GL_POINTS, - GL_LINES, - GL_LINE_STRIP, - GL_LINE_LOOP, - GL_TRIANGLES, - GL_TRIANGLE_STRIP, - GL_TRIANGLE_FAN -}; - -void RasterizerSceneGLES2::_set_cull(bool p_front, bool p_disabled, bool p_reverse_cull) { - - bool front = p_front; - if (p_reverse_cull) - front = !front; - - if (p_disabled != state.cull_disabled) { - if (p_disabled) - glDisable(GL_CULL_FACE); - else - glEnable(GL_CULL_FACE); - - state.cull_disabled = p_disabled; - } - - if (front != state.cull_front) { - - glCullFace(front ? GL_FRONT : GL_BACK); - state.cull_front = front; - } -} - -bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_material, bool p_alpha_pass, Size2i p_skeleton_tex_size) { - - // material parameters - - state.scene_shader.set_custom_shader(p_material->shader->custom_code_id); - - if (p_material->shader->spatial.uses_screen_texture && storage->frame.current_rt) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->copy_screen_effect.color); - } - - if (p_material->shader->spatial.uses_depth_texture && storage->frame.current_rt) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); - } - - bool shader_rebind = state.scene_shader.bind(); - - if (p_material->shader->spatial.no_depth_test || p_material->shader->spatial.uses_depth_texture) { - glDisable(GL_DEPTH_TEST); - } else { - glEnable(GL_DEPTH_TEST); - } - - switch (p_material->shader->spatial.depth_draw_mode) { - case RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS: - case RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_OPAQUE: { - - glDepthMask(!p_alpha_pass && !p_material->shader->spatial.uses_depth_texture); - } break; - case RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALWAYS: { - glDepthMask(GL_TRUE && !p_material->shader->spatial.uses_depth_texture); - } break; - case RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_NEVER: { - glDepthMask(GL_FALSE); - } break; - } - - int tc = p_material->textures.size(); - const Pair<StringName, RID> *textures = p_material->textures.ptr(); - - const ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = p_material->shader->texture_hints.ptr(); - const ShaderLanguage::DataType *texture_types = p_material->shader->texture_types.ptr(); - - state.scene_shader.set_uniform(SceneShaderGLES2::SKELETON_TEXTURE_SIZE, p_skeleton_tex_size); - - state.current_main_tex = 0; - - for (int i = 0; i < tc; i++) { - - glActiveTexture(GL_TEXTURE0 + i); - - RasterizerStorageGLES2::Texture *t = storage->texture_owner.getornull(textures[i].second); - - if (!t) { - - GLenum target = GL_TEXTURE_2D; - GLuint tex = 0; - switch (texture_types[i]) { - case ShaderLanguage::TYPE_ISAMPLER2D: - case ShaderLanguage::TYPE_USAMPLER2D: - case ShaderLanguage::TYPE_SAMPLER2D: { - - switch (texture_hints[i]) { - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: { - tex = storage->resources.black_tex; - } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: { - tex = storage->resources.aniso_tex; - } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: { - tex = storage->resources.normal_tex; - } break; - default: { - tex = storage->resources.white_tex; - } break; - } - - } break; - - case ShaderLanguage::TYPE_SAMPLERCUBE: { - // TODO - } break; - - case ShaderLanguage::TYPE_ISAMPLER3D: - case ShaderLanguage::TYPE_USAMPLER3D: - case ShaderLanguage::TYPE_SAMPLER3D: { - - target = GL_TEXTURE_3D; - tex = storage->resources.white_tex_3d; - - //switch (texture_hints[i]) { - // TODO - //} - - } break; - - case ShaderLanguage::TYPE_ISAMPLER2DARRAY: - case ShaderLanguage::TYPE_USAMPLER2DARRAY: - case ShaderLanguage::TYPE_SAMPLER2DARRAY: { - - target = GL_TEXTURE_2D_ARRAY; - tex = storage->resources.white_tex_array; - - //switch (texture_hints[i]) { - // TODO - //} - - } break; - - default: { - } - } - - glBindTexture(target, tex); - continue; - } - - if (t->redraw_if_visible) { //must check before proxy because this is often used with proxies - RenderingServerRaster::redraw_request(); - } - - t = t->get_ptr(); - -#ifdef TOOLS_ENABLED - if (t->detect_3d) { - t->detect_3d(t->detect_3d_ud); - } -#endif - -#ifdef TOOLS_ENABLED - if (t->detect_normal && texture_hints[i] == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL) { - t->detect_normal(t->detect_normal_ud); - } -#endif - if (t->render_target) - t->render_target->used_in_frame = true; - - glBindTexture(t->target, t->tex_id); - if (i == 0) { - state.current_main_tex = t->tex_id; - } - } - state.scene_shader.use_material((void *)p_material); - - return shader_rebind; -} - -void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton) { - - switch (p_element->instance->base_type) { - - case RS::INSTANCE_MESH: { - RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); - - glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); - - if (s->index_array_len > 0) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id); - } - - for (int i = 0; i < RS::ARRAY_MAX - 1; i++) { - if (s->attribs[i].enabled) { - glEnableVertexAttribArray(i); - glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, s->attribs[i].type, s->attribs[i].normalized, s->attribs[i].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[i].offset)); - } else { - glDisableVertexAttribArray(i); - switch (i) { - case RS::ARRAY_NORMAL: { - glVertexAttrib4f(RS::ARRAY_NORMAL, 0.0, 0.0, 1, 1); - } break; - case RS::ARRAY_COLOR: { - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - - } break; - default: { - } - } - } - } - - bool clear_skeleton_buffer = storage->config.use_skeleton_software; - - if (p_skeleton) { - - if (!storage->config.use_skeleton_software) { - //use float texture workflow - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); - glBindTexture(GL_TEXTURE_2D, p_skeleton->tex_id); - } else { - //use transform buffer workflow - ERR_FAIL_COND(p_skeleton->use_2d); - - Vector<float> &transform_buffer = storage->resources.skeleton_transform_cpu_buffer; - - if (!s->attribs[RS::ARRAY_BONES].enabled || !s->attribs[RS::ARRAY_WEIGHTS].enabled) { - break; // the whole instance has a skeleton, but this surface is not affected by it. - } - - // 3 * vec4 per vertex - if (transform_buffer.size() < s->array_len * 12) { - transform_buffer.resize(s->array_len * 12); - } - - const size_t bones_offset = s->attribs[RS::ARRAY_BONES].offset; - const size_t bones_stride = s->attribs[RS::ARRAY_BONES].stride; - const size_t bone_weight_offset = s->attribs[RS::ARRAY_WEIGHTS].offset; - const size_t bone_weight_stride = s->attribs[RS::ARRAY_WEIGHTS].stride; - - { - float *write = transform_buffer.ptrw(); - float *buffer = write.ptr(); - - const uint8_t *vertex_array_read = s->data.ptr(); - const uint8_t *vertex_data = vertex_array_read.ptr(); - - for (int i = 0; i < s->array_len; i++) { - - // do magic - - size_t bones[4]; - float bone_weight[4]; - - if (s->attribs[RS::ARRAY_BONES].type == GL_UNSIGNED_BYTE) { - // read as byte - const uint8_t *bones_ptr = vertex_data + bones_offset + (i * bones_stride); - bones[0] = bones_ptr[0]; - bones[1] = bones_ptr[1]; - bones[2] = bones_ptr[2]; - bones[3] = bones_ptr[3]; - } else { - // read as short - const uint16_t *bones_ptr = (const uint16_t *)(vertex_data + bones_offset + (i * bones_stride)); - bones[0] = bones_ptr[0]; - bones[1] = bones_ptr[1]; - bones[2] = bones_ptr[2]; - bones[3] = bones_ptr[3]; - } - - if (s->attribs[RS::ARRAY_WEIGHTS].type == GL_FLOAT) { - // read as float - const float *weight_ptr = (const float *)(vertex_data + bone_weight_offset + (i * bone_weight_stride)); - bone_weight[0] = weight_ptr[0]; - bone_weight[1] = weight_ptr[1]; - bone_weight[2] = weight_ptr[2]; - bone_weight[3] = weight_ptr[3]; - } else { - // read as half - const uint16_t *weight_ptr = (const uint16_t *)(vertex_data + bone_weight_offset + (i * bone_weight_stride)); - bone_weight[0] = (weight_ptr[0] / (float)0xFFFF); - bone_weight[1] = (weight_ptr[1] / (float)0xFFFF); - bone_weight[2] = (weight_ptr[2] / (float)0xFFFF); - bone_weight[3] = (weight_ptr[3] / (float)0xFFFF); - } - - Transform transform; - - Transform bone_transforms[4] = { - storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[0]), - storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[1]), - storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[2]), - storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[3]), - }; - - transform.origin = - bone_weight[0] * bone_transforms[0].origin + - bone_weight[1] * bone_transforms[1].origin + - bone_weight[2] * bone_transforms[2].origin + - bone_weight[3] * bone_transforms[3].origin; - - transform.basis = - bone_transforms[0].basis * bone_weight[0] + - bone_transforms[1].basis * bone_weight[1] + - bone_transforms[2].basis * bone_weight[2] + - bone_transforms[3].basis * bone_weight[3]; - - float row[3][4] = { - { transform.basis[0][0], transform.basis[0][1], transform.basis[0][2], transform.origin[0] }, - { transform.basis[1][0], transform.basis[1][1], transform.basis[1][2], transform.origin[1] }, - { transform.basis[2][0], transform.basis[2][1], transform.basis[2][2], transform.origin[2] }, - }; - - size_t transform_buffer_offset = i * 12; - - copymem(&buffer[transform_buffer_offset], row, sizeof(row)); - } - } - - storage->_update_skeleton_transform_buffer(transform_buffer, s->array_len * 12); - - //enable transform buffer and bind it - glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); - - glEnableVertexAttribArray(INSTANCE_BONE_BASE + 0); - glEnableVertexAttribArray(INSTANCE_BONE_BASE + 1); - glEnableVertexAttribArray(INSTANCE_BONE_BASE + 2); - - glVertexAttribPointer(INSTANCE_BONE_BASE + 0, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 0)); - glVertexAttribPointer(INSTANCE_BONE_BASE + 1, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 1)); - glVertexAttribPointer(INSTANCE_BONE_BASE + 2, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 2)); - - clear_skeleton_buffer = false; - } - } - - if (clear_skeleton_buffer) { - - glDisableVertexAttribArray(INSTANCE_BONE_BASE + 0); - glDisableVertexAttribArray(INSTANCE_BONE_BASE + 1); - glDisableVertexAttribArray(INSTANCE_BONE_BASE + 2); - } - - } break; - - case RS::INSTANCE_MULTIMESH: { - RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); - - glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); - - if (s->index_array_len > 0) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id); - } - - for (int i = 0; i < RS::ARRAY_MAX - 1; i++) { - if (s->attribs[i].enabled) { - glEnableVertexAttribArray(i); - glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, s->attribs[i].type, s->attribs[i].normalized, s->attribs[i].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[i].offset)); - } else { - glDisableVertexAttribArray(i); - switch (i) { - case RS::ARRAY_NORMAL: { - glVertexAttrib4f(RS::ARRAY_NORMAL, 0.0, 0.0, 1, 1); - } break; - case RS::ARRAY_COLOR: { - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - - } break; - default: { - } - } - } - } - - // prepare multimesh (disable) - glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 0); - glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 1); - glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 2); - glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 3); - glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 4); - glDisableVertexAttribArray(INSTANCE_BONE_BASE + 0); - glDisableVertexAttribArray(INSTANCE_BONE_BASE + 1); - glDisableVertexAttribArray(INSTANCE_BONE_BASE + 2); - - } break; - - case RS::INSTANCE_IMMEDIATE: { - } break; - - default: { - } - } -} - -void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { - - switch (p_element->instance->base_type) { - - case RS::INSTANCE_MESH: { - - RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); - - // drawing - - if (s->index_array_len > 0) { - glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); - storage->info.render.vertices_count += s->index_array_len; - } else { - glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); - storage->info.render.vertices_count += s->array_len; - } - /* - if (p_element->instance->skeleton.is_valid() && s->attribs[RS::ARRAY_BONES].enabled && s->attribs[RS::ARRAY_WEIGHTS].enabled) { - //clean up after skeleton - glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); - - glDisableVertexAttribArray(RS::ARRAY_MAX + 0); - glDisableVertexAttribArray(RS::ARRAY_MAX + 1); - glDisableVertexAttribArray(RS::ARRAY_MAX + 2); - - glVertexAttrib4f(RS::ARRAY_MAX + 0, 1, 0, 0, 0); - glVertexAttrib4f(RS::ARRAY_MAX + 1, 0, 1, 0, 0); - glVertexAttrib4f(RS::ARRAY_MAX + 2, 0, 0, 1, 0); - } -*/ - } break; - - case RS::INSTANCE_MULTIMESH: { - - RasterizerStorageGLES2::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES2::MultiMesh *>(p_element->owner); - RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); - - int amount = MIN(multi_mesh->size, multi_mesh->visible_instances); - - if (amount == -1) { - amount = multi_mesh->size; - } - - int stride = multi_mesh->color_floats + multi_mesh->custom_data_floats + multi_mesh->xform_floats; - - int color_ofs = multi_mesh->xform_floats; - int custom_data_ofs = color_ofs + multi_mesh->color_floats; - - // drawing - - const float *base_buffer = multi_mesh->data.ptr(); - - for (int i = 0; i < amount; i++) { - const float *buffer = base_buffer + i * stride; - - { - - glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 0, &buffer[0]); - glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 1, &buffer[4]); - glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 2, &buffer[8]); - } - - if (multi_mesh->color_floats) { - if (multi_mesh->color_format == RS::MULTIMESH_COLOR_8BIT) { - uint8_t *color_data = (uint8_t *)(buffer + color_ofs); - glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, color_data[0] / 255.0, color_data[1] / 255.0, color_data[2] / 255.0, color_data[3] / 255.0); - } else { - glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 3, buffer + color_ofs); - } - } else { - glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, 1.0, 1.0, 1.0, 1.0); - } - - if (multi_mesh->custom_data_floats) { - if (multi_mesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_8BIT) { - uint8_t *custom_data = (uint8_t *)(buffer + custom_data_ofs); - glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 4, custom_data[0] / 255.0, custom_data[1] / 255.0, custom_data[2] / 255.0, custom_data[3] / 255.0); - } else { - glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 4, buffer + custom_data_ofs); - } - } - - if (s->index_array_len > 0) { - glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); - storage->info.render.vertices_count += s->index_array_len; - } else { - glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); - storage->info.render.vertices_count += s->array_len; - } - } - - } break; - - case RS::INSTANCE_IMMEDIATE: { - const RasterizerStorageGLES2::Immediate *im = static_cast<const RasterizerStorageGLES2::Immediate *>(p_element->geometry); - - if (im->building) { - return; - } - - bool restore_tex = false; - - glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer); - - for (const List<RasterizerStorageGLES2::Immediate::Chunk>::Element *E = im->chunks.front(); E; E = E->next()) { - const RasterizerStorageGLES2::Immediate::Chunk &c = E->get(); - - if (c.vertices.empty()) { - continue; - } - - int vertices = c.vertices.size(); - - uint32_t buf_ofs = 0; - - storage->info.render.vertices_count += vertices; - - if (c.texture.is_valid() && storage->texture_owner.owns(c.texture)) { - RasterizerStorageGLES2::Texture *t = storage->texture_owner.getornull(c.texture); - - if (t->redraw_if_visible) { - RenderingServerRaster::redraw_request(); - } - t = t->get_ptr(); - -#ifdef TOOLS_ENABLED - if (t->detect_3d) { - t->detect_3d(t->detect_3d_ud); - } -#endif - if (t->render_target) { - t->render_target->used_in_frame = true; - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(t->target, t->tex_id); - restore_tex = true; - } else if (restore_tex) { - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, state.current_main_tex); - restore_tex = false; - } - - if (!c.normals.empty()) { - glEnableVertexAttribArray(RS::ARRAY_NORMAL); - glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector3) * vertices, c.normals.ptr()); - glVertexAttribPointer(RS::ARRAY_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), CAST_INT_TO_UCHAR_PTR(buf_ofs)); - buf_ofs += sizeof(Vector3) * vertices; - } else { - glDisableVertexAttribArray(RS::ARRAY_NORMAL); - } - - if (!c.tangents.empty()) { - glEnableVertexAttribArray(RS::ARRAY_TANGENT); - glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Plane) * vertices, c.tangents.ptr()); - glVertexAttribPointer(RS::ARRAY_TANGENT, 4, GL_FLOAT, GL_FALSE, sizeof(Plane), CAST_INT_TO_UCHAR_PTR(buf_ofs)); - buf_ofs += sizeof(Plane) * vertices; - } else { - glDisableVertexAttribArray(RS::ARRAY_TANGENT); - } - - if (!c.colors.empty()) { - glEnableVertexAttribArray(RS::ARRAY_COLOR); - glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Color) * vertices, c.colors.ptr()); - glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buf_ofs)); - buf_ofs += sizeof(Color) * vertices; - } else { - glDisableVertexAttribArray(RS::ARRAY_COLOR); - } - - if (!c.uvs.empty()) { - glEnableVertexAttribArray(RS::ARRAY_TEX_UV); - glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector2) * vertices, c.uvs.ptr()); - glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buf_ofs)); - buf_ofs += sizeof(Vector2) * vertices; - } else { - glDisableVertexAttribArray(RS::ARRAY_TEX_UV); - } - - if (!c.uv2s.empty()) { - glEnableVertexAttribArray(RS::ARRAY_TEX_UV2); - glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector2) * vertices, c.uv2s.ptr()); - glVertexAttribPointer(RS::ARRAY_TEX_UV2, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buf_ofs)); - buf_ofs += sizeof(Vector2) * vertices; - } else { - glDisableVertexAttribArray(RS::ARRAY_TEX_UV2); - } - - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector3) * vertices, c.vertices.ptr()); - glVertexAttribPointer(RS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), CAST_INT_TO_UCHAR_PTR(buf_ofs)); - - glDrawArrays(gl_primitive[c.primitive], 0, c.vertices.size()); - } - - if (restore_tex) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, state.current_main_tex); - restore_tex = false; - } - - } break; - default: { - } - } -} - -void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas *shadow_atlas) { - - //turn off all by default - state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTING, false); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, false); - state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, false); - state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, false); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_DIRECTIONAL, false); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_OMNI, false); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_SPOT, false); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, false); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, false); - - if (!p_light) { //no light, return off - return; - } - - //turn on lighting - state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTING, true); - - switch (p_light->light_ptr->type) { - case RS::LIGHT_DIRECTIONAL: { - - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_DIRECTIONAL, true); - switch (p_light->light_ptr->directional_shadow_mode) { - case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { - //no need - } break; - case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, true); - - } break; - case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, true); - } break; - } - - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, p_light->light_ptr->directional_blend_splits); - if (!state.render_no_shadows && p_light->light_ptr->shadow) { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); - if (storage->config.use_rgba_3d_shadows) { - glBindTexture(GL_TEXTURE_2D, directional_shadow.color); - } else { - glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); - } - state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5); - state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13); - } - - } break; - case RS::LIGHT_OMNI: { - - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_OMNI, true); - if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); - if (storage->config.use_rgba_3d_shadows) { - glBindTexture(GL_TEXTURE_2D, shadow_atlas->color); - } else { - glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); - } - state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5); - state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13); - } - } break; - case RS::LIGHT_SPOT: { - - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_SPOT, true); - if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); - if (storage->config.use_rgba_3d_shadows) { - glBindTexture(GL_TEXTURE_2D, shadow_atlas->color); - } else { - glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); - } - state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5); - state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13); - } - } break; - } -} - -void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform, bool accum_pass) { - - RasterizerStorageGLES2::Light *light_ptr = light->light_ptr; - - //common parameters - float energy = light_ptr->param[RS::LIGHT_PARAM_ENERGY]; - float specular = light_ptr->param[RS::LIGHT_PARAM_SPECULAR]; - float sign = (light_ptr->negative && !accum_pass) ? -1 : 1; //inverse color for base pass lights only - - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPECULAR, specular); - Color color = light_ptr->color * sign * energy * Math_PI; - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_COLOR, color); - - state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_COLOR, light_ptr->shadow_color); - - //specific parameters - - switch (light_ptr->type) { - case RS::LIGHT_DIRECTIONAL: { - //not using inverse for performance, view should be normalized anyway - Vector3 direction = p_view_transform.basis.xform_inv(light->transform.basis.xform(Vector3(0, 0, -1))).normalized(); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction); - - CameraMatrix matrices[4]; - - if (!state.render_no_shadows && light_ptr->shadow && directional_shadow.depth) { - - int shadow_count = 0; - Color split_offsets; - - switch (light_ptr->directional_shadow_mode) { - case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { - shadow_count = 1; - } break; - - case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { - shadow_count = 2; - } break; - - case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { - shadow_count = 4; - } break; - } - - for (int k = 0; k < shadow_count; k++) { - - uint32_t x = light->directional_rect.position.x; - uint32_t y = light->directional_rect.position.y; - uint32_t width = light->directional_rect.size.x; - uint32_t height = light->directional_rect.size.y; - - if (light_ptr->directional_shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { - - width /= 2; - height /= 2; - - if (k == 1) { - x += width; - } else if (k == 2) { - y += height; - } else if (k == 3) { - x += width; - y += height; - } - - } else if (light_ptr->directional_shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { - - height /= 2; - - if (k != 0) { - y += height; - } - } - - split_offsets[k] = light->shadow_transform[k].split; - - Transform modelview = (p_view_transform.inverse() * light->shadow_transform[k].transform).affine_inverse(); - - CameraMatrix bias; - bias.set_light_bias(); - CameraMatrix rectm; - Rect2 atlas_rect = Rect2(float(x) / directional_shadow.size, float(y) / directional_shadow.size, float(width) / directional_shadow.size, float(height) / directional_shadow.size); - rectm.set_light_atlas_rect(atlas_rect); - - CameraMatrix shadow_mtx = rectm * bias * light->shadow_transform[k].camera * modelview; - matrices[k] = shadow_mtx; - - /*Color light_clamp; - light_clamp[0] = atlas_rect.position.x; - light_clamp[1] = atlas_rect.position.y; - light_clamp[2] = atlas_rect.size.x; - light_clamp[3] = atlas_rect.size.y;*/ - } - - // state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp); - state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_PIXEL_SIZE, Size2(1.0 / directional_shadow.size, 1.0 / directional_shadow.size)); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPLIT_OFFSETS, split_offsets); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX, matrices[0]); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX2, matrices[1]); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX3, matrices[2]); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX4, matrices[3]); - } - } break; - case RS::LIGHT_OMNI: { - - Vector3 position = p_view_transform.xform_inv(light->transform.origin); - - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_POSITION, position); - - float range = light_ptr->param[RS::LIGHT_PARAM_RANGE]; - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range); - - float attenuation = light_ptr->param[RS::LIGHT_PARAM_ATTENUATION]; - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation); - - if (!state.render_no_shadows && light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) { - - uint32_t key = shadow_atlas->shadow_owners[light->self]; - - uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03; - uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; - - ERR_BREAK(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size()); - - uint32_t atlas_size = shadow_atlas->size; - uint32_t quadrant_size = atlas_size >> 1; - - uint32_t x = (quadrant & 1) * quadrant_size; - uint32_t y = (quadrant >> 1) * quadrant_size; - - uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); - x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - - uint32_t width = shadow_size; - uint32_t height = shadow_size; - - if (light->light_ptr->omni_shadow_detail == RS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { - height /= 2; - } else { - width /= 2; - } - - Transform proj = (p_view_transform.inverse() * light->transform).inverse(); - - Color light_clamp; - light_clamp[0] = float(x) / atlas_size; - light_clamp[1] = float(y) / atlas_size; - light_clamp[2] = float(width) / atlas_size; - light_clamp[3] = float(height) / atlas_size; - - state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_PIXEL_SIZE, Size2(1.0 / shadow_atlas->size, 1.0 / shadow_atlas->size)); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX, proj); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp); - } - } break; - - case RS::LIGHT_SPOT: { - - Vector3 position = p_view_transform.xform_inv(light->transform.origin); - - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_POSITION, position); - - Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized(); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction); - float attenuation = light_ptr->param[RS::LIGHT_PARAM_ATTENUATION]; - float range = light_ptr->param[RS::LIGHT_PARAM_RANGE]; - float spot_attenuation = light_ptr->param[RS::LIGHT_PARAM_SPOT_ATTENUATION]; - float angle = light_ptr->param[RS::LIGHT_PARAM_SPOT_ANGLE]; - angle = Math::cos(Math::deg2rad(angle)); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ATTENUATION, spot_attenuation); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_RANGE, spot_attenuation); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ANGLE, angle); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range); - - if (!state.render_no_shadows && light->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) { - uint32_t key = shadow_atlas->shadow_owners[light->self]; - - uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03; - uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; - - ERR_BREAK(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size()); - - uint32_t atlas_size = shadow_atlas->size; - uint32_t quadrant_size = atlas_size >> 1; - - uint32_t x = (quadrant & 1) * quadrant_size; - uint32_t y = (quadrant >> 1) * quadrant_size; - - uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); - x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - - uint32_t width = shadow_size; - uint32_t height = shadow_size; - - Rect2 rect(float(x) / atlas_size, float(y) / atlas_size, float(width) / atlas_size, float(height) / atlas_size); - - Color light_clamp; - light_clamp[0] = rect.position.x; - light_clamp[1] = rect.position.y; - light_clamp[2] = rect.size.x; - light_clamp[3] = rect.size.y; - - Transform modelview = (p_view_transform.inverse() * light->transform).inverse(); - - CameraMatrix bias; - bias.set_light_bias(); - - CameraMatrix rectm; - rectm.set_light_atlas_rect(rect); - - CameraMatrix shadow_matrix = rectm * bias * light->shadow_transform[0].camera * modelview; - - state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_PIXEL_SIZE, Size2(1.0 / shadow_atlas->size, 1.0 / shadow_atlas->size)); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX, shadow_matrix); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp); - } - - } break; - default: { - } - } -} - -void RasterizerSceneGLES2::_setup_refprobes(ReflectionProbeInstance *p_refprobe1, ReflectionProbeInstance *p_refprobe2, const Transform &p_view_transform, Environment *p_env) { - - if (p_refprobe1) { - state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_USE_BOX_PROJECT, p_refprobe1->probe_ptr->box_projection); - state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_BOX_EXTENTS, p_refprobe1->probe_ptr->extents); - state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_BOX_OFFSET, p_refprobe1->probe_ptr->origin_offset); - state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_EXTERIOR, !p_refprobe1->probe_ptr->interior); - state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_INTENSITY, p_refprobe1->probe_ptr->intensity); - - Color ambient; - if (p_refprobe1->probe_ptr->interior) { - ambient = p_refprobe1->probe_ptr->interior_ambient * p_refprobe1->probe_ptr->interior_ambient_energy; - ambient.a = p_refprobe1->probe_ptr->interior_ambient_probe_contrib; - } else if (p_env) { - ambient = p_env->ambient_color * p_env->ambient_energy; - ambient.a = p_env->ambient_sky_contribution; - } - - state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_AMBIENT, ambient); - - Transform proj = (p_view_transform.inverse() * p_refprobe1->transform).affine_inverse(); - - state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_LOCAL_MATRIX, proj); - } - - if (p_refprobe2) { - state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_USE_BOX_PROJECT, p_refprobe2->probe_ptr->box_projection); - state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_BOX_EXTENTS, p_refprobe2->probe_ptr->extents); - state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_BOX_OFFSET, p_refprobe2->probe_ptr->origin_offset); - state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_EXTERIOR, p_refprobe2->probe_ptr->interior); - state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_INTENSITY, p_refprobe2->probe_ptr->intensity); - - Color ambient; - if (p_refprobe2->probe_ptr->interior) { - ambient = p_refprobe2->probe_ptr->interior_ambient * p_refprobe2->probe_ptr->interior_ambient_energy; - ambient.a = p_refprobe2->probe_ptr->interior_ambient_probe_contrib; - } else if (p_env) { - ambient = p_env->ambient_color * p_env->ambient_energy; - ambient.a = p_env->ambient_sky_contribution; - } - - state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_AMBIENT, ambient); - - Transform proj = (p_view_transform.inverse() * p_refprobe2->transform).affine_inverse(); - - state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_LOCAL_MATRIX, proj); - } -} - -void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, int p_element_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, Environment *p_env, GLuint p_base_env, float p_shadow_bias, float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow) { - - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); - - Vector2 viewport_size = state.viewport_size; - - Vector2 screen_pixel_size = state.screen_pixel_size; - - bool use_radiance_map = false; - if (!p_shadow && p_base_env) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); - glBindTexture(GL_TEXTURE_CUBE_MAP, p_base_env); - use_radiance_map = true; - state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, true); //since prev unshaded is false, this needs to be true if exists - } - - bool prev_unshaded = false; - bool prev_instancing = false; - bool prev_depth_prepass = false; - state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, false); - RasterizerStorageGLES2::Material *prev_material = nullptr; - RasterizerStorageGLES2::Geometry *prev_geometry = nullptr; - RasterizerStorageGLES2::Skeleton *prev_skeleton = nullptr; - RasterizerStorageGLES2::GeometryOwner *prev_owner = nullptr; - - Transform view_transform_inverse = p_view_transform.inverse(); - CameraMatrix projection_inverse = p_projection.inverse(); - - bool prev_base_pass = false; - LightInstance *prev_light = nullptr; - bool prev_vertex_lit = false; - ReflectionProbeInstance *prev_refprobe_1 = nullptr; - ReflectionProbeInstance *prev_refprobe_2 = nullptr; - - int prev_blend_mode = -2; //will always catch the first go - - state.cull_front = false; - state.cull_disabled = false; - glCullFace(GL_BACK); - glEnable(GL_CULL_FACE); - - if (p_alpha_pass) { - glEnable(GL_BLEND); - } else { - glDisable(GL_BLEND); - } - - float fog_max_distance = 0; - bool using_fog = false; - if (p_env && !p_shadow && p_env->fog_enabled && (p_env->fog_depth_enabled || p_env->fog_height_enabled)) { - state.scene_shader.set_conditional(SceneShaderGLES2::FOG_DEPTH_ENABLED, p_env->fog_depth_enabled); - state.scene_shader.set_conditional(SceneShaderGLES2::FOG_HEIGHT_ENABLED, p_env->fog_height_enabled); - if (p_env->fog_depth_end > 0) { - fog_max_distance = p_env->fog_depth_end; - } else { - fog_max_distance = p_projection.get_z_far(); - } - using_fog = true; - } - - RasterizerStorageGLES2::Texture *prev_lightmap = nullptr; - float lightmap_energy = 1.0; - bool prev_use_lightmap_capture = false; - - storage->info.render.draw_call_count += p_element_count; - - for (int i = 0; i < p_element_count; i++) { - RenderList::Element *e = p_elements[i]; - - RasterizerStorageGLES2::Material *material = e->material; - - bool rebind = false; - bool accum_pass = *e->use_accum_ptr; - *e->use_accum_ptr = true; //set to accum for next time this is found - LightInstance *light = nullptr; - ReflectionProbeInstance *refprobe_1 = nullptr; - ReflectionProbeInstance *refprobe_2 = nullptr; - RasterizerStorageGLES2::Texture *lightmap = nullptr; - bool use_lightmap_capture = false; - bool rebind_light = false; - bool rebind_reflection = false; - bool rebind_lightmap = false; - - if (!p_shadow && material->shader) { - - bool unshaded = material->shader->spatial.unshaded; - - if (unshaded != prev_unshaded) { - rebind = true; - if (unshaded) { - state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, true); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTING, false); - } else { - state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, false); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, use_radiance_map); - } - - prev_unshaded = unshaded; - } - - bool base_pass = !accum_pass && !unshaded; //conditions for a base pass - - if (base_pass != prev_base_pass) { - state.scene_shader.set_conditional(SceneShaderGLES2::BASE_PASS, base_pass); - rebind = true; - prev_base_pass = base_pass; - } - - if (!unshaded && e->light_index < RenderList::MAX_LIGHTS) { - light = render_light_instances[e->light_index]; - } - - if (light != prev_light) { - - _setup_light_type(light, shadow_atlas); - rebind = true; - rebind_light = true; - } - - int blend_mode = p_alpha_pass ? material->shader->spatial.blend_mode : -1; // -1 no blend, no mix - - if (accum_pass) { //accum pass force pass - blend_mode = RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_ADD; - if (light && light->light_ptr->negative) { - blend_mode = RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_SUB; - } - } - - if (prev_blend_mode != blend_mode) { - - if (prev_blend_mode == -1 && blend_mode != -1) { - //does blend - glEnable(GL_BLEND); - } else if (blend_mode == -1 && prev_blend_mode != -1) { - //do not blend - glDisable(GL_BLEND); - } - - switch (blend_mode) { - //-1 not handled because not blend is enabled anyway - case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_MIX: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - - } break; - case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_ADD: { - - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(p_alpha_pass ? GL_SRC_ALPHA : GL_ONE, GL_ONE); - - } break; - case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_SUB: { - - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - } break; - case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_MUL: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO); - } else { - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE); - } - - } break; - } - - prev_blend_mode = blend_mode; - } - - //condition to enable vertex lighting on this object - bool vertex_lit = (material->shader->spatial.uses_vertex_lighting || storage->config.force_vertex_shading) && ((!unshaded && light) || using_fog); //fog forces vertex lighting because it still applies even if unshaded or no fog - - if (vertex_lit != prev_vertex_lit) { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, vertex_lit); - prev_vertex_lit = vertex_lit; - } - - if (!unshaded && !accum_pass && e->refprobe_0_index != RenderList::MAX_REFLECTION_PROBES) { - ERR_FAIL_INDEX(e->refprobe_0_index, reflection_probe_count); - refprobe_1 = reflection_probe_instances[e->refprobe_0_index]; - } - if (!unshaded && !accum_pass && e->refprobe_1_index != RenderList::MAX_REFLECTION_PROBES) { - ERR_FAIL_INDEX(e->refprobe_1_index, reflection_probe_count); - refprobe_2 = reflection_probe_instances[e->refprobe_1_index]; - } - - if (refprobe_1 != prev_refprobe_1 || refprobe_2 != prev_refprobe_2) { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE1, refprobe_1 != nullptr); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE2, refprobe_2 != nullptr); - if (refprobe_1 != nullptr && refprobe_1 != prev_refprobe_1) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 5); - glBindTexture(GL_TEXTURE_CUBE_MAP, refprobe_1->cubemap); - } - if (refprobe_2 != nullptr && refprobe_2 != prev_refprobe_2) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 6); - glBindTexture(GL_TEXTURE_CUBE_MAP, refprobe_2->cubemap); - } - rebind = true; - rebind_reflection = true; - } - - use_lightmap_capture = !unshaded && !accum_pass && !e->instance->lightmap_capture_data.empty(); - - if (use_lightmap_capture != prev_use_lightmap_capture) { - - state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP_CAPTURE, use_lightmap_capture); - rebind = true; - } - - if (!unshaded && !accum_pass && e->instance->lightmap.is_valid()) { - - lightmap = storage->texture_owner.getornull(e->instance->lightmap); - lightmap_energy = 1.0; - if (lightmap) { - RasterizerStorageGLES2::LightmapCapture *capture = storage->lightmap_capture_data_owner.getornull(e->instance->lightmap_capture->base); - if (capture) { - lightmap_energy = capture->energy; - } - } - } - - if (lightmap != prev_lightmap) { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP, lightmap != nullptr); - if (lightmap != nullptr) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); - glBindTexture(GL_TEXTURE_2D, lightmap->tex_id); - } - rebind = true; - rebind_lightmap = true; - } - } - - bool depth_prepass = false; - - if (!p_alpha_pass && material->shader->spatial.depth_draw_mode == RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { - depth_prepass = true; - } - - if (depth_prepass != prev_depth_prepass) { - - state.scene_shader.set_conditional(SceneShaderGLES2::USE_DEPTH_PREPASS, depth_prepass); - prev_depth_prepass = depth_prepass; - rebind = true; - } - - bool instancing = e->instance->base_type == RS::INSTANCE_MULTIMESH; - - if (instancing != prev_instancing) { - - state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, instancing); - rebind = true; - } - - RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton); - - if (skeleton != prev_skeleton) { - if ((prev_skeleton == nullptr) != (skeleton == nullptr)) { - if (skeleton) { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, true); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, storage->config.use_skeleton_software); - } else { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, false); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, false); - } - rebind = true; - } - } - - if (e->owner != prev_owner || e->geometry != prev_geometry || skeleton != prev_skeleton) { - _setup_geometry(e, skeleton); - storage->info.render.surface_switch_count++; - } - - bool shader_rebind = false; - if (rebind || material != prev_material) { - - storage->info.render.material_switch_count++; - shader_rebind = _setup_material(material, p_alpha_pass, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); - if (shader_rebind) { - storage->info.render.shader_rebind_count++; - } - } - - _set_cull(e->front_facing, material->shader->spatial.cull_mode == RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_DISABLED, p_reverse_cull); - - if (i == 0 || shader_rebind) { //first time must rebind - - if (p_shadow) { - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_BIAS, p_shadow_bias); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_NORMAL_BIAS, p_shadow_normal_bias); - if (state.shadow_is_dual_parabolloid) { - state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_DUAL_PARABOLOID_RENDER_SIDE, state.dual_parbolloid_direction); - state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_DUAL_PARABOLOID_RENDER_ZFAR, state.dual_parbolloid_zfar); - } - } else { - if (use_radiance_map) { - if (p_env) { - Transform sky_orientation(p_env->sky_orientation, Vector3(0.0, 0.0, 0.0)); - state.scene_shader.set_uniform(SceneShaderGLES2::RADIANCE_INVERSE_XFORM, sky_orientation.affine_inverse() * p_view_transform); - } else { - // would be a bit weird if we don't have this... - state.scene_shader.set_uniform(SceneShaderGLES2::RADIANCE_INVERSE_XFORM, p_view_transform); - } - } - - if (p_env) { - state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, p_env->bg_energy); - state.scene_shader.set_uniform(SceneShaderGLES2::BG_COLOR, p_env->bg_color); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, p_env->ambient_sky_contribution); - - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, p_env->ambient_color); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, p_env->ambient_energy); - - } else { - state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, 1.0); - state.scene_shader.set_uniform(SceneShaderGLES2::BG_COLOR, state.default_bg); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, 1.0); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, state.default_ambient); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, 1.0); - } - - //rebind all these - rebind_light = true; - rebind_reflection = true; - rebind_lightmap = true; - - if (using_fog) { - - state.scene_shader.set_uniform(SceneShaderGLES2::FOG_COLOR_BASE, p_env->fog_color); - Color sun_color_amount = p_env->fog_sun_color; - sun_color_amount.a = p_env->fog_sun_amount; - - state.scene_shader.set_uniform(SceneShaderGLES2::FOG_SUN_COLOR_AMOUNT, sun_color_amount); - state.scene_shader.set_uniform(SceneShaderGLES2::FOG_TRANSMIT_ENABLED, p_env->fog_transmit_enabled); - state.scene_shader.set_uniform(SceneShaderGLES2::FOG_TRANSMIT_CURVE, p_env->fog_transmit_curve); - - if (p_env->fog_depth_enabled) { - state.scene_shader.set_uniform(SceneShaderGLES2::FOG_DEPTH_BEGIN, p_env->fog_depth_begin); - state.scene_shader.set_uniform(SceneShaderGLES2::FOG_DEPTH_CURVE, p_env->fog_depth_curve); - state.scene_shader.set_uniform(SceneShaderGLES2::FOG_MAX_DISTANCE, fog_max_distance); - } - - if (p_env->fog_height_enabled) { - state.scene_shader.set_uniform(SceneShaderGLES2::FOG_HEIGHT_MIN, p_env->fog_height_min); - state.scene_shader.set_uniform(SceneShaderGLES2::FOG_HEIGHT_MAX, p_env->fog_height_max); - state.scene_shader.set_uniform(SceneShaderGLES2::FOG_HEIGHT_MAX, p_env->fog_height_max); - state.scene_shader.set_uniform(SceneShaderGLES2::FOG_HEIGHT_CURVE, p_env->fog_height_curve); - } - } - } - - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform); - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, view_transform_inverse); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, projection_inverse); - - state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]); - - state.scene_shader.set_uniform(SceneShaderGLES2::VIEWPORT_SIZE, viewport_size); - - state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); - } - - if (rebind_light && light) { - _setup_light(light, shadow_atlas, p_view_transform, accum_pass); - } - - if (rebind_reflection && (refprobe_1 || refprobe_2)) { - _setup_refprobes(refprobe_1, refprobe_2, p_view_transform, p_env); - } - - if (rebind_lightmap && lightmap) { - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHTMAP_ENERGY, lightmap_energy); - } - - state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform); - - if (use_lightmap_capture) { //this is per instance, must be set always if present - glUniform4fv(state.scene_shader.get_uniform_location(SceneShaderGLES2::LIGHTMAP_CAPTURES), 12, (const GLfloat *)e->instance->lightmap_capture_data.ptr()); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHTMAP_CAPTURE_SKY, false); - } - - _render_geometry(e); - - prev_geometry = e->geometry; - prev_owner = e->owner; - prev_material = material; - prev_skeleton = skeleton; - prev_instancing = instancing; - prev_light = light; - prev_refprobe_1 = refprobe_1; - prev_refprobe_2 = refprobe_2; - prev_lightmap = lightmap; - prev_use_lightmap_capture = use_lightmap_capture; - } - - _setup_light_type(nullptr, nullptr); //clear light stuff - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, false); - state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, false); - state.scene_shader.set_conditional(SceneShaderGLES2::BASE_PASS, false); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, false); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, false); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, false); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, false); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE1, false); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE2, false); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP, false); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP_CAPTURE, false); - state.scene_shader.set_conditional(SceneShaderGLES2::FOG_DEPTH_ENABLED, false); - state.scene_shader.set_conditional(SceneShaderGLES2::FOG_HEIGHT_ENABLED, false); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_DEPTH_PREPASS, false); -} - -void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy, const Basis &p_sky_orientation) { - ERR_FAIL_COND(!p_sky); - - RasterizerStorageGLES2::Texture *tex = storage->texture_owner.getornull(p_sky->panorama); - ERR_FAIL_COND(!tex); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(tex->target, tex->tex_id); - - glDepthMask(GL_TRUE); - glEnable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glDepthFunc(GL_LEQUAL); - - // Camera - CameraMatrix camera; - - if (p_custom_fov) { - - float near_plane = p_projection.get_z_near(); - float far_plane = p_projection.get_z_far(); - float aspect = p_projection.get_aspect(); - - camera.set_perspective(p_custom_fov, aspect, near_plane, far_plane); - } else { - camera = p_projection; - } - - float flip_sign = p_vflip ? -1 : 1; - - // If matrix[2][0] or matrix[2][1] we're dealing with an asymmetrical projection matrix. This is the case for stereoscopic rendering (i.e. VR). - // To ensure the image rendered is perspective correct we need to move some logic into the shader. For this the USE_ASYM_PANO option is introduced. - // It also means the uv coordinates are ignored in this mode and we don't need our loop. - bool asymmetrical = ((camera.matrix[2][0] != 0.0) || (camera.matrix[2][1] != 0.0)); - - Vector3 vertices[8] = { - Vector3(-1, -1 * flip_sign, 1), - Vector3(0, 1, 0), - Vector3(1, -1 * flip_sign, 1), - Vector3(1, 1, 0), - Vector3(1, 1 * flip_sign, 1), - Vector3(1, 0, 0), - Vector3(-1, 1 * flip_sign, 1), - Vector3(0, 0, 0), - }; - - if (!asymmetrical) { - Vector2 vp_he = camera.get_viewport_half_extents(); - float zn; - zn = p_projection.get_z_near(); - - for (int i = 0; i < 4; i++) { - Vector3 uv = vertices[i * 2 + 1]; - uv.x = (uv.x * 2.0 - 1.0) * vp_he.x; - uv.y = -(uv.y * 2.0 - 1.0) * vp_he.y; - uv.z = -zn; - vertices[i * 2 + 1] = p_transform.basis.xform(uv).normalized(); - vertices[i * 2 + 1].z = -vertices[i * 2 + 1].z; - } - } - - glBindBuffer(GL_ARRAY_BUFFER, state.sky_verts); - glBufferData(GL_ARRAY_BUFFER, sizeof(Vector3) * 8, vertices, GL_DYNAMIC_DRAW); - - // bind sky vertex array.... - glVertexAttribPointer(RS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, 0); - glVertexAttribPointer(RS::ARRAY_TEX_UV, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, CAST_INT_TO_UCHAR_PTR(sizeof(Vector3))); - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glEnableVertexAttribArray(RS::ARRAY_TEX_UV); - - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_ASYM_PANO, asymmetrical); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, !asymmetrical); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, true); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUSTOM_ALPHA, false); - storage->shaders.copy.bind(); - storage->shaders.copy.set_uniform(CopyShaderGLES2::MULTIPLIER, p_energy); - - // don't know why but I always have problems setting a uniform mat3, so we're using a transform - storage->shaders.copy.set_uniform(CopyShaderGLES2::SKY_TRANSFORM, Transform(p_sky_orientation, Vector3(0.0, 0.0, 0.0)).affine_inverse()); - - if (asymmetrical) { - // pack the bits we need from our projection matrix - storage->shaders.copy.set_uniform(CopyShaderGLES2::ASYM_PROJ, camera.matrix[2][0], camera.matrix[0][0], camera.matrix[2][1], camera.matrix[1][1]); - ///@TODO I couldn't get mat3 + p_transform.basis to work, that would be better here. - storage->shaders.copy.set_uniform(CopyShaderGLES2::PANO_TRANSFORM, p_transform); - } - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glDisableVertexAttribArray(RS::ARRAY_VERTEX); - glDisableVertexAttribArray(RS::ARRAY_TEX_UV); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_ASYM_PANO, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false); -} - -void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p_cam_projection) { - - //copy to front buffer - - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glDepthFunc(GL_LEQUAL); - glColorMask(1, 1, 1, 1); - - //no post process on small, transparent or render targets without an env - bool use_post_process = env && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]; - use_post_process = use_post_process && storage->frame.current_rt->width >= 4 && storage->frame.current_rt->height >= 4; - use_post_process = use_post_process && storage->frame.current_rt->mip_maps_allocated; - - if (env) { - use_post_process = use_post_process && (env->adjustments_enabled || env->glow_enabled || env->dof_blur_far_enabled || env->dof_blur_near_enabled); - } - - GLuint next_buffer; - - if (use_post_process) { - next_buffer = storage->frame.current_rt->mip_maps[0].sizes[0].fbo; - } else if (storage->frame.current_rt->external.fbo != 0) { - next_buffer = storage->frame.current_rt->external.fbo; - } else { - // set next_buffer to front buffer so multisample blit can happen if needed - next_buffer = storage->frame.current_rt->fbo; - } - - // If using multisample buffer, resolve to post_process_effect buffer or to front buffer - if (storage->frame.current_rt && storage->frame.current_rt->multisample_active) { -#ifdef GLES_OVER_GL - - glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo); - glReadBuffer(GL_COLOR_ATTACHMENT0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, next_buffer); - glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -#elif IPHONE_ENABLED - - glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, next_buffer); - glResolveMultisampleFramebufferAPPLE(); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -#elif ANDROID_ENABLED - - // In GLES2 Android Blit is not available, so just copy color texture manually - _copy_texture_to_buffer(storage->frame.current_rt->multisample_color, next_buffer); -#else - // TODO: any other platform not supported? this will fail.. maybe we should just call _copy_texture_to_buffer here as well? -#endif - } else if (use_post_process) { - if (storage->frame.current_rt->external.fbo != 0) { - _copy_texture_to_buffer(storage->frame.current_rt->external.color, storage->frame.current_rt->mip_maps[0].sizes[0].fbo); - } else { - _copy_texture_to_buffer(storage->frame.current_rt->color, storage->frame.current_rt->mip_maps[0].sizes[0].fbo); - } - } - - if (!use_post_process) { - return; - } - - // Order of operation - //1) DOF Blur (first blur, then copy to buffer applying the blur) //only on desktop - //2) Bloom (Glow) //only on desktop - //3) Adjustments - - // DOF Blur - - if (env->dof_blur_far_enabled) { - - int vp_h = storage->frame.current_rt->height; - int vp_w = storage->frame.current_rt->width; - - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal()); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_FAR_BLUR, true); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, env->dof_blur_far_quality == RS::ENV_DOF_BLUR_QUALITY_LOW); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, env->dof_blur_far_quality == RS::ENV_DOF_BLUR_QUALITY_MEDIUM); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, env->dof_blur_far_quality == RS::ENV_DOF_BLUR_QUALITY_HIGH); - - state.effect_blur_shader.bind(); - int qsteps[3] = { 4, 10, 20 }; - - float radius = (env->dof_blur_far_amount * env->dof_blur_far_amount) / qsteps[env->dof_blur_far_quality]; - - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_BEGIN, env->dof_blur_far_distance); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_END, env->dof_blur_far_distance + env->dof_blur_far_transition); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_DIR, Vector2(1, 0)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_RADIUS, radius); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::CAMERA_Z_FAR, p_cam_projection.get_z_far()); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); - - glActiveTexture(GL_TEXTURE0); - - if (storage->frame.current_rt->mip_maps[0].color) { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color); - } else { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[0].color); - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); //copy to front first - - storage->_copy_screen(); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_DIR, Vector2(0, 1)); - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->mip_maps[0].sizes[0].fbo); // copy to base level - storage->_copy_screen(); - - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_FAR_BLUR, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::USE_ORTHOGONAL_PROJECTION, false); - } - - if (env->dof_blur_near_enabled) { - - //convert texture to RGBA format if not already - if (!storage->frame.current_rt->used_dof_blur_near) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - } - - int vp_h = storage->frame.current_rt->height; - int vp_w = storage->frame.current_rt->width; - - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal()); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_BLUR, true); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_FIRST_TAP, true); - - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, env->dof_blur_near_quality == RS::ENV_DOF_BLUR_QUALITY_LOW); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, env->dof_blur_near_quality == RS::ENV_DOF_BLUR_QUALITY_MEDIUM); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, env->dof_blur_near_quality == RS::ENV_DOF_BLUR_QUALITY_HIGH); - - state.effect_blur_shader.bind(); - int qsteps[3] = { 4, 10, 20 }; - - float radius = (env->dof_blur_near_amount * env->dof_blur_near_amount) / qsteps[env->dof_blur_near_quality]; - - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_BEGIN, env->dof_blur_near_distance); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_END, env->dof_blur_near_distance - env->dof_blur_near_transition); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_DIR, Vector2(1, 0)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_RADIUS, radius); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::CAMERA_Z_FAR, p_cam_projection.get_z_far()); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); - - glActiveTexture(GL_TEXTURE0); - if (storage->frame.current_rt->mip_maps[0].color) { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color); - } else { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[0].color); - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); //copy to front first - - storage->_copy_screen(); - - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_FIRST_TAP, false); - state.effect_blur_shader.bind(); - - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_BEGIN, env->dof_blur_near_distance); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_END, env->dof_blur_near_distance - env->dof_blur_near_transition); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_DIR, Vector2(0, 1)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_RADIUS, radius); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::CAMERA_Z_FAR, p_cam_projection.get_z_far()); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->mip_maps[0].sizes[0].fbo); // copy to base level - - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - storage->_copy_screen(); - - glDisable(GL_BLEND); - - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_BLUR, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_FIRST_TAP, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::USE_ORTHOGONAL_PROJECTION, false); - storage->frame.current_rt->used_dof_blur_near = true; - } - - if (env->dof_blur_near_enabled || env->dof_blur_far_enabled) { - //these needed to disable filtering, reenamble - glActiveTexture(GL_TEXTURE0); - if (storage->frame.current_rt->mip_maps[0].color) { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } else { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[0].color); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - - //glow - - int max_glow_level = -1; - int glow_mask = 0; - - if (env->glow_enabled) { - - for (int i = 0; i < RS::MAX_GLOW_LEVELS; i++) { - if (env->glow_levels & (1 << i)) { - - if (i >= storage->frame.current_rt->mip_maps[1].sizes.size()) { - max_glow_level = storage->frame.current_rt->mip_maps[1].sizes.size() - 1; - glow_mask |= 1 << max_glow_level; - - } else { - max_glow_level = i; - glow_mask |= (1 << i); - } - } - } - - for (int i = 0; i < (max_glow_level + 1); i++) { - - int vp_w = storage->frame.current_rt->mip_maps[1].sizes[i].width; - int vp_h = storage->frame.current_rt->mip_maps[1].sizes[i].height; - glViewport(0, 0, vp_w, vp_h); - //horizontal pass - if (i == 0) { - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::GLOW_FIRST_PASS, true); - } - - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::GLOW_GAUSSIAN_HORIZONTAL, true); - state.effect_blur_shader.bind(); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::LOD, storage->frame.current_rt->mip_maps[0].color ? float(i) : 0.0); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::GLOW_STRENGTH, env->glow_strength); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::LUMINANCE_CAP, env->glow_hdr_luminance_cap); - - glActiveTexture(GL_TEXTURE0); - - if (storage->frame.current_rt->mip_maps[0].color) { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color); - } else { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[i].color); - } - - if (i == 0) { - - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::GLOW_BLOOM, env->glow_bloom); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::GLOW_HDR_THRESHOLD, env->glow_hdr_bleed_threshold); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::GLOW_HDR_SCALE, env->glow_hdr_bleed_scale); - } - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->mip_maps[1].sizes[i].fbo); - storage->_copy_screen(); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::GLOW_GAUSSIAN_HORIZONTAL, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::GLOW_FIRST_PASS, false); - - //vertical pass - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::GLOW_GAUSSIAN_VERTICAL, true); - state.effect_blur_shader.bind(); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::LOD, storage->frame.current_rt->mip_maps[0].color ? float(i) : 0.0); - state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::GLOW_STRENGTH, env->glow_strength); - glActiveTexture(GL_TEXTURE0); - - if (storage->frame.current_rt->mip_maps[0].color) { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[1].color); - } else { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[1].sizes[i].color); - } - - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->mip_maps[0].sizes[i + 1].fbo); //next level, since mipmaps[0] starts one level bigger - storage->_copy_screen(); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::GLOW_GAUSSIAN_VERTICAL, false); - } - - glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); - } - - if (storage->frame.current_rt->external.fbo != 0) { - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->external.fbo); - } else { - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); - } - - glActiveTexture(GL_TEXTURE0); - if (storage->frame.current_rt->mip_maps[0].color) { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color); - } else { - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[0].color); - } - - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_FILTER_BICUBIC, env->glow_bicubic_upscale); - - if (max_glow_level >= 0) { - if (storage->frame.current_rt->mip_maps[0].color) { - for (int i = 0; i < (max_glow_level + 1); i++) { - - if (glow_mask & (1 << i)) { - if (i == 0) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL1, true); - } - if (i == 1) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL2, true); - } - if (i == 2) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL3, true); - } - if (i == 3) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL4, true); - } - if (i == 4) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL5, true); - } - if (i == 5) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL6, true); - } - if (i == 6) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL7, true); - } - } - } - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color); - } else { - - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_MULTI_TEXTURE_GLOW, true); - int active_glow_level = 0; - for (int i = 0; i < (max_glow_level + 1); i++) { - - if (glow_mask & (1 << i)) { - active_glow_level++; - glActiveTexture(GL_TEXTURE0 + active_glow_level); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[i + 1].color); - if (active_glow_level == 1) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL1, true); - } - if (active_glow_level == 2) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL2, true); - } - if (active_glow_level == 3) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL3, true); - } - if (active_glow_level == 4) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL4, true); - } - if (active_glow_level == 5) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL5, true); - } - if (active_glow_level == 6) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL6, true); - } - if (active_glow_level == 7) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL7, true); - } - } - } - } - - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SCREEN, env->glow_blend_mode == RS::ENV_GLOW_BLEND_MODE_SCREEN); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SOFTLIGHT, env->glow_blend_mode == RS::ENV_GLOW_BLEND_MODE_SOFTLIGHT); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_REPLACE, env->glow_blend_mode == RS::ENV_GLOW_BLEND_MODE_REPLACE); - } - - //Adjustments - if (env->adjustments_enabled) { - - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_BCS, true); - RasterizerStorageGLES2::Texture *tex = storage->texture_owner.getornull(env->color_correction); - if (tex) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_COLOR_CORRECTION, true); - glActiveTexture(GL_TEXTURE2); - glBindTexture(tex->target, tex->tex_id); - } - } - - state.tonemap_shader.bind(); - - if (max_glow_level >= 0) { - - state.tonemap_shader.set_uniform(TonemapShaderGLES2::GLOW_INTENSITY, env->glow_intensity); - int ss[2] = { - storage->frame.current_rt->width, - storage->frame.current_rt->height, - }; - glUniform2iv(state.tonemap_shader.get_uniform(TonemapShaderGLES2::GLOW_TEXTURE_SIZE), 1, ss); - } - - if (env->adjustments_enabled) { - - state.tonemap_shader.set_uniform(TonemapShaderGLES2::BCS, Vector3(env->adjustments_brightness, env->adjustments_contrast, env->adjustments_saturation)); - } - - storage->_copy_screen(); - - //turn off everything used - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL1, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL2, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL3, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL4, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL5, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL6, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL7, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_REPLACE, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SCREEN, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SOFTLIGHT, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_FILTER_BICUBIC, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_MULTI_TEXTURE_GLOW, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_BCS, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_COLOR_CORRECTION, false); -} - -void RasterizerSceneGLES2::render_scene(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_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { - - Transform cam_transform = p_cam_transform; - - storage->info.render.object_count += p_cull_count; - - GLuint current_fb = 0; - Environment *env = nullptr; - - int viewport_width, viewport_height; - int viewport_x = 0; - int viewport_y = 0; - bool probe_interior = false; - bool reverse_cull = false; - - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { - cam_transform.basis.set_axis(1, -cam_transform.basis.get_axis(1)); - reverse_cull = true; - } - - if (p_reflection_probe.is_valid()) { - ReflectionProbeInstance *probe = reflection_probe_instance_owner.getornull(p_reflection_probe); - ERR_FAIL_COND(!probe); - state.render_no_shadows = !probe->probe_ptr->enable_shadows; - - if (!probe->probe_ptr->interior) { //use env only if not interior - env = environment_owner.getornull(p_environment); - } - - current_fb = probe->fbo[p_reflection_probe_pass]; - - viewport_width = probe->probe_ptr->resolution; - viewport_height = probe->probe_ptr->resolution; - - probe_interior = probe->probe_ptr->interior; - - } else { - state.render_no_shadows = false; - if (storage->frame.current_rt->multisample_active) { - current_fb = storage->frame.current_rt->multisample_fbo; - } else if (storage->frame.current_rt->external.fbo != 0) { - current_fb = storage->frame.current_rt->external.fbo; - } else { - current_fb = storage->frame.current_rt->fbo; - } - env = environment_owner.getornull(p_environment); - - viewport_width = storage->frame.current_rt->width; - viewport_height = storage->frame.current_rt->height; - viewport_x = storage->frame.current_rt->x; - - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { - viewport_y = DisplayServer::get_singleton()->window_get_size().height - viewport_height - storage->frame.current_rt->y; - } else { - viewport_y = storage->frame.current_rt->y; - } - } - - state.used_screen_texture = false; - state.viewport_size.x = viewport_width; - state.viewport_size.y = viewport_height; - state.screen_pixel_size.x = 1.0 / viewport_width; - state.screen_pixel_size.y = 1.0 / viewport_height; - - //push back the directional lights - - if (p_light_cull_count) { - //hardcoded limit of 256 lights - render_light_instance_count = MIN(RenderList::MAX_LIGHTS, p_light_cull_count); - render_light_instances = (LightInstance **)alloca(sizeof(LightInstance *) * render_light_instance_count); - render_directional_lights = 0; - - //doing this because directional lights are at the end, put them at the beginning - int index = 0; - for (int i = render_light_instance_count - 1; i >= 0; i--) { - RID light_rid = p_light_cull_result[i]; - - LightInstance *light = light_instance_owner.getornull(light_rid); - - if (light->light_ptr->type == RS::LIGHT_DIRECTIONAL) { - render_directional_lights++; - //as going in reverse, directional lights are always first anyway - } - - light->light_index = index; - render_light_instances[index] = light; - - index++; - } - - } else { - render_light_instances = nullptr; - render_directional_lights = 0; - render_light_instance_count = 0; - } - - if (p_reflection_probe_cull_count) { - - reflection_probe_instances = (ReflectionProbeInstance **)alloca(sizeof(ReflectionProbeInstance *) * p_reflection_probe_cull_count); - reflection_probe_count = p_reflection_probe_cull_count; - for (int i = 0; i < p_reflection_probe_cull_count; i++) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_reflection_probe_cull_result[i]); - ERR_CONTINUE(!rpi); - rpi->last_pass = render_pass + 1; //will be incremented later - rpi->index = i; - reflection_probe_instances[i] = rpi; - } - - } else { - reflection_probe_instances = nullptr; - reflection_probe_count = 0; - } - - if (env && env->bg_mode == RS::ENV_BG_CANVAS) { - // If using canvas background, copy 2d to screen copy texture - // TODO: When GLES2 renders to current_rt->mip_maps[], this copy will no longer be needed - _copy_texture_to_buffer(storage->frame.current_rt->color, storage->frame.current_rt->copy_screen_effect.fbo); - } - - // render list stuff - - render_list.clear(); - _fill_render_list(p_cull_result, p_cull_count, false, false); - - // other stuff - - glBindFramebuffer(GL_FRAMEBUFFER, current_fb); - glViewport(viewport_x, viewport_y, viewport_width, viewport_height); - - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { - - glScissor(viewport_x, viewport_y, viewport_width, viewport_height); - glEnable(GL_SCISSOR_TEST); - } - - glDepthFunc(GL_LEQUAL); - glDepthMask(GL_TRUE); - glClearDepth(1.0f); - glEnable(GL_DEPTH_TEST); - glClear(GL_DEPTH_BUFFER_BIT); - - // clear color - - Color clear_color(0, 0, 0, 1); - Ref<CameraFeed> feed; - - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - clear_color = Color(0, 0, 0, 0); - storage->frame.clear_request = false; - } else if (!env || env->bg_mode == RS::ENV_BG_CLEAR_COLOR || env->bg_mode == RS::ENV_BG_SKY) { - if (storage->frame.clear_request) { - clear_color = storage->frame.clear_request_color; - storage->frame.clear_request = false; - } - } else if (env->bg_mode == RS::ENV_BG_CANVAS || env->bg_mode == RS::ENV_BG_COLOR || env->bg_mode == RS::ENV_BG_COLOR_SKY) { - clear_color = env->bg_color; - storage->frame.clear_request = false; - } else if (env->bg_mode == RS::ENV_BG_CAMERA_FEED) { - feed = CameraServer::get_singleton()->get_feed_by_id(env->camera_feed_id); - storage->frame.clear_request = false; - } else { - storage->frame.clear_request = false; - } - - if (!env || env->bg_mode != RS::ENV_BG_KEEP) { - glClearColor(clear_color.r, clear_color.g, clear_color.b, clear_color.a); - glClear(GL_COLOR_BUFFER_BIT); - } - - state.default_ambient = Color(clear_color.r, clear_color.g, clear_color.b, 1.0); - state.default_bg = Color(clear_color.r, clear_color.g, clear_color.b, 1.0); - - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { - glDisable(GL_SCISSOR_TEST); - } - - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - // render sky - RasterizerStorageGLES2::Sky *sky = nullptr; - GLuint env_radiance_tex = 0; - if (env) { - switch (env->bg_mode) { - - case RS::ENV_BG_COLOR_SKY: - case RS::ENV_BG_SKY: { - sky = storage->sky_owner.getornull(env->sky); - - if (sky) { - env_radiance_tex = sky->radiance; - } - } break; - case RS::ENV_BG_CAMERA_FEED: { - if (feed.is_valid() && (feed->get_base_width() > 0) && (feed->get_base_height() > 0)) { - // copy our camera feed to our background - - glDisable(GL_BLEND); - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_NO_ALPHA, true); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_DISPLAY_TRANSFORM, true); - - if (feed->get_datatype() == CameraFeed::FEED_RGB) { - RID camera_RGBA = feed->get_texture(CameraServer::FEED_RGBA_IMAGE); - - RS::get_singleton()->texture_bind(camera_RGBA, 0); - - } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR) { - RID camera_YCbCr = feed->get_texture(CameraServer::FEED_YCBCR_IMAGE); - - RS::get_singleton()->texture_bind(camera_YCbCr, 0); - - storage->shaders.copy.set_conditional(CopyShaderGLES2::YCBCR_TO_RGB, true); - - } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR_SEP) { - RID camera_Y = feed->get_texture(CameraServer::FEED_Y_IMAGE); - RID camera_CbCr = feed->get_texture(CameraServer::FEED_CBCR_IMAGE); - - RS::get_singleton()->texture_bind(camera_Y, 0); - RS::get_singleton()->texture_bind(camera_CbCr, 1); - - storage->shaders.copy.set_conditional(CopyShaderGLES2::SEP_CBCR_TEXTURE, true); - storage->shaders.copy.set_conditional(CopyShaderGLES2::YCBCR_TO_RGB, true); - }; - - storage->shaders.copy.bind(); - storage->shaders.copy.set_uniform(CopyShaderGLES2::DISPLAY_TRANSFORM, feed->get_transform()); - - storage->bind_quad_array(); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisableVertexAttribArray(RS::ARRAY_VERTEX); - glDisableVertexAttribArray(RS::ARRAY_TEX_UV); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - // turn off everything used - storage->shaders.copy.set_conditional(CopyShaderGLES2::SEP_CBCR_TEXTURE, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::YCBCR_TO_RGB, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_NO_ALPHA, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_DISPLAY_TRANSFORM, false); - - //restore - glEnable(GL_BLEND); - glDepthMask(GL_TRUE); - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - } else { - // don't have a feed, just show greenscreen :) - clear_color = Color(0.0, 1.0, 0.0, 1.0); - } - } break; - case RS::ENV_BG_CANVAS: { - // use screen copy as background - _copy_texture_to_buffer(storage->frame.current_rt->copy_screen_effect.color, current_fb); - } break; - default: { - } break; - } - } - - if (probe_interior) { - env_radiance_tex = 0; //do not use radiance texture on interiors - state.default_ambient = Color(0, 0, 0, 1); //black as default ambient for interior - state.default_bg = Color(0, 0, 0, 1); //black as default background for interior - } - - // render opaque things first - render_list.sort_by_key(false); - _render_render_list(render_list.elements, render_list.element_count, cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, reverse_cull, false, false); - - // then draw the sky after - if (env && env->bg_mode == RS::ENV_BG_SKY && (!storage->frame.current_rt || !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT])) { - - if (sky && sky->panorama.is_valid()) { - _draw_sky(sky, p_cam_projection, cam_transform, false, env->sky_custom_fov, env->bg_energy, env->sky_orientation); - } - } - - if (storage->frame.current_rt && state.used_screen_texture) { - //copy screen texture - - if (storage->frame.current_rt->multisample_active) { - // Resolve framebuffer to front buffer before copying -#ifdef GLES_OVER_GL - - glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo); - glReadBuffer(GL_COLOR_ATTACHMENT0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo); - glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -#elif IPHONE_ENABLED - - glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo); - glResolveMultisampleFramebufferAPPLE(); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -#elif ANDROID_ENABLED - - // In GLES2 AndroidBlit is not available, so just copy color texture manually - _copy_texture_to_buffer(storage->frame.current_rt->multisample_color, storage->frame.current_rt->fbo); -#endif - } - - storage->canvas->_copy_screen(Rect2()); - - if (storage->frame.current_rt && storage->frame.current_rt->multisample_active) { - // Rebind the current framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, current_fb); - glViewport(0, 0, viewport_width, viewport_height); - } - } - // alpha pass - - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - render_list.sort_by_reverse_depth_and_priority(true); - - _render_render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, reverse_cull, true, false); - - if (p_reflection_probe.is_valid()) { - // Rendering to a probe so no need for post_processing - return; - } - - //post process - _post_process(env, p_cam_projection); - - //#define GLES2_SHADOW_ATLAS_DEBUG_VIEW - -#ifdef GLES2_SHADOW_ATLAS_DEBUG_VIEW - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); - if (shadow_atlas) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); - - glViewport(0, 0, storage->frame.current_rt->width / 4, storage->frame.current_rt->height / 4); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUSTOM_ALPHA, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, false); - storage->shaders.copy.bind(); - - storage->_copy_screen(); - } -#endif - - //#define GLES2_SHADOW_DIRECTIONAL_DEBUG_VIEW - -#ifdef GLES2_SHADOW_DIRECTIONAL_DEBUG_VIEW - if (true) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); - - glViewport(0, 0, storage->frame.current_rt->width / 4, storage->frame.current_rt->height / 4); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUSTOM_ALPHA, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, false); - storage->shaders.copy.bind(); - - storage->_copy_screen(); - } -#endif -} - -void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) { - - state.render_no_shadows = false; - - LightInstance *light_instance = light_instance_owner.getornull(p_light); - ERR_FAIL_COND(!light_instance); - - RasterizerStorageGLES2::Light *light = light_instance->light_ptr; - ERR_FAIL_COND(!light); - - uint32_t x; - uint32_t y; - uint32_t width; - uint32_t height; - - float zfar = 0; - bool flip_facing = false; - int custom_vp_size = 0; - GLuint fbo = 0; - state.shadow_is_dual_parabolloid = false; - state.dual_parbolloid_direction = 0.0; - - int current_cubemap = -1; - float bias = 0; - float normal_bias = 0; - - CameraMatrix light_projection; - Transform light_transform; - - // TODO directional light - - if (light->type == RS::LIGHT_DIRECTIONAL) { - // set pssm stuff - - // TODO set this only when changed - - light_instance->light_directional_index = directional_shadow.current_light; - light_instance->last_scene_shadow_pass = scene_pass; - - directional_shadow.current_light++; - - if (directional_shadow.light_count == 1) { - light_instance->directional_rect = Rect2(0, 0, directional_shadow.size, directional_shadow.size); - } else if (directional_shadow.light_count == 2) { - light_instance->directional_rect = Rect2(0, 0, directional_shadow.size, directional_shadow.size / 2); - if (light_instance->light_directional_index == 1) { - light_instance->directional_rect.position.x += light_instance->directional_rect.size.x; - } - } else { //3 and 4 - light_instance->directional_rect = Rect2(0, 0, directional_shadow.size / 2, directional_shadow.size / 2); - if (light_instance->light_directional_index & 1) { - light_instance->directional_rect.position.x += light_instance->directional_rect.size.x; - } - if (light_instance->light_directional_index / 2) { - light_instance->directional_rect.position.y += light_instance->directional_rect.size.y; - } - } - - light_projection = light_instance->shadow_transform[p_pass].camera; - light_transform = light_instance->shadow_transform[p_pass].transform; - - x = light_instance->directional_rect.position.x; - y = light_instance->directional_rect.position.y; - width = light_instance->directional_rect.size.width; - height = light_instance->directional_rect.size.height; - - if (light->directional_shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { - - width /= 2; - height /= 2; - - if (p_pass == 1) { - x += width; - } else if (p_pass == 2) { - y += height; - } else if (p_pass == 3) { - x += width; - y += height; - } - - } else if (light->directional_shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { - - height /= 2; - - if (p_pass == 0) { - - } else { - y += height; - } - } - - float bias_mult = Math::lerp(1.0f, light_instance->shadow_transform[p_pass].bias_scale, light->param[RS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE]); - zfar = light->param[RS::LIGHT_PARAM_RANGE]; - bias = light->param[RS::LIGHT_PARAM_SHADOW_BIAS] * bias_mult; - normal_bias = light->param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * bias_mult; - - fbo = directional_shadow.fbo; - } else { - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); - ERR_FAIL_COND(!shadow_atlas); - ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light)); - - fbo = shadow_atlas->fbo; - - uint32_t key = shadow_atlas->shadow_owners[p_light]; - - uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03; - uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; - - ERR_FAIL_INDEX((int)shadow, shadow_atlas->quadrants[quadrant].shadows.size()); - - uint32_t quadrant_size = shadow_atlas->size >> 1; - - x = (quadrant & 1) * quadrant_size; - y = (quadrant >> 1) * quadrant_size; - - uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); - x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - - width = shadow_size; - height = shadow_size; - - if (light->type == RS::LIGHT_OMNI) { - // cubemap only - if (light->omni_shadow_mode == RS::LIGHT_OMNI_SHADOW_CUBE && storage->config.support_shadow_cubemaps) { - int cubemap_index = shadow_cubemaps.size() - 1; - - // find an appropriate cubemap to render to - for (int i = shadow_cubemaps.size() - 1; i >= 0; i--) { - if (shadow_cubemaps[i].size > shadow_size * 2) { - break; - } - - cubemap_index = i; - } - - fbo = shadow_cubemaps[cubemap_index].fbo[p_pass]; - light_projection = light_instance->shadow_transform[0].camera; - light_transform = light_instance->shadow_transform[0].transform; - - custom_vp_size = shadow_cubemaps[cubemap_index].size; - zfar = light->param[RS::LIGHT_PARAM_RANGE]; - - current_cubemap = cubemap_index; - } else { - //dual parabolloid - state.shadow_is_dual_parabolloid = true; - light_projection = light_instance->shadow_transform[0].camera; - light_transform = light_instance->shadow_transform[0].transform; - - if (light->omni_shadow_detail == RS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { - - height /= 2; - y += p_pass * height; - } else { - width /= 2; - x += p_pass * width; - } - - state.dual_parbolloid_direction = p_pass == 0 ? 1.0 : -1.0; - flip_facing = (p_pass == 1); - zfar = light->param[RS::LIGHT_PARAM_RANGE]; - bias = light->param[RS::LIGHT_PARAM_SHADOW_BIAS]; - - state.dual_parbolloid_zfar = zfar; - - state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH_DUAL_PARABOLOID, true); - } - - } else if (light->type == RS::LIGHT_SPOT) { - light_projection = light_instance->shadow_transform[0].camera; - light_transform = light_instance->shadow_transform[0].transform; - - flip_facing = false; - zfar = light->param[RS::LIGHT_PARAM_RANGE]; - bias = light->param[RS::LIGHT_PARAM_SHADOW_BIAS]; - normal_bias = light->param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS]; - } - } - - render_list.clear(); - - _fill_render_list(p_cull_result, p_cull_count, true, true); - - render_list.sort_by_depth(false); - - glDisable(GL_BLEND); - glDisable(GL_DITHER); - glEnable(GL_DEPTH_TEST); - - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - glDepthMask(GL_TRUE); - if (!storage->config.use_rgba_3d_shadows) { - glColorMask(0, 0, 0, 0); - } - - if (custom_vp_size) { - glViewport(0, 0, custom_vp_size, custom_vp_size); - glScissor(0, 0, custom_vp_size, custom_vp_size); - } else { - glViewport(x, y, width, height); - glScissor(x, y, width, height); - } - - glEnable(GL_SCISSOR_TEST); - glClearDepth(1.0f); - glClear(GL_DEPTH_BUFFER_BIT); - if (storage->config.use_rgba_3d_shadows) { - glClearColor(1.0, 1.0, 1.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); - } - glDisable(GL_SCISSOR_TEST); - - if (light->reverse_cull) { - flip_facing = !flip_facing; - } - - state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH, true); - - _render_render_list(render_list.elements, render_list.element_count, light_transform, light_projection, RID(), nullptr, 0, bias, normal_bias, flip_facing, false, true); - - state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH, false); - state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH_DUAL_PARABOLOID, false); - - // convert cubemap to dual paraboloid if needed - if (light->type == RS::LIGHT_OMNI && (light->omni_shadow_mode == RS::LIGHT_OMNI_SHADOW_CUBE && storage->config.support_shadow_cubemaps) && p_pass == 5) { - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); - - glBindFramebuffer(GL_FRAMEBUFFER, shadow_atlas->fbo); - state.cube_to_dp_shader.bind(); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, shadow_cubemaps[current_cubemap].cubemap); - - glDisable(GL_CULL_FACE); - - for (int i = 0; i < 2; i++) { - state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES2::Z_FLIP, i == 1); - state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES2::Z_NEAR, light_projection.get_z_near()); - state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES2::Z_FAR, light_projection.get_z_far()); - state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES2::BIAS, light->param[RS::LIGHT_PARAM_SHADOW_BIAS]); - - uint32_t local_width = width; - uint32_t local_height = height; - uint32_t local_x = x; - uint32_t local_y = y; - - if (light->omni_shadow_detail == RS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { - local_height /= 2; - local_y += i * local_height; - } else { - local_width /= 2; - local_x += i * local_width; - } - - glViewport(local_x, local_y, local_width, local_height); - glScissor(local_x, local_y, local_width, local_height); - - glEnable(GL_SCISSOR_TEST); - - glClearDepth(1.0f); - - glClear(GL_DEPTH_BUFFER_BIT); - glDisable(GL_SCISSOR_TEST); - - glDisable(GL_BLEND); - - storage->_copy_screen(); - } - } - - if (storage->frame.current_rt) { - glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); - } - if (!storage->config.use_rgba_3d_shadows) { - glColorMask(1, 1, 1, 1); - } -} - -void RasterizerSceneGLES2::set_scene_pass(uint64_t p_pass) { - scene_pass = p_pass; -} - -bool RasterizerSceneGLES2::free(RID p_rid) { - - if (light_instance_owner.owns(p_rid)) { - - LightInstance *light_instance = light_instance_owner.getornull(p_rid); - - //remove from shadow atlases.. - for (Set<RID>::Element *E = light_instance->shadow_atlases.front(); E; E = E->next()) { - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(E->get()); - ERR_CONTINUE(!shadow_atlas->shadow_owners.has(p_rid)); - uint32_t key = shadow_atlas->shadow_owners[p_rid]; - uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; - uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK; - - shadow_atlas->quadrants[q].shadows.write[s].owner = RID(); - shadow_atlas->shadow_owners.erase(p_rid); - } - - light_instance_owner.free(p_rid); - memdelete(light_instance); - - } else if (shadow_atlas_owner.owns(p_rid)) { - - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_rid); - shadow_atlas_set_size(p_rid, 0); - shadow_atlas_owner.free(p_rid); - memdelete(shadow_atlas); - } else if (reflection_probe_instance_owner.owns(p_rid)) { - - ReflectionProbeInstance *reflection_instance = reflection_probe_instance_owner.getornull(p_rid); - - for (int i = 0; i < 6; i++) { - glDeleteFramebuffers(1, &reflection_instance->fbo[i]); - glDeleteTextures(1, &reflection_instance->color[i]); - } - - if (reflection_instance->cubemap != 0) { - glDeleteTextures(1, &reflection_instance->cubemap); - } - glDeleteRenderbuffers(1, &reflection_instance->depth); - - reflection_probe_release_atlas_index(p_rid); - reflection_probe_instance_owner.free(p_rid); - memdelete(reflection_instance); - - } else { - return false; - } - - return true; -} - -void RasterizerSceneGLES2::set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) { -} - -void RasterizerSceneGLES2::initialize() { - state.scene_shader.init(); - - state.scene_shader.set_conditional(SceneShaderGLES2::USE_RGBA_SHADOWS, storage->config.use_rgba_3d_shadows); - state.cube_to_dp_shader.init(); - state.effect_blur_shader.init(); - state.tonemap_shader.init(); - - render_list.init(); - - render_pass = 1; - - shadow_atlas_realloc_tolerance_msec = 500; - - { - //default material and shader - - default_shader = storage->shader_create(); - storage->shader_set_code(default_shader, "shader_type spatial;\n"); - default_material = storage->material_create(); - storage->material_set_shader(default_material, default_shader); - - default_shader_twosided = storage->shader_create(); - default_material_twosided = storage->material_create(); - storage->shader_set_code(default_shader_twosided, "shader_type spatial; render_mode cull_disabled;\n"); - storage->material_set_shader(default_material_twosided, default_shader_twosided); - } - - { - default_worldcoord_shader = storage->shader_create(); - storage->shader_set_code(default_worldcoord_shader, "shader_type spatial; render_mode world_vertex_coords;\n"); - default_worldcoord_material = storage->material_create(); - storage->material_set_shader(default_worldcoord_material, default_worldcoord_shader); - - default_worldcoord_shader_twosided = storage->shader_create(); - default_worldcoord_material_twosided = storage->material_create(); - storage->shader_set_code(default_worldcoord_shader_twosided, "shader_type spatial; render_mode cull_disabled,world_vertex_coords;\n"); - storage->material_set_shader(default_worldcoord_material_twosided, default_worldcoord_shader_twosided); - } - - { - //default material and shader - - default_overdraw_shader = storage->shader_create(); - storage->shader_set_code(default_overdraw_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }"); - default_overdraw_material = storage->material_create(); - storage->material_set_shader(default_overdraw_material, default_overdraw_shader); - } - - { - glGenBuffers(1, &state.sky_verts); - glBindBuffer(GL_ARRAY_BUFFER, state.sky_verts); - glBufferData(GL_ARRAY_BUFFER, sizeof(Vector3) * 8, nullptr, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - { - uint32_t immediate_buffer_size = GLOBAL_DEF("rendering/limits/buffers/immediate_buffer_size_kb", 2048); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/immediate_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/immediate_buffer_size_kb", PROPERTY_HINT_RANGE, "0,8192,1,or_greater")); - - glGenBuffers(1, &state.immediate_buffer); - glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer); - glBufferData(GL_ARRAY_BUFFER, immediate_buffer_size * 1024, nullptr, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - // cubemaps for shadows - if (storage->config.support_shadow_cubemaps) { //not going to be used - int max_shadow_cubemap_sampler_size = 512; - - int cube_size = max_shadow_cubemap_sampler_size; - - glActiveTexture(GL_TEXTURE0); - - while (cube_size >= 32) { - - ShadowCubeMap cube; - - cube.size = cube_size; - - glGenTextures(1, &cube.cubemap); - glBindTexture(GL_TEXTURE_CUBE_MAP, cube.cubemap); - - for (int i = 0; i < 6; i++) { - - glTexImage2D(_cube_side_enum[i], 0, storage->config.depth_internalformat, cube_size, cube_size, 0, GL_DEPTH_COMPONENT, storage->config.depth_type, nullptr); - } - - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glGenFramebuffers(6, cube.fbo); - for (int i = 0; i < 6; i++) { - - glBindFramebuffer(GL_FRAMEBUFFER, cube.fbo[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, _cube_side_enum[i], cube.cubemap, 0); - } - - shadow_cubemaps.push_back(cube); - - cube_size >>= 1; - } - } - - { - // directional shadows - - directional_shadow.light_count = 0; - directional_shadow.size = next_power_of_2(GLOBAL_GET("rendering/quality/directional_shadow/size")); - - glGenFramebuffers(1, &directional_shadow.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, directional_shadow.fbo); - - if (storage->config.use_rgba_3d_shadows) { - //maximum compatibility, renderbuffer and RGBA shadow - glGenRenderbuffers(1, &directional_shadow.depth); - glBindRenderbuffer(GL_RENDERBUFFER, directional_shadow.depth); - glRenderbufferStorage(GL_RENDERBUFFER, storage->config.depth_buffer_internalformat, directional_shadow.size, directional_shadow.size); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, directional_shadow.depth); - - glGenTextures(1, &directional_shadow.color); - glBindTexture(GL_TEXTURE_2D, directional_shadow.color); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, directional_shadow.size, directional_shadow.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, directional_shadow.color, 0); - } else { - //just a depth buffer - glGenTextures(1, &directional_shadow.depth); - glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); - - glTexImage2D(GL_TEXTURE_2D, 0, storage->config.depth_internalformat, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, storage->config.depth_type, nullptr); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, directional_shadow.depth, 0); - } - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - ERR_PRINT("Directional shadow framebuffer status invalid"); - } - } - - shadow_filter_mode = SHADOW_FILTER_NEAREST; - - glFrontFace(GL_CW); -} - -void RasterizerSceneGLES2::iteration() { - shadow_filter_mode = ShadowFilterMode(int(GLOBAL_GET("rendering/quality/shadows/filter_mode"))); -} - -void RasterizerSceneGLES2::finalize() { -} - -RasterizerSceneGLES2::RasterizerSceneGLES2() { -} diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h deleted file mode 100644 index 56c0e632c2..0000000000 --- a/drivers/gles2/rasterizer_scene_gles2.h +++ /dev/null @@ -1,661 +0,0 @@ -/*************************************************************************/ -/* rasterizer_scene_gles2.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 RASTERIZERSCENEGLES2_H -#define RASTERIZERSCENEGLES2_H - -/* Must come before shaders or the Windows build fails... */ -#include "rasterizer_storage_gles2.h" - -#include "shaders/cube_to_dp.glsl.gen.h" -#include "shaders/effect_blur.glsl.gen.h" -#include "shaders/scene.glsl.gen.h" -#include "shaders/tonemap.glsl.gen.h" - -class RasterizerSceneGLES2 : public RasterizerScene { -public: - enum ShadowFilterMode { - SHADOW_FILTER_NEAREST, - SHADOW_FILTER_PCF5, - SHADOW_FILTER_PCF13, - }; - - enum { - INSTANCE_ATTRIB_BASE = 8, - INSTANCE_BONE_BASE = 13, - }; - - ShadowFilterMode shadow_filter_mode; - - RID default_material; - RID default_material_twosided; - RID default_shader; - RID default_shader_twosided; - - RID default_worldcoord_material; - RID default_worldcoord_material_twosided; - RID default_worldcoord_shader; - RID default_worldcoord_shader_twosided; - - RID default_overdraw_material; - RID default_overdraw_shader; - - uint64_t render_pass; - uint64_t scene_pass; - uint32_t current_material_index; - uint32_t current_geometry_index; - uint32_t current_light_index; - uint32_t current_refprobe_index; - uint32_t current_shader_index; - - RasterizerStorageGLES2 *storage; - struct State { - - bool texscreen_copied; - int current_blend_mode; - float current_line_width; - int current_depth_draw; - bool current_depth_test; - GLuint current_main_tex; - - SceneShaderGLES2 scene_shader; - CubeToDpShaderGLES2 cube_to_dp_shader; - TonemapShaderGLES2 tonemap_shader; - EffectBlurShaderGLES2 effect_blur_shader; - - GLuint sky_verts; - - GLuint immediate_buffer; - Color default_ambient; - Color default_bg; - - bool cull_front; - bool cull_disabled; - - bool used_screen_texture; - bool shadow_is_dual_parabolloid; - float dual_parbolloid_direction; - float dual_parbolloid_zfar; - - bool render_no_shadows; - - Vector2 viewport_size; - - Vector2 screen_pixel_size; - } state; - - /* SHADOW ATLAS API */ - - uint64_t shadow_atlas_realloc_tolerance_msec; - - struct ShadowAtlas { - enum { - QUADRANT_SHIFT = 27, - SHADOW_INDEX_MASK = (1 << QUADRANT_SHIFT) - 1, - SHADOW_INVALID = 0xFFFFFFFF, - }; - - struct Quadrant { - uint32_t subdivision; - - struct Shadow { - RID owner; - uint64_t version; - uint64_t alloc_tick; - - Shadow() { - version = 0; - alloc_tick = 0; - } - }; - - Vector<Shadow> shadows; - - Quadrant() { - subdivision = 0; - } - } quadrants[4]; - - int size_order[4]; - uint32_t smallest_subdiv; - - int size; - - GLuint fbo; - GLuint depth; - GLuint color; - - Map<RID, uint32_t> shadow_owners; - }; - - struct ShadowCubeMap { - GLuint fbo[6]; - GLuint cubemap; - uint32_t size; - }; - - Vector<ShadowCubeMap> shadow_cubemaps; - - RID_PtrOwner<ShadowAtlas> shadow_atlas_owner; - - RID shadow_atlas_create(); - void shadow_atlas_set_size(RID p_atlas, int p_size); - void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision); - 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); - bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version); - - struct DirectionalShadow { - GLuint fbo; - GLuint depth; - GLuint color; - - int light_count; - int size; - int current_light; - } directional_shadow; - - virtual int get_directional_light_shadow_size(RID p_light_intance); - virtual void set_directional_shadow_count(int p_count); - - /* REFLECTION PROBE ATLAS API */ - - virtual RID reflection_atlas_create(); - virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_size); - virtual void reflection_atlas_set_subdivision(RID p_ref_atlas, int p_subdiv); - - /* REFLECTION CUBEMAPS */ - - /* REFLECTION PROBE INSTANCE */ - - struct ReflectionProbeInstance { - - RasterizerStorageGLES2::ReflectionProbe *probe_ptr; - RID probe; - RID self; - RID atlas; - - int reflection_atlas_index; - - int render_step; - int reflection_index; - - GLuint fbo[6]; - GLuint color[6]; - GLuint depth; - GLuint cubemap; - - int current_resolution; - mutable bool dirty; - - uint64_t last_pass; - uint32_t index; - - Transform transform; - }; - - mutable RID_PtrOwner<ReflectionProbeInstance> reflection_probe_instance_owner; - - ReflectionProbeInstance **reflection_probe_instances; - int reflection_probe_count; - - virtual RID reflection_probe_instance_create(RID p_probe); - virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform); - virtual void reflection_probe_release_atlas_index(RID p_instance); - virtual bool reflection_probe_instance_needs_redraw(RID p_instance); - virtual bool reflection_probe_instance_has_reflection(RID p_instance); - virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas); - virtual bool reflection_probe_instance_postprocess_step(RID p_instance); - - /* ENVIRONMENT API */ - - struct Environment { - RS::EnvironmentBG bg_mode; - - RID sky; - float sky_custom_fov; - Basis sky_orientation; - - Color bg_color; - float bg_energy; - float sky_ambient; - - int camera_feed_id; - - Color ambient_color; - float ambient_energy; - float ambient_sky_contribution; - - int canvas_max_layer; - - bool glow_enabled; - int glow_levels; - float glow_intensity; - float glow_strength; - float glow_bloom; - RS::EnvironmentGlowBlendMode glow_blend_mode; - float glow_hdr_bleed_threshold; - float glow_hdr_bleed_scale; - float glow_hdr_luminance_cap; - bool glow_bicubic_upscale; - - bool dof_blur_far_enabled; - float dof_blur_far_distance; - float dof_blur_far_transition; - float dof_blur_far_amount; - RS::EnvironmentDOFBlurQuality dof_blur_far_quality; - - bool dof_blur_near_enabled; - float dof_blur_near_distance; - float dof_blur_near_transition; - float dof_blur_near_amount; - RS::EnvironmentDOFBlurQuality dof_blur_near_quality; - - bool adjustments_enabled; - float adjustments_brightness; - float adjustments_contrast; - float adjustments_saturation; - RID color_correction; - - bool fog_enabled; - Color fog_color; - Color fog_sun_color; - float fog_sun_amount; - - bool fog_depth_enabled; - float fog_depth_begin; - float fog_depth_end; - float fog_depth_curve; - bool fog_transmit_enabled; - float fog_transmit_curve; - bool fog_height_enabled; - float fog_height_min; - float fog_height_max; - float fog_height_curve; - - Environment() : - bg_mode(RS::ENV_BG_CLEAR_COLOR), - sky_custom_fov(0.0), - bg_energy(1.0), - sky_ambient(0), - camera_feed_id(0), - ambient_energy(1.0), - ambient_sky_contribution(0.0), - canvas_max_layer(0), - glow_enabled(false), - glow_levels((1 << 2) | (1 << 4)), - glow_intensity(0.8), - glow_strength(1.0), - glow_bloom(0.0), - glow_blend_mode(RS::ENV_GLOW_BLEND_MODE_SOFTLIGHT), - glow_hdr_bleed_threshold(1.0), - glow_hdr_bleed_scale(2.0), - glow_hdr_luminance_cap(12.0), - glow_bicubic_upscale(false), - dof_blur_far_enabled(false), - dof_blur_far_distance(10), - dof_blur_far_transition(5), - dof_blur_far_amount(0.1), - dof_blur_far_quality(RS::ENV_DOF_BLUR_QUALITY_MEDIUM), - dof_blur_near_enabled(false), - dof_blur_near_distance(2), - dof_blur_near_transition(1), - dof_blur_near_amount(0.1), - dof_blur_near_quality(RS::ENV_DOF_BLUR_QUALITY_MEDIUM), - adjustments_enabled(false), - adjustments_brightness(1.0), - adjustments_contrast(1.0), - adjustments_saturation(1.0), - fog_enabled(false), - fog_color(Color(0.5, 0.5, 0.5)), - fog_sun_color(Color(0.8, 0.8, 0.0)), - fog_sun_amount(0), - fog_depth_enabled(true), - fog_depth_begin(10), - fog_depth_end(0), - fog_depth_curve(1), - fog_transmit_enabled(true), - fog_transmit_curve(1), - fog_height_enabled(false), - fog_height_min(10), - fog_height_max(0), - fog_height_curve(1) { - } - }; - - mutable RID_PtrOwner<Environment> environment_owner; - - virtual RID environment_create(); - - virtual void environment_set_background(RID p_env, RS::EnvironmentBG p_bg); - virtual void environment_set_sky(RID p_env, RID p_sky); - virtual void environment_set_sky_custom_fov(RID p_env, float p_scale); - virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation); - virtual void environment_set_bg_color(RID p_env, const Color &p_color); - virtual void environment_set_bg_energy(RID p_env, float p_energy); - virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer); - virtual void environment_set_ambient_light(RID p_env, const Color &p_color, float p_energy = 1.0, float p_sky_contribution = 0.0); - virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id); - - virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, RS::EnvironmentDOFBlurQuality p_quality); - virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, RS::EnvironmentDOFBlurQuality p_quality); - virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale); - virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture); - - 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, bool p_roughness); - virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, float p_ao_channel_affect, const Color &p_color, RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness); - - 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); - - virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp); - - virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount); - virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve); - virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve); - - virtual bool is_environment(RID p_env); - - virtual RS::EnvironmentBG environment_get_background(RID p_env); - virtual int environment_get_canvas_max_layer(RID p_env); - - /* LIGHT INSTANCE */ - - struct LightInstance { - - struct ShadowTransform { - CameraMatrix camera; - Transform transform; - float farplane; - float split; - float bias_scale; - }; - - ShadowTransform shadow_transform[4]; - - RID self; - RID light; - - RasterizerStorageGLES2::Light *light_ptr; - Transform transform; - - Vector3 light_vector; - Vector3 spot_vector; - float linear_att; - - // TODO passes and all that stuff ? - uint64_t last_scene_pass; - uint64_t last_scene_shadow_pass; - - uint16_t light_index; - uint16_t light_directional_index; - - Rect2 directional_rect; - - Set<RID> shadow_atlases; // atlases where this light is registered - }; - - mutable RID_PtrOwner<LightInstance> light_instance_owner; - - virtual RID light_instance_create(RID p_light); - virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform); - 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_bias_scale = 1.0); - virtual void light_instance_mark_visible(RID p_light_instance); - virtual bool light_instances_can_render_shadow_cube() const { return storage->config.support_shadow_cubemaps; } - - LightInstance **render_light_instances; - int render_directional_lights; - int render_light_instance_count; - - /* REFLECTION INSTANCE */ - - virtual RID gi_probe_instance_create(); - virtual void gi_probe_instance_set_light_data(RID p_probe, RID p_base, RID p_data); - virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform); - virtual void gi_probe_instance_set_bounds(RID p_probe, const Vector3 &p_bounds); - - /* RENDER LIST */ - - enum LightMode { - LIGHTMODE_NORMAL, - LIGHTMODE_UNSHADED, - LIGHTMODE_LIGHTMAP, - LIGHTMODE_LIGHTMAP_CAPTURE, - }; - - struct RenderList { - - enum { - MAX_LIGHTS = 255, - MAX_REFLECTION_PROBES = 255, - DEFAULT_MAX_ELEMENTS = 65536 - }; - - int max_elements; - - struct Element { - RasterizerScene::InstanceBase *instance; - - RasterizerStorageGLES2::Geometry *geometry; - RasterizerStorageGLES2::Material *material; - RasterizerStorageGLES2::GeometryOwner *owner; - - bool use_accum; //is this an add pass for multipass - bool *use_accum_ptr; - bool front_facing; - - union { - //TODO: should be endian swapped on big endian - struct { - int32_t depth_layer : 16; - int32_t priority : 16; - }; - - uint32_t depth_key; - }; - - union { - struct { - //from least significant to most significant in sort, TODO: should be endian swapped on big endian - - uint64_t geometry_index : 14; - uint64_t instancing : 1; - uint64_t skeleton : 1; - uint64_t shader_index : 10; - uint64_t material_index : 10; - uint64_t light_index : 8; - uint64_t light_type2 : 1; // if 1==0 : nolight/directional, else omni/spot - uint64_t refprobe_1_index : 8; - uint64_t refprobe_0_index : 8; - uint64_t light_type1 : 1; //no light, directional is 0, omni spot is 1 - uint64_t light_mode : 2; // LightMode enum - }; - - uint64_t sort_key; - }; - }; - - Element *base_elements; - Element **elements; - - int element_count; - int alpha_element_count; - - void clear() { - element_count = 0; - alpha_element_count = 0; - } - - // sorts - - struct SortByKey { - _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - if (A->depth_key == B->depth_key) { - return A->sort_key < B->sort_key; - } else { - return A->depth_key < B->depth_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 { - if (A->priority == B->priority) { - return A->instance->depth > B->instance->depth; - } else { - return A->priority < B->priority; - } - } - }; - - 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); - } - } - - // element adding and stuff - - _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]; - } - } - - RenderList() { - max_elements = DEFAULT_MAX_ELEMENTS; - } - - ~RenderList() { - memdelete_arr(elements); - memdelete_arr(base_elements); - } - }; - - RenderList render_list; - - void _add_geometry(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, int p_material, bool p_depth_pass, bool p_shadow_pass); - void _add_geometry_with_material(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, RasterizerStorageGLES2::Material *p_material, bool p_depth_pass, bool p_shadow_pass); - - void _copy_texture_to_buffer(GLuint p_texture, GLuint p_buffer); - void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass); - void _render_render_list(RenderList::Element **p_elements, int p_element_count, - const Transform &p_view_transform, - const CameraMatrix &p_projection, - RID p_shadow_atlas, - Environment *p_env, - GLuint p_base_env, - float p_shadow_bias, - float p_shadow_normal_bias, - bool p_reverse_cull, - bool p_alpha_pass, - bool p_shadow); - - void _draw_sky(RasterizerStorageGLES2::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy, const Basis &p_sky_orientation); - - _FORCE_INLINE_ void _set_cull(bool p_front, bool p_disabled, bool p_reverse_cull); - _FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES2::Material *p_material, bool p_alpha_pass, Size2i p_skeleton_tex_size = Size2i(0, 0)); - _FORCE_INLINE_ void _setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton); - _FORCE_INLINE_ void _setup_light_type(LightInstance *p_light, ShadowAtlas *shadow_atlas); - _FORCE_INLINE_ void _setup_light(LightInstance *p_light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform, bool accum_pass); - _FORCE_INLINE_ void _setup_refprobes(ReflectionProbeInstance *p_refprobe1, ReflectionProbeInstance *p_refprobe2, const Transform &p_view_transform, Environment *p_env); - _FORCE_INLINE_ void _render_geometry(RenderList::Element *p_element); - - void _post_process(Environment *env, const CameraMatrix &p_cam_projection); - - virtual void render_scene(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_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); - virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count); - virtual bool free(RID p_rid); - - virtual void set_scene_pass(uint64_t p_pass); - virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw); - - void iteration(); - void initialize(); - void finalize(); - RasterizerSceneGLES2(); -}; - -#endif // RASTERIZERSCENEGLES2_H diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp deleted file mode 100644 index b8c7815f6a..0000000000 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ /dev/null @@ -1,6275 +0,0 @@ -/*************************************************************************/ -/* rasterizer_storage_gles2.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 "rasterizer_storage_gles2.h" - -#include "core/math/transform.h" -#include "core/project_settings.h" -#include "rasterizer_canvas_gles2.h" -#include "rasterizer_scene_gles2.h" -#include "servers/rendering/shader_language.h" - -GLuint RasterizerStorageGLES2::system_fbo = 0; - -/* TEXTURE API */ - -#define _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 -#define _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 -#define _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 - -#define _EXT_COMPRESSED_RED_RGTC1_EXT 0x8DBB -#define _EXT_COMPRESSED_RED_RGTC1 0x8DBB -#define _EXT_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC -#define _EXT_COMPRESSED_RG_RGTC2 0x8DBD -#define _EXT_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE -#define _EXT_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC -#define _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD -#define _EXT_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE -#define _EXT_ETC1_RGB8_OES 0x8D64 - -#define _EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 -#define _EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 -#define _EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 -#define _EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 - -#define _EXT_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54 -#define _EXT_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT 0x8A55 -#define _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT 0x8A56 -#define _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT 0x8A57 - -#define _EXT_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C -#define _EXT_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D -#define _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E -#define _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F - -#ifdef GLES_OVER_GL -#define _GL_HALF_FLOAT_OES 0x140B -#else -#define _GL_HALF_FLOAT_OES 0x8D61 -#endif - -#define _EXT_TEXTURE_CUBE_MAP_SEAMLESS 0x884F - -#define _RED_OES 0x1903 - -#define _DEPTH_COMPONENT24_OES 0x81A6 - -#ifndef GLES_OVER_GL -#define glClearDepth glClearDepthf - -// enable extensions manually for android and ios -#ifndef UWP_ENABLED -#include <dlfcn.h> // needed to load extensions -#endif - -#ifdef IPHONE_ENABLED - -#include <OpenGLES/ES2/glext.h> -//void *glRenderbufferStorageMultisampleAPPLE; -//void *glResolveMultisampleFramebufferAPPLE; -#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleAPPLE -#elif defined(ANDROID_ENABLED) - -#include <GLES2/gl2ext.h> -PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT; -PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT; -#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleEXT -#define glFramebufferTexture2DMultisample glFramebufferTexture2DMultisampleEXT - -PFNGLTEXIMAGE3DOESPROC glTexImage3DOES; -PFNGLTEXSUBIMAGE3DOESPROC glTexSubImage3DOES; -PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC glCompressedTexSubImage3DOES; -#define glTexImage3D glTexImage3DOES -#define glTexSubImage3D glTexSubImage3DOES -#define glCompressedTexSubImage3D glCompressedTexSubImage3DOES - -#elif defined(UWP_ENABLED) -#include <GLES2/gl2ext.h> -#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleANGLE -#define glFramebufferTexture2DMultisample glFramebufferTexture2DMultisampleANGLE -#endif - -#define GL_TEXTURE_3D 0x806F -#define GL_MAX_SAMPLES 0x8D57 -#endif //!GLES_OVER_GL - -#if !defined(GLES_OVER_GL) -#define GL_TEXTURE_2D_ARRAY 0x8C1A -#define GL_TEXTURE_3D 0x806F -#endif - -void RasterizerStorageGLES2::bind_quad_array() const { - glBindBuffer(GL_ARRAY_BUFFER, resources.quadie); - glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); - glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(8)); - - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glEnableVertexAttribArray(RS::ARRAY_TEX_UV); -} - -Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const { - - r_gl_format = 0; - Ref<Image> image = p_image; - r_compressed = false; - r_real_format = p_format; - - bool need_decompress = false; - - switch (p_format) { - - case Image::FORMAT_L8: { - - r_gl_internal_format = GL_LUMINANCE; - r_gl_format = GL_LUMINANCE; - r_gl_type = GL_UNSIGNED_BYTE; - } break; - case Image::FORMAT_LA8: { - r_gl_internal_format = GL_LUMINANCE_ALPHA; - r_gl_format = GL_LUMINANCE_ALPHA; - r_gl_type = GL_UNSIGNED_BYTE; - } break; - case Image::FORMAT_R8: { - - r_gl_internal_format = GL_ALPHA; - r_gl_format = GL_ALPHA; - r_gl_type = GL_UNSIGNED_BYTE; - - } break; - case Image::FORMAT_RG8: { - ERR_PRINT("RG texture not supported, converting to RGB8."); - if (image.is_valid()) - image->convert(Image::FORMAT_RGB8); - r_real_format = Image::FORMAT_RGB8; - r_gl_internal_format = GL_RGB; - r_gl_format = GL_RGB; - r_gl_type = GL_UNSIGNED_BYTE; - - } break; - case Image::FORMAT_RGB8: { - - r_gl_internal_format = GL_RGB; - r_gl_format = GL_RGB; - r_gl_type = GL_UNSIGNED_BYTE; - - } break; - case Image::FORMAT_RGBA8: { - - r_gl_format = GL_RGBA; - r_gl_internal_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - - } break; - case Image::FORMAT_RGBA4444: { - - r_gl_internal_format = GL_RGBA; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_SHORT_4_4_4_4; - - } break; - case Image::FORMAT_RGB565: { - - r_gl_internal_format = GL_RGB5_A1; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_SHORT_5_5_5_1; - - } break; - case Image::FORMAT_RF: { - if (!config.float_texture_supported) { - ERR_PRINT("R float texture not supported, converting to RGB8."); - if (image.is_valid()) - image->convert(Image::FORMAT_RGB8); - r_real_format = Image::FORMAT_RGB8; - r_gl_internal_format = GL_RGB; - r_gl_format = GL_RGB; - r_gl_type = GL_UNSIGNED_BYTE; - } else { - r_gl_internal_format = GL_ALPHA; - r_gl_format = GL_ALPHA; - r_gl_type = GL_FLOAT; - } - } break; - case Image::FORMAT_RGF: { - ERR_PRINT("RG float texture not supported, converting to RGB8."); - if (image.is_valid()) - image->convert(Image::FORMAT_RGB8); - r_real_format = Image::FORMAT_RGB8; - r_gl_internal_format = GL_RGB; - r_gl_format = GL_RGB; - r_gl_type = GL_UNSIGNED_BYTE; - } break; - case Image::FORMAT_RGBF: { - if (!config.float_texture_supported) { - ERR_PRINT("RGB float texture not supported, converting to RGB8."); - if (image.is_valid()) - image->convert(Image::FORMAT_RGB8); - r_real_format = Image::FORMAT_RGB8; - r_gl_internal_format = GL_RGB; - r_gl_format = GL_RGB; - r_gl_type = GL_UNSIGNED_BYTE; - } else { - r_gl_internal_format = GL_RGB; - r_gl_format = GL_RGB; - r_gl_type = GL_FLOAT; - } - } break; - case Image::FORMAT_RGBAF: { - if (!config.float_texture_supported) { - ERR_PRINT("RGBA float texture not supported, converting to RGBA8."); - if (image.is_valid()) - image->convert(Image::FORMAT_RGBA8); - r_real_format = Image::FORMAT_RGBA8; - r_gl_internal_format = GL_RGBA; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - } else { - r_gl_internal_format = GL_RGBA; - r_gl_format = GL_RGBA; - r_gl_type = GL_FLOAT; - } - } break; - case Image::FORMAT_RH: { - need_decompress = true; - } break; - case Image::FORMAT_RGH: { - need_decompress = true; - } break; - case Image::FORMAT_RGBH: { - need_decompress = true; - } break; - case Image::FORMAT_RGBAH: { - need_decompress = true; - } break; - case Image::FORMAT_RGBE9995: { - r_gl_internal_format = GL_RGB; - r_gl_format = GL_RGB; - r_gl_type = GL_UNSIGNED_BYTE; - - if (image.is_valid()) - - image = image->rgbe_to_srgb(); - - return image; - - } break; - case Image::FORMAT_DXT1: { - - if (config.s3tc_supported) { - r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - } else { - need_decompress = true; - } - - } break; - case Image::FORMAT_DXT3: { - - if (config.s3tc_supported) { - r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - } else { - need_decompress = true; - } - - } break; - case Image::FORMAT_DXT5: { - - if (config.s3tc_supported) { - r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - } else { - need_decompress = true; - } - - } break; - case Image::FORMAT_RGTC_R: { - - if (config.rgtc_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_RED_RGTC1_EXT; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - - need_decompress = true; - } - - } break; - case Image::FORMAT_RGTC_RG: { - - if (config.rgtc_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - } else { - - need_decompress = true; - } - - } break; - case Image::FORMAT_BPTC_RGBA: { - - if (config.bptc_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_RGBA_BPTC_UNORM; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - - need_decompress = true; - } - } break; - case Image::FORMAT_BPTC_RGBF: { - - if (config.bptc_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT; - r_gl_format = GL_RGB; - r_gl_type = GL_FLOAT; - r_compressed = true; - } else { - - need_decompress = true; - } - } break; - case Image::FORMAT_BPTC_RGBFU: { - if (config.bptc_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT; - r_gl_format = GL_RGB; - r_gl_type = GL_FLOAT; - r_compressed = true; - } else { - - need_decompress = true; - } - } break; - case Image::FORMAT_PVRTC2: { - - if (config.pvrtc_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - - need_decompress = true; - } - } break; - case Image::FORMAT_PVRTC2A: { - - if (config.pvrtc_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - - need_decompress = true; - } - - } break; - case Image::FORMAT_PVRTC4: { - - if (config.pvrtc_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - - need_decompress = true; - } - - } break; - case Image::FORMAT_PVRTC4A: { - - if (config.pvrtc_supported) { - - r_gl_internal_format = _EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - - need_decompress = true; - } - - } break; - case Image::FORMAT_ETC: { - - if (config.etc1_supported) { - r_gl_internal_format = _EXT_ETC1_RGB8_OES; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - } else { - need_decompress = true; - } - } break; - case Image::FORMAT_ETC2_R11: { - - need_decompress = true; - } break; - case Image::FORMAT_ETC2_R11S: { - - need_decompress = true; - } break; - case Image::FORMAT_ETC2_RG11: { - - need_decompress = true; - } break; - case Image::FORMAT_ETC2_RG11S: { - - need_decompress = true; - } break; - case Image::FORMAT_ETC2_RGB8: { - - need_decompress = true; - } break; - case Image::FORMAT_ETC2_RGBA8: { - - need_decompress = true; - } break; - case Image::FORMAT_ETC2_RGB8A1: { - - need_decompress = true; - } break; - default: { - - ERR_FAIL_V(Ref<Image>()); - } - } - - if (need_decompress || p_force_decompress) { - - if (!image.is_null()) { - - image = image->duplicate(); - image->decompress(); - ERR_FAIL_COND_V(image->is_compressed(), image); - switch (image->get_format()) { - case Image::FORMAT_RGB8: { - r_gl_format = GL_RGB; - r_gl_internal_format = GL_RGB; - r_gl_type = GL_UNSIGNED_BYTE; - r_real_format = Image::FORMAT_RGB8; - r_compressed = false; - } break; - case Image::FORMAT_RGBA8: { - r_gl_format = GL_RGBA; - r_gl_internal_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_real_format = Image::FORMAT_RGBA8; - r_compressed = false; - } break; - default: { - image->convert(Image::FORMAT_RGBA8); - r_gl_format = GL_RGBA; - r_gl_internal_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_real_format = Image::FORMAT_RGBA8; - r_compressed = false; - - } break; - } - } - - return image; - } - - return p_image; -} - -static const GLenum _cube_side_enum[6] = { - - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_X, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - -}; - -RID RasterizerStorageGLES2::texture_create() { - - Texture *texture = memnew(Texture); - ERR_FAIL_COND_V(!texture, RID()); - glGenTextures(1, &texture->tex_id); - texture->active = false; - texture->total_data_size = 0; - - return texture_owner.make_rid(texture); -} - -void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, RenderingServer::TextureType p_type, uint32_t p_flags) { - GLenum format; - GLenum internal_format; - GLenum type; - - bool compressed = false; - - if (p_flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING) { - p_flags &= ~RS::TEXTURE_FLAG_MIPMAPS; // no mipies for video - } - - Texture *texture = texture_owner.getornull(p_texture); - ERR_FAIL_COND(!texture); - texture->width = p_width; - texture->height = p_height; - texture->format = p_format; - texture->flags = p_flags; - texture->stored_cube_sides = 0; - texture->type = p_type; - - switch (p_type) { - case RS::TEXTURE_TYPE_2D: { - texture->target = GL_TEXTURE_2D; - texture->images.resize(1); - } break; - case RS::TEXTURE_TYPE_CUBEMAP: { - texture->target = GL_TEXTURE_CUBE_MAP; - texture->images.resize(6); - } break; - case RS::TEXTURE_TYPE_2D_ARRAY: { - if (config.texture_array_supported) { - texture->target = GL_TEXTURE_2D_ARRAY; - texture->images.resize(p_depth_3d); - } else { - WARN_PRINT_ONCE("Texture Arrays not supported on this hardware."); - return; - } - } break; - case RS::TEXTURE_TYPE_3D: { - if (config.texture_3d_supported) { - texture->target = GL_TEXTURE_3D; - texture->images.resize(p_depth_3d); - } else { - WARN_PRINT_ONCE("3D textures not supported on this hardware."); - return; - } - } break; - default: { - ERR_PRINT("Unknown texture type!"); - return; - } - } - - texture->alloc_width = texture->width; - texture->alloc_height = texture->height; - texture->resize_to_po2 = false; - if (!config.support_npot_repeat_mipmap) { - int po2_width = next_power_of_2(p_width); - int po2_height = next_power_of_2(p_height); - - bool is_po2 = p_width == po2_width && p_height == po2_height; - - if (!is_po2 && (p_flags & RS::TEXTURE_FLAG_REPEAT || p_flags & RS::TEXTURE_FLAG_MIPMAPS)) { - - if (p_flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING) { - //not supported - ERR_PRINT("Streaming texture for non power of 2 or has mipmaps on this hardware: " + texture->path + "'. Mipmaps and repeat disabled."); - texture->flags &= ~(RS::TEXTURE_FLAG_REPEAT | RS::TEXTURE_FLAG_MIPMAPS); - } else { - texture->alloc_height = po2_height; - texture->alloc_width = po2_width; - texture->resize_to_po2 = true; - } - } - } - - Image::Format real_format; - _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, format, internal_format, type, compressed, texture->resize_to_po2); - - texture->gl_format_cache = format; - texture->gl_type_cache = type; - texture->gl_internal_format_cache = internal_format; - texture->data_size = 0; - texture->mipmaps = 1; - - texture->compressed = compressed; - - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - -#if defined(GLES_OVER_GL) || defined(ANDROID_ENABLED) - if ((p_type == RS::TEXTURE_TYPE_3D && config.texture_3d_supported) || (p_type == RS::TEXTURE_TYPE_2D_ARRAY && config.texture_array_supported)) { - - int width = p_width; - int height = p_height; - int depth = p_depth_3d; - - int mipmaps = 0; - - while (width > 0 || height > 0 || (p_type == RS::TEXTURE_TYPE_3D && depth > 0)) { - width = MAX(1, width); - height = MAX(1, height); - depth = MAX(1, depth); - - glTexImage3D(texture->target, mipmaps, internal_format, width, height, depth, 0, format, type, nullptr); - - width /= 2; - height /= 2; - - if (p_type == RS::TEXTURE_TYPE_3D) { - depth /= 2; - } - - mipmaps++; - - if (!(p_flags & RS::TEXTURE_FLAG_MIPMAPS)) - break; - } -#ifdef GLES_OVER_GL - glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1); -#endif - - } else -#endif - if (p_flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING) { - //prealloc if video - glTexImage2D(texture->target, 0, internal_format, texture->alloc_width, texture->alloc_height, 0, format, type, nullptr); - } - - texture->active = true; -} - -void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer) { - Texture *texture = texture_owner.getornull(p_texture); - - ERR_FAIL_COND(!texture); - if ((texture->type == RS::TEXTURE_TYPE_2D_ARRAY && !config.texture_array_supported) || (texture->type == RS::TEXTURE_TYPE_3D && !config.texture_3d_supported)) { - return; - } - ERR_FAIL_COND(!texture->active); - ERR_FAIL_COND(texture->render_target); - ERR_FAIL_COND(texture->format != p_image->get_format()); - ERR_FAIL_COND(p_image.is_null()); - - GLenum type; - GLenum format; - GLenum internal_format; - bool compressed = false; - - if (config.keep_original_textures && !(texture->flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING)) { - texture->images.write[p_layer] = p_image; - } - - Image::Format real_format; - Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed, texture->resize_to_po2); - - if (texture->resize_to_po2) { - if (p_image->is_compressed()) { - ERR_PRINT("Texture '" + texture->path + "' is required to be a power of 2 because it uses either mipmaps or repeat, so it was decompressed. This will hurt performance and memory usage."); - } - - if (img == p_image) { - img = img->duplicate(); - } - img->resize_to_po2(false); - } - - if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING)) { - - texture->alloc_height = MAX(1, texture->alloc_height / 2); - texture->alloc_width = MAX(1, texture->alloc_width / 2); - - if (texture->alloc_width == img->get_width() / 2 && texture->alloc_height == img->get_height() / 2) { - - img->shrink_x2(); - } else if (img->get_format() <= Image::FORMAT_RGBA8) { - - img->resize(texture->alloc_width, texture->alloc_height, Image::INTERPOLATE_BILINEAR); - } - } - - GLenum blit_target = GL_TEXTURE_2D; - - switch (texture->type) { - case RS::TEXTURE_TYPE_2D: { - blit_target = GL_TEXTURE_2D; - } break; - case RS::TEXTURE_TYPE_CUBEMAP: { - ERR_FAIL_INDEX(p_layer, 6); - blit_target = _cube_side_enum[p_layer]; - } break; - case RS::TEXTURE_TYPE_2D_ARRAY: { - blit_target = GL_TEXTURE_2D_ARRAY; - } break; - case RS::TEXTURE_TYPE_3D: { - blit_target = GL_TEXTURE_3D; - } break; - } - - texture->data_size = img->get_data().size(); - const uint8_t *read = img->get_data().ptr(); - ERR_FAIL_COND(!read.ptr()); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - - texture->ignore_mipmaps = compressed && !img->has_mipmaps(); - - if ((texture->flags & RS::TEXTURE_FLAG_MIPMAPS) && !texture->ignore_mipmaps) - glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, config.use_fast_texture_filter ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR); - else { - if (texture->flags & RS::TEXTURE_FLAG_FILTER) { - glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } else { - glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - } - - if (texture->flags & RS::TEXTURE_FLAG_FILTER) { - - glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Filtering - - } else { - - glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // raw Filtering - } - - if (((texture->flags & RS::TEXTURE_FLAG_REPEAT) || (texture->flags & RS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) { - - if (texture->flags & RS::TEXTURE_FLAG_MIRRORED_REPEAT) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); - } else { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - } else { - - //glTexParameterf( texture->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); - glTexParameterf(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - - int mipmaps = ((texture->flags & RS::TEXTURE_FLAG_MIPMAPS) && img->has_mipmaps()) ? img->get_mipmap_count() + 1 : 1; - - int w = img->get_width(); - int h = img->get_height(); - - int tsize = 0; - - for (int i = 0; i < mipmaps; i++) { - - int size, ofs; - img->get_mipmap_offset_and_size(i, ofs, size); - if (texture->type == RS::TEXTURE_TYPE_2D || texture->type == RS::TEXTURE_TYPE_CUBEMAP) { - - if (compressed) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - - int bw = w; - int bh = h; - - glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]); - } else { - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - if (texture->flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING) { - glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]); - } else { - glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]); - } - } - } -#if defined(GLES_OVER_GL) || defined(ANDROID_ENABLED) - else { - if (texture->compressed) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - - int bw = w; - int bh = h; - - glCompressedTexSubImage3D(blit_target, i, 0, 0, p_layer, bw, bh, 1, internal_format, size, &read[ofs]); - } else { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - glTexSubImage3D(blit_target, i, 0, 0, p_layer, w, h, 1, format, type, &read[ofs]); - } - } -#endif - - tsize += size; - - w = MAX(1, w >> 1); - h = MAX(1, h >> 1); - } - - info.texture_mem -= texture->total_data_size; - texture->total_data_size = tsize; - info.texture_mem += texture->total_data_size; - - // printf("texture: %i x %i - size: %i - total: %i\n", texture->width, texture->height, tsize, info.texture_mem); - - texture->stored_cube_sides |= (1 << p_layer); - - if ((texture->flags & RS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != RS::TEXTURE_TYPE_CUBEMAP || texture->stored_cube_sides == (1 << 6) - 1)) { - //generate mipmaps if they were requested and the image does not contain them - glGenerateMipmap(texture->target); - } - - texture->mipmaps = mipmaps; -} - -void RasterizerStorageGLES2::texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer) { - // TODO - ERR_PRINT("Not implemented (ask Karroffel to do it :p)"); -} - -Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer) const { - - Texture *texture = texture_owner.getornull(p_texture); - - ERR_FAIL_COND_V(!texture, Ref<Image>()); - ERR_FAIL_COND_V(!texture->active, Ref<Image>()); - ERR_FAIL_COND_V(texture->data_size == 0 && !texture->render_target, Ref<Image>()); - - if (texture->type == RS::TEXTURE_TYPE_CUBEMAP && p_layer < 6 && p_layer >= 0 && !texture->images[p_layer].is_null()) { - return texture->images[p_layer]; - } - -#ifdef GLES_OVER_GL - - Image::Format real_format; - GLenum gl_format; - GLenum gl_internal_format; - GLenum gl_type; - bool compressed; - _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, false); - - Vector<uint8_t> data; - - int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, texture->mipmaps > 1); - - data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers - uint8_t *wb = data.ptrw(); - - glActiveTexture(GL_TEXTURE0); - - glBindTexture(texture->target, texture->tex_id); - - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - - for (int i = 0; i < texture->mipmaps; i++) { - - int ofs = Image::get_image_mipmap_offset(texture->alloc_width, texture->alloc_height, real_format, i); - - if (texture->compressed) { - glPixelStorei(GL_PACK_ALIGNMENT, 4); - glGetCompressedTexImage(texture->target, i, &wb[ofs]); - } else { - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glGetTexImage(texture->target, i, texture->gl_format_cache, texture->gl_type_cache, &wb[ofs]); - } - } - - wb.release(); - - data.resize(data_size); - - Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1, real_format, data)); - - return Ref<Image>(img); -#else - - Image::Format real_format; - GLenum gl_format; - GLenum gl_internal_format; - GLenum gl_type; - bool compressed; - _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, texture->resize_to_po2); - - Vector<uint8_t> data; - - int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false); - - data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers - uint8_t *wb = data.ptrw(); - - GLuint temp_framebuffer; - glGenFramebuffers(1, &temp_framebuffer); - - GLuint temp_color_texture; - glGenTextures(1, &temp_color_texture); - - glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer); - - glBindTexture(GL_TEXTURE_2D, temp_color_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_color_texture, 0); - - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glDepthFunc(GL_LEQUAL); - glColorMask(1, 1, 1, 1); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texture->tex_id); - - glViewport(0, 0, texture->alloc_width, texture->alloc_height); - - shaders.copy.bind(); - - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); - bind_quad_array(); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &wb[0]); - - glDeleteTextures(1, &temp_color_texture); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glDeleteFramebuffers(1, &temp_framebuffer); - - wb.release(); - - data.resize(data_size); - - Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, false, Image::FORMAT_RGBA8, data)); - if (!texture->compressed) { - img->convert(real_format); - } - - return Ref<Image>(img); - -#endif -} - -void RasterizerStorageGLES2::texture_set_flags(RID p_texture, uint32_t p_flags) { - - Texture *texture = texture_owner.getornull(p_texture); - ERR_FAIL_COND(!texture); - - bool had_mipmaps = texture->flags & RS::TEXTURE_FLAG_MIPMAPS; - - texture->flags = p_flags; - - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - - if (((texture->flags & RS::TEXTURE_FLAG_REPEAT) || (texture->flags & RS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) { - - if (texture->flags & RS::TEXTURE_FLAG_MIRRORED_REPEAT) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); - } else { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - } else { - //glTexParameterf( texture->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); - glTexParameterf(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - - if ((texture->flags & RS::TEXTURE_FLAG_MIPMAPS) && !texture->ignore_mipmaps) { - if (!had_mipmaps && texture->mipmaps == 1) { - glGenerateMipmap(texture->target); - } - glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, config.use_fast_texture_filter ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR); - - } else { - if (texture->flags & RS::TEXTURE_FLAG_FILTER) { - glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } else { - glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - } - - if (texture->flags & RS::TEXTURE_FLAG_FILTER) { - - glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Filtering - - } else { - - glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // raw Filtering - } -} - -uint32_t RasterizerStorageGLES2::texture_get_flags(RID p_texture) const { - Texture *texture = texture_owner.getornull(p_texture); - - ERR_FAIL_COND_V(!texture, 0); - - return texture->flags; -} - -Image::Format RasterizerStorageGLES2::texture_get_format(RID p_texture) const { - Texture *texture = texture_owner.getornull(p_texture); - - ERR_FAIL_COND_V(!texture, Image::FORMAT_L8); - - return texture->format; -} - -RenderingServer::TextureType RasterizerStorageGLES2::texture_get_type(RID p_texture) const { - Texture *texture = texture_owner.getornull(p_texture); - - ERR_FAIL_COND_V(!texture, RS::TEXTURE_TYPE_2D); - - return texture->type; -} - -uint32_t RasterizerStorageGLES2::texture_get_texid(RID p_texture) const { - Texture *texture = texture_owner.getornull(p_texture); - - ERR_FAIL_COND_V(!texture, 0); - - return texture->tex_id; -} - -void RasterizerStorageGLES2::texture_bind(RID p_texture, uint32_t p_texture_no) { - Texture *texture = texture_owner.getornull(p_texture); - - ERR_FAIL_COND(!texture); - - glActiveTexture(GL_TEXTURE0 + p_texture_no); - glBindTexture(texture->target, texture->tex_id); -} - -uint32_t RasterizerStorageGLES2::texture_get_width(RID p_texture) const { - Texture *texture = texture_owner.getornull(p_texture); - - ERR_FAIL_COND_V(!texture, 0); - - return texture->width; -} - -uint32_t RasterizerStorageGLES2::texture_get_height(RID p_texture) const { - Texture *texture = texture_owner.getornull(p_texture); - - ERR_FAIL_COND_V(!texture, 0); - - return texture->height; -} - -uint32_t RasterizerStorageGLES2::texture_get_depth(RID p_texture) const { - Texture *texture = texture_owner.getornull(p_texture); - - ERR_FAIL_COND_V(!texture, 0); - - return texture->depth; -} - -void RasterizerStorageGLES2::texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth) { - Texture *texture = texture_owner.getornull(p_texture); - - ERR_FAIL_COND(!texture); - ERR_FAIL_COND(texture->render_target); - - ERR_FAIL_COND(p_width <= 0 || p_width > 16384); - ERR_FAIL_COND(p_height <= 0 || p_height > 16384); - //real texture size is in alloc width and height - texture->width = p_width; - texture->height = p_height; -} - -void RasterizerStorageGLES2::texture_set_path(RID p_texture, const String &p_path) { - Texture *texture = texture_owner.getornull(p_texture); - ERR_FAIL_COND(!texture); - - texture->path = p_path; -} - -String RasterizerStorageGLES2::texture_get_path(RID p_texture) const { - Texture *texture = texture_owner.getornull(p_texture); - ERR_FAIL_COND_V(!texture, ""); - - return texture->path; -} - -void RasterizerStorageGLES2::texture_debug_usage(List<RS::TextureInfo> *r_info) { - List<RID> textures; - texture_owner.get_owned_list(&textures); - - for (List<RID>::Element *E = textures.front(); E; E = E->next()) { - - Texture *t = texture_owner.getornull(E->get()); - if (!t) - continue; - RS::TextureInfo tinfo; - tinfo.path = t->path; - tinfo.format = t->format; - tinfo.width = t->alloc_width; - tinfo.height = t->alloc_height; - tinfo.depth = 0; - tinfo.bytes = t->total_data_size; - r_info->push_back(tinfo); - } -} - -void RasterizerStorageGLES2::texture_set_shrink_all_x2_on_set_data(bool p_enable) { - config.shrink_textures_x2 = p_enable; -} - -void RasterizerStorageGLES2::textures_keep_original(bool p_enable) { - config.keep_original_textures = p_enable; -} - -Size2 RasterizerStorageGLES2::texture_size_with_proxy(RID p_texture) const { - - const Texture *texture = texture_owner.getornull(p_texture); - ERR_FAIL_COND_V(!texture, Size2()); - if (texture->proxy) { - return Size2(texture->proxy->width, texture->proxy->height); - } else { - return Size2(texture->width, texture->height); - } -} - -void RasterizerStorageGLES2::texture_set_proxy(RID p_texture, RID p_proxy) { - Texture *texture = texture_owner.getornull(p_texture); - ERR_FAIL_COND(!texture); - - if (texture->proxy) { - texture->proxy->proxy_owners.erase(texture); - texture->proxy = nullptr; - } - - if (p_proxy.is_valid()) { - Texture *proxy = texture_owner.getornull(p_proxy); - ERR_FAIL_COND(!proxy); - ERR_FAIL_COND(proxy == texture); - proxy->proxy_owners.insert(texture); - texture->proxy = proxy; - } -} - -void RasterizerStorageGLES2::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) { - - Texture *texture = texture_owner.getornull(p_texture); - ERR_FAIL_COND(!texture); - - texture->redraw_if_visible = p_enable; -} - -void RasterizerStorageGLES2::texture_set_detect_3d_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) { - Texture *texture = texture_owner.getornull(p_texture); - ERR_FAIL_COND(!texture); - - texture->detect_3d = p_callback; - texture->detect_3d_ud = p_userdata; -} - -void RasterizerStorageGLES2::texture_set_detect_srgb_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) { - Texture *texture = texture_owner.getornull(p_texture); - ERR_FAIL_COND(!texture); - - texture->detect_srgb = p_callback; - texture->detect_srgb_ud = p_userdata; -} - -void RasterizerStorageGLES2::texture_set_detect_normal_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) { - Texture *texture = texture_owner.getornull(p_texture); - ERR_FAIL_COND(!texture); - - texture->detect_normal = p_callback; - texture->detect_normal_ud = p_userdata; -} - -RID RasterizerStorageGLES2::texture_create_radiance_cubemap(RID p_source, int p_resolution) const { - - return RID(); -} - -RID RasterizerStorageGLES2::sky_create() { - Sky *sky = memnew(Sky); - sky->radiance = 0; - return sky_owner.make_rid(sky); -} - -void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size) { - Sky *sky = sky_owner.getornull(p_sky); - ERR_FAIL_COND(!sky); - - if (sky->panorama.is_valid()) { - sky->panorama = RID(); - glDeleteTextures(1, &sky->radiance); - sky->radiance = 0; - } - - sky->panorama = p_panorama; - if (!sky->panorama.is_valid()) { - return; // the panorama was cleared - } - - Texture *texture = texture_owner.getornull(sky->panorama); - if (!texture) { - sky->panorama = RID(); - ERR_FAIL_COND(!texture); - } - - // glBindVertexArray(0) and more - { - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - - for (int i = 0; i < RS::ARRAY_MAX - 1; i++) { - glDisableVertexAttribArray(i); - } - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //need this for proper sampling - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, resources.radical_inverse_vdc_cache_tex); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - // New cubemap that will hold the mipmaps with different roughness values - glActiveTexture(GL_TEXTURE2); - glGenTextures(1, &sky->radiance); - glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance); - - int size = p_radiance_size / 2; //divide by two because its a cubemap (this is an approximation because GLES3 uses a dual paraboloid) - - GLenum internal_format = GL_RGB; - GLenum format = GL_RGB; - GLenum type = GL_UNSIGNED_BYTE; - - // Set the initial (empty) mipmaps - // Mobile hardware (PowerVR specially) prefers this approach, - // the previous approach with manual lod levels kills the game. - for (int i = 0; i < 6; i++) { - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, size, size, 0, format, type, nullptr); - } - - glGenerateMipmap(GL_TEXTURE_CUBE_MAP); - - // No filters for now - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - // Framebuffer - - glBindFramebuffer(GL_FRAMEBUFFER, resources.mipmap_blur_fbo); - - int mipmaps = 6; - int lod = 0; - int mm_level = mipmaps; - size = p_radiance_size / 2; - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, true); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_DIRECT_WRITE, true); - shaders.cubemap_filter.bind(); - - // third, render to the framebuffer using separate textures, then copy to mipmaps - while (size >= 1) { - - //make framebuffer size the texture size, need to use a separate texture for compatibility - glActiveTexture(GL_TEXTURE3); - glBindTexture(GL_TEXTURE_2D, resources.mipmap_blur_color); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resources.mipmap_blur_color, 0); - - if (lod == 1) { - //bind panorama for smaller lods - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_DIRECT_WRITE, false); - shaders.cubemap_filter.bind(); - } - glViewport(0, 0, size, size); - bind_quad_array(); - - glActiveTexture(GL_TEXTURE2); //back to panorama - - for (int i = 0; i < 6; i++) { - - shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::FACE_ID, i); - - float roughness = mm_level >= 0 ? lod / (float)(mipmaps - 1) : 1; - roughness = MIN(1.0, roughness); //keep max at 1 - shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::ROUGHNESS, roughness); - shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::Z_FLIP, false); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glCopyTexSubImage2D(_cube_side_enum[i], lod, 0, 0, 0, 0, size, size); - } - - size >>= 1; - - mm_level--; - - lod++; - } - - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_DIRECT_WRITE, false); - - // restore ranges - glActiveTexture(GL_TEXTURE2); //back to panorama - - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE3); //back to panorama - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, 0); - - // Framebuffer did its job. thank mr framebuffer - glActiveTexture(GL_TEXTURE0); //back to panorama - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); -} - -/* SHADER API */ - -RID RasterizerStorageGLES2::shader_create() { - - Shader *shader = memnew(Shader); - shader->mode = RS::SHADER_SPATIAL; - shader->shader = &scene->state.scene_shader; - RID rid = shader_owner.make_rid(shader); - _shader_make_dirty(shader); - shader->self = rid; - - return rid; -} - -void RasterizerStorageGLES2::_shader_make_dirty(Shader *p_shader) { - if (p_shader->dirty_list.in_list()) - return; - - _shader_dirty_list.add(&p_shader->dirty_list); -} - -void RasterizerStorageGLES2::shader_set_code(RID p_shader, const String &p_code) { - - Shader *shader = shader_owner.getornull(p_shader); - ERR_FAIL_COND(!shader); - - shader->code = p_code; - - String mode_string = ShaderLanguage::get_shader_type(p_code); - RS::ShaderMode mode; - - if (mode_string == "canvas_item") - mode = RS::SHADER_CANVAS_ITEM; - else if (mode_string == "particles") - mode = RS::SHADER_PARTICLES; - else if (mode_string == "sky") - mode = RS::SHADER_SKY; - else - mode = RS::SHADER_SPATIAL; - - if (shader->custom_code_id && mode != shader->mode) { - shader->shader->free_custom_shader(shader->custom_code_id); - shader->custom_code_id = 0; - } - - shader->mode = mode; - - // TODO handle all shader types - if (mode == RS::SHADER_CANVAS_ITEM) { - shader->shader = &canvas->state.canvas_shader; - - } else if (mode == RS::SHADER_SPATIAL) { - shader->shader = &scene->state.scene_shader; - } else { - return; - } - - if (shader->custom_code_id == 0) { - shader->custom_code_id = shader->shader->create_custom_shader(); - } - - _shader_make_dirty(shader); -} - -String RasterizerStorageGLES2::shader_get_code(RID p_shader) const { - - const Shader *shader = shader_owner.getornull(p_shader); - ERR_FAIL_COND_V(!shader, ""); - - return shader->code; -} - -void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const { - - _shader_dirty_list.remove(&p_shader->dirty_list); - - p_shader->valid = false; - - p_shader->uniforms.clear(); - - if (p_shader->code == String()) { - return; //just invalid, but no error - } - - ShaderCompilerGLES2::GeneratedCode gen_code; - ShaderCompilerGLES2::IdentifierActions *actions = nullptr; - - switch (p_shader->mode) { - - case RS::SHADER_CANVAS_ITEM: { - - p_shader->canvas_item.light_mode = Shader::CanvasItem::LIGHT_MODE_NORMAL; - p_shader->canvas_item.blend_mode = Shader::CanvasItem::BLEND_MODE_MIX; - - p_shader->canvas_item.uses_screen_texture = false; - p_shader->canvas_item.uses_screen_uv = false; - p_shader->canvas_item.uses_time = false; - - shaders.actions_canvas.render_mode_values["blend_add"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_ADD); - shaders.actions_canvas.render_mode_values["blend_mix"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_MIX); - shaders.actions_canvas.render_mode_values["blend_sub"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_SUB); - shaders.actions_canvas.render_mode_values["blend_mul"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_MUL); - shaders.actions_canvas.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_PMALPHA); - - shaders.actions_canvas.render_mode_values["unshaded"] = Pair<int *, int>(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_UNSHADED); - shaders.actions_canvas.render_mode_values["light_only"] = Pair<int *, int>(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY); - - shaders.actions_canvas.usage_flag_pointers["SCREEN_UV"] = &p_shader->canvas_item.uses_screen_uv; - shaders.actions_canvas.usage_flag_pointers["SCREEN_PIXEL_SIZE"] = &p_shader->canvas_item.uses_screen_uv; - shaders.actions_canvas.usage_flag_pointers["SCREEN_TEXTURE"] = &p_shader->canvas_item.uses_screen_texture; - shaders.actions_canvas.usage_flag_pointers["TIME"] = &p_shader->canvas_item.uses_time; - - actions = &shaders.actions_canvas; - actions->uniforms = &p_shader->uniforms; - } break; - - case RS::SHADER_SPATIAL: { - p_shader->spatial.blend_mode = Shader::Spatial::BLEND_MODE_MIX; - p_shader->spatial.depth_draw_mode = Shader::Spatial::DEPTH_DRAW_OPAQUE; - p_shader->spatial.cull_mode = Shader::Spatial::CULL_MODE_BACK; - p_shader->spatial.uses_alpha = false; - p_shader->spatial.uses_alpha_scissor = false; - p_shader->spatial.uses_discard = false; - p_shader->spatial.unshaded = false; - p_shader->spatial.no_depth_test = false; - p_shader->spatial.uses_sss = false; - p_shader->spatial.uses_time = false; - p_shader->spatial.uses_vertex_lighting = false; - p_shader->spatial.uses_screen_texture = false; - p_shader->spatial.uses_depth_texture = false; - p_shader->spatial.uses_vertex = false; - p_shader->spatial.writes_modelview_or_projection = false; - p_shader->spatial.uses_world_coordinates = false; - - shaders.actions_scene.render_mode_values["blend_add"] = Pair<int *, int>(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_ADD); - shaders.actions_scene.render_mode_values["blend_mix"] = Pair<int *, int>(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_MIX); - shaders.actions_scene.render_mode_values["blend_sub"] = Pair<int *, int>(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_SUB); - shaders.actions_scene.render_mode_values["blend_mul"] = Pair<int *, int>(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_MUL); - - shaders.actions_scene.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_OPAQUE); - shaders.actions_scene.render_mode_values["depth_draw_always"] = Pair<int *, int>(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_ALWAYS); - shaders.actions_scene.render_mode_values["depth_draw_never"] = Pair<int *, int>(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_NEVER); - shaders.actions_scene.render_mode_values["depth_draw_alpha_prepass"] = Pair<int *, int>(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS); - - shaders.actions_scene.render_mode_values["cull_front"] = Pair<int *, int>(&p_shader->spatial.cull_mode, Shader::Spatial::CULL_MODE_FRONT); - shaders.actions_scene.render_mode_values["cull_back"] = Pair<int *, int>(&p_shader->spatial.cull_mode, Shader::Spatial::CULL_MODE_BACK); - shaders.actions_scene.render_mode_values["cull_disabled"] = Pair<int *, int>(&p_shader->spatial.cull_mode, Shader::Spatial::CULL_MODE_DISABLED); - - shaders.actions_scene.render_mode_flags["unshaded"] = &p_shader->spatial.unshaded; - shaders.actions_scene.render_mode_flags["depth_test_disable"] = &p_shader->spatial.no_depth_test; - - shaders.actions_scene.render_mode_flags["vertex_lighting"] = &p_shader->spatial.uses_vertex_lighting; - - shaders.actions_scene.render_mode_flags["world_vertex_coords"] = &p_shader->spatial.uses_world_coordinates; - - shaders.actions_scene.usage_flag_pointers["ALPHA"] = &p_shader->spatial.uses_alpha; - shaders.actions_scene.usage_flag_pointers["ALPHA_SCISSOR"] = &p_shader->spatial.uses_alpha_scissor; - - shaders.actions_scene.usage_flag_pointers["SSS_STRENGTH"] = &p_shader->spatial.uses_sss; - shaders.actions_scene.usage_flag_pointers["DISCARD"] = &p_shader->spatial.uses_discard; - shaders.actions_scene.usage_flag_pointers["SCREEN_TEXTURE"] = &p_shader->spatial.uses_screen_texture; - shaders.actions_scene.usage_flag_pointers["DEPTH_TEXTURE"] = &p_shader->spatial.uses_depth_texture; - shaders.actions_scene.usage_flag_pointers["TIME"] = &p_shader->spatial.uses_time; - - shaders.actions_scene.write_flag_pointers["MODELVIEW_MATRIX"] = &p_shader->spatial.writes_modelview_or_projection; - shaders.actions_scene.write_flag_pointers["PROJECTION_MATRIX"] = &p_shader->spatial.writes_modelview_or_projection; - shaders.actions_scene.write_flag_pointers["VERTEX"] = &p_shader->spatial.uses_vertex; - - actions = &shaders.actions_scene; - actions->uniforms = &p_shader->uniforms; - - if (p_shader->spatial.uses_screen_texture && p_shader->spatial.uses_depth_texture) { - ERR_PRINT_ONCE("Using both SCREEN_TEXTURE and DEPTH_TEXTURE is not supported in GLES2"); - } - - if (p_shader->spatial.uses_depth_texture && !config.support_depth_texture) { - ERR_PRINT_ONCE("Using DEPTH_TEXTURE is not permitted on this hardware, operation will fail."); - } - } break; - - default: { - return; - } break; - } - - Error err = shaders.compiler.compile(p_shader->mode, p_shader->code, actions, p_shader->path, gen_code); - if (err != OK) { - return; - } - - p_shader->shader->set_custom_shader_code(p_shader->custom_code_id, gen_code.vertex, gen_code.vertex_global, gen_code.fragment, gen_code.light, gen_code.fragment_global, gen_code.uniforms, gen_code.texture_uniforms, gen_code.custom_defines); - - p_shader->texture_count = gen_code.texture_uniforms.size(); - p_shader->texture_hints = gen_code.texture_hints; - p_shader->texture_types = gen_code.texture_types; - - p_shader->uses_vertex_time = gen_code.uses_vertex_time; - p_shader->uses_fragment_time = gen_code.uses_fragment_time; - - p_shader->shader->set_custom_shader(p_shader->custom_code_id); - p_shader->shader->bind(); - - // cache uniform locations - - for (SelfList<Material> *E = p_shader->materials.first(); E; E = E->next()) { - _material_make_dirty(E->self()); - } - - p_shader->valid = true; - p_shader->version++; -} - -void RasterizerStorageGLES2::update_dirty_shaders() { - while (_shader_dirty_list.first()) { - _update_shader(_shader_dirty_list.first()->self()); - } -} - -void RasterizerStorageGLES2::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->dirty_list.in_list()) { - _update_shader(shader); - } - - Map<int, StringName> order; - - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = shader->uniforms.front(); E; E = E->next()) { - - if (E->get().texture_order >= 0) { - order[E->get().texture_order + 100000] = E->key(); - } else { - order[E->get().order] = E->key(); - } - } - - for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) { - - PropertyInfo pi; - ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[E->get()]; - - pi.name = E->get(); - - switch (u.type) { - case ShaderLanguage::TYPE_STRUCT: { - pi.type = Variant::ARRAY; - } break; - case ShaderLanguage::TYPE_VOID: { - pi.type = Variant::NIL; - } break; - - case ShaderLanguage::TYPE_BOOL: { - pi.type = Variant::BOOL; - } break; - - // bool vectors - case ShaderLanguage::TYPE_BVEC2: { - pi.type = Variant::INT; - pi.hint = PROPERTY_HINT_FLAGS; - pi.hint_string = "x,y"; - } break; - case ShaderLanguage::TYPE_BVEC3: { - pi.type = Variant::INT; - pi.hint = PROPERTY_HINT_FLAGS; - pi.hint_string = "x,y,z"; - } break; - case ShaderLanguage::TYPE_BVEC4: { - pi.type = Variant::INT; - pi.hint = PROPERTY_HINT_FLAGS; - pi.hint_string = "x,y,z,w"; - } break; - - // int stuff - case ShaderLanguage::TYPE_UINT: - case ShaderLanguage::TYPE_INT: { - pi.type = Variant::INT; - - if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { - pi.hint = PROPERTY_HINT_RANGE; - pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]) + "," + rtos(u.hint_range[2]); - } - } break; - - case ShaderLanguage::TYPE_IVEC2: - case ShaderLanguage::TYPE_UVEC2: - case ShaderLanguage::TYPE_IVEC3: - case ShaderLanguage::TYPE_UVEC3: - case ShaderLanguage::TYPE_IVEC4: - case ShaderLanguage::TYPE_UVEC4: { - pi.type = Variant::PACKED_INT32_ARRAY; - } break; - - case ShaderLanguage::TYPE_FLOAT: { - pi.type = Variant::FLOAT; - if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { - pi.hint = PROPERTY_HINT_RANGE; - pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]) + "," + rtos(u.hint_range[2]); - } - } break; - - case ShaderLanguage::TYPE_VEC2: { - pi.type = Variant::VECTOR2; - } break; - case ShaderLanguage::TYPE_VEC3: { - pi.type = Variant::VECTOR3; - } break; - - case ShaderLanguage::TYPE_VEC4: { - if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { - pi.type = Variant::COLOR; - } else { - pi.type = Variant::PLANE; - } - } break; - - case ShaderLanguage::TYPE_MAT2: { - pi.type = Variant::TRANSFORM2D; - } break; - - case ShaderLanguage::TYPE_MAT3: { - pi.type = Variant::BASIS; - } break; - - case ShaderLanguage::TYPE_MAT4: { - pi.type = Variant::TRANSFORM; - } break; - - case ShaderLanguage::TYPE_SAMPLER2D: - case ShaderLanguage::TYPE_ISAMPLER2D: - case ShaderLanguage::TYPE_USAMPLER2D: { - pi.type = Variant::OBJECT; - pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "Texture2D"; - } break; - - case ShaderLanguage::TYPE_SAMPLERCUBE: { - pi.type = Variant::OBJECT; - pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "CubeMap"; - } break; - - case ShaderLanguage::TYPE_SAMPLER2DARRAY: - case ShaderLanguage::TYPE_ISAMPLER2DARRAY: - case ShaderLanguage::TYPE_USAMPLER2DARRAY: { - - pi.type = Variant::OBJECT; - pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "TextureArray"; - } break; - - case ShaderLanguage::TYPE_SAMPLER3D: - case ShaderLanguage::TYPE_ISAMPLER3D: - case ShaderLanguage::TYPE_USAMPLER3D: { - pi.type = Variant::OBJECT; - pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "Texture3D"; - } break; - } - - p_param_list->push_back(pi); - } -} - -void RasterizerStorageGLES2::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); - ERR_FAIL_COND(p_texture.is_valid() && !texture_owner.owns(p_texture)); - - if (p_texture.is_valid()) { - shader->default_textures[p_name] = p_texture; - } else { - shader->default_textures.erase(p_name); - } - - _shader_make_dirty(shader); -} - -RID RasterizerStorageGLES2::shader_get_default_texture_param(RID p_shader, const StringName &p_name) const { - - const Shader *shader = shader_owner.getornull(p_shader); - ERR_FAIL_COND_V(!shader, RID()); - - const Map<StringName, RID>::Element *E = shader->default_textures.find(p_name); - - if (!E) { - return RID(); - } - - return E->get(); -} - -/* COMMON MATERIAL API */ - -void RasterizerStorageGLES2::_material_make_dirty(Material *p_material) const { - - if (p_material->dirty_list.in_list()) - return; - - _material_dirty_list.add(&p_material->dirty_list); -} - -RID RasterizerStorageGLES2::material_create() { - - Material *material = memnew(Material); - - return material_owner.make_rid(material); -} - -void RasterizerStorageGLES2::material_set_shader(RID p_material, RID p_shader) { - - Material *material = material_owner.getornull(p_material); - ERR_FAIL_COND(!material); - - Shader *shader = shader_owner.getornull(p_shader); - - if (material->shader) { - // if a shader is present, remove the old shader - material->shader->materials.remove(&material->list); - } - - material->shader = shader; - - if (shader) { - shader->materials.add(&material->list); - } - - _material_make_dirty(material); -} - -RID RasterizerStorageGLES2::material_get_shader(RID p_material) const { - - const Material *material = material_owner.getornull(p_material); - ERR_FAIL_COND_V(!material, RID()); - - if (material->shader) { - return material->shader->self; - } - - return RID(); -} - -void RasterizerStorageGLES2::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); - - if (p_value.get_type() == Variant::NIL) { - material->params.erase(p_param); - } else { - material->params[p_param] = p_value; - } - - _material_make_dirty(material); -} - -Variant RasterizerStorageGLES2::material_get_param(RID p_material, const StringName &p_param) const { - - const Material *material = material_owner.getornull(p_material); - ERR_FAIL_COND_V(!material, RID()); - - if (material->params.has(p_param)) { - return material->params[p_param]; - } - - return material_get_param_default(p_material, p_param); -} - -Variant RasterizerStorageGLES2::material_get_param_default(RID p_material, const StringName &p_param) const { - const Material *material = material_owner.getornull(p_material); - ERR_FAIL_COND_V(!material, Variant()); - - if (material->shader) { - if (material->shader->uniforms.has(p_param)) { - ShaderLanguage::ShaderNode::Uniform uniform = material->shader->uniforms[p_param]; - Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); - } - } - return Variant(); -} - -void RasterizerStorageGLES2::material_set_line_width(RID p_material, float p_width) { - Material *material = material_owner.getornull(p_material); - ERR_FAIL_COND(!material); - - material->line_width = p_width; -} - -void RasterizerStorageGLES2::material_set_next_pass(RID p_material, RID p_next_material) { - Material *material = material_owner.getornull(p_material); - ERR_FAIL_COND(!material); - - material->next_pass = p_next_material; -} - -bool RasterizerStorageGLES2::material_is_animated(RID p_material) { - Material *material = material_owner.getornull(p_material); - ERR_FAIL_COND_V(!material, false); - if (material->dirty_list.in_list()) { - _update_material(material); - } - - bool animated = material->is_animated_cache; - if (!animated && material->next_pass.is_valid()) { - animated = material_is_animated(material->next_pass); - } - return animated; -} - -bool RasterizerStorageGLES2::material_casts_shadows(RID p_material) { - Material *material = material_owner.getornull(p_material); - ERR_FAIL_COND_V(!material, false); - if (material->dirty_list.in_list()) { - _update_material(material); - } - - bool casts_shadows = material->can_cast_shadow_cache; - - if (!casts_shadows && material->next_pass.is_valid()) { - casts_shadows = material_casts_shadows(material->next_pass); - } - - return casts_shadows; -} - -void RasterizerStorageGLES2::material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) { - - Material *material = material_owner.getornull(p_material); - ERR_FAIL_COND(!material); - - Map<RasterizerScene::InstanceBase *, int>::Element *E = material->instance_owners.find(p_instance); - if (E) { - E->get()++; - } else { - material->instance_owners[p_instance] = 1; - } -} - -void RasterizerStorageGLES2::material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) { - - Material *material = material_owner.getornull(p_material); - ERR_FAIL_COND(!material); - - Map<RasterizerScene::InstanceBase *, int>::Element *E = material->instance_owners.find(p_instance); - ERR_FAIL_COND(!E); - - E->get()--; - - if (E->get() == 0) { - material->instance_owners.erase(E); - } -} - -void RasterizerStorageGLES2::material_set_render_priority(RID p_material, int priority) { - ERR_FAIL_COND(priority < RS::MATERIAL_RENDER_PRIORITY_MIN); - ERR_FAIL_COND(priority > RS::MATERIAL_RENDER_PRIORITY_MAX); - - Material *material = material_owner.getornull(p_material); - ERR_FAIL_COND(!material); - - material->render_priority = priority; -} - -void RasterizerStorageGLES2::_update_material(Material *p_material) { - if (p_material->dirty_list.in_list()) { - _material_dirty_list.remove(&p_material->dirty_list); - } - - if (p_material->shader && p_material->shader->dirty_list.in_list()) { - _update_shader(p_material->shader); - } - - if (p_material->shader && !p_material->shader->valid) { - return; - } - - { - bool can_cast_shadow = false; - bool is_animated = false; - - if (p_material->shader && p_material->shader->mode == RS::SHADER_SPATIAL) { - - if (p_material->shader->spatial.blend_mode == Shader::Spatial::BLEND_MODE_MIX && - (!p_material->shader->spatial.uses_alpha || p_material->shader->spatial.depth_draw_mode == Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) { - can_cast_shadow = true; - } - - if (p_material->shader->spatial.uses_discard && p_material->shader->uses_fragment_time) { - is_animated = true; - } - - if (p_material->shader->spatial.uses_vertex && p_material->shader->uses_vertex_time) { - is_animated = true; - } - - if (can_cast_shadow != p_material->can_cast_shadow_cache || is_animated != p_material->is_animated_cache) { - p_material->can_cast_shadow_cache = can_cast_shadow; - p_material->is_animated_cache = is_animated; - - for (Map<Geometry *, int>::Element *E = p_material->geometry_owners.front(); E; E = E->next()) { - E->key()->material_changed_notify(); - } - - for (Map<RasterizerScene::InstanceBase *, int>::Element *E = p_material->instance_owners.front(); E; E = E->next()) { - E->key()->base_changed(false, true); - } - } - } - } - - // uniforms and other things will be set in the use_material method in ShaderGLES2 - - if (p_material->shader && p_material->shader->texture_count > 0) { - - p_material->textures.resize(p_material->shader->texture_count); - - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = p_material->shader->uniforms.front(); E; E = E->next()) { - if (E->get().texture_order < 0) - continue; // not a texture, does not go here - - RID texture; - - Map<StringName, Variant>::Element *V = p_material->params.find(E->key()); - - if (V) { - texture = V->get(); - } - - if (!texture.is_valid()) { - Map<StringName, RID>::Element *W = p_material->shader->default_textures.find(E->key()); - - if (W) { - texture = W->get(); - } - } - - p_material->textures.write[E->get().texture_order] = Pair<StringName, RID>(E->key(), texture); - } - } else { - p_material->textures.clear(); - } -} - -void RasterizerStorageGLES2::_material_add_geometry(RID p_material, Geometry *p_geometry) { - Material *material = material_owner.getornull(p_material); - ERR_FAIL_COND(!material); - - Map<Geometry *, int>::Element *I = material->geometry_owners.find(p_geometry); - - if (I) { - I->get()++; - } else { - material->geometry_owners[p_geometry] = 1; - } -} - -void RasterizerStorageGLES2::_material_remove_geometry(RID p_material, Geometry *p_geometry) { - - Material *material = material_owner.getornull(p_material); - ERR_FAIL_COND(!material); - - Map<Geometry *, int>::Element *I = material->geometry_owners.find(p_geometry); - ERR_FAIL_COND(!I); - - I->get()--; - - if (I->get() == 0) { - material->geometry_owners.erase(I); - } -} - -void RasterizerStorageGLES2::update_dirty_materials() { - while (_material_dirty_list.first()) { - - Material *material = _material_dirty_list.first()->self(); - _update_material(material); - } -} - -/* MESH API */ - -RID RasterizerStorageGLES2::mesh_create() { - - Mesh *mesh = memnew(Mesh); - - return mesh_owner.make_rid(mesh); -} - -static Vector<uint8_t> _unpack_half_floats(const Vector<uint8_t> &array, uint32_t &format, int p_vertices) { - - uint32_t p_format = format; - - static int src_size[RS::ARRAY_MAX]; - static int dst_size[RS::ARRAY_MAX]; - static int to_convert[RS::ARRAY_MAX]; - - int src_stride = 0; - int dst_stride = 0; - - for (int i = 0; i < RS::ARRAY_MAX; i++) { - - to_convert[i] = 0; - if (!(p_format & (1 << i))) { - src_size[i] = 0; - dst_size[i] = 0; - continue; - } - - switch (i) { - - case RS::ARRAY_VERTEX: { - - if (p_format & RS::ARRAY_COMPRESS_VERTEX) { - - if (p_format & RS::ARRAY_FLAG_USE_2D_VERTICES) { - src_size[i] = 4; - dst_size[i] = 8; - to_convert[i] = 2; - } else { - src_size[i] = 8; - dst_size[i] = 12; - to_convert[i] = 3; - } - - format &= ~RS::ARRAY_COMPRESS_VERTEX; - } else { - - if (p_format & RS::ARRAY_FLAG_USE_2D_VERTICES) { - src_size[i] = 8; - dst_size[i] = 8; - } else { - src_size[i] = 12; - dst_size[i] = 12; - } - } - - } break; - case RS::ARRAY_NORMAL: { - - if (p_format & RS::ARRAY_COMPRESS_NORMAL) { - src_size[i] = 4; - dst_size[i] = 4; - } else { - src_size[i] = 12; - dst_size[i] = 12; - } - - } break; - case RS::ARRAY_TANGENT: { - - if (p_format & RS::ARRAY_COMPRESS_TANGENT) { - src_size[i] = 4; - dst_size[i] = 4; - } else { - src_size[i] = 16; - dst_size[i] = 16; - } - - } break; - case RS::ARRAY_COLOR: { - - if (p_format & RS::ARRAY_COMPRESS_COLOR) { - src_size[i] = 4; - dst_size[i] = 4; - } else { - src_size[i] = 16; - dst_size[i] = 16; - } - - } break; - case RS::ARRAY_TEX_UV: { - - if (p_format & RS::ARRAY_COMPRESS_TEX_UV) { - src_size[i] = 4; - to_convert[i] = 2; - format &= ~RS::ARRAY_COMPRESS_TEX_UV; - } else { - src_size[i] = 8; - } - - dst_size[i] = 8; - - } break; - case RS::ARRAY_TEX_UV2: { - - if (p_format & RS::ARRAY_COMPRESS_TEX_UV2) { - src_size[i] = 4; - to_convert[i] = 2; - format &= ~RS::ARRAY_COMPRESS_TEX_UV2; - } else { - src_size[i] = 8; - } - - dst_size[i] = 8; - - } break; - case RS::ARRAY_BONES: { - - if (p_format & RS::ARRAY_FLAG_USE_16_BIT_BONES) { - src_size[i] = 8; - dst_size[i] = 8; - } else { - src_size[i] = 4; - dst_size[i] = 4; - } - - } break; - case RS::ARRAY_WEIGHTS: { - - if (p_format & RS::ARRAY_COMPRESS_WEIGHTS) { - src_size[i] = 8; - dst_size[i] = 8; - } else { - src_size[i] = 16; - dst_size[i] = 16; - } - - } break; - case RS::ARRAY_INDEX: { - - src_size[i] = 0; - dst_size[i] = 0; - - } break; - } - - src_stride += src_size[i]; - dst_stride += dst_size[i]; - } - - Vector<uint8_t> ret; - ret.resize(p_vertices * dst_stride); - - const uint8_t *r = array.ptr(); - uint8_t *w = ret.ptrw(); - - int src_offset = 0; - int dst_offset = 0; - - for (int i = 0; i < RS::ARRAY_MAX; i++) { - - if (src_size[i] == 0) { - continue; //no go - } - const uint8_t *rptr = r.ptr(); - uint8_t *wptr = w.ptr(); - if (to_convert[i]) { //converting - - for (int j = 0; j < p_vertices; j++) { - const uint16_t *src = (const uint16_t *)&rptr[src_stride * j + src_offset]; - float *dst = (float *)&wptr[dst_stride * j + dst_offset]; - - for (int k = 0; k < to_convert[i]; k++) { - - dst[k] = Math::half_to_float(src[k]); - } - } - - } else { - //just copy - for (int j = 0; j < p_vertices; j++) { - for (int k = 0; k < src_size[i]; k++) { - wptr[dst_stride * j + dst_offset + k] = rptr[src_stride * j + src_offset + k]; - } - } - } - - src_offset += src_size[i]; - dst_offset += dst_size[i]; - } - - r.release(); - w.release(); - - return ret; -} - -void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, RS::PrimitiveType p_primitive, const Vector<uint8_t> &p_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<Vector<uint8_t>> &p_blend_shapes, const Vector<AABB> &p_bone_aabbs) { - - Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!mesh); - - ERR_FAIL_COND(!(p_format & RS::ARRAY_FORMAT_VERTEX)); - - //must have index and bones, both. - { - uint32_t bones_weight = RS::ARRAY_FORMAT_BONES | RS::ARRAY_FORMAT_WEIGHTS; - ERR_FAIL_COND_MSG((p_format & bones_weight) && (p_format & bones_weight) != bones_weight, "Array must have both bones and weights in format or none."); - } - - //bool has_morph = p_blend_shapes.size(); - - Surface::Attrib attribs[RS::ARRAY_MAX]; - - int stride = 0; - bool uses_half_float = false; - - for (int i = 0; i < RS::ARRAY_MAX; i++) { - - attribs[i].index = i; - - if (!(p_format & (1 << i))) { - attribs[i].enabled = false; - attribs[i].integer = false; - continue; - } - - attribs[i].enabled = true; - attribs[i].offset = stride; - attribs[i].integer = false; - - switch (i) { - - case RS::ARRAY_VERTEX: { - - if (p_format & RS::ARRAY_FLAG_USE_2D_VERTICES) { - attribs[i].size = 2; - } else { - attribs[i].size = (p_format & RS::ARRAY_COMPRESS_VERTEX) ? 4 : 3; - } - - if (p_format & RS::ARRAY_COMPRESS_VERTEX) { - attribs[i].type = _GL_HALF_FLOAT_OES; - stride += attribs[i].size * 2; - uses_half_float = true; - } else { - attribs[i].type = GL_FLOAT; - stride += attribs[i].size * 4; - } - - attribs[i].normalized = GL_FALSE; - - } break; - case RS::ARRAY_NORMAL: { - - attribs[i].size = 3; - - if (p_format & RS::ARRAY_COMPRESS_NORMAL) { - attribs[i].type = GL_BYTE; - stride += 4; //pad extra byte - attribs[i].normalized = GL_TRUE; - } else { - attribs[i].type = GL_FLOAT; - stride += 12; - attribs[i].normalized = GL_FALSE; - } - - } break; - case RS::ARRAY_TANGENT: { - - attribs[i].size = 4; - - if (p_format & RS::ARRAY_COMPRESS_TANGENT) { - attribs[i].type = GL_BYTE; - stride += 4; - attribs[i].normalized = GL_TRUE; - } else { - attribs[i].type = GL_FLOAT; - stride += 16; - attribs[i].normalized = GL_FALSE; - } - - } break; - case RS::ARRAY_COLOR: { - - attribs[i].size = 4; - - if (p_format & RS::ARRAY_COMPRESS_COLOR) { - attribs[i].type = GL_UNSIGNED_BYTE; - stride += 4; - attribs[i].normalized = GL_TRUE; - } else { - attribs[i].type = GL_FLOAT; - stride += 16; - attribs[i].normalized = GL_FALSE; - } - - } break; - case RS::ARRAY_TEX_UV: { - - attribs[i].size = 2; - - if (p_format & RS::ARRAY_COMPRESS_TEX_UV) { - attribs[i].type = _GL_HALF_FLOAT_OES; - stride += 4; - uses_half_float = true; - } else { - attribs[i].type = GL_FLOAT; - stride += 8; - } - - attribs[i].normalized = GL_FALSE; - - } break; - case RS::ARRAY_TEX_UV2: { - - attribs[i].size = 2; - - if (p_format & RS::ARRAY_COMPRESS_TEX_UV2) { - attribs[i].type = _GL_HALF_FLOAT_OES; - stride += 4; - uses_half_float = true; - } else { - attribs[i].type = GL_FLOAT; - stride += 8; - } - attribs[i].normalized = GL_FALSE; - - } break; - case RS::ARRAY_BONES: { - - attribs[i].size = 4; - - if (p_format & RS::ARRAY_FLAG_USE_16_BIT_BONES) { - attribs[i].type = GL_UNSIGNED_SHORT; - stride += 8; - } else { - attribs[i].type = GL_UNSIGNED_BYTE; - stride += 4; - } - - attribs[i].normalized = GL_FALSE; - attribs[i].integer = true; - - } break; - case RS::ARRAY_WEIGHTS: { - - attribs[i].size = 4; - - if (p_format & RS::ARRAY_COMPRESS_WEIGHTS) { - - attribs[i].type = GL_UNSIGNED_SHORT; - stride += 8; - attribs[i].normalized = GL_TRUE; - } else { - attribs[i].type = GL_FLOAT; - stride += 16; - attribs[i].normalized = GL_FALSE; - } - - } break; - case RS::ARRAY_INDEX: { - - attribs[i].size = 1; - - if (p_vertex_count >= (1 << 16)) { - attribs[i].type = GL_UNSIGNED_INT; - attribs[i].stride = 4; - } else { - attribs[i].type = GL_UNSIGNED_SHORT; - attribs[i].stride = 2; - } - - attribs[i].normalized = GL_FALSE; - - } break; - } - } - - for (int i = 0; i < RS::ARRAY_MAX - 1; i++) { - attribs[i].stride = stride; - } - - //validate sizes - Vector<uint8_t> array = p_array; - - int array_size = stride * p_vertex_count; - int index_array_size = 0; - if (array.size() != array_size && array.size() + p_vertex_count * 2 == array_size) { - //old format, convert - array = Vector<uint8_t>(); - - array.resize(p_array.size() + p_vertex_count * 2); - - uint8_t *w = array.ptrw(); - const uint8_t *r = p_array.ptr(); - - uint16_t *w16 = (uint16_t *)w.ptr(); - const uint16_t *r16 = (uint16_t *)r.ptr(); - - uint16_t one = Math::make_half_float(1); - - for (int i = 0; i < p_vertex_count; i++) { - - *w16++ = *r16++; - *w16++ = *r16++; - *w16++ = *r16++; - *w16++ = one; - for (int j = 0; j < (stride / 2) - 4; j++) { - *w16++ = *r16++; - } - } - } - - ERR_FAIL_COND(array.size() != array_size); - - if (!config.support_half_float_vertices && uses_half_float) { - - uint32_t new_format = p_format; - Vector<uint8_t> unpacked_array = _unpack_half_floats(array, new_format, p_vertex_count); - - mesh_add_surface(p_mesh, new_format, p_primitive, unpacked_array, p_vertex_count, p_index_array, p_index_count, p_aabb, p_blend_shapes, p_bone_aabbs); - return; //do not go any further, above function used unpacked stuff will be used instead. - } - - if (p_format & RS::ARRAY_FORMAT_INDEX) { - - index_array_size = attribs[RS::ARRAY_INDEX].stride * p_index_count; - } - - ERR_FAIL_COND(p_index_array.size() != index_array_size); - - ERR_FAIL_COND(p_blend_shapes.size() != mesh->blend_shape_count); - - for (int i = 0; i < p_blend_shapes.size(); i++) { - ERR_FAIL_COND(p_blend_shapes[i].size() != array_size); - } - - // all valid, create stuff - - Surface *surface = memnew(Surface); - - surface->active = true; - surface->array_len = p_vertex_count; - surface->index_array_len = p_index_count; - surface->array_byte_size = array.size(); - surface->index_array_byte_size = p_index_array.size(); - surface->primitive = p_primitive; - surface->mesh = mesh; - surface->format = p_format; - surface->skeleton_bone_aabb = p_bone_aabbs; - surface->skeleton_bone_used.resize(surface->skeleton_bone_aabb.size()); - - surface->aabb = p_aabb; - surface->max_bone = p_bone_aabbs.size(); -#ifdef TOOLS_ENABLED - surface->blend_shape_data = p_blend_shapes; - if (surface->blend_shape_data.size()) { - ERR_PRINT_ONCE("Blend shapes are not supported in OpenGL ES 2.0"); - } -#endif - - surface->data = array; - surface->index_data = p_index_array; - surface->total_data_size += surface->array_byte_size + surface->index_array_byte_size; - - for (int i = 0; i < surface->skeleton_bone_used.size(); i++) { - surface->skeleton_bone_used.write[i] = !(surface->skeleton_bone_aabb[i].size.x < 0 || surface->skeleton_bone_aabb[i].size.y < 0 || surface->skeleton_bone_aabb[i].size.z < 0); - } - - for (int i = 0; i < RS::ARRAY_MAX; i++) { - surface->attribs[i] = attribs[i]; - } - - // Okay, now the OpenGL stuff, wheeeeey \o/ - { - const uint8_t *vr = array.ptr(); - - glGenBuffers(1, &surface->vertex_id); - glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_id); - glBufferData(GL_ARRAY_BUFFER, array_size, vr.ptr(), (p_format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - - if (p_format & RS::ARRAY_FORMAT_INDEX) { - const uint8_t *ir = p_index_array.ptr(); - - glGenBuffers(1, &surface->index_id); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_id); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_array_size, ir.ptr(), GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } else { - surface->index_id = 0; - } - - // TODO generate wireframes - } - - { - // blend shapes - - for (int i = 0; i < p_blend_shapes.size(); i++) { - - Surface::BlendShape mt; - - const uint8_t *vr = p_blend_shapes[i].ptr(); - - surface->total_data_size += array_size; - - glGenBuffers(1, &mt.vertex_id); - glBindBuffer(GL_ARRAY_BUFFER, mt.vertex_id); - glBufferData(GL_ARRAY_BUFFER, array_size, vr.ptr(), GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - surface->blend_shapes.push_back(mt); - } - } - - mesh->surfaces.push_back(surface); - mesh->instance_change_notify(true, true); - - info.vertex_mem += surface->total_data_size; -} - -void RasterizerStorageGLES2::mesh_set_blend_shape_count(RID p_mesh, int p_amount) { - Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!mesh); - - ERR_FAIL_COND(mesh->surfaces.size() != 0); - ERR_FAIL_COND(p_amount < 0); - - mesh->blend_shape_count = p_amount; - mesh->instance_change_notify(true, false); -} - -int RasterizerStorageGLES2::mesh_get_blend_shape_count(RID p_mesh) const { - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, 0); - return mesh->blend_shape_count; -} - -void RasterizerStorageGLES2::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) { - Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!mesh); - - mesh->blend_shape_mode = p_mode; -} - -RS::BlendShapeMode RasterizerStorageGLES2::mesh_get_blend_shape_mode(RID p_mesh) const { - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, RS::BLEND_SHAPE_MODE_NORMALIZED); - - return mesh->blend_shape_mode; -} - -void RasterizerStorageGLES2::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_INDEX(p_surface, mesh->surfaces.size()); - - int total_size = p_data.size(); - ERR_FAIL_COND(p_offset + total_size > mesh->surfaces[p_surface]->array_byte_size); - - const uint8_t *r = p_data.ptr(); - - glBindBuffer(GL_ARRAY_BUFFER, mesh->surfaces[p_surface]->vertex_id); - glBufferSubData(GL_ARRAY_BUFFER, p_offset, total_size, r.ptr()); - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind -} - -void RasterizerStorageGLES2::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_INDEX(p_surface, mesh->surfaces.size()); - - if (mesh->surfaces[p_surface]->material == p_material) - return; - - if (mesh->surfaces[p_surface]->material.is_valid()) { - _material_remove_geometry(mesh->surfaces[p_surface]->material, mesh->surfaces[p_surface]); - } - - mesh->surfaces[p_surface]->material = p_material; - - if (mesh->surfaces[p_surface]->material.is_valid()) { - _material_add_geometry(mesh->surfaces[p_surface]->material, mesh->surfaces[p_surface]); - } - - mesh->instance_change_notify(false, true); -} - -RID RasterizerStorageGLES2::mesh_surface_get_material(RID p_mesh, int p_surface) const { - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, RID()); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), RID()); - - return mesh->surfaces[p_surface]->material; -} - -int RasterizerStorageGLES2::mesh_surface_get_array_len(RID p_mesh, int p_surface) const { - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, 0); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), 0); - - return mesh->surfaces[p_surface]->array_len; -} - -int RasterizerStorageGLES2::mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const { - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, 0); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), 0); - - return mesh->surfaces[p_surface]->index_array_len; -} - -Vector<uint8_t> RasterizerStorageGLES2::mesh_surface_get_array(RID p_mesh, int p_surface) const { - - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, Vector<uint8_t>()); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Vector<uint8_t>()); - - Surface *surface = mesh->surfaces[p_surface]; -#ifndef TOOLS_ENABLED - ERR_PRINT("OpenGL ES 2.0 does not allow retrieving mesh array data"); -#endif - return surface->data; -} - -Vector<uint8_t> RasterizerStorageGLES2::mesh_surface_get_index_array(RID p_mesh, int p_surface) const { - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, Vector<uint8_t>()); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Vector<uint8_t>()); - - Surface *surface = mesh->surfaces[p_surface]; - - return surface->index_data; -} - -uint32_t RasterizerStorageGLES2::mesh_surface_get_format(RID p_mesh, int p_surface) const { - const Mesh *mesh = mesh_owner.getornull(p_mesh); - - ERR_FAIL_COND_V(!mesh, 0); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), 0); - - return mesh->surfaces[p_surface]->format; -} - -RS::PrimitiveType RasterizerStorageGLES2::mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const { - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, RS::PRIMITIVE_MAX); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), RS::PRIMITIVE_MAX); - - return mesh->surfaces[p_surface]->primitive; -} - -AABB RasterizerStorageGLES2::mesh_surface_get_aabb(RID p_mesh, int p_surface) const { - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, AABB()); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), AABB()); - - return mesh->surfaces[p_surface]->aabb; -} - -Vector<Vector<uint8_t>> RasterizerStorageGLES2::mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const { - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, Vector<Vector<uint8_t>>()); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Vector<Vector<uint8_t>>()); -#ifndef TOOLS_ENABLED - ERR_PRINT("OpenGL ES 2.0 does not allow retrieving mesh array data"); -#endif - - return mesh->surfaces[p_surface]->blend_shape_data; -} -Vector<AABB> RasterizerStorageGLES2::mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const { - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, Vector<AABB>()); - ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Vector<AABB>()); - - return mesh->surfaces[p_surface]->skeleton_bone_aabb; -} - -void RasterizerStorageGLES2::mesh_remove_surface(RID p_mesh, int p_surface) { - - Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!mesh); - ERR_FAIL_INDEX(p_surface, mesh->surfaces.size()); - - Surface *surface = mesh->surfaces[p_surface]; - - if (surface->material.is_valid()) { - _material_remove_geometry(surface->material, mesh->surfaces[p_surface]); - } - - glDeleteBuffers(1, &surface->vertex_id); - if (surface->index_id) { - glDeleteBuffers(1, &surface->index_id); - } - - for (int i = 0; i < surface->blend_shapes.size(); i++) { - glDeleteBuffers(1, &surface->blend_shapes[i].vertex_id); - } - - info.vertex_mem -= surface->total_data_size; - - memdelete(surface); - - mesh->surfaces.remove(p_surface); - - mesh->instance_change_notify(true, true); -} - -int RasterizerStorageGLES2::mesh_get_surface_count(RID p_mesh) const { - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, 0); - return mesh->surfaces.size(); -} - -void RasterizerStorageGLES2::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; - mesh->instance_change_notify(true, false); -} - -AABB RasterizerStorageGLES2::mesh_get_custom_aabb(RID p_mesh) const { - const Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, AABB()); - - return mesh->custom_aabb; -} - -AABB RasterizerStorageGLES2::mesh_get_aabb(RID p_mesh, RID p_skeleton) const { - Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND_V(!mesh, AABB()); - - if (mesh->custom_aabb != AABB()) - return mesh->custom_aabb; - - Skeleton *sk = nullptr; - if (p_skeleton.is_valid()) { - sk = skeleton_owner.getornull(p_skeleton); - } - - AABB aabb; - - if (sk && sk->size != 0) { - - for (int i = 0; i < mesh->surfaces.size(); i++) { - - AABB laabb; - if ((mesh->surfaces[i]->format & RS::ARRAY_FORMAT_BONES) && mesh->surfaces[i]->skeleton_bone_aabb.size()) { - - int bs = mesh->surfaces[i]->skeleton_bone_aabb.size(); - const AABB *skbones = mesh->surfaces[i]->skeleton_bone_aabb.ptr(); - const bool *skused = mesh->surfaces[i]->skeleton_bone_used.ptr(); - - int sbs = sk->size; - ERR_CONTINUE(bs > sbs); - const float *texture = sk->bone_data.ptr(); - - bool first = true; - if (sk->use_2d) { - for (int j = 0; j < bs; j++) { - - if (!skused[j]) - continue; - - int base_ofs = j * 2 * 4; - - Transform mtx; - - mtx.basis[0].x = texture[base_ofs + 0]; - mtx.basis[0].y = texture[base_ofs + 1]; - mtx.origin.x = texture[base_ofs + 3]; - base_ofs += 4; - mtx.basis[1].x = texture[base_ofs + 0]; - mtx.basis[1].y = texture[base_ofs + 1]; - mtx.origin.y = texture[base_ofs + 3]; - - AABB baabb = mtx.xform(skbones[j]); - - if (first) { - laabb = baabb; - first = false; - } else { - laabb.merge_with(baabb); - } - } - } else { - for (int j = 0; j < bs; j++) { - - if (!skused[j]) - continue; - - int base_ofs = j * 3 * 4; - - Transform mtx; - - mtx.basis[0].x = texture[base_ofs + 0]; - mtx.basis[0].y = texture[base_ofs + 1]; - mtx.basis[0].z = texture[base_ofs + 2]; - mtx.origin.x = texture[base_ofs + 3]; - base_ofs += 4; - mtx.basis[1].x = texture[base_ofs + 0]; - mtx.basis[1].y = texture[base_ofs + 1]; - mtx.basis[1].z = texture[base_ofs + 2]; - mtx.origin.y = texture[base_ofs + 3]; - base_ofs += 4; - mtx.basis[2].x = texture[base_ofs + 0]; - mtx.basis[2].y = texture[base_ofs + 1]; - mtx.basis[2].z = texture[base_ofs + 2]; - mtx.origin.z = texture[base_ofs + 3]; - - AABB baabb = mtx.xform(skbones[j]); - if (first) { - laabb = baabb; - first = false; - } else { - laabb.merge_with(baabb); - } - } - } - - } else { - - laabb = mesh->surfaces[i]->aabb; - } - - if (i == 0) - aabb = laabb; - else - aabb.merge_with(laabb); - } - } else { - - for (int i = 0; i < mesh->surfaces.size(); i++) { - - if (i == 0) - aabb = mesh->surfaces[i]->aabb; - else - aabb.merge_with(mesh->surfaces[i]->aabb); - } - } - - return aabb; -} -void RasterizerStorageGLES2::mesh_clear(RID p_mesh) { - Mesh *mesh = mesh_owner.getornull(p_mesh); - ERR_FAIL_COND(!mesh); - - while (mesh->surfaces.size()) { - mesh_remove_surface(p_mesh, 0); - } -} - -/* MULTIMESH API */ - -RID RasterizerStorageGLES2::multimesh_create() { - MultiMesh *multimesh = memnew(MultiMesh); - return multimesh_owner.make_rid(multimesh); -} - -void RasterizerStorageGLES2::multimesh_allocate(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, RS::MultimeshColorFormat p_color_format, RS::MultimeshCustomDataFormat p_data) { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND(!multimesh); - - if (multimesh->size == p_instances && multimesh->transform_format == p_transform_format && multimesh->color_format == p_color_format && multimesh->custom_data_format == p_data) { - return; - } - - multimesh->size = p_instances; - - multimesh->color_format = p_color_format; - multimesh->transform_format = p_transform_format; - multimesh->custom_data_format = p_data; - - if (multimesh->size) { - multimesh->data.resize(0); - } - - if (multimesh->transform_format == RS::MULTIMESH_TRANSFORM_2D) { - multimesh->xform_floats = 8; - } else { - multimesh->xform_floats = 12; - } - - if (multimesh->color_format == RS::MULTIMESH_COLOR_8BIT) { - multimesh->color_floats = 1; - } else if (multimesh->color_format == RS::MULTIMESH_COLOR_FLOAT) { - multimesh->color_floats = 4; - } else { - multimesh->color_floats = 0; - } - - if (multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_8BIT) { - multimesh->custom_data_floats = 1; - } else if (multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_FLOAT) { - multimesh->custom_data_floats = 4; - } else { - multimesh->custom_data_floats = 0; - } - - int format_floats = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - - multimesh->data.resize(format_floats * p_instances); - - for (int i = 0; i < p_instances * format_floats; i += format_floats) { - int color_from = 0; - int custom_data_from = 0; - - if (multimesh->transform_format == RS::MULTIMESH_TRANSFORM_2D) { - multimesh->data.write[i + 0] = 1.0; - multimesh->data.write[i + 1] = 0.0; - multimesh->data.write[i + 2] = 0.0; - multimesh->data.write[i + 3] = 0.0; - multimesh->data.write[i + 4] = 0.0; - multimesh->data.write[i + 5] = 1.0; - multimesh->data.write[i + 6] = 0.0; - multimesh->data.write[i + 7] = 0.0; - color_from = 8; - custom_data_from = 8; - } else { - multimesh->data.write[i + 0] = 1.0; - multimesh->data.write[i + 1] = 0.0; - multimesh->data.write[i + 2] = 0.0; - multimesh->data.write[i + 3] = 0.0; - multimesh->data.write[i + 4] = 0.0; - multimesh->data.write[i + 5] = 1.0; - multimesh->data.write[i + 6] = 0.0; - multimesh->data.write[i + 7] = 0.0; - multimesh->data.write[i + 8] = 0.0; - multimesh->data.write[i + 9] = 0.0; - multimesh->data.write[i + 10] = 1.0; - multimesh->data.write[i + 11] = 0.0; - color_from = 12; - custom_data_from = 12; - } - - if (multimesh->color_format == RS::MULTIMESH_COLOR_8BIT) { - union { - uint32_t colu; - float colf; - } cu; - - cu.colu = 0xFFFFFFFF; - multimesh->data.write[i + color_from + 0] = cu.colf; - custom_data_from = color_from + 1; - } else if (multimesh->color_format == RS::MULTIMESH_COLOR_FLOAT) { - multimesh->data.write[i + color_from + 0] = 1.0; - multimesh->data.write[i + color_from + 1] = 1.0; - multimesh->data.write[i + color_from + 2] = 1.0; - multimesh->data.write[i + color_from + 3] = 1.0; - custom_data_from = color_from + 4; - } - - if (multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_8BIT) { - union { - uint32_t colu; - float colf; - } cu; - - cu.colu = 0; - multimesh->data.write[i + custom_data_from + 0] = cu.colf; - } else if (multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_FLOAT) { - multimesh->data.write[i + custom_data_from + 0] = 0.0; - multimesh->data.write[i + custom_data_from + 1] = 0.0; - multimesh->data.write[i + custom_data_from + 2] = 0.0; - multimesh->data.write[i + custom_data_from + 3] = 0.0; - } - } - - multimesh->dirty_aabb = true; - multimesh->dirty_data = true; - - if (!multimesh->update_list.in_list()) { - multimesh_update_list.add(&multimesh->update_list); - } -} - -int RasterizerStorageGLES2::multimesh_get_instance_count(RID p_multimesh) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND_V(!multimesh, 0); - - return multimesh->size; -} - -void RasterizerStorageGLES2::multimesh_set_mesh(RID p_multimesh, RID p_mesh) { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND(!multimesh); - - if (multimesh->mesh.is_valid()) { - Mesh *mesh = mesh_owner.getornull(multimesh->mesh); - if (mesh) { - mesh->multimeshes.remove(&multimesh->mesh_list); - } - } - - multimesh->mesh = p_mesh; - - if (multimesh->mesh.is_valid()) { - Mesh *mesh = mesh_owner.getornull(multimesh->mesh); - if (mesh) { - mesh->multimeshes.add(&multimesh->mesh_list); - } - } - - multimesh->dirty_aabb = true; - - if (!multimesh->update_list.in_list()) { - multimesh_update_list.add(&multimesh->update_list); - } -} - -void RasterizerStorageGLES2::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->size); - ERR_FAIL_COND(multimesh->transform_format == RS::MULTIMESH_TRANSFORM_2D); - - int stride = multimesh->color_floats + multimesh->custom_data_floats + multimesh->xform_floats; - - float *dataptr = &multimesh->data.write[stride * p_index]; - - dataptr[0] = p_transform.basis.elements[0][0]; - dataptr[1] = p_transform.basis.elements[0][1]; - dataptr[2] = p_transform.basis.elements[0][2]; - dataptr[3] = p_transform.origin.x; - dataptr[4] = p_transform.basis.elements[1][0]; - dataptr[5] = p_transform.basis.elements[1][1]; - dataptr[6] = p_transform.basis.elements[1][2]; - dataptr[7] = p_transform.origin.y; - dataptr[8] = p_transform.basis.elements[2][0]; - dataptr[9] = p_transform.basis.elements[2][1]; - dataptr[10] = p_transform.basis.elements[2][2]; - dataptr[11] = p_transform.origin.z; - - multimesh->dirty_data = true; - multimesh->dirty_aabb = true; - - if (!multimesh->update_list.in_list()) { - multimesh_update_list.add(&multimesh->update_list); - } -} - -void RasterizerStorageGLES2::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->size); - ERR_FAIL_COND(multimesh->transform_format == RS::MULTIMESH_TRANSFORM_3D); - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data.write[stride * p_index]; - - dataptr[0] = p_transform.elements[0][0]; - dataptr[1] = p_transform.elements[1][0]; - dataptr[2] = 0; - dataptr[3] = p_transform.elements[2][0]; - dataptr[4] = p_transform.elements[0][1]; - dataptr[5] = p_transform.elements[1][1]; - dataptr[6] = 0; - dataptr[7] = p_transform.elements[2][1]; - - multimesh->dirty_data = true; - multimesh->dirty_aabb = true; - - if (!multimesh->update_list.in_list()) { - multimesh_update_list.add(&multimesh->update_list); - } -} - -void RasterizerStorageGLES2::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->size); - ERR_FAIL_COND(multimesh->color_format == RS::MULTIMESH_COLOR_NONE); - ERR_FAIL_INDEX(multimesh->color_format, RS::MULTIMESH_COLOR_MAX); - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats]; - - if (multimesh->color_format == RS::MULTIMESH_COLOR_8BIT) { - - uint8_t *data8 = (uint8_t *)dataptr; - data8[0] = CLAMP(p_color.r * 255.0, 0, 255); - data8[1] = CLAMP(p_color.g * 255.0, 0, 255); - data8[2] = CLAMP(p_color.b * 255.0, 0, 255); - data8[3] = CLAMP(p_color.a * 255.0, 0, 255); - - } else if (multimesh->color_format == RS::MULTIMESH_COLOR_FLOAT) { - dataptr[0] = p_color.r; - dataptr[1] = p_color.g; - dataptr[2] = p_color.b; - dataptr[3] = p_color.a; - } - - multimesh->dirty_data = true; - multimesh->dirty_aabb = true; - - if (!multimesh->update_list.in_list()) { - multimesh_update_list.add(&multimesh->update_list); - } -} - -void RasterizerStorageGLES2::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_custom_data) { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND(!multimesh); - ERR_FAIL_INDEX(p_index, multimesh->size); - ERR_FAIL_COND(multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_NONE); - ERR_FAIL_INDEX(multimesh->custom_data_format, RS::MULTIMESH_CUSTOM_DATA_MAX); - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats + multimesh->color_floats]; - - if (multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_8BIT) { - - uint8_t *data8 = (uint8_t *)dataptr; - data8[0] = CLAMP(p_custom_data.r * 255.0, 0, 255); - data8[1] = CLAMP(p_custom_data.g * 255.0, 0, 255); - data8[2] = CLAMP(p_custom_data.b * 255.0, 0, 255); - data8[3] = CLAMP(p_custom_data.a * 255.0, 0, 255); - - } else if (multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_FLOAT) { - dataptr[0] = p_custom_data.r; - dataptr[1] = p_custom_data.g; - dataptr[2] = p_custom_data.b; - dataptr[3] = p_custom_data.a; - } - - multimesh->dirty_data = true; - multimesh->dirty_aabb = true; - - if (!multimesh->update_list.in_list()) { - multimesh_update_list.add(&multimesh->update_list); - } -} - -RID RasterizerStorageGLES2::multimesh_get_mesh(RID p_multimesh) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND_V(!multimesh, RID()); - - return multimesh->mesh; -} - -Transform RasterizerStorageGLES2::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->size, Transform()); - ERR_FAIL_COND_V(multimesh->transform_format == RS::MULTIMESH_TRANSFORM_2D, Transform()); - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data.write[stride * p_index]; - - Transform xform; - - xform.basis.elements[0][0] = dataptr[0]; - xform.basis.elements[0][1] = dataptr[1]; - xform.basis.elements[0][2] = dataptr[2]; - xform.origin.x = dataptr[3]; - xform.basis.elements[1][0] = dataptr[4]; - xform.basis.elements[1][1] = dataptr[5]; - xform.basis.elements[1][2] = dataptr[6]; - xform.origin.y = dataptr[7]; - xform.basis.elements[2][0] = dataptr[8]; - xform.basis.elements[2][1] = dataptr[9]; - xform.basis.elements[2][2] = dataptr[10]; - xform.origin.z = dataptr[11]; - - return xform; -} - -Transform2D RasterizerStorageGLES2::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->size, Transform2D()); - ERR_FAIL_COND_V(multimesh->transform_format == RS::MULTIMESH_TRANSFORM_3D, Transform2D()); - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data.write[stride * p_index]; - - Transform2D xform; - - xform.elements[0][0] = dataptr[0]; - xform.elements[1][0] = dataptr[1]; - xform.elements[2][0] = dataptr[3]; - xform.elements[0][1] = dataptr[4]; - xform.elements[1][1] = dataptr[5]; - xform.elements[2][1] = dataptr[7]; - - return xform; -} - -Color RasterizerStorageGLES2::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->size, Color()); - ERR_FAIL_COND_V(multimesh->color_format == RS::MULTIMESH_COLOR_NONE, Color()); - ERR_FAIL_INDEX_V(multimesh->color_format, RS::MULTIMESH_COLOR_MAX, Color()); - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats]; - - if (multimesh->color_format == RS::MULTIMESH_COLOR_8BIT) { - union { - uint32_t colu; - float colf; - } cu; - - cu.colf = dataptr[0]; - - return Color::hex(BSWAP32(cu.colu)); - - } else if (multimesh->color_format == RS::MULTIMESH_COLOR_FLOAT) { - Color c; - c.r = dataptr[0]; - c.g = dataptr[1]; - c.b = dataptr[2]; - c.a = dataptr[3]; - - return c; - } - - return Color(); -} - -Color RasterizerStorageGLES2::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->size, Color()); - ERR_FAIL_COND_V(multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_NONE, Color()); - ERR_FAIL_INDEX_V(multimesh->custom_data_format, RS::MULTIMESH_CUSTOM_DATA_MAX, Color()); - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats + multimesh->color_floats]; - - if (multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_8BIT) { - union { - uint32_t colu; - float colf; - } cu; - - cu.colf = dataptr[0]; - - return Color::hex(BSWAP32(cu.colu)); - - } else if (multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_FLOAT) { - Color c; - c.r = dataptr[0]; - c.g = dataptr[1]; - c.b = dataptr[2]; - c.a = dataptr[3]; - - return c; - } - - return Color(); -} - -void RasterizerStorageGLES2::multimesh_set_as_bulk_array(RID p_multimesh, const Vector<float> &p_array) { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND(!multimesh); - ERR_FAIL_COND(!multimesh->data.ptr()); - - int dsize = multimesh->data.size(); - - ERR_FAIL_COND(dsize != p_array.size()); - - const float *r = p_array.ptr(); - ERR_FAIL_COND(!r.ptr()); - copymem(multimesh->data.ptrw(), r.ptr(), dsize * sizeof(float)); - - multimesh->dirty_data = true; - multimesh->dirty_aabb = true; - - if (!multimesh->update_list.in_list()) { - multimesh_update_list.add(&multimesh->update_list); - } -} - -void RasterizerStorageGLES2::multimesh_set_visible_instances(RID p_multimesh, int p_visible) { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND(!multimesh); - - multimesh->visible_instances = p_visible; -} - -int RasterizerStorageGLES2::multimesh_get_visible_instances(RID p_multimesh) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND_V(!multimesh, -1); - - return multimesh->visible_instances; -} - -AABB RasterizerStorageGLES2::multimesh_get_aabb(RID p_multimesh) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND_V(!multimesh, AABB()); - - const_cast<RasterizerStorageGLES2 *>(this)->update_dirty_multimeshes(); - - return multimesh->aabb; -} - -void RasterizerStorageGLES2::update_dirty_multimeshes() { - - while (multimesh_update_list.first()) { - - MultiMesh *multimesh = multimesh_update_list.first()->self(); - - if (multimesh->size && multimesh->dirty_aabb) { - - AABB mesh_aabb; - - if (multimesh->mesh.is_valid()) { - mesh_aabb = mesh_get_aabb(multimesh->mesh, RID()); - } - - mesh_aabb.size += Vector3(0.001, 0.001, 0.001); //in case mesh is empty in one of the sides - - int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - int count = multimesh->data.size(); - float *data = multimesh->data.ptrw(); - - AABB aabb; - - if (multimesh->transform_format == RS::MULTIMESH_TRANSFORM_2D) { - - for (int i = 0; i < count; i += stride) { - - float *dataptr = &data[i]; - - Transform xform; - xform.basis[0][0] = dataptr[0]; - xform.basis[0][1] = dataptr[1]; - xform.origin[0] = dataptr[3]; - xform.basis[1][0] = dataptr[4]; - xform.basis[1][1] = dataptr[5]; - xform.origin[1] = dataptr[7]; - - AABB laabb = xform.xform(mesh_aabb); - - if (i == 0) { - aabb = laabb; - } else { - aabb.merge_with(laabb); - } - } - - } else { - - for (int i = 0; i < count; i += stride) { - - float *dataptr = &data[i]; - - Transform xform; - xform.basis.elements[0][0] = dataptr[0]; - xform.basis.elements[0][1] = dataptr[1]; - xform.basis.elements[0][2] = dataptr[2]; - xform.origin.x = dataptr[3]; - xform.basis.elements[1][0] = dataptr[4]; - xform.basis.elements[1][1] = dataptr[5]; - xform.basis.elements[1][2] = dataptr[6]; - xform.origin.y = dataptr[7]; - xform.basis.elements[2][0] = dataptr[8]; - xform.basis.elements[2][1] = dataptr[9]; - xform.basis.elements[2][2] = dataptr[10]; - xform.origin.z = dataptr[11]; - - AABB laabb = xform.xform(mesh_aabb); - - if (i == 0) { - aabb = laabb; - } else { - aabb.merge_with(laabb); - } - } - } - - multimesh->aabb = aabb; - } - - multimesh->dirty_aabb = false; - multimesh->dirty_data = false; - - multimesh->instance_change_notify(true, false); - - multimesh_update_list.remove(multimesh_update_list.first()); - } -} - -/* IMMEDIATE API */ - -RID RasterizerStorageGLES2::immediate_create() { - Immediate *im = memnew(Immediate); - return immediate_owner.make_rid(im); -} - -void RasterizerStorageGLES2::immediate_begin(RID p_immediate, RS::PrimitiveType p_primitive, RID p_texture) { - Immediate *im = immediate_owner.getornull(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(im->building); - - Immediate::Chunk ic; - ic.texture = p_texture; - ic.primitive = p_primitive; - im->chunks.push_back(ic); - im->mask = 0; - im->building = true; -} - -void RasterizerStorageGLES2::immediate_vertex(RID p_immediate, const Vector3 &p_vertex) { - Immediate *im = immediate_owner.getornull(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(!im->building); - - Immediate::Chunk *c = &im->chunks.back()->get(); - - if (c->vertices.empty() && im->chunks.size() == 1) { - im->aabb.position = p_vertex; - im->aabb.size = Vector3(); - } else { - im->aabb.expand_to(p_vertex); - } - - if (im->mask & RS::ARRAY_FORMAT_NORMAL) - c->normals.push_back(chunk_normal); - if (im->mask & RS::ARRAY_FORMAT_TANGENT) - c->tangents.push_back(chunk_tangent); - if (im->mask & RS::ARRAY_FORMAT_COLOR) - c->colors.push_back(chunk_color); - if (im->mask & RS::ARRAY_FORMAT_TEX_UV) - c->uvs.push_back(chunk_uv); - if (im->mask & RS::ARRAY_FORMAT_TEX_UV2) - c->uv2s.push_back(chunk_uv2); - im->mask |= RS::ARRAY_FORMAT_VERTEX; - c->vertices.push_back(p_vertex); -} - -void RasterizerStorageGLES2::immediate_normal(RID p_immediate, const Vector3 &p_normal) { - Immediate *im = immediate_owner.getornull(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(!im->building); - - im->mask |= RS::ARRAY_FORMAT_NORMAL; - chunk_normal = p_normal; -} - -void RasterizerStorageGLES2::immediate_tangent(RID p_immediate, const Plane &p_tangent) { - Immediate *im = immediate_owner.getornull(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(!im->building); - - im->mask |= RS::ARRAY_FORMAT_TANGENT; - chunk_tangent = p_tangent; -} - -void RasterizerStorageGLES2::immediate_color(RID p_immediate, const Color &p_color) { - Immediate *im = immediate_owner.getornull(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(!im->building); - - im->mask |= RS::ARRAY_FORMAT_COLOR; - chunk_color = p_color; -} - -void RasterizerStorageGLES2::immediate_uv(RID p_immediate, const Vector2 &tex_uv) { - Immediate *im = immediate_owner.getornull(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(!im->building); - - im->mask |= RS::ARRAY_FORMAT_TEX_UV; - chunk_uv = tex_uv; -} - -void RasterizerStorageGLES2::immediate_uv2(RID p_immediate, const Vector2 &tex_uv) { - Immediate *im = immediate_owner.getornull(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(!im->building); - - im->mask |= RS::ARRAY_FORMAT_TEX_UV2; - chunk_uv2 = tex_uv; -} - -void RasterizerStorageGLES2::immediate_end(RID p_immediate) { - Immediate *im = immediate_owner.getornull(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(!im->building); - - im->building = false; - im->instance_change_notify(true, false); -} - -void RasterizerStorageGLES2::immediate_clear(RID p_immediate) { - Immediate *im = immediate_owner.getornull(p_immediate); - ERR_FAIL_COND(!im); - ERR_FAIL_COND(im->building); - - im->chunks.clear(); - im->instance_change_notify(true, false); -} - -AABB RasterizerStorageGLES2::immediate_get_aabb(RID p_immediate) const { - Immediate *im = immediate_owner.getornull(p_immediate); - ERR_FAIL_COND_V(!im, AABB()); - return im->aabb; -} - -void RasterizerStorageGLES2::immediate_set_material(RID p_immediate, RID p_material) { - Immediate *im = immediate_owner.getornull(p_immediate); - ERR_FAIL_COND(!im); - - im->material = p_material; - im->instance_change_notify(false, true); -} - -RID RasterizerStorageGLES2::immediate_get_material(RID p_immediate) const { - const Immediate *im = immediate_owner.getornull(p_immediate); - ERR_FAIL_COND_V(!im, RID()); - return im->material; -} - -/* SKELETON API */ - -RID RasterizerStorageGLES2::skeleton_create() { - - Skeleton *skeleton = memnew(Skeleton); - - glGenTextures(1, &skeleton->tex_id); - - return skeleton_owner.make_rid(skeleton); -} - -void RasterizerStorageGLES2::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); - - if (skeleton->size == p_bones && skeleton->use_2d == p_2d_skeleton) { - return; - } - - skeleton->size = p_bones; - skeleton->use_2d = p_2d_skeleton; - - if (!config.use_skeleton_software) { - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, skeleton->tex_id); - -#ifdef GLES_OVER_GL - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, p_bones * (skeleton->use_2d ? 2 : 3), 1, 0, GL_RGBA, GL_FLOAT, nullptr); -#else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, p_bones * (skeleton->use_2d ? 2 : 3), 1, 0, GL_RGBA, GL_FLOAT, nullptr); -#endif - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glBindTexture(GL_TEXTURE_2D, 0); - } - if (skeleton->use_2d) { - skeleton->bone_data.resize(p_bones * 4 * 2); - } else { - skeleton->bone_data.resize(p_bones * 4 * 3); - } -} - -int RasterizerStorageGLES2::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 RasterizerStorageGLES2::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); - - ERR_FAIL_INDEX(p_bone, skeleton->size); - ERR_FAIL_COND(skeleton->use_2d); - - float *bone_data = skeleton->bone_data.ptrw(); - - int base_offset = p_bone * 4 * 3; - - bone_data[base_offset + 0] = p_transform.basis[0].x; - bone_data[base_offset + 1] = p_transform.basis[0].y; - bone_data[base_offset + 2] = p_transform.basis[0].z; - bone_data[base_offset + 3] = p_transform.origin.x; - - bone_data[base_offset + 4] = p_transform.basis[1].x; - bone_data[base_offset + 5] = p_transform.basis[1].y; - bone_data[base_offset + 6] = p_transform.basis[1].z; - bone_data[base_offset + 7] = p_transform.origin.y; - - bone_data[base_offset + 8] = p_transform.basis[2].x; - bone_data[base_offset + 9] = p_transform.basis[2].y; - bone_data[base_offset + 10] = p_transform.basis[2].z; - bone_data[base_offset + 11] = p_transform.origin.z; - - if (!skeleton->update_list.in_list()) { - skeleton_update_list.add(&skeleton->update_list); - } -} - -Transform RasterizerStorageGLES2::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); - ERR_FAIL_COND_V(!skeleton, Transform()); - - ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform()); - ERR_FAIL_COND_V(skeleton->use_2d, Transform()); - - const float *bone_data = skeleton->bone_data.ptr(); - - Transform ret; - - int base_offset = p_bone * 4 * 3; - - ret.basis[0].x = bone_data[base_offset + 0]; - ret.basis[0].y = bone_data[base_offset + 1]; - ret.basis[0].z = bone_data[base_offset + 2]; - ret.origin.x = bone_data[base_offset + 3]; - - ret.basis[1].x = bone_data[base_offset + 4]; - ret.basis[1].y = bone_data[base_offset + 5]; - ret.basis[1].z = bone_data[base_offset + 6]; - ret.origin.y = bone_data[base_offset + 7]; - - ret.basis[2].x = bone_data[base_offset + 8]; - ret.basis[2].y = bone_data[base_offset + 9]; - ret.basis[2].z = bone_data[base_offset + 10]; - ret.origin.z = bone_data[base_offset + 11]; - - return ret; -} -void RasterizerStorageGLES2::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); - - ERR_FAIL_INDEX(p_bone, skeleton->size); - ERR_FAIL_COND(!skeleton->use_2d); - - float *bone_data = skeleton->bone_data.ptrw(); - - int base_offset = p_bone * 4 * 2; - - bone_data[base_offset + 0] = p_transform[0][0]; - bone_data[base_offset + 1] = p_transform[1][0]; - bone_data[base_offset + 2] = 0; - bone_data[base_offset + 3] = p_transform[2][0]; - bone_data[base_offset + 4] = p_transform[0][1]; - bone_data[base_offset + 5] = p_transform[1][1]; - bone_data[base_offset + 6] = 0; - bone_data[base_offset + 7] = p_transform[2][1]; - - if (!skeleton->update_list.in_list()) { - skeleton_update_list.add(&skeleton->update_list); - } -} - -Transform2D RasterizerStorageGLES2::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()); - - ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform2D()); - ERR_FAIL_COND_V(!skeleton->use_2d, Transform2D()); - - const float *bone_data = skeleton->bone_data.ptr(); - - Transform2D ret; - - int base_offset = p_bone * 4 * 2; - - ret[0][0] = bone_data[base_offset + 0]; - ret[1][0] = bone_data[base_offset + 1]; - ret[2][0] = bone_data[base_offset + 3]; - ret[0][1] = bone_data[base_offset + 4]; - ret[1][1] = bone_data[base_offset + 5]; - ret[2][1] = bone_data[base_offset + 7]; - - return ret; -} - -void RasterizerStorageGLES2::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) { - - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); - ERR_FAIL_COND(!skeleton); - - skeleton->base_transform_2d = p_base_transform; -} - -void RasterizerStorageGLES2::_update_skeleton_transform_buffer(const Vector<float> &p_data, size_t p_size) { - - glBindBuffer(GL_ARRAY_BUFFER, resources.skeleton_transform_buffer); - - if (p_size > resources.skeleton_transform_buffer_size) { - // new requested buffer is bigger, so resizing the GPU buffer - - resources.skeleton_transform_buffer_size = p_size; - - glBufferData(GL_ARRAY_BUFFER, p_size * sizeof(float), p_data.ptr(), GL_DYNAMIC_DRAW); - } else { - glBufferSubData(GL_ARRAY_BUFFER, 0, p_size * sizeof(float), p_data.ptr()); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void RasterizerStorageGLES2::update_dirty_skeletons() { - - if (config.use_skeleton_software) - return; - - glActiveTexture(GL_TEXTURE0); - - while (skeleton_update_list.first()) { - Skeleton *skeleton = skeleton_update_list.first()->self(); - - if (skeleton->size) { - glBindTexture(GL_TEXTURE_2D, skeleton->tex_id); - - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, skeleton->size * (skeleton->use_2d ? 2 : 3), 1, GL_RGBA, GL_FLOAT, skeleton->bone_data.ptr()); - } - - for (Set<RasterizerScene::InstanceBase *>::Element *E = skeleton->instances.front(); E; E = E->next()) { - E->get()->base_changed(true, false); - } - - skeleton_update_list.remove(skeleton_update_list.first()); - } -} - -/* Light API */ - -RID RasterizerStorageGLES2::light_create(RS::LightType p_type) { - - Light *light = memnew(Light); - - light->type = p_type; - - light->param[RS::LIGHT_PARAM_ENERGY] = 1.0; - light->param[RS::LIGHT_PARAM_INDIRECT_ENERGY] = 1.0; - light->param[RS::LIGHT_PARAM_SPECULAR] = 0.5; - light->param[RS::LIGHT_PARAM_RANGE] = 1.0; - light->param[RS::LIGHT_PARAM_SPOT_ANGLE] = 45; - light->param[RS::LIGHT_PARAM_CONTACT_SHADOW_SIZE] = 45; - 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_NORMAL_BIAS] = 0.1; - light->param[RS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE] = 0.1; - - light->color = Color(1, 1, 1, 1); - light->shadow = false; - light->negative = false; - light->cull_mask = 0xFFFFFFFF; - light->directional_shadow_mode = RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; - light->omni_shadow_mode = RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; - light->omni_shadow_detail = RS::LIGHT_OMNI_SHADOW_DETAIL_VERTICAL; - light->directional_blend_splits = false; - light->directional_range_mode = RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE; - light->reverse_cull = false; - light->use_gi = true; - light->version = 0; - - return light_owner.make_rid(light); -} - -void RasterizerStorageGLES2::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 RasterizerStorageGLES2::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); - - switch (p_param) { - case RS::LIGHT_PARAM_RANGE: - case RS::LIGHT_PARAM_SPOT_ANGLE: - case RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE: - case RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET: - case RS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET: - case RS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET: - case RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS: - case RS::LIGHT_PARAM_SHADOW_BIAS: { - light->version++; - light->instance_change_notify(true, false); - } break; - default: { - } - } - - light->param[p_param] = p_value; -} - -void RasterizerStorageGLES2::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_change_notify(true, false); -} - -void RasterizerStorageGLES2::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 RasterizerStorageGLES2::light_set_projector(RID p_light, RID p_texture) { - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - - light->projector = p_texture; -} - -void RasterizerStorageGLES2::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 RasterizerStorageGLES2::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_change_notify(true, false); -} - -void RasterizerStorageGLES2::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_change_notify(true, false); -} - -void RasterizerStorageGLES2::light_set_use_gi(RID p_light, bool p_enabled) { - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - - light->use_gi = p_enabled; - - light->version++; - light->instance_change_notify(true, false); -} - -void RasterizerStorageGLES2::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_change_notify(true, false); -} - -RS::LightOmniShadowMode RasterizerStorageGLES2::light_omni_get_shadow_mode(RID p_light) { - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, RS::LIGHT_OMNI_SHADOW_CUBE); - - return light->omni_shadow_mode; -} - -void RasterizerStorageGLES2::light_omni_set_shadow_detail(RID p_light, RS::LightOmniShadowDetail p_detail) { - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - - light->omni_shadow_detail = p_detail; - - light->version++; - light->instance_change_notify(true, false); -} - -void RasterizerStorageGLES2::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_change_notify(true, false); -} - -void RasterizerStorageGLES2::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_change_notify(true, false); -} - -bool RasterizerStorageGLES2::light_directional_get_blend_splits(RID p_light) const { - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, false); - return light->directional_blend_splits; -} - -RS::LightDirectionalShadowMode RasterizerStorageGLES2::light_directional_get_shadow_mode(RID p_light) { - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL); - return light->directional_shadow_mode; -} - -void RasterizerStorageGLES2::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 RasterizerStorageGLES2::light_directional_get_shadow_depth_range_mode(RID p_light) 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; -} - -RS::LightType RasterizerStorageGLES2::light_get_type(RID p_light) const { - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL); - - return light->type; -} - -float RasterizerStorageGLES2::light_get_param(RID p_light, RS::LightParam p_param) { - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, 0.0); - ERR_FAIL_INDEX_V(p_param, RS::LIGHT_PARAM_MAX, 0.0); - - return light->param[p_param]; -} - -Color RasterizerStorageGLES2::light_get_color(RID p_light) { - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, Color()); - - return light->color; -} - -bool RasterizerStorageGLES2::light_get_use_gi(RID p_light) { - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, false); - - return light->use_gi; -} - -bool RasterizerStorageGLES2::light_has_shadow(RID p_light) const { - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, false); - - return light->shadow; -} - -uint64_t RasterizerStorageGLES2::light_get_version(RID p_light) const { - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, 0); - - return light->version; -} - -AABB RasterizerStorageGLES2::light_get_aabb(RID p_light) const { - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, AABB()); - - switch (light->type) { - - case RS::LIGHT_SPOT: { - float len = light->param[RS::LIGHT_PARAM_RANGE]; - float size = Math::tan(Math::deg2rad(light->param[RS::LIGHT_PARAM_SPOT_ANGLE])) * len; - return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len)); - }; - - case RS::LIGHT_OMNI: { - float r = light->param[RS::LIGHT_PARAM_RANGE]; - return AABB(-Vector3(r, r, r), Vector3(r, r, r) * 2); - }; - - case RS::LIGHT_DIRECTIONAL: { - return AABB(); - }; - } - - ERR_FAIL_V(AABB()); -} - -/* PROBE API */ - -RID RasterizerStorageGLES2::reflection_probe_create() { - - ReflectionProbe *reflection_probe = memnew(ReflectionProbe); - - reflection_probe->intensity = 1.0; - reflection_probe->interior_ambient = Color(); - reflection_probe->interior_ambient_energy = 1.0; - reflection_probe->interior_ambient_probe_contrib = 0.0; - reflection_probe->max_distance = 0; - reflection_probe->extents = Vector3(1, 1, 1); - reflection_probe->origin_offset = Vector3(0, 0, 0); - reflection_probe->interior = false; - reflection_probe->box_projection = false; - reflection_probe->enable_shadows = false; - reflection_probe->cull_mask = (1 << 20) - 1; - reflection_probe->update_mode = RS::REFLECTION_PROBE_UPDATE_ONCE; - reflection_probe->resolution = 128; - - return reflection_probe_owner.make_rid(reflection_probe); -} - -void RasterizerStorageGLES2::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_change_notify(true, false); -} - -void RasterizerStorageGLES2::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 RasterizerStorageGLES2::reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient) { - - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!reflection_probe); - - reflection_probe->interior_ambient = p_ambient; -} - -void RasterizerStorageGLES2::reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) { - - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!reflection_probe); - - reflection_probe->interior_ambient_energy = p_energy; -} - -void RasterizerStorageGLES2::reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) { - - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!reflection_probe); - - reflection_probe->interior_ambient_probe_contrib = p_contrib; -} - -void RasterizerStorageGLES2::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_change_notify(true, false); -} -void RasterizerStorageGLES2::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); - - reflection_probe->extents = p_extents; - reflection_probe->instance_change_notify(true, false); -} -void RasterizerStorageGLES2::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_change_notify(true, false); -} - -void RasterizerStorageGLES2::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_change_notify(true, false); -} -void RasterizerStorageGLES2::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 RasterizerStorageGLES2::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_change_notify(true, false); -} -void RasterizerStorageGLES2::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_change_notify(true, false); -} - -void RasterizerStorageGLES2::reflection_probe_set_resolution(RID p_probe, int p_resolution) { - - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); - ERR_FAIL_COND(!reflection_probe); - - reflection_probe->resolution = p_resolution; -} - -AABB RasterizerStorageGLES2::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()); - - AABB aabb; - aabb.position = -reflection_probe->extents; - aabb.size = reflection_probe->extents * 2.0; - - return aabb; -} -RS::ReflectionProbeUpdateMode RasterizerStorageGLES2::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 RasterizerStorageGLES2::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 RasterizerStorageGLES2::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 RasterizerStorageGLES2::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 RasterizerStorageGLES2::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 RasterizerStorageGLES2::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 RasterizerStorageGLES2::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; -} - -RID RasterizerStorageGLES2::gi_probe_create() { - return RID(); -} - -void RasterizerStorageGLES2::gi_probe_set_bounds(RID p_probe, const AABB &p_bounds) { -} - -AABB RasterizerStorageGLES2::gi_probe_get_bounds(RID p_probe) const { - return AABB(); -} - -void RasterizerStorageGLES2::gi_probe_set_cell_size(RID p_probe, float p_size) { -} - -float RasterizerStorageGLES2::gi_probe_get_cell_size(RID p_probe) const { - return 0.0; -} - -void RasterizerStorageGLES2::gi_probe_set_to_cell_xform(RID p_probe, const Transform &p_xform) { -} - -Transform RasterizerStorageGLES2::gi_probe_get_to_cell_xform(RID p_probe) const { - return Transform(); -} - -void RasterizerStorageGLES2::gi_probe_set_dynamic_data(RID p_probe, const Vector<int> &p_data) { -} - -Vector<int> RasterizerStorageGLES2::gi_probe_get_dynamic_data(RID p_probe) const { - return Vector<int>(); -} - -void RasterizerStorageGLES2::gi_probe_set_dynamic_range(RID p_probe, int p_range) { -} - -int RasterizerStorageGLES2::gi_probe_get_dynamic_range(RID p_probe) const { - return 0; -} - -void RasterizerStorageGLES2::gi_probe_set_energy(RID p_probe, float p_range) { -} - -void RasterizerStorageGLES2::gi_probe_set_bias(RID p_probe, float p_range) { -} - -void RasterizerStorageGLES2::gi_probe_set_normal_bias(RID p_probe, float p_range) { -} - -void RasterizerStorageGLES2::gi_probe_set_propagation(RID p_probe, float p_range) { -} - -void RasterizerStorageGLES2::gi_probe_set_interior(RID p_probe, bool p_enable) { -} - -bool RasterizerStorageGLES2::gi_probe_is_interior(RID p_probe) const { - return false; -} - -void RasterizerStorageGLES2::gi_probe_set_compress(RID p_probe, bool p_enable) { -} - -bool RasterizerStorageGLES2::gi_probe_is_compressed(RID p_probe) const { - return false; -} -float RasterizerStorageGLES2::gi_probe_get_energy(RID p_probe) const { - return 0; -} - -float RasterizerStorageGLES2::gi_probe_get_bias(RID p_probe) const { - return 0; -} - -float RasterizerStorageGLES2::gi_probe_get_normal_bias(RID p_probe) const { - return 0; -} - -float RasterizerStorageGLES2::gi_probe_get_propagation(RID p_probe) const { - return 0; -} - -uint32_t RasterizerStorageGLES2::gi_probe_get_version(RID p_probe) { - return 0; -} - -RasterizerStorage::GIProbeCompression RasterizerStorageGLES2::gi_probe_get_dynamic_data_get_preferred_compression() const { - return GI_PROBE_UNCOMPRESSED; -} - -RID RasterizerStorageGLES2::gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression) { - return RID(); -} - -void RasterizerStorageGLES2::gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) { -} - -/////// - -RID RasterizerStorageGLES2::lightmap_capture_create() { - - LightmapCapture *capture = memnew(LightmapCapture); - return lightmap_capture_data_owner.make_rid(capture); -} - -void RasterizerStorageGLES2::lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) { - - LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND(!capture); - capture->bounds = p_bounds; - capture->instance_change_notify(true, false); -} -AABB RasterizerStorageGLES2::lightmap_capture_get_bounds(RID p_capture) const { - - const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND_V(!capture, AABB()); - return capture->bounds; -} -void RasterizerStorageGLES2::lightmap_capture_set_octree(RID p_capture, const Vector<uint8_t> &p_octree) { - - LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND(!capture); - - ERR_FAIL_COND(p_octree.size() == 0 || (p_octree.size() % sizeof(LightmapCaptureOctree)) != 0); - - capture->octree.resize(p_octree.size() / sizeof(LightmapCaptureOctree)); - if (p_octree.size()) { - LightmapCaptureOctree *w = capture->octree.ptrw(); - const uint8_t *r = p_octree.ptr(); - copymem(w.ptr(), r.ptr(), p_octree.size()); - } - capture->instance_change_notify(true, false); -} -Vector<uint8_t> RasterizerStorageGLES2::lightmap_capture_get_octree(RID p_capture) const { - - const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND_V(!capture, Vector<uint8_t>()); - - if (capture->octree.size() == 0) - return Vector<uint8_t>(); - - Vector<uint8_t> ret; - ret.resize(capture->octree.size() * sizeof(LightmapCaptureOctree)); - { - const LightmapCaptureOctree *r = capture->octree.ptr(); - uint8_t *w = ret.ptrw(); - copymem(w.ptr(), r.ptr(), ret.size()); - } - - return ret; -} - -void RasterizerStorageGLES2::lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) { - LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND(!capture); - capture->cell_xform = p_xform; -} - -Transform RasterizerStorageGLES2::lightmap_capture_get_octree_cell_transform(RID p_capture) const { - const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND_V(!capture, Transform()); - return capture->cell_xform; -} - -void RasterizerStorageGLES2::lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) { - LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND(!capture); - capture->cell_subdiv = p_subdiv; -} - -int RasterizerStorageGLES2::lightmap_capture_get_octree_cell_subdiv(RID p_capture) const { - const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND_V(!capture, 0); - return capture->cell_subdiv; -} - -void RasterizerStorageGLES2::lightmap_capture_set_energy(RID p_capture, float p_energy) { - - LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND(!capture); - capture->energy = p_energy; -} - -float RasterizerStorageGLES2::lightmap_capture_get_energy(RID p_capture) const { - - const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND_V(!capture, 0); - return capture->energy; -} - -const Vector<RasterizerStorage::LightmapCaptureOctree> *RasterizerStorageGLES2::lightmap_capture_get_octree_ptr(RID p_capture) const { - const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); - ERR_FAIL_COND_V(!capture, nullptr); - return &capture->octree; -} - -/////// - -RID RasterizerStorageGLES2::particles_create() { - return RID(); -} - -void RasterizerStorageGLES2::particles_set_emitting(RID p_particles, bool p_emitting) { -} - -bool RasterizerStorageGLES2::particles_get_emitting(RID p_particles) { - return false; -} - -void RasterizerStorageGLES2::particles_set_amount(RID p_particles, int p_amount) { -} - -void RasterizerStorageGLES2::particles_set_lifetime(RID p_particles, float p_lifetime) { -} - -void RasterizerStorageGLES2::particles_set_one_shot(RID p_particles, bool p_one_shot) { -} - -void RasterizerStorageGLES2::particles_set_pre_process_time(RID p_particles, float p_time) { -} - -void RasterizerStorageGLES2::particles_set_explosiveness_ratio(RID p_particles, float p_ratio) { -} - -void RasterizerStorageGLES2::particles_set_randomness_ratio(RID p_particles, float p_ratio) { -} - -void RasterizerStorageGLES2::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) { -} - -void RasterizerStorageGLES2::particles_set_speed_scale(RID p_particles, float p_scale) { -} - -void RasterizerStorageGLES2::particles_set_use_local_coordinates(RID p_particles, bool p_enable) { -} - -void RasterizerStorageGLES2::particles_set_fixed_fps(RID p_particles, int p_fps) { -} - -void RasterizerStorageGLES2::particles_set_fractional_delta(RID p_particles, bool p_enable) { -} - -void RasterizerStorageGLES2::particles_set_process_material(RID p_particles, RID p_material) { -} - -void RasterizerStorageGLES2::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) { -} - -void RasterizerStorageGLES2::particles_set_draw_passes(RID p_particles, int p_passes) { -} - -void RasterizerStorageGLES2::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) { -} - -void RasterizerStorageGLES2::particles_restart(RID p_particles) { -} - -void RasterizerStorageGLES2::particles_request_process(RID p_particles) { -} - -AABB RasterizerStorageGLES2::particles_get_current_aabb(RID p_particles) { - return AABB(); -} - -AABB RasterizerStorageGLES2::particles_get_aabb(RID p_particles) const { - return AABB(); -} - -void RasterizerStorageGLES2::particles_set_emission_transform(RID p_particles, const Transform &p_transform) { -} - -int RasterizerStorageGLES2::particles_get_draw_passes(RID p_particles) const { - return 0; -} - -RID RasterizerStorageGLES2::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { - return RID(); -} - -void RasterizerStorageGLES2::update_particles() { -} - -bool RasterizerStorageGLES2::particles_is_inactive(RID p_particles) const { - return true; -} - -//////// - -void RasterizerStorageGLES2::instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) { - - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); - ERR_FAIL_COND(!skeleton); - - skeleton->instances.insert(p_instance); -} - -void RasterizerStorageGLES2::instance_remove_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) { - - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); - ERR_FAIL_COND(!skeleton); - - skeleton->instances.erase(p_instance); -} - -void RasterizerStorageGLES2::instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) { - - Instantiable *inst = nullptr; - switch (p_instance->base_type) { - case RS::INSTANCE_MESH: { - inst = mesh_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case RS::INSTANCE_MULTIMESH: { - inst = multimesh_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case RS::INSTANCE_IMMEDIATE: { - inst = immediate_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - /*case RS::INSTANCE_PARTICLES: { - inst = particles_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break;*/ - case RS::INSTANCE_REFLECTION_PROBE: { - inst = reflection_probe_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case RS::INSTANCE_LIGHT: { - inst = light_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - /*case RS::INSTANCE_GI_PROBE: { - inst = gi_probe_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break;*/ - case RS::INSTANCE_LIGHTMAP_CAPTURE: { - inst = lightmap_capture_data_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - default: { - ERR_FAIL(); - } - } - - inst->instance_list.add(&p_instance->dependency_item); -} - -void RasterizerStorageGLES2::instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) { - - Instantiable *inst = nullptr; - - switch (p_instance->base_type) { - case RS::INSTANCE_MESH: { - inst = mesh_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case RS::INSTANCE_MULTIMESH: { - inst = multimesh_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case RS::INSTANCE_IMMEDIATE: { - inst = immediate_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - /*case RS::INSTANCE_PARTICLES: { - inst = particles_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break;*/ - case RS::INSTANCE_REFLECTION_PROBE: { - inst = reflection_probe_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - case RS::INSTANCE_LIGHT: { - inst = light_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - /*case RS::INSTANCE_GI_PROBE: { - inst = gi_probe_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; */ - case RS::INSTANCE_LIGHTMAP_CAPTURE: { - inst = lightmap_capture_data_owner.getornull(p_base); - ERR_FAIL_COND(!inst); - } break; - default: { - ERR_FAIL(); - } - } - - inst->instance_list.remove(&p_instance->dependency_item); -} - -/* RENDER TARGET */ - -void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) { - - // do not allocate a render target with no size - if (rt->width <= 0 || rt->height <= 0) - return; - - // do not allocate a render target that is attached to the screen - if (rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) { - rt->fbo = RasterizerStorageGLES2::system_fbo; - return; - } - - GLuint color_internal_format; - GLuint color_format; - GLuint color_type = GL_UNSIGNED_BYTE; - Image::Format image_format; - - if (rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { -#ifdef GLES_OVER_GL - color_internal_format = GL_RGBA8; -#else - color_internal_format = GL_RGBA; -#endif - color_format = GL_RGBA; - image_format = Image::FORMAT_RGBA8; - } else { -#ifdef GLES_OVER_GL - color_internal_format = GL_RGB8; -#else - color_internal_format = GL_RGB; -#endif - color_format = GL_RGB; - image_format = Image::FORMAT_RGB8; - } - - rt->used_dof_blur_near = false; - rt->mip_maps_allocated = false; - - { - - /* Front FBO */ - - Texture *texture = texture_owner.getornull(rt->texture); - ERR_FAIL_COND(!texture); - - // framebuffer - glGenFramebuffers(1, &rt->fbo); - glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo); - - // color - glGenTextures(1, &rt->color); - glBindTexture(GL_TEXTURE_2D, rt->color); - - glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, nullptr); - - if (texture->flags & RS::TEXTURE_FLAG_FILTER) { - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } else { - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); - - // depth - - if (config.support_depth_texture) { - - glGenTextures(1, &rt->depth); - glBindTexture(GL_TEXTURE_2D, rt->depth); - glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, rt->width, rt->height, 0, GL_DEPTH_COMPONENT, config.depth_type, nullptr); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); - } else { - - glGenRenderbuffers(1, &rt->depth); - glBindRenderbuffer(GL_RENDERBUFFER, rt->depth); - - glRenderbufferStorage(GL_RENDERBUFFER, config.depth_buffer_internalformat, rt->width, rt->height); - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); - } - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - - glDeleteFramebuffers(1, &rt->fbo); - if (config.support_depth_texture) { - - glDeleteTextures(1, &rt->depth); - } else { - - glDeleteRenderbuffers(1, &rt->depth); - } - - glDeleteTextures(1, &rt->color); - rt->fbo = 0; - rt->width = 0; - rt->height = 0; - rt->color = 0; - rt->depth = 0; - texture->tex_id = 0; - texture->active = false; - WARN_PRINT("Could not create framebuffer!!"); - return; - } - - texture->format = image_format; - texture->gl_format_cache = color_format; - texture->gl_type_cache = GL_UNSIGNED_BYTE; - texture->gl_internal_format_cache = color_internal_format; - texture->tex_id = rt->color; - texture->width = rt->width; - texture->alloc_width = rt->width; - texture->height = rt->height; - texture->alloc_height = rt->height; - texture->active = true; - - texture_set_flags(rt->texture, texture->flags); - } - - /* BACK FBO */ - /* For MSAA */ - -#ifndef JAVASCRIPT_ENABLED - if (rt->msaa >= RS::VIEWPORT_MSAA_2X && rt->msaa <= RS::VIEWPORT_MSAA_16X && config.multisample_supported) { - - rt->multisample_active = true; - - static const int msaa_value[] = { 0, 2, 4, 8, 16 }; - int msaa = msaa_value[rt->msaa]; - - int max_samples = 0; - glGetIntegerv(GL_MAX_SAMPLES, &max_samples); - if (msaa > max_samples) { - WARN_PRINT("MSAA must be <= GL_MAX_SAMPLES, falling-back to GL_MAX_SAMPLES = " + itos(max_samples)); - msaa = max_samples; - } - - //regular fbo - glGenFramebuffers(1, &rt->multisample_fbo); - glBindFramebuffer(GL_FRAMEBUFFER, rt->multisample_fbo); - - glGenRenderbuffers(1, &rt->multisample_depth); - glBindRenderbuffer(GL_RENDERBUFFER, rt->multisample_depth); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, config.depth_buffer_internalformat, rt->width, rt->height); - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->multisample_depth); - -#if defined(GLES_OVER_GL) || defined(IPHONE_ENABLED) - - glGenRenderbuffers(1, &rt->multisample_color); - glBindRenderbuffer(GL_RENDERBUFFER, rt->multisample_color); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, color_internal_format, rt->width, rt->height); - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rt->multisample_color); -#elif ANDROID_ENABLED - // Render to a texture in android - glGenTextures(1, &rt->multisample_color); - glBindTexture(GL_TEXTURE_2D, rt->multisample_color); - - glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, nullptr); - - // multisample buffer is same size as front buffer, so just use nearest - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - glFramebufferTexture2DMultisample(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->multisample_color, 0, msaa); -#endif - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - // Delete allocated resources and default to no MSAA - WARN_PRINT_ONCE("Cannot allocate back framebuffer for MSAA"); - printf("err status: %x\n", status); - config.multisample_supported = false; - rt->multisample_active = false; - - glDeleteFramebuffers(1, &rt->multisample_fbo); - rt->multisample_fbo = 0; - - glDeleteRenderbuffers(1, &rt->multisample_depth); - rt->multisample_depth = 0; -#ifdef ANDROID_ENABLED - glDeleteTextures(1, &rt->multisample_color); -#else - glDeleteRenderbuffers(1, &rt->multisample_color); -#endif - rt->multisample_color = 0; - } - - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); -#ifdef ANDROID_ENABLED - glBindTexture(GL_TEXTURE_2D, 0); -#endif - - } else -#endif // JAVASCRIPT_ENABLED - { - rt->multisample_active = false; - } - - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // copy texscreen buffers - if (!(rt->flags[RasterizerStorage::RENDER_TARGET_NO_SAMPLING])) { - - glGenTextures(1, &rt->copy_screen_effect.color); - glBindTexture(GL_TEXTURE_2D, rt->copy_screen_effect.color); - - if (rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - } else { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rt->width, rt->height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glGenFramebuffers(1, &rt->copy_screen_effect.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, rt->copy_screen_effect.fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->copy_screen_effect.color, 0); - - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - _render_target_clear(rt); - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); - } - } - - // Allocate mipmap chains for post_process effects - if (!rt->flags[RasterizerStorage::RENDER_TARGET_NO_3D] && rt->width >= 2 && rt->height >= 2) { - - for (int i = 0; i < 2; i++) { - - ERR_FAIL_COND(rt->mip_maps[i].sizes.size()); - int w = rt->width; - int h = rt->height; - - if (i > 0) { - w >>= 1; - h >>= 1; - } - - int level = 0; - int fb_w = w; - int fb_h = h; - - while (true) { - - RenderTarget::MipMaps::Size mm; - mm.width = w; - mm.height = h; - rt->mip_maps[i].sizes.push_back(mm); - - w >>= 1; - h >>= 1; - - if (w < 2 || h < 2) - break; - - level++; - } - - GLsizei width = fb_w; - GLsizei height = fb_h; - - if (config.render_to_mipmap_supported) { - - glGenTextures(1, &rt->mip_maps[i].color); - glBindTexture(GL_TEXTURE_2D, rt->mip_maps[i].color); - - for (int l = 0; l < level + 1; l++) { - glTexImage2D(GL_TEXTURE_2D, l, color_internal_format, width, height, 0, color_format, color_type, nullptr); - width = MAX(1, (width / 2)); - height = MAX(1, (height / 2)); - } -#ifdef GLES_OVER_GL - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level); -#endif - } else { - - // Can't render to specific levels of a mipmap in ES 2.0 or Webgl so create a texture for each level - for (int l = 0; l < level + 1; l++) { - glGenTextures(1, &rt->mip_maps[i].sizes.write[l].color); - glBindTexture(GL_TEXTURE_2D, rt->mip_maps[i].sizes[l].color); - glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, width, height, 0, color_format, color_type, nullptr); - width = MAX(1, (width / 2)); - height = MAX(1, (height / 2)); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - } - - glDisable(GL_SCISSOR_TEST); - glColorMask(1, 1, 1, 1); - glDepthMask(GL_TRUE); - - for (int j = 0; j < rt->mip_maps[i].sizes.size(); j++) { - - RenderTarget::MipMaps::Size &mm = rt->mip_maps[i].sizes.write[j]; - - glGenFramebuffers(1, &mm.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, mm.fbo); - - if (config.render_to_mipmap_supported) { - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->mip_maps[i].color, j); - } else { - - glBindTexture(GL_TEXTURE_2D, rt->mip_maps[i].sizes[j].color); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->mip_maps[i].sizes[j].color, 0); - } - - bool used_depth = false; - if (j == 0 && i == 0) { //use always - if (config.support_depth_texture) { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); - } else { - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); - } - used_depth = true; - } - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - WARN_PRINT_ONCE("Cannot allocate mipmaps for 3D post processing effects"); - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); - return; - } - - glClearColor(1.0, 0.0, 1.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); - if (used_depth) { - glClearDepth(1.0); - glClear(GL_DEPTH_BUFFER_BIT); - } - } - - rt->mip_maps[i].levels = level; - - if (config.render_to_mipmap_supported) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - } - rt->mip_maps_allocated = true; - } - - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); -} - -void RasterizerStorageGLES2::_render_target_clear(RenderTarget *rt) { - - // there is nothing to clear when DIRECT_TO_SCREEN is used - if (rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) - return; - - if (rt->fbo) { - glDeleteFramebuffers(1, &rt->fbo); - glDeleteTextures(1, &rt->color); - rt->fbo = 0; - } - - if (rt->external.fbo != 0) { - // free this - glDeleteFramebuffers(1, &rt->external.fbo); - - // clean up our texture - Texture *t = texture_owner.getornull(rt->external.texture); - t->alloc_height = 0; - t->alloc_width = 0; - t->width = 0; - t->height = 0; - t->active = false; - texture_owner.free(rt->external.texture); - memdelete(t); - - rt->external.fbo = 0; - } - - if (rt->depth) { - if (config.support_depth_texture) { - glDeleteTextures(1, &rt->depth); - } else { - glDeleteRenderbuffers(1, &rt->depth); - } - - rt->depth = 0; - } - - Texture *tex = texture_owner.getornull(rt->texture); - tex->alloc_height = 0; - tex->alloc_width = 0; - tex->width = 0; - tex->height = 0; - tex->active = false; - - if (rt->copy_screen_effect.color) { - glDeleteFramebuffers(1, &rt->copy_screen_effect.fbo); - rt->copy_screen_effect.fbo = 0; - - glDeleteTextures(1, &rt->copy_screen_effect.color); - rt->copy_screen_effect.color = 0; - } - - for (int i = 0; i < 2; i++) { - if (rt->mip_maps[i].sizes.size()) { - for (int j = 0; j < rt->mip_maps[i].sizes.size(); j++) { - glDeleteFramebuffers(1, &rt->mip_maps[i].sizes[j].fbo); - glDeleteTextures(1, &rt->mip_maps[i].sizes[j].color); - } - - glDeleteTextures(1, &rt->mip_maps[i].color); - rt->mip_maps[i].sizes.clear(); - rt->mip_maps[i].levels = 0; - rt->mip_maps[i].color = 0; - } - } - - if (rt->multisample_active) { - glDeleteFramebuffers(1, &rt->multisample_fbo); - rt->multisample_fbo = 0; - - glDeleteRenderbuffers(1, &rt->multisample_depth); - rt->multisample_depth = 0; -#ifdef ANDROID_ENABLED - glDeleteTextures(1, &rt->multisample_color); -#else - glDeleteRenderbuffers(1, &rt->multisample_color); -#endif - rt->multisample_color = 0; - } -} - -RID RasterizerStorageGLES2::render_target_create() { - - RenderTarget *rt = memnew(RenderTarget); - - Texture *t = memnew(Texture); - - t->type = RS::TEXTURE_TYPE_2D; - t->flags = 0; - t->width = 0; - t->height = 0; - t->alloc_height = 0; - t->alloc_width = 0; - t->format = Image::FORMAT_R8; - t->target = GL_TEXTURE_2D; - t->gl_format_cache = 0; - t->gl_internal_format_cache = 0; - t->gl_type_cache = 0; - t->data_size = 0; - t->total_data_size = 0; - t->ignore_mipmaps = false; - t->compressed = false; - t->mipmaps = 1; - t->active = true; - t->tex_id = 0; - t->render_target = rt; - - rt->texture = texture_owner.make_rid(t); - - return render_target_owner.make_rid(rt); -} - -void RasterizerStorageGLES2::render_target_set_position(RID p_render_target, int p_x, int p_y) { - - RenderTarget *rt = render_target_owner.getornull(p_render_target); - ERR_FAIL_COND(!rt); - - rt->x = p_x; - rt->y = p_y; -} - -void RasterizerStorageGLES2::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); - - if (p_width == rt->width && p_height == rt->height) - return; - - _render_target_clear(rt); - - rt->width = p_width; - rt->height = p_height; - - _render_target_allocate(rt); -} - -RID RasterizerStorageGLES2::render_target_get_texture(RID p_render_target) const { - - RenderTarget *rt = render_target_owner.getornull(p_render_target); - ERR_FAIL_COND_V(!rt, RID()); - - if (rt->external.fbo == 0) { - return rt->texture; - } else { - return rt->external.texture; - } -} - -void RasterizerStorageGLES2::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); - ERR_FAIL_COND(!rt); - - if (p_texture_id == 0) { - if (rt->external.fbo != 0) { - // free this - glDeleteFramebuffers(1, &rt->external.fbo); - - // and this - if (rt->external.depth != 0) { - glDeleteRenderbuffers(1, &rt->external.depth); - } - - // clean up our texture - Texture *t = texture_owner.getornull(rt->external.texture); - t->alloc_height = 0; - t->alloc_width = 0; - t->width = 0; - t->height = 0; - t->active = false; - texture_owner.free(rt->external.texture); - memdelete(t); - - rt->external.fbo = 0; - rt->external.color = 0; - rt->external.depth = 0; - } - } else { - Texture *t; - - if (rt->external.fbo == 0) { - // create our fbo - glGenFramebuffers(1, &rt->external.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo); - - // allocate a texture - t = memnew(Texture); - - t->type = RS::TEXTURE_TYPE_2D; - t->flags = 0; - t->width = 0; - t->height = 0; - t->alloc_height = 0; - t->alloc_width = 0; - t->format = Image::FORMAT_RGBA8; - t->target = GL_TEXTURE_2D; - t->gl_format_cache = 0; - t->gl_internal_format_cache = 0; - t->gl_type_cache = 0; - t->data_size = 0; - t->compressed = false; - t->srgb = false; - t->total_data_size = 0; - t->ignore_mipmaps = false; - t->mipmaps = 1; - t->active = true; - t->tex_id = 0; - t->render_target = rt; - - rt->external.texture = texture_owner.make_rid(t); - - } else { - // bind our frame buffer - glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo); - - // find our texture - t = texture_owner.getornull(rt->external.texture); - } - - // set our texture - t->tex_id = p_texture_id; - rt->external.color = p_texture_id; - - // size shouldn't be different - t->width = rt->width; - t->height = rt->height; - t->alloc_height = rt->width; - t->alloc_width = rt->height; - - // Switch our texture on our frame buffer -#if ANDROID_ENABLED - if (rt->msaa >= RS::VIEWPORT_MSAA_EXT_2X && rt->msaa <= RS::VIEWPORT_MSAA_EXT_4X) { - // This code only applies to the Oculus Go and Oculus Quest. Due to the the tiled nature - // of the GPU we can do a single render pass by rendering directly into our texture chains - // texture and apply MSAA as we render. - - // On any other hardware these two modes are ignored and we do not have any MSAA, - // the normal MSAA modes need to be used to enable our two pass approach - - static const int msaa_value[] = { 2, 4 }; - int msaa = msaa_value[rt->msaa - RS::VIEWPORT_MSAA_EXT_2X]; - - if (rt->external.depth == 0) { - // create a multisample depth buffer, we're not reusing Godots because Godot's didn't get created.. - glGenRenderbuffers(1, &rt->external.depth); - glBindRenderbuffer(GL_RENDERBUFFER, rt->external.depth); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, config.depth_buffer_internalformat, rt->width, rt->height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->external.depth); - } - - // and set our external texture as the texture... - glFramebufferTexture2DMultisample(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture_id, 0, msaa); - - } else -#endif - { - // set our texture as the destination for our framebuffer - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture_id, 0); - - // seeing we're rendering into this directly, better also use our depth buffer, just use our existing one :) - if (config.support_depth_texture) { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); - } else { - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); - } - } - - // check status and unbind - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - printf("framebuffer fail, status: %x\n", status); - } - - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); - } -} - -void RasterizerStorageGLES2::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); - - // When setting DIRECT_TO_SCREEN, you need to clear before the value is set, but allocate after as - // those functions change how they operate depending on the value of DIRECT_TO_SCREEN - if (p_flag == RENDER_TARGET_DIRECT_TO_SCREEN && p_value != rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) { - _render_target_clear(rt); - rt->flags[p_flag] = p_value; - _render_target_allocate(rt); - } - - rt->flags[p_flag] = p_value; - - switch (p_flag) { - case RENDER_TARGET_TRANSPARENT: - case RENDER_TARGET_HDR: - case RENDER_TARGET_NO_3D: - case RENDER_TARGET_NO_SAMPLING: - case RENDER_TARGET_NO_3D_EFFECTS: { - //must reset for these formats - _render_target_clear(rt); - _render_target_allocate(rt); - - } break; - default: { - } - } -} - -bool RasterizerStorageGLES2::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->used_in_frame; -} - -void RasterizerStorageGLES2::render_target_set_as_unused(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); - ERR_FAIL_COND(!rt); - - rt->used_in_frame = false; -} - -void RasterizerStorageGLES2::render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); - ERR_FAIL_COND(!rt); - - if (rt->msaa == p_msaa) - return; - - if (!config.multisample_supported) { - ERR_PRINT("MSAA not supported on this hardware."); - return; - } - - _render_target_clear(rt); - rt->msaa = p_msaa; - _render_target_allocate(rt); -} - -/* CANVAS SHADOW */ - -RID RasterizerStorageGLES2::canvas_light_shadow_buffer_create(int p_width) { - - CanvasLightShadow *cls = memnew(CanvasLightShadow); - - if (p_width > config.max_texture_size) - p_width = config.max_texture_size; - - cls->size = p_width; - cls->height = 16; - - glActiveTexture(GL_TEXTURE0); - - glGenFramebuffers(1, &cls->fbo); - glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); - - glGenRenderbuffers(1, &cls->depth); - glBindRenderbuffer(GL_RENDERBUFFER, cls->depth); - glRenderbufferStorage(GL_RENDERBUFFER, config.depth_buffer_internalformat, cls->size, cls->height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, cls->depth); - - glGenTextures(1, &cls->distance); - glBindTexture(GL_TEXTURE_2D, cls->distance); - if (config.use_rgba_2d_shadows) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cls->size, cls->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - } else { -#ifdef GLES_OVER_GL - glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, cls->size, cls->height, 0, _RED_OES, GL_FLOAT, nullptr); -#else - glTexImage2D(GL_TEXTURE_2D, 0, GL_FLOAT, cls->size, cls->height, 0, _RED_OES, GL_FLOAT, nullptr); -#endif - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cls->distance, 0); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - //printf("errnum: %x\n",status); - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - memdelete(cls); - ERR_FAIL_COND_V(status != GL_FRAMEBUFFER_COMPLETE, RID()); - } - - return canvas_light_shadow_owner.make_rid(cls); -} - -/* LIGHT SHADOW MAPPING */ - -RID RasterizerStorageGLES2::canvas_light_occluder_create() { - - CanvasOccluder *co = memnew(CanvasOccluder); - co->index_id = 0; - co->vertex_id = 0; - co->len = 0; - - return canvas_occluder_owner.make_rid(co); -} - -void RasterizerStorageGLES2::canvas_light_occluder_set_polylines(RID p_occluder, const Vector<Vector2> &p_lines) { - - CanvasOccluder *co = canvas_occluder_owner.getornull(p_occluder); - ERR_FAIL_COND(!co); - - co->lines = p_lines; - - if (p_lines.size() != co->len) { - - if (co->index_id) - glDeleteBuffers(1, &co->index_id); - if (co->vertex_id) - glDeleteBuffers(1, &co->vertex_id); - - co->index_id = 0; - co->vertex_id = 0; - co->len = 0; - } - - if (p_lines.size()) { - - Vector<float> geometry; - Vector<uint16_t> indices; - int lc = p_lines.size(); - - geometry.resize(lc * 6); - indices.resize(lc * 3); - - float *vw = geometry.ptrw(); - uint16_t *iw = indices.ptrw(); - - const Vector2 *lr = p_lines.ptr(); - - const int POLY_HEIGHT = 16384; - - for (int i = 0; i < lc / 2; i++) { - - vw[i * 12 + 0] = lr[i * 2 + 0].x; - vw[i * 12 + 1] = lr[i * 2 + 0].y; - vw[i * 12 + 2] = POLY_HEIGHT; - - vw[i * 12 + 3] = lr[i * 2 + 1].x; - vw[i * 12 + 4] = lr[i * 2 + 1].y; - vw[i * 12 + 5] = POLY_HEIGHT; - - vw[i * 12 + 6] = lr[i * 2 + 1].x; - vw[i * 12 + 7] = lr[i * 2 + 1].y; - vw[i * 12 + 8] = -POLY_HEIGHT; - - vw[i * 12 + 9] = lr[i * 2 + 0].x; - vw[i * 12 + 10] = lr[i * 2 + 0].y; - vw[i * 12 + 11] = -POLY_HEIGHT; - - iw[i * 6 + 0] = i * 4 + 0; - iw[i * 6 + 1] = i * 4 + 1; - iw[i * 6 + 2] = i * 4 + 2; - - iw[i * 6 + 3] = i * 4 + 2; - iw[i * 6 + 4] = i * 4 + 3; - iw[i * 6 + 5] = i * 4 + 0; - } - - //if same buffer len is being set, just use BufferSubData to avoid a pipeline flush - - if (!co->vertex_id) { - glGenBuffers(1, &co->vertex_id); - glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); - glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(real_t), vw.ptr(), GL_STATIC_DRAW); - } else { - - glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); - glBufferSubData(GL_ARRAY_BUFFER, 0, lc * 6 * sizeof(real_t), vw.ptr()); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - - if (!co->index_id) { - - glGenBuffers(1, &co->index_id); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, lc * 3 * sizeof(uint16_t), iw.ptr(), GL_DYNAMIC_DRAW); - } else { - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, lc * 3 * sizeof(uint16_t), iw.ptr()); - } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind - - co->len = lc; - } -} - -RS::InstanceType RasterizerStorageGLES2::get_base_type(RID p_rid) const { - - if (mesh_owner.owns(p_rid)) { - return RS::INSTANCE_MESH; - } else if (light_owner.owns(p_rid)) { - return RS::INSTANCE_LIGHT; - } else if (multimesh_owner.owns(p_rid)) { - return RS::INSTANCE_MULTIMESH; - } else if (immediate_owner.owns(p_rid)) { - return RS::INSTANCE_IMMEDIATE; - } else if (reflection_probe_owner.owns(p_rid)) { - return RS::INSTANCE_REFLECTION_PROBE; - } else if (lightmap_capture_data_owner.owns(p_rid)) { - return RS::INSTANCE_LIGHTMAP_CAPTURE; - } else { - return RS::INSTANCE_NONE; - } -} - -bool RasterizerStorageGLES2::free(RID p_rid) { - - if (render_target_owner.owns(p_rid)) { - - RenderTarget *rt = render_target_owner.getornull(p_rid); - _render_target_clear(rt); - - Texture *t = texture_owner.getornull(rt->texture); - texture_owner.free(rt->texture); - memdelete(t); - render_target_owner.free(p_rid); - memdelete(rt); - - return true; - } else if (texture_owner.owns(p_rid)) { - - Texture *t = texture_owner.getornull(p_rid); - // can't free a render target texture - ERR_FAIL_COND_V(t->render_target, true); - - info.texture_mem -= t->total_data_size; - texture_owner.free(p_rid); - memdelete(t); - - return true; - } else if (sky_owner.owns(p_rid)) { - - Sky *sky = sky_owner.getornull(p_rid); - sky_set_texture(p_rid, RID(), 256); - sky_owner.free(p_rid); - memdelete(sky); - - return true; - } else if (shader_owner.owns(p_rid)) { - - Shader *shader = shader_owner.getornull(p_rid); - - if (shader->shader && shader->custom_code_id) { - shader->shader->free_custom_shader(shader->custom_code_id); - } - - if (shader->dirty_list.in_list()) { - _shader_dirty_list.remove(&shader->dirty_list); - } - - while (shader->materials.first()) { - Material *m = shader->materials.first()->self(); - - m->shader = nullptr; - _material_make_dirty(m); - - shader->materials.remove(shader->materials.first()); - } - - shader_owner.free(p_rid); - memdelete(shader); - - return true; - } else if (material_owner.owns(p_rid)) { - - Material *m = material_owner.getornull(p_rid); - - if (m->shader) { - m->shader->materials.remove(&m->list); - } - - for (Map<Geometry *, int>::Element *E = m->geometry_owners.front(); E; E = E->next()) { - Geometry *g = E->key(); - g->material = RID(); - } - - for (Map<RasterizerScene::InstanceBase *, int>::Element *E = m->instance_owners.front(); E; E = E->next()) { - - RasterizerScene::InstanceBase *ins = E->key(); - - if (ins->material_override == p_rid) { - ins->material_override = RID(); - } - - for (int i = 0; i < ins->materials.size(); i++) { - if (ins->materials[i] == p_rid) { - ins->materials.write[i] = RID(); - } - } - } - - material_owner.free(p_rid); - memdelete(m); - - return true; - } else if (skeleton_owner.owns(p_rid)) { - - Skeleton *s = skeleton_owner.getornull(p_rid); - - if (s->update_list.in_list()) { - skeleton_update_list.remove(&s->update_list); - } - - for (Set<RasterizerScene::InstanceBase *>::Element *E = s->instances.front(); E; E = E->next()) { - E->get()->skeleton = RID(); - } - - skeleton_allocate(p_rid, 0, false); - - if (s->tex_id) { - glDeleteTextures(1, &s->tex_id); - } - - skeleton_owner.free(p_rid); - memdelete(s); - - return true; - } else if (mesh_owner.owns(p_rid)) { - - Mesh *mesh = mesh_owner.getornull(p_rid); - - mesh->instance_remove_deps(); - mesh_clear(p_rid); - - while (mesh->multimeshes.first()) { - MultiMesh *multimesh = mesh->multimeshes.first()->self(); - multimesh->mesh = RID(); - multimesh->dirty_aabb = true; - - mesh->multimeshes.remove(mesh->multimeshes.first()); - - if (!multimesh->update_list.in_list()) { - multimesh_update_list.add(&multimesh->update_list); - } - } - - mesh_owner.free(p_rid); - memdelete(mesh); - - return true; - } else if (multimesh_owner.owns(p_rid)) { - - MultiMesh *multimesh = multimesh_owner.getornull(p_rid); - multimesh->instance_remove_deps(); - - if (multimesh->mesh.is_valid()) { - Mesh *mesh = mesh_owner.getornull(multimesh->mesh); - if (mesh) { - mesh->multimeshes.remove(&multimesh->mesh_list); - } - } - - multimesh_allocate(p_rid, 0, RS::MULTIMESH_TRANSFORM_3D, RS::MULTIMESH_COLOR_NONE); - - update_dirty_multimeshes(); - - multimesh_owner.free(p_rid); - memdelete(multimesh); - - return true; - } else if (immediate_owner.owns(p_rid)) { - Immediate *im = immediate_owner.getornull(p_rid); - im->instance_remove_deps(); - - immediate_owner.free(p_rid); - memdelete(im); - - return true; - } else if (light_owner.owns(p_rid)) { - - Light *light = light_owner.getornull(p_rid); - light->instance_remove_deps(); - - light_owner.free(p_rid); - memdelete(light); - - return true; - } else if (reflection_probe_owner.owns(p_rid)) { - - // delete the texture - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_rid); - reflection_probe->instance_remove_deps(); - - reflection_probe_owner.free(p_rid); - memdelete(reflection_probe); - - return true; - } else if (lightmap_capture_data_owner.owns(p_rid)) { - - // delete the texture - LightmapCapture *lightmap_capture = lightmap_capture_data_owner.getornull(p_rid); - lightmap_capture->instance_remove_deps(); - - lightmap_capture_data_owner.free(p_rid); - memdelete(lightmap_capture); - return true; - - } else if (canvas_occluder_owner.owns(p_rid)) { - - CanvasOccluder *co = canvas_occluder_owner.getornull(p_rid); - if (co->index_id) - glDeleteBuffers(1, &co->index_id); - if (co->vertex_id) - glDeleteBuffers(1, &co->vertex_id); - - canvas_occluder_owner.free(p_rid); - memdelete(co); - - return true; - - } else if (canvas_light_shadow_owner.owns(p_rid)) { - - CanvasLightShadow *cls = canvas_light_shadow_owner.getornull(p_rid); - glDeleteFramebuffers(1, &cls->fbo); - glDeleteRenderbuffers(1, &cls->depth); - glDeleteTextures(1, &cls->distance); - canvas_light_shadow_owner.free(p_rid); - memdelete(cls); - - return true; - } else { - return false; - } -} - -bool RasterizerStorageGLES2::has_os_feature(const String &p_feature) const { - - if (p_feature == "pvrtc") - return config.pvrtc_supported; - - if (p_feature == "s3tc") - return config.s3tc_supported; - - if (p_feature == "etc") - return config.etc1_supported; - - return false; -} - -//////////////////////////////////////////// - -void RasterizerStorageGLES2::set_debug_generate_wireframes(bool p_generate) { -} - -void RasterizerStorageGLES2::render_info_begin_capture() { - - info.snap = info.render; -} - -void RasterizerStorageGLES2::render_info_end_capture() { - - info.snap.object_count = info.render.object_count - info.snap.object_count; - info.snap.draw_call_count = info.render.draw_call_count - info.snap.draw_call_count; - info.snap.material_switch_count = info.render.material_switch_count - info.snap.material_switch_count; - info.snap.surface_switch_count = info.render.surface_switch_count - info.snap.surface_switch_count; - info.snap.shader_rebind_count = info.render.shader_rebind_count - info.snap.shader_rebind_count; - info.snap.vertices_count = info.render.vertices_count - info.snap.vertices_count; -} - -int RasterizerStorageGLES2::get_captured_render_info(RS::RenderInfo p_info) { - - switch (p_info) { - case RS::INFO_OBJECTS_IN_FRAME: { - return info.snap.object_count; - } break; - case RS::INFO_VERTICES_IN_FRAME: { - return info.snap.vertices_count; - } break; - case RS::INFO_MATERIAL_CHANGES_IN_FRAME: { - return info.snap.material_switch_count; - } break; - case RS::INFO_SHADER_CHANGES_IN_FRAME: { - return info.snap.shader_rebind_count; - } break; - case RS::INFO_SURFACE_CHANGES_IN_FRAME: { - return info.snap.surface_switch_count; - } break; - case RS::INFO_DRAW_CALLS_IN_FRAME: { - return info.snap.draw_call_count; - } break; - default: { - return get_render_info(p_info); - } - } -} - -int RasterizerStorageGLES2::get_render_info(RS::RenderInfo p_info) { - switch (p_info) { - case RS::INFO_OBJECTS_IN_FRAME: - return info.render_final.object_count; - case RS::INFO_VERTICES_IN_FRAME: - return info.render_final.vertices_count; - case RS::INFO_MATERIAL_CHANGES_IN_FRAME: - return info.render_final.material_switch_count; - case RS::INFO_SHADER_CHANGES_IN_FRAME: - return info.render_final.shader_rebind_count; - case RS::INFO_SURFACE_CHANGES_IN_FRAME: - return info.render_final.surface_switch_count; - case RS::INFO_DRAW_CALLS_IN_FRAME: - return info.render_final.draw_call_count; - case RS::INFO_USAGE_VIDEO_MEM_TOTAL: - return 0; //no idea - case RS::INFO_VIDEO_MEM_USED: - return info.vertex_mem + info.texture_mem; - case RS::INFO_TEXTURE_MEM_USED: - return info.texture_mem; - case RS::INFO_VERTEX_MEM_USED: - return info.vertex_mem; - default: - return 0; //no idea either - } -} - -String RasterizerStorageGLES2::get_video_adapter_name() const { - - return (const char *)glGetString(GL_RENDERER); -} - -String RasterizerStorageGLES2::get_video_adapter_vendor() const { - - return (const char *)glGetString(GL_VENDOR); -} - -void RasterizerStorageGLES2::initialize() { - RasterizerStorageGLES2::system_fbo = 0; - - { - - const GLubyte *extension_string = glGetString(GL_EXTENSIONS); - - Vector<String> extensions = String((const char *)extension_string).split(" "); - - for (int i = 0; i < extensions.size(); i++) { - config.extensions.insert(extensions[i]); - } - } - - config.keep_original_textures = false; - config.shrink_textures_x2 = false; - config.depth_internalformat = GL_DEPTH_COMPONENT; - config.depth_type = GL_UNSIGNED_INT; - -#ifdef GLES_OVER_GL - config.texture_3d_supported = true; - config.texture_array_supported = config.extensions.has("GL_EXT_texture_array"); - config.float_texture_supported = true; - config.s3tc_supported = true; - config.pvrtc_supported = false; - config.etc1_supported = false; - config.support_npot_repeat_mipmap = true; - config.depth_buffer_internalformat = GL_DEPTH_COMPONENT24; -#else - config.texture_3d_supported = config.extensions.has("GL_OES_texture_3D"); - config.texture_array_supported = false; - config.float_texture_supported = config.extensions.has("GL_ARB_texture_float") || config.extensions.has("GL_OES_texture_float"); - config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_s3tc") || config.extensions.has("WEBGL_compressed_texture_s3tc"); - config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture") || config.extensions.has("WEBGL_compressed_texture_etc1"); - config.pvrtc_supported = config.extensions.has("IMG_texture_compression_pvrtc") || config.extensions.has("WEBGL_compressed_texture_pvrtc"); - config.support_npot_repeat_mipmap = config.extensions.has("GL_OES_texture_npot"); - -#ifdef JAVASCRIPT_ENABLED - // RenderBuffer internal format must be 16 bits in WebGL, - // but depth_texture should default to 32 always - // if the implementation doesn't support 32, it should just quietly use 16 instead - // https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/ - config.depth_buffer_internalformat = GL_DEPTH_COMPONENT16; - config.depth_type = GL_UNSIGNED_INT; -#else - // on mobile check for 24 bit depth support for RenderBufferStorage - if (config.extensions.has("GL_OES_depth24")) { - config.depth_buffer_internalformat = _DEPTH_COMPONENT24_OES; - config.depth_type = GL_UNSIGNED_INT; - } else { - config.depth_buffer_internalformat = GL_DEPTH_COMPONENT16; - config.depth_type = GL_UNSIGNED_SHORT; - } -#endif -#endif - -#ifndef GLES_OVER_GL - //Manually load extensions for android and ios - -#ifdef IPHONE_ENABLED - // appears that IPhone doesn't need to dlopen TODO: test this rigorously before removing - //void *gles2_lib = dlopen(nullptr, RTLD_LAZY); - //glRenderbufferStorageMultisampleAPPLE = dlsym(gles2_lib, "glRenderbufferStorageMultisampleAPPLE"); - //glResolveMultisampleFramebufferAPPLE = dlsym(gles2_lib, "glResolveMultisampleFramebufferAPPLE"); -#elif ANDROID_ENABLED - - void *gles2_lib = dlopen("libGLESv2.so", RTLD_LAZY); - glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glRenderbufferStorageMultisampleEXT"); - glFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glFramebufferTexture2DMultisampleEXT"); - glTexImage3DOES = (PFNGLTEXIMAGE3DOESPROC)dlsym(gles2_lib, "glTexImage3DOES"); - glTexSubImage3DOES = (PFNGLTEXSUBIMAGE3DOESPROC)dlsym(gles2_lib, "glTexSubImage3DOES"); - glCompressedTexSubImage3DOES = (PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC)dlsym(gles2_lib, "glCompressedTexSubImage3DOES"); -#endif -#endif - - // Check for multisample support - config.multisample_supported = config.extensions.has("GL_EXT_framebuffer_multisample") || config.extensions.has("GL_EXT_multisampled_render_to_texture") || config.extensions.has("GL_APPLE_framebuffer_multisample"); - -#ifdef GLES_OVER_GL - //TODO: causes huge problems with desktop video drivers. Making false for now, needs to be true to render SCREEN_TEXTURE mipmaps - config.render_to_mipmap_supported = false; -#else - //check if mipmaps can be used for SCREEN_TEXTURE and Glow on Mobile and web platforms - config.render_to_mipmap_supported = config.extensions.has("GL_OES_fbo_render_mipmap") && config.extensions.has("GL_EXT_texture_lod"); -#endif - -#ifdef GLES_OVER_GL - config.use_rgba_2d_shadows = false; - config.support_depth_texture = true; - config.use_rgba_3d_shadows = false; - config.support_depth_cubemaps = true; -#else - config.use_rgba_2d_shadows = !(config.float_texture_supported && config.extensions.has("GL_EXT_texture_rg")); - config.support_depth_texture = config.extensions.has("GL_OES_depth_texture") || config.extensions.has("WEBGL_depth_texture"); - config.use_rgba_3d_shadows = !config.support_depth_texture; - config.support_depth_cubemaps = config.extensions.has("GL_OES_depth_texture_cube_map"); -#endif - -#ifdef GLES_OVER_GL - config.support_32_bits_indices = true; -#else - config.support_32_bits_indices = config.extensions.has("GL_OES_element_index_uint"); -#endif - -#ifdef GLES_OVER_GL - config.support_write_depth = true; -#elif defined(JAVASCRIPT_ENABLED) - config.support_write_depth = false; -#else - config.support_write_depth = config.extensions.has("GL_EXT_frag_depth"); -#endif - -#ifdef JAVASCRIPT_ENABLED - config.support_half_float_vertices = false; -#else - //every other platform, be it mobile or desktop, supports this (even if not in the GLES2 spec). - config.support_half_float_vertices = true; -#endif - - config.rgtc_supported = config.extensions.has("GL_EXT_texture_compression_rgtc") || config.extensions.has("GL_ARB_texture_compression_rgtc") || config.extensions.has("EXT_texture_compression_rgtc"); - config.bptc_supported = config.extensions.has("GL_ARB_texture_compression_bptc") || config.extensions.has("EXT_texture_compression_bptc"); - - //determine formats for depth textures (or renderbuffers) - if (config.support_depth_texture) { - // Will use texture for depth - // have to manually see if we can create a valid framebuffer texture using UNSIGNED_INT, - // as there is no extension to test for this. - GLuint fbo; - glGenFramebuffers(1, &fbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - GLuint depth; - glGenTextures(1, &depth); - glBindTexture(GL_TEXTURE_2D, depth); - glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, 32, 32, 0, GL_DEPTH_COMPONENT, config.depth_type, nullptr); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - - glBindFramebuffer(GL_FRAMEBUFFER, system_fbo); - glDeleteFramebuffers(1, &fbo); - glBindTexture(GL_TEXTURE_2D, 0); - glDeleteTextures(1, &depth); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - // If it fails, test to see if it supports a framebuffer texture using UNSIGNED_SHORT - // This is needed because many OSX devices don't support either UNSIGNED_INT or UNSIGNED_SHORT -#ifdef GLES_OVER_GL - config.depth_internalformat = GL_DEPTH_COMPONENT16; -#else - // OES_depth_texture extension only specifies GL_DEPTH_COMPONENT. - config.depth_internalformat = GL_DEPTH_COMPONENT; -#endif - config.depth_type = GL_UNSIGNED_SHORT; - - glGenFramebuffers(1, &fbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - glGenTextures(1, &depth); - glBindTexture(GL_TEXTURE_2D, depth); - glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, 32, 32, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, nullptr); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0); - - status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - //if it fails again depth textures aren't supported, use rgba shadows and renderbuffer for depth - config.support_depth_texture = false; - config.use_rgba_3d_shadows = true; - } - - glBindFramebuffer(GL_FRAMEBUFFER, system_fbo); - glDeleteFramebuffers(1, &fbo); - glBindTexture(GL_TEXTURE_2D, 0); - glDeleteTextures(1, &depth); - } - } - - //picky requirements for these - config.support_shadow_cubemaps = config.support_depth_texture && config.support_write_depth && config.support_depth_cubemaps; - - frame.count = 0; - frame.delta = 0; - frame.current_rt = nullptr; - frame.clear_request = false; - - glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &config.max_vertex_texture_image_units); - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units); - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &config.max_texture_size); - - // the use skeleton software path should be used if either float texture is not supported, - // OR max_vertex_texture_image_units is zero - config.use_skeleton_software = (config.float_texture_supported == false) || (config.max_vertex_texture_image_units == 0); - - shaders.copy.init(); - shaders.cubemap_filter.init(); - bool ggx_hq = GLOBAL_GET("rendering/quality/reflections/high_quality_ggx"); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::LOW_QUALITY, !ggx_hq); - - { - // quad for copying stuff - - glGenBuffers(1, &resources.quadie); - glBindBuffer(GL_ARRAY_BUFFER, resources.quadie); - { - const float qv[16] = { - -1, - -1, - 0, - 0, - -1, - 1, - 0, - 1, - 1, - 1, - 1, - 1, - 1, - -1, - 1, - 0, - }; - - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, qv, GL_STATIC_DRAW); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - { - //default textures - - glGenTextures(1, &resources.white_tex); - unsigned char whitetexdata[8 * 8 * 3]; - for (int i = 0; i < 8 * 8 * 3; i++) { - whitetexdata[i] = 255; - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, resources.white_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata); - glGenerateMipmap(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - - glGenTextures(1, &resources.black_tex); - unsigned char blacktexdata[8 * 8 * 3]; - for (int i = 0; i < 8 * 8 * 3; i++) { - blacktexdata[i] = 0; - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, resources.black_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, blacktexdata); - glGenerateMipmap(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - - glGenTextures(1, &resources.normal_tex); - unsigned char normaltexdata[8 * 8 * 3]; - for (int i = 0; i < 8 * 8 * 3; i += 3) { - normaltexdata[i + 0] = 128; - normaltexdata[i + 1] = 128; - normaltexdata[i + 2] = 255; - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, resources.normal_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, normaltexdata); - glGenerateMipmap(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - - glGenTextures(1, &resources.aniso_tex); - unsigned char anisotexdata[8 * 8 * 3]; - for (int i = 0; i < 8 * 8 * 3; i += 3) { - anisotexdata[i + 0] = 255; - anisotexdata[i + 1] = 128; - anisotexdata[i + 2] = 0; - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, resources.aniso_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, anisotexdata); - glGenerateMipmap(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - -#if defined(GLES_OVER_GL) || defined(ANDROID_ENABLED) - glGenTextures(1, &resources.white_tex_3d); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_3D, resources.white_tex_3d); - glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 2, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata); - -#ifdef GLES_OVER_GL - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0); -#endif - - glGenTextures(1, &resources.white_tex_array); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D_ARRAY, resources.white_tex_array); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 8, 8, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 8, 8, 1, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata); - glGenerateMipmap(GL_TEXTURE_2D_ARRAY); - glBindTexture(GL_TEXTURE_2D, 0); -#endif - } - - // skeleton buffer - { - resources.skeleton_transform_buffer_size = 0; - glGenBuffers(1, &resources.skeleton_transform_buffer); - } - - // radical inverse vdc cache texture - // used for cubemap filtering - if (true /*||config.float_texture_supported*/) { //uint8 is similar and works everywhere - glGenTextures(1, &resources.radical_inverse_vdc_cache_tex); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, resources.radical_inverse_vdc_cache_tex); - - uint8_t radical_inverse[512]; - - for (uint32_t i = 0; i < 512; i++) { - uint32_t bits = i; - - bits = (bits << 16) | (bits >> 16); - bits = ((bits & 0x55555555) << 1) | ((bits & 0xAAAAAAAA) >> 1); - bits = ((bits & 0x33333333) << 2) | ((bits & 0xCCCCCCCC) >> 2); - bits = ((bits & 0x0F0F0F0F) << 4) | ((bits & 0xF0F0F0F0) >> 4); - bits = ((bits & 0x00FF00FF) << 8) | ((bits & 0xFF00FF00) >> 8); - - float value = float(bits) * 2.3283064365386963e-10; - radical_inverse[i] = uint8_t(CLAMP(value * 255.0, 0, 255)); - } - - glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 512, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, radical_inverse); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //need this for proper sampling - - glBindTexture(GL_TEXTURE_2D, 0); - } - - { - - glGenFramebuffers(1, &resources.mipmap_blur_fbo); - glGenTextures(1, &resources.mipmap_blur_color); - } - -#ifdef GLES_OVER_GL - //this needs to be enabled manually in OpenGL 2.1 - - if (config.extensions.has("GL_ARB_seamless_cube_map")) { - glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS); - } - glEnable(GL_POINT_SPRITE); - glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); -#endif - - config.force_vertex_shading = GLOBAL_GET("rendering/quality/shading/force_vertex_shading"); - config.use_fast_texture_filter = GLOBAL_GET("rendering/quality/texture_filters/use_nearest_mipmap_filter"); -} - -void RasterizerStorageGLES2::finalize() { -} - -void RasterizerStorageGLES2::_copy_screen() { - bind_quad_array(); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); -} - -void RasterizerStorageGLES2::update_dirty_resources() { - update_dirty_shaders(); - update_dirty_materials(); - update_dirty_skeletons(); - update_dirty_multimeshes(); -} - -RasterizerStorageGLES2::RasterizerStorageGLES2() { - RasterizerStorageGLES2::system_fbo = 0; -} diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h deleted file mode 100644 index 29651936fb..0000000000 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ /dev/null @@ -1,1321 +0,0 @@ -/*************************************************************************/ -/* rasterizer_storage_gles2.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 RASTERIZERSTORAGEGLES2_H -#define RASTERIZERSTORAGEGLES2_H - -#include "core/self_list.h" -#include "servers/rendering/rasterizer.h" -#include "servers/rendering/shader_language.h" -#include "shader_compiler_gles2.h" -#include "shader_gles2.h" - -#include "core/rid_owner.h" -#include "shaders/copy.glsl.gen.h" -#include "shaders/cubemap_filter.glsl.gen.h" -/* -#include "shaders/blend_shape.glsl.gen.h" -#include "shaders/canvas.glsl.gen.h" -#include "shaders/particles.glsl.gen.h" -*/ - -class RasterizerCanvasGLES2; -class RasterizerSceneGLES2; - -class RasterizerStorageGLES2 : public RasterizerStorage { -public: - RasterizerCanvasGLES2 *canvas; - RasterizerSceneGLES2 *scene; - - static GLuint system_fbo; - - struct Config { - - bool shrink_textures_x2; - bool use_fast_texture_filter; - bool use_skeleton_software; - - int max_vertex_texture_image_units; - int max_texture_image_units; - int max_texture_size; - - // TODO implement wireframe in GLES2 - // bool generate_wireframes; - - Set<String> extensions; - - bool texture_3d_supported; - bool texture_array_supported; - bool float_texture_supported; - bool s3tc_supported; - bool etc1_supported; - bool pvrtc_supported; - bool rgtc_supported; - bool bptc_supported; - - bool keep_original_textures; - - bool force_vertex_shading; - - bool use_rgba_2d_shadows; - bool use_rgba_3d_shadows; - - bool support_32_bits_indices; - bool support_write_depth; - bool support_half_float_vertices; - bool support_npot_repeat_mipmap; - bool support_depth_texture; - bool support_depth_cubemaps; - - bool support_shadow_cubemaps; - - bool multisample_supported; - bool render_to_mipmap_supported; - - GLuint depth_internalformat; - GLuint depth_type; - GLuint depth_buffer_internalformat; - - } config; - - struct Resources { - - GLuint white_tex; - GLuint black_tex; - GLuint normal_tex; - GLuint aniso_tex; - GLuint white_tex_3d; - GLuint white_tex_array; - - GLuint mipmap_blur_fbo; - GLuint mipmap_blur_color; - - GLuint radical_inverse_vdc_cache_tex; - bool use_rgba_2d_shadows; - - GLuint quadie; - - size_t skeleton_transform_buffer_size; - GLuint skeleton_transform_buffer; - Vector<float> skeleton_transform_cpu_buffer; - - } resources; - - mutable struct Shaders { - - ShaderCompilerGLES2 compiler; - - CopyShaderGLES2 copy; - CubemapFilterShaderGLES2 cubemap_filter; - - ShaderCompilerGLES2::IdentifierActions actions_canvas; - ShaderCompilerGLES2::IdentifierActions actions_scene; - ShaderCompilerGLES2::IdentifierActions actions_particles; - - } shaders; - - struct Info { - - uint64_t texture_mem; - uint64_t vertex_mem; - - struct Render { - uint32_t object_count; - uint32_t draw_call_count; - uint32_t material_switch_count; - uint32_t surface_switch_count; - uint32_t shader_rebind_count; - uint32_t vertices_count; - - void reset() { - object_count = 0; - draw_call_count = 0; - material_switch_count = 0; - surface_switch_count = 0; - shader_rebind_count = 0; - vertices_count = 0; - } - } render, render_final, snap; - - Info() : - texture_mem(0), - vertex_mem(0) { - render.reset(); - render_final.reset(); - } - - } info; - - void bind_quad_array() const; - - ///////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////DATA/////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////////// - - struct Instantiable { - SelfList<RasterizerScene::InstanceBase>::List instance_list; - - _FORCE_INLINE_ void instance_change_notify(bool p_aabb, bool p_materials) { - - SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); - while (instances) { - - instances->self()->base_changed(p_aabb, p_materials); - instances = instances->next(); - } - } - - _FORCE_INLINE_ void instance_remove_deps() { - SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); - - while (instances) { - instances->self()->base_removed(); - instances = instances->next(); - } - } - - Instantiable() {} - - virtual ~Instantiable() {} - }; - - struct GeometryOwner : public Instantiable { - }; - - struct Geometry : public Instantiable { - - enum Type { - GEOMETRY_INVALID, - GEOMETRY_SURFACE, - GEOMETRY_IMMEDIATE, - GEOMETRY_MULTISURFACE - }; - - Type type; - RID material; - uint64_t last_pass; - uint32_t index; - - virtual void material_changed_notify() {} - - Geometry() { - last_pass = 0; - index = 0; - } - }; - - ///////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////API//////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////////// - - /* TEXTURE API */ - - struct RenderTarget; - - struct Texture { - - Texture *proxy; - Set<Texture *> proxy_owners; - - String path; - uint32_t flags; - int width, height, depth; - int alloc_width, alloc_height; - Image::Format format; - RS::TextureType type; - - GLenum target; - GLenum gl_format_cache; - GLenum gl_internal_format_cache; - GLenum gl_type_cache; - - int data_size; - int total_data_size; - bool ignore_mipmaps; - - bool compressed; - - bool srgb; - - int mipmaps; - - bool resize_to_po2; - - bool active; - GLenum tex_id; - - uint16_t stored_cube_sides; - - RenderTarget *render_target; - - Vector<Ref<Image>> images; - - bool redraw_if_visible; - - RenderingServer::TextureDetectCallback detect_3d; - void *detect_3d_ud; - - RenderingServer::TextureDetectCallback detect_srgb; - void *detect_srgb_ud; - - RenderingServer::TextureDetectCallback detect_normal; - void *detect_normal_ud; - - Texture() : - proxy(nullptr), - flags(0), - width(0), - height(0), - alloc_width(0), - alloc_height(0), - format(Image::FORMAT_L8), - type(RS::TEXTURE_TYPE_2D), - target(0), - data_size(0), - total_data_size(0), - ignore_mipmaps(false), - compressed(false), - mipmaps(0), - resize_to_po2(false), - active(false), - tex_id(0), - stored_cube_sides(0), - render_target(nullptr), - redraw_if_visible(false), - detect_3d(nullptr), - detect_3d_ud(nullptr), - detect_srgb(nullptr), - detect_srgb_ud(nullptr), - detect_normal(nullptr), - detect_normal_ud(nullptr) { - } - - _ALWAYS_INLINE_ Texture *get_ptr() { - if (proxy) { - return proxy; //->get_ptr(); only one level of indirection, else not inlining possible. - } else { - return this; - } - } - - ~Texture() { - if (tex_id != 0) { - glDeleteTextures(1, &tex_id); - } - - for (Set<Texture *>::Element *E = proxy_owners.front(); E; E = E->next()) { - E->get()->proxy = nullptr; - } - - if (proxy) { - proxy->proxy_owners.erase(this); - } - } - }; - - mutable RID_PtrOwner<Texture2D> texture_owner; - - Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const; - - virtual RID texture_create(); - virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, RS::TextureType p_type, uint32_t p_flags = RS::TEXTURE_FLAGS_DEFAULT); - virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0); - virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer = 0); - virtual Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const; - virtual void texture_set_flags(RID p_texture, uint32_t p_flags); - virtual uint32_t texture_get_flags(RID p_texture) const; - virtual Image::Format texture_get_format(RID p_texture) const; - virtual RS::TextureType texture_get_type(RID p_texture) const; - virtual uint32_t texture_get_texid(RID p_texture) const; - virtual uint32_t texture_get_width(RID p_texture) const; - virtual uint32_t texture_get_height(RID p_texture) const; - virtual uint32_t texture_get_depth(RID p_texture) const; - virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth); - virtual void texture_bind(RID p_texture, uint32_t p_texture_no); - - virtual void texture_set_path(RID p_texture, const String &p_path); - virtual String texture_get_path(RID p_texture) const; - - virtual void texture_set_shrink_all_x2_on_set_data(bool p_enable); - - virtual void texture_debug_usage(List<RS::TextureInfo> *r_info); - - virtual RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const; - - virtual void textures_keep_original(bool p_enable); - - virtual void texture_set_proxy(RID p_texture, RID p_proxy); - virtual Size2 texture_size_with_proxy(RID p_texture) const; - - virtual void texture_set_detect_3d_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata); - virtual void texture_set_detect_srgb_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata); - virtual void texture_set_detect_normal_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata); - - virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable); - - /* SKY API */ - - struct Sky { - - RID panorama; - GLuint radiance; - int radiance_size; - }; - - mutable RID_PtrOwner<Sky> sky_owner; - - virtual RID sky_create(); - virtual void sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size); - - /* SHADER API */ - - struct Material; - - struct Shader { - - RID self; - - RS::ShaderMode mode; - ShaderGLES2 *shader; - String code; - SelfList<Material>::List materials; - - Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; - - uint32_t texture_count; - - uint32_t custom_code_id; - uint32_t version; - - SelfList<Shader> dirty_list; - - Map<StringName, RID> default_textures; - - Vector<ShaderLanguage::DataType> texture_types; - Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints; - - bool valid; - - String path; - - uint32_t index; - uint64_t last_pass; - - struct CanvasItem { - - enum BlendMode { - BLEND_MODE_MIX, - BLEND_MODE_ADD, - BLEND_MODE_SUB, - BLEND_MODE_MUL, - BLEND_MODE_PMALPHA, - }; - - int blend_mode; - - enum LightMode { - LIGHT_MODE_NORMAL, - LIGHT_MODE_UNSHADED, - LIGHT_MODE_LIGHT_ONLY - }; - - int light_mode; - - bool uses_screen_texture; - bool uses_screen_uv; - bool uses_time; - - } canvas_item; - - struct Spatial { - - enum BlendMode { - BLEND_MODE_MIX, - BLEND_MODE_ADD, - BLEND_MODE_SUB, - BLEND_MODE_MUL, - }; - - int blend_mode; - - enum DepthDrawMode { - DEPTH_DRAW_OPAQUE, - DEPTH_DRAW_ALWAYS, - DEPTH_DRAW_NEVER, - DEPTH_DRAW_ALPHA_PREPASS, - }; - - int depth_draw_mode; - - enum CullMode { - CULL_MODE_FRONT, - CULL_MODE_BACK, - CULL_MODE_DISABLED, - }; - - int cull_mode; - - bool uses_alpha; - bool uses_alpha_scissor; - bool unshaded; - bool no_depth_test; - bool uses_vertex; - bool uses_discard; - bool uses_sss; - bool uses_screen_texture; - bool uses_depth_texture; - bool uses_time; - bool writes_modelview_or_projection; - bool uses_vertex_lighting; - bool uses_world_coordinates; - - } spatial; - - struct Particles { - - } particles; - - bool uses_vertex_time; - bool uses_fragment_time; - - Shader() : - dirty_list(this) { - - shader = nullptr; - valid = false; - custom_code_id = 0; - version = 1; - last_pass = 0; - } - }; - - mutable RID_PtrOwner<Shader> shader_owner; - mutable SelfList<Shader>::List _shader_dirty_list; - - void _shader_make_dirty(Shader *p_shader); - - virtual RID shader_create(); - - virtual void shader_set_code(RID p_shader, const String &p_code); - virtual String shader_get_code(RID p_shader) const; - virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const; - - virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture); - virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const; - - void _update_shader(Shader *p_shader) const; - void update_dirty_shaders(); - - /* COMMON MATERIAL API */ - - struct Material { - - Shader *shader; - Map<StringName, Variant> params; - SelfList<Material> list; - SelfList<Material> dirty_list; - Vector<Pair<StringName, RID>> textures; - float line_width; - int render_priority; - - RID next_pass; - - uint32_t index; - uint64_t last_pass; - - Map<Geometry *, int> geometry_owners; - Map<RasterizerScene::InstanceBase *, int> instance_owners; - - bool can_cast_shadow_cache; - bool is_animated_cache; - - Material() : - list(this), - dirty_list(this) { - can_cast_shadow_cache = false; - is_animated_cache = false; - shader = nullptr; - line_width = 1.0; - last_pass = 0; - render_priority = 0; - } - }; - - mutable SelfList<Material>::List _material_dirty_list; - void _material_make_dirty(Material *p_material) const; - - void _material_add_geometry(RID p_material, Geometry *p_geometry); - void _material_remove_geometry(RID p_material, Geometry *p_geometry); - - void _update_material(Material *p_material); - - mutable RID_PtrOwner<Material> material_owner; - - virtual RID material_create(); - - virtual void material_set_shader(RID p_material, RID p_shader); - virtual RID material_get_shader(RID p_material) const; - - virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value); - virtual Variant material_get_param(RID p_material, const StringName &p_param) const; - virtual Variant material_get_param_default(RID p_material, const StringName &p_param) const; - - virtual void material_set_line_width(RID p_material, float p_width); - virtual void material_set_next_pass(RID p_material, RID p_next_material); - - virtual bool material_is_animated(RID p_material); - virtual bool material_casts_shadows(RID p_material); - - virtual void material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance); - virtual void material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance); - - virtual void material_set_render_priority(RID p_material, int priority); - - void update_dirty_materials(); - - /* MESH API */ - - struct Mesh; - - struct Surface : public Geometry { - - struct Attrib { - bool enabled; - bool integer; - GLuint index; - GLint size; - GLenum type; - GLboolean normalized; - GLsizei stride; - uint32_t offset; - }; - - Attrib attribs[RS::ARRAY_MAX]; - - Mesh *mesh; - uint32_t format; - - GLuint vertex_id; - GLuint index_id; - - struct BlendShape { - GLuint vertex_id; - GLuint array_id; - }; - - Vector<BlendShape> blend_shapes; - - AABB aabb; - - int array_len; - int index_array_len; - int max_bone; - - int array_byte_size; - int index_array_byte_size; - - RS::PrimitiveType primitive; - - Vector<AABB> skeleton_bone_aabb; - Vector<bool> skeleton_bone_used; - - bool active; - - Vector<uint8_t> data; - Vector<uint8_t> index_data; - Vector<Vector<uint8_t>> blend_shape_data; - - int total_data_size; - - Surface() : - mesh(nullptr), - array_len(0), - index_array_len(0), - array_byte_size(0), - index_array_byte_size(0), - primitive(RS::PRIMITIVE_POINTS), - active(false), - total_data_size(0) { - } - }; - - struct MultiMesh; - - struct Mesh : public GeometryOwner { - - bool active; - - Vector<Surface *> surfaces; - - int blend_shape_count; - RS::BlendShapeMode blend_shape_mode; - - AABB custom_aabb; - - mutable uint64_t last_pass; - - SelfList<MultiMesh>::List multimeshes; - - _FORCE_INLINE_ void update_multimeshes() { - SelfList<MultiMesh> *mm = multimeshes.first(); - - while (mm) { - mm->self()->instance_change_notify(false, true); - mm = mm->next(); - } - } - - Mesh() : - blend_shape_count(0), - blend_shape_mode(RS::BLEND_SHAPE_MODE_NORMALIZED) { - } - }; - - mutable RID_PtrOwner<Mesh> mesh_owner; - - virtual RID mesh_create(); - - virtual void mesh_add_surface(RID p_mesh, uint32_t p_format, RS::PrimitiveType p_primitive, const Vector<uint8_t> &p_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<Vector<uint8_t>> &p_blend_shapes = Vector<Vector<uint8_t>>(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>()); - - virtual void mesh_set_blend_shape_count(RID p_mesh, int p_amount); - virtual int mesh_get_blend_shape_count(RID p_mesh) const; - - virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode); - virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const; - - virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data); - - virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material); - virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const; - - virtual int mesh_surface_get_array_len(RID p_mesh, int p_surface) const; - virtual int mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const; - - virtual Vector<uint8_t> mesh_surface_get_array(RID p_mesh, int p_surface) const; - virtual Vector<uint8_t> mesh_surface_get_index_array(RID p_mesh, int p_surface) const; - - virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const; - virtual RS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const; - - virtual AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const; - virtual Vector<Vector<uint8_t>> mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const; - virtual Vector<AABB> mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const; - - virtual void mesh_remove_surface(RID p_mesh, int p_surface); - virtual int mesh_get_surface_count(RID p_mesh) const; - - virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb); - virtual AABB mesh_get_custom_aabb(RID p_mesh) const; - - virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton) const; - virtual void mesh_clear(RID p_mesh); - - /* MULTIMESH API */ - - struct MultiMesh : public GeometryOwner { - - RID mesh; - int size; - - RS::MultimeshTransformFormat transform_format; - RS::MultimeshColorFormat color_format; - RS::MultimeshCustomDataFormat custom_data_format; - - Vector<float> data; - - AABB aabb; - - SelfList<MultiMesh> update_list; - SelfList<MultiMesh> mesh_list; - - int visible_instances; - - int xform_floats; - int color_floats; - int custom_data_floats; - - bool dirty_aabb; - bool dirty_data; - - MultiMesh() : - size(0), - transform_format(RS::MULTIMESH_TRANSFORM_2D), - color_format(RS::MULTIMESH_COLOR_NONE), - custom_data_format(RS::MULTIMESH_CUSTOM_DATA_NONE), - update_list(this), - mesh_list(this), - visible_instances(-1), - xform_floats(0), - color_floats(0), - custom_data_floats(0), - dirty_aabb(true), - dirty_data(true) { - } - }; - - mutable RID_PtrOwner<MultiMesh> multimesh_owner; - - SelfList<MultiMesh>::List multimesh_update_list; - - virtual RID multimesh_create(); - - virtual void multimesh_allocate(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, RS::MultimeshColorFormat p_color_format, RS::MultimeshCustomDataFormat p_data = RS::MULTIMESH_CUSTOM_DATA_NONE); - virtual int multimesh_get_instance_count(RID p_multimesh) const; - - virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh); - virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform); - virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform); - virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color); - virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_custom_data); - - virtual RID multimesh_get_mesh(RID p_multimesh) const; - - virtual Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const; - virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const; - virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const; - virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const; - - virtual void multimesh_set_as_bulk_array(RID p_multimesh, const Vector<float> &p_array); - - virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible); - virtual int multimesh_get_visible_instances(RID p_multimesh) const; - - virtual AABB multimesh_get_aabb(RID p_multimesh) const; - - void update_dirty_multimeshes(); - - /* IMMEDIATE API */ - - struct Immediate : public Geometry { - - struct Chunk { - RID texture; - RS::PrimitiveType primitive; - Vector<Vector3> vertices; - Vector<Vector3> normals; - Vector<Plane> tangents; - Vector<Color> colors; - Vector<Vector2> uvs; - Vector<Vector2> uv2s; - }; - - List<Chunk> chunks; - bool building; - int mask; - AABB aabb; - - Immediate() { - type = GEOMETRY_IMMEDIATE; - building = false; - } - }; - - Vector3 chunk_normal; - Plane chunk_tangent; - Color chunk_color; - Vector2 chunk_uv; - Vector2 chunk_uv2; - - mutable RID_PtrOwner<Immediate> immediate_owner; - - virtual RID immediate_create(); - virtual void immediate_begin(RID p_immediate, RS::PrimitiveType p_primitive, RID p_texture = RID()); - virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex); - virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal); - virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent); - virtual void immediate_color(RID p_immediate, const Color &p_color); - virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv); - virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv); - virtual void immediate_end(RID p_immediate); - virtual void immediate_clear(RID p_immediate); - virtual void immediate_set_material(RID p_immediate, RID p_material); - virtual RID immediate_get_material(RID p_immediate) const; - virtual AABB immediate_get_aabb(RID p_immediate) const; - - /* SKELETON API */ - - struct Skeleton { - - bool use_2d; - - int size; - - // TODO use float textures for storage - - Vector<float> bone_data; - - GLuint tex_id; - - SelfList<Skeleton> update_list; - Set<RasterizerScene::InstanceBase *> instances; - - Transform2D base_transform_2d; - - Skeleton() : - use_2d(false), - size(0), - tex_id(0), - update_list(this) { - } - }; - - mutable RID_PtrOwner<Skeleton> skeleton_owner; - - SelfList<Skeleton>::List skeleton_update_list; - - void update_dirty_skeletons(); - - virtual RID skeleton_create(); - virtual void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false); - virtual int skeleton_get_bone_count(RID p_skeleton) const; - virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform); - virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const; - virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform); - virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const; - virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform); - - void _update_skeleton_transform_buffer(const Vector<float> &p_data, size_t p_size); - - /* Light API */ - - struct Light : Instantiable { - RS::LightType type; - float param[RS::LIGHT_PARAM_MAX]; - - Color color; - Color shadow_color; - - RID projector; - - bool shadow; - bool negative; - bool reverse_cull; - bool use_gi; - - uint32_t cull_mask; - - RS::LightOmniShadowMode omni_shadow_mode; - RS::LightOmniShadowDetail omni_shadow_detail; - - RS::LightDirectionalShadowMode directional_shadow_mode; - RS::LightDirectionalShadowDepthRangeMode directional_range_mode; - - bool directional_blend_splits; - - uint64_t version; - }; - - mutable RID_PtrOwner<Light> light_owner; - - virtual RID light_create(RS::LightType p_type); - - virtual void light_set_color(RID p_light, const Color &p_color); - virtual void light_set_param(RID p_light, RS::LightParam p_param, float p_value); - virtual void light_set_shadow(RID p_light, bool p_enabled); - virtual void light_set_shadow_color(RID p_light, const Color &p_color); - virtual void light_set_projector(RID p_light, RID p_texture); - virtual void light_set_negative(RID p_light, bool p_enable); - virtual void light_set_cull_mask(RID p_light, uint32_t p_mask); - virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled); - virtual void light_set_use_gi(RID p_light, bool p_enabled); - - virtual void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode); - virtual void light_omni_set_shadow_detail(RID p_light, RS::LightOmniShadowDetail p_detail); - - virtual void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode); - virtual void light_directional_set_blend_splits(RID p_light, bool p_enable); - virtual bool light_directional_get_blend_splits(RID p_light) const; - - virtual RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light); - virtual RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light); - - virtual void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode); - virtual RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const; - - virtual bool light_has_shadow(RID p_light) const; - - virtual RS::LightType light_get_type(RID p_light) const; - virtual float light_get_param(RID p_light, RS::LightParam p_param); - virtual Color light_get_color(RID p_light); - virtual bool light_get_use_gi(RID p_light); - - virtual AABB light_get_aabb(RID p_light) const; - virtual uint64_t light_get_version(RID p_light) const; - - /* PROBE API */ - - struct ReflectionProbe : Instantiable { - - RS::ReflectionProbeUpdateMode update_mode; - float intensity; - Color interior_ambient; - float interior_ambient_energy; - float interior_ambient_probe_contrib; - float max_distance; - Vector3 extents; - Vector3 origin_offset; - bool interior; - bool box_projection; - bool enable_shadows; - uint32_t cull_mask; - int resolution; - }; - - mutable RID_PtrOwner<ReflectionProbe> reflection_probe_owner; - - virtual RID reflection_probe_create(); - - virtual void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode); - virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity); - virtual void reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient); - virtual void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy); - virtual void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib); - virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance); - virtual void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents); - virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset); - virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable); - virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable); - virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable); - virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers); - virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution); - - virtual AABB reflection_probe_get_aabb(RID p_probe) const; - virtual RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const; - virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const; - - virtual int reflection_probe_get_resolution(RID p_probe) const; - - virtual Vector3 reflection_probe_get_extents(RID p_probe) const; - virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const; - virtual float reflection_probe_get_origin_max_distance(RID p_probe) const; - virtual bool reflection_probe_renders_shadows(RID p_probe) const; - - /* GI PROBE API */ - virtual RID gi_probe_create(); - - virtual void gi_probe_set_bounds(RID p_probe, const AABB &p_bounds); - virtual AABB gi_probe_get_bounds(RID p_probe) const; - - virtual void gi_probe_set_cell_size(RID p_probe, float p_size); - virtual float gi_probe_get_cell_size(RID p_probe) const; - - virtual void gi_probe_set_to_cell_xform(RID p_probe, const Transform &p_xform); - virtual Transform gi_probe_get_to_cell_xform(RID p_probe) const; - - virtual void gi_probe_set_dynamic_data(RID p_probe, const Vector<int> &p_data); - virtual Vector<int> gi_probe_get_dynamic_data(RID p_probe) const; - - virtual void gi_probe_set_dynamic_range(RID p_probe, int p_range); - virtual int gi_probe_get_dynamic_range(RID p_probe) const; - - virtual void gi_probe_set_energy(RID p_probe, float p_range); - virtual float gi_probe_get_energy(RID p_probe) const; - - virtual void gi_probe_set_bias(RID p_probe, float p_range); - virtual float gi_probe_get_bias(RID p_probe) const; - - virtual void gi_probe_set_normal_bias(RID p_probe, float p_range); - virtual float gi_probe_get_normal_bias(RID p_probe) const; - - virtual void gi_probe_set_propagation(RID p_probe, float p_range); - virtual float gi_probe_get_propagation(RID p_probe) const; - - virtual void gi_probe_set_interior(RID p_probe, bool p_enable); - virtual bool gi_probe_is_interior(RID p_probe) const; - - virtual void gi_probe_set_compress(RID p_probe, bool p_enable); - virtual bool gi_probe_is_compressed(RID p_probe) const; - - virtual uint32_t gi_probe_get_version(RID p_probe); - - virtual GIProbeCompression gi_probe_get_dynamic_data_get_preferred_compression() const; - virtual RID gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression); - virtual void gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data); - - /* LIGHTMAP */ - - struct LightmapCapture : public Instantiable { - - Vector<LightmapCaptureOctree> octree; - AABB bounds; - Transform cell_xform; - int cell_subdiv; - float energy; - LightmapCapture() { - energy = 1.0; - cell_subdiv = 1; - } - }; - - mutable RID_PtrOwner<LightmapCapture> lightmap_capture_data_owner; - - virtual RID lightmap_capture_create(); - virtual void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds); - virtual AABB lightmap_capture_get_bounds(RID p_capture) const; - virtual void lightmap_capture_set_octree(RID p_capture, const Vector<uint8_t> &p_octree); - virtual Vector<uint8_t> lightmap_capture_get_octree(RID p_capture) const; - virtual void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform); - virtual Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const; - virtual void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv); - virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const; - virtual void lightmap_capture_set_energy(RID p_capture, float p_energy); - virtual float lightmap_capture_get_energy(RID p_capture) const; - virtual const Vector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const; - - /* PARTICLES */ - void update_particles(); - - virtual RID particles_create(); - - virtual void particles_set_emitting(RID p_particles, bool p_emitting); - virtual bool particles_get_emitting(RID p_particles); - - virtual void particles_set_amount(RID p_particles, int p_amount); - virtual void particles_set_lifetime(RID p_particles, float p_lifetime); - virtual void particles_set_one_shot(RID p_particles, bool p_one_shot); - virtual void particles_set_pre_process_time(RID p_particles, float p_time); - virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio); - virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio); - virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb); - virtual void particles_set_speed_scale(RID p_particles, float p_scale); - virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable); - virtual void particles_set_process_material(RID p_particles, RID p_material); - virtual void particles_set_fixed_fps(RID p_particles, int p_fps); - virtual void particles_set_fractional_delta(RID p_particles, bool p_enable); - virtual void particles_restart(RID p_particles); - - virtual void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order); - - virtual void particles_set_draw_passes(RID p_particles, int p_passes); - virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh); - - virtual void particles_request_process(RID p_particles); - virtual AABB particles_get_current_aabb(RID p_particles); - virtual AABB particles_get_aabb(RID p_particles) const; - - virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform); - - virtual int particles_get_draw_passes(RID p_particles) const; - virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const; - - virtual bool particles_is_inactive(RID p_particles) const; - - /* INSTANCE */ - - virtual void instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance); - virtual void instance_remove_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance); - - virtual void instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance); - virtual void instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance); - - /* RENDER TARGET */ - - struct RenderTarget { - GLuint fbo; - GLuint color; - GLuint depth; - - GLuint multisample_fbo; - GLuint multisample_color; - GLuint multisample_depth; - bool multisample_active; - - struct Effect { - GLuint fbo; - int width; - int height; - - GLuint color; - - Effect() : - fbo(0), - width(0), - height(0), - color(0) { - } - }; - - Effect copy_screen_effect; - - struct MipMaps { - - struct Size { - GLuint fbo; - GLuint color; - int width; - int height; - }; - - Vector<Size> sizes; - GLuint color; - int levels; - - MipMaps() : - color(0), - levels(0) { - } - }; - - MipMaps mip_maps[2]; - - struct External { - GLuint fbo; - GLuint color; - GLuint depth; - RID texture; - - External() : - fbo(0), - color(0), - depth(0) { - } - } external; - - int x, y, width, height; - - bool flags[RENDER_TARGET_FLAG_MAX]; - - bool used_in_frame; - RS::ViewportMSAA msaa; - - RID texture; - - bool used_dof_blur_near; - bool mip_maps_allocated; - - RenderTarget() : - fbo(0), - color(0), - depth(0), - multisample_fbo(0), - multisample_color(0), - multisample_depth(0), - multisample_active(false), - x(0), - y(0), - width(0), - height(0), - used_in_frame(false), - msaa(RS::VIEWPORT_MSAA_DISABLED), - used_dof_blur_near(false), - mip_maps_allocated(false) { - for (int i = 0; i < RENDER_TARGET_FLAG_MAX; ++i) { - flags[i] = false; - } - external.fbo = 0; - } - }; - - mutable RID_PtrOwner<RenderTarget> render_target_owner; - - void _render_target_clear(RenderTarget *rt); - void _render_target_allocate(RenderTarget *rt); - - virtual RID render_target_create(); - virtual void render_target_set_position(RID p_render_target, int p_x, int p_y); - virtual void render_target_set_size(RID p_render_target, int p_width, int p_height); - virtual RID render_target_get_texture(RID p_render_target) const; - virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id); - - virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value); - virtual bool render_target_was_used(RID p_render_target); - virtual void render_target_set_as_unused(RID p_render_target); - virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa); - - /* CANVAS SHADOW */ - - struct CanvasLightShadow { - - int size; - int height; - GLuint fbo; - GLuint depth; - GLuint distance; //for older devices - }; - - RID_PtrOwner<CanvasLightShadow> canvas_light_shadow_owner; - - virtual RID canvas_light_shadow_buffer_create(int p_width); - - /* LIGHT SHADOW MAPPING */ - - struct CanvasOccluder { - - GLuint vertex_id; // 0 means, unconfigured - GLuint index_id; // 0 means, unconfigured - Vector<Vector2> lines; - int len; - }; - - RID_PtrOwner<CanvasOccluder> canvas_occluder_owner; - - virtual RID canvas_light_occluder_create(); - virtual void canvas_light_occluder_set_polylines(RID p_occluder, const Vector<Vector2> &p_lines); - - virtual RS::InstanceType get_base_type(RID p_rid) const; - - virtual bool free(RID p_rid); - - struct Frame { - - RenderTarget *current_rt; - - bool clear_request; - Color clear_request_color; - int canvas_draw_commands; - float time[4]; - float delta; - uint64_t count; - - } frame; - - void initialize(); - void finalize(); - - void _copy_screen(); - - virtual bool has_os_feature(const String &p_feature) const; - - virtual void update_dirty_resources(); - - virtual void set_debug_generate_wireframes(bool p_generate); - - virtual void render_info_begin_capture(); - virtual void render_info_end_capture(); - virtual int get_captured_render_info(RS::RenderInfo p_info); - - virtual int get_render_info(RS::RenderInfo p_info); - virtual String get_video_adapter_name() const; - virtual String get_video_adapter_vendor() const; - - RasterizerStorageGLES2(); -}; - -#endif // RASTERIZERSTORAGEGLES2_H diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp deleted file mode 100644 index 92c1ada850..0000000000 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ /dev/null @@ -1,1198 +0,0 @@ -/*************************************************************************/ -/* shader_compiler_gles2.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 "shader_compiler_gles2.h" - -#include "core/os/os.h" -#include "core/project_settings.h" -#include "core/string_buffer.h" -#include "core/string_builder.h" - -#define SL ShaderLanguage - -static String _mktab(int p_level) { - - String tb; - for (int i = 0; i < p_level; i++) { - tb += "\t"; - } - - return tb; -} - -static String _typestr(SL::DataType p_type) { - - return ShaderLanguage::get_datatype_name(p_type); -} - -static String _prestr(SL::DataPrecision p_pres) { - - switch (p_pres) { - case SL::PRECISION_LOWP: return "lowp "; - case SL::PRECISION_MEDIUMP: return "mediump "; - case SL::PRECISION_HIGHP: return "highp "; - case SL::PRECISION_DEFAULT: return ""; - } - return ""; -} - -static String _qualstr(SL::ArgumentQualifier p_qual) { - - switch (p_qual) { - case SL::ARGUMENT_QUALIFIER_IN: return "in "; - case SL::ARGUMENT_QUALIFIER_OUT: return "out "; - case SL::ARGUMENT_QUALIFIER_INOUT: return "inout "; - } - return ""; -} - -static String _opstr(SL::Operator p_op) { - - return SL::get_operator_text(p_op); -} - -static String _mkid(const String &p_id) { - - String id = "m_" + p_id.replace("__", "_dus_"); - return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl -} - -static String f2sp0(float p_float) { - - String num = rtoss(p_float); - if (num.find(".") == -1 && num.find("e") == -1) { - num += ".0"; - } - return num; -} - -static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value> &p_values) { - - switch (p_type) { - case SL::TYPE_BOOL: return p_values[0].boolean ? "true" : "false"; - case SL::TYPE_BVEC2: - case SL::TYPE_BVEC3: - case SL::TYPE_BVEC4: { - - StringBuffer<> text; - - text += "bvec"; - text += itos(p_type - SL::TYPE_BOOL + 1); - text += "("; - - for (int i = 0; i < p_values.size(); i++) { - if (i > 0) - text += ","; - - text += p_values[i].boolean ? "true" : "false"; - } - text += ")"; - return text.as_string(); - } - - // GLSL ES 2 doesn't support uints, so we just use signed ints instead... - case SL::TYPE_UINT: return itos(p_values[0].uint); - case SL::TYPE_UVEC2: - case SL::TYPE_UVEC3: - case SL::TYPE_UVEC4: { - - StringBuffer<> text; - - text += "ivec"; - text += itos(p_type - SL::TYPE_UINT + 1); - text += "("; - - for (int i = 0; i < p_values.size(); i++) { - if (i > 0) - text += ","; - - text += itos(p_values[i].uint); - } - text += ")"; - return text.as_string(); - - } break; - - case SL::TYPE_INT: return itos(p_values[0].sint); - case SL::TYPE_IVEC2: - case SL::TYPE_IVEC3: - case SL::TYPE_IVEC4: { - - StringBuffer<> text; - - text += "ivec"; - text += itos(p_type - SL::TYPE_INT + 1); - text += "("; - - for (int i = 0; i < p_values.size(); i++) { - if (i > 0) - text += ","; - - text += itos(p_values[i].sint); - } - text += ")"; - return text.as_string(); - - } break; - case SL::TYPE_FLOAT: return f2sp0(p_values[0].real); - case SL::TYPE_VEC2: - case SL::TYPE_VEC3: - case SL::TYPE_VEC4: { - - StringBuffer<> text; - - text += "vec"; - text += itos(p_type - SL::TYPE_FLOAT + 1); - text += "("; - - for (int i = 0; i < p_values.size(); i++) { - if (i > 0) - text += ","; - - text += f2sp0(p_values[i].real); - } - text += ")"; - return text.as_string(); - - } break; - case SL::TYPE_MAT2: - case SL::TYPE_MAT3: - case SL::TYPE_MAT4: { - - StringBuffer<> text; - - text += "mat"; - text += itos(p_type - SL::TYPE_MAT2 + 2); - text += "("; - - for (int i = 0; i < p_values.size(); i++) { - if (i > 0) - text += ","; - - text += f2sp0(p_values[i].real); - } - text += ")"; - return text.as_string(); - - } break; - default: ERR_FAIL_V(String()); - } -} - -void ShaderCompilerGLES2::_dump_function_deps(SL::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, StringBuilder &r_to_add, Set<StringName> &r_added) { - int fidx = -1; - - for (int i = 0; i < p_node->functions.size(); i++) { - if (p_node->functions[i].name == p_for_func) { - fidx = i; - break; - } - } - - ERR_FAIL_COND(fidx == -1); - - for (Set<StringName>::Element *E = p_node->functions[fidx].uses_function.front(); E; E = E->next()) { - - if (r_added.has(E->get())) { - continue; - } - - _dump_function_deps(p_node, E->get(), p_func_code, r_to_add, r_added); - - SL::FunctionNode *fnode = nullptr; - - for (int i = 0; i < p_node->functions.size(); i++) { - if (p_node->functions[i].name == E->get()) { - fnode = p_node->functions[i].function; - break; - } - } - - ERR_FAIL_COND(!fnode); - - r_to_add += "\n"; - - StringBuffer<128> header; - if (fnode->return_type == SL::TYPE_STRUCT) { - header += _mkid(fnode->return_struct_name) + " " + _mkid(fnode->name) + "("; - } else { - header += _typestr(fnode->return_type) + " " + _mkid(fnode->name) + "("; - } - - for (int i = 0; i < fnode->arguments.size(); i++) { - if (i > 0) - header += ", "; - if (fnode->arguments[i].type == SL::TYPE_STRUCT) { - header += _qualstr(fnode->arguments[i].qualifier) + _mkid(fnode->arguments[i].type_str) + " " + _mkid(fnode->arguments[i].name); - } else { - header += _qualstr(fnode->arguments[i].qualifier) + _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name); - } - } - - header += ")\n"; - r_to_add += header.as_string(); - r_to_add += p_func_code[E->get()]; - - r_added.insert(E->get()); - } -} - -String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning) { - - StringBuilder code; - - switch (p_node->type) { - - case SL::Node::TYPE_SHADER: { - - SL::ShaderNode *snode = (SL::ShaderNode *)p_node; - - for (int i = 0; i < snode->render_modes.size(); i++) { - - if (p_default_actions.render_mode_defines.has(snode->render_modes[i]) && !used_rmode_defines.has(snode->render_modes[i])) { - - r_gen_code.custom_defines.push_back(p_default_actions.render_mode_defines[snode->render_modes[i]].utf8()); - used_rmode_defines.insert(snode->render_modes[i]); - } - - if (p_actions.render_mode_flags.has(snode->render_modes[i])) { - *p_actions.render_mode_flags[snode->render_modes[i]] = true; - } - - if (p_actions.render_mode_values.has(snode->render_modes[i])) { - Pair<int *, int> &p = p_actions.render_mode_values[snode->render_modes[i]]; - *p.first = p.second; - } - } - - int max_texture_uniforms = 0; - int max_uniforms = 0; - - for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = snode->uniforms.front(); E; E = E->next()) { - if (SL::is_sampler_type(E->get().type)) - max_texture_uniforms++; - else - max_uniforms++; - } - - r_gen_code.texture_uniforms.resize(max_texture_uniforms); - r_gen_code.texture_hints.resize(max_texture_uniforms); - r_gen_code.texture_types.resize(max_texture_uniforms); - - r_gen_code.uniforms.resize(max_uniforms + max_texture_uniforms); - - StringBuilder vertex_global; - StringBuilder fragment_global; - - // structs - - for (int i = 0; i < snode->vstructs.size(); i++) { - - SL::StructNode *st = snode->vstructs[i].shader_struct; - String struct_code; - - struct_code += "struct "; - struct_code += _mkid(snode->vstructs[i].name); - struct_code += " "; - struct_code += "{\n"; - for (int j = 0; j < st->members.size(); j++) { - SL::MemberNode *m = st->members[j]; - if (m->datatype == SL::TYPE_STRUCT) { - struct_code += _mkid(m->struct_name); - } else { - struct_code += _prestr(m->precision); - struct_code += _typestr(m->datatype); - } - struct_code += " "; - struct_code += m->name; - if (m->array_size > 0) { - struct_code += "["; - struct_code += itos(m->array_size); - struct_code += "]"; - } - struct_code += ";\n"; - } - struct_code += "}"; - struct_code += ";\n"; - - vertex_global += struct_code; - fragment_global += struct_code; - } - - // uniforms - - for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = snode->uniforms.front(); E; E = E->next()) { - StringBuffer<> uniform_code; - - // use highp if no precision is specified to prevent different default values in fragment and vertex shader - SL::DataPrecision precision = E->get().precision; - if (precision == SL::PRECISION_DEFAULT && E->get().type != SL::TYPE_BOOL) { - precision = SL::PRECISION_HIGHP; - } - - uniform_code += "uniform "; - uniform_code += _prestr(precision); - uniform_code += _typestr(E->get().type); - uniform_code += " "; - uniform_code += _mkid(E->key()); - uniform_code += ";\n"; - - if (SL::is_sampler_type(E->get().type)) { - r_gen_code.texture_uniforms.write[E->get().texture_order] = E->key(); - r_gen_code.texture_hints.write[E->get().texture_order] = E->get().hint; - r_gen_code.texture_types.write[E->get().texture_order] = E->get().type; - } else { - r_gen_code.uniforms.write[E->get().order] = E->key(); - } - - vertex_global += uniform_code.as_string(); - fragment_global += uniform_code.as_string(); - - p_actions.uniforms->insert(E->key(), E->get()); - } - - // varyings - - for (Map<StringName, SL::ShaderNode::Varying>::Element *E = snode->varyings.front(); E; E = E->next()) { - - StringBuffer<> varying_code; - - varying_code += "varying "; - varying_code += _prestr(E->get().precision); - varying_code += _typestr(E->get().type); - varying_code += " "; - varying_code += _mkid(E->key()); - if (E->get().array_size > 0) { - varying_code += "["; - varying_code += itos(E->get().array_size); - varying_code += "]"; - } - varying_code += ";\n"; - - String final_code = varying_code.as_string(); - - vertex_global += final_code; - fragment_global += final_code; - } - - // constants - - for (int i = 0; i < snode->vconstants.size(); i++) { - const SL::ShaderNode::Constant &cnode = snode->vconstants[i]; - String gcode; - gcode += "const "; - gcode += _prestr(cnode.precision); - if (cnode.type == SL::TYPE_STRUCT) { - gcode += _mkid(cnode.type_str); - } else { - gcode += _typestr(cnode.type); - } - gcode += " " + _mkid(String(cnode.name)); - gcode += "="; - gcode += _dump_node_code(cnode.initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - gcode += ";\n"; - vertex_global += gcode; - fragment_global += gcode; - } - - // functions - - Map<StringName, String> function_code; - - for (int i = 0; i < snode->functions.size(); i++) { - SL::FunctionNode *fnode = snode->functions[i].function; - current_func_name = fnode->name; - function_code[fnode->name] = _dump_node_code(fnode->body, 1, r_gen_code, p_actions, p_default_actions, p_assigning); - } - - Set<StringName> added_vertex; - Set<StringName> added_fragment; - - for (int i = 0; i < snode->functions.size(); i++) { - - SL::FunctionNode *fnode = snode->functions[i].function; - - current_func_name = fnode->name; - - if (fnode->name == vertex_name) { - _dump_function_deps(snode, fnode->name, function_code, vertex_global, added_vertex); - r_gen_code.vertex = function_code[vertex_name]; - - } else if (fnode->name == fragment_name) { - _dump_function_deps(snode, fnode->name, function_code, fragment_global, added_fragment); - r_gen_code.fragment = function_code[fragment_name]; - - } else if (fnode->name == light_name) { - _dump_function_deps(snode, fnode->name, function_code, fragment_global, added_fragment); - r_gen_code.light = function_code[light_name]; - } - } - - r_gen_code.vertex_global = vertex_global.as_string(); - r_gen_code.fragment_global = fragment_global.as_string(); - - } break; - case SL::Node::TYPE_STRUCT: { - - } break; - case SL::Node::TYPE_FUNCTION: { - - } break; - - case SL::Node::TYPE_BLOCK: { - - SL::BlockNode *bnode = (SL::BlockNode *)p_node; - - if (!bnode->single_statement) { - code += _mktab(p_level - 1); - code += "{\n"; - } - - for (int i = 0; i < bnode->statements.size(); i++) { - String statement_code = _dump_node_code(bnode->statements[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - - if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW || bnode->single_statement) { - code += statement_code; - } else { - code += _mktab(p_level); - code += statement_code; - code += ";\n"; - } - } - - if (!bnode->single_statement) { - code += _mktab(p_level - 1); - code += "}\n"; - } - } break; - - case SL::Node::TYPE_VARIABLE_DECLARATION: { - SL::VariableDeclarationNode *var_dec_node = (SL::VariableDeclarationNode *)p_node; - - StringBuffer<> declaration; - if (var_dec_node->is_const) { - declaration += "const "; - } - if (var_dec_node->datatype == SL::TYPE_STRUCT) { - declaration += _mkid(var_dec_node->struct_name); - } else { - declaration += _prestr(var_dec_node->precision); - declaration += _typestr(var_dec_node->datatype); - } - - for (int i = 0; i < var_dec_node->declarations.size(); i++) { - - if (i > 0) { - declaration += ","; - } - - declaration += " "; - - declaration += _mkid(var_dec_node->declarations[i].name); - - if (var_dec_node->declarations[i].initializer) { - declaration += " = "; - declaration += _dump_node_code(var_dec_node->declarations[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - } - } - - code += declaration.as_string(); - } break; - - case SL::Node::TYPE_VARIABLE: { - SL::VariableNode *var_node = (SL::VariableNode *)p_node; - - if (p_assigning && p_actions.write_flag_pointers.has(var_node->name)) { - *p_actions.write_flag_pointers[var_node->name] = true; - } - - if (p_default_actions.usage_defines.has(var_node->name) && !used_name_defines.has(var_node->name)) { - String define = p_default_actions.usage_defines[var_node->name]; - - if (define.begins_with("@")) { - define = p_default_actions.usage_defines[define.substr(1, define.length())]; - } - - r_gen_code.custom_defines.push_back(define.utf8()); - used_name_defines.insert(var_node->name); - } - - if (p_actions.usage_flag_pointers.has(var_node->name) && !used_flag_pointers.has(var_node->name)) { - *p_actions.usage_flag_pointers[var_node->name] = true; - used_flag_pointers.insert(var_node->name); - } - - if (p_default_actions.renames.has(var_node->name)) { - code += p_default_actions.renames[var_node->name]; - } else { - code += _mkid(var_node->name); - } - - if (var_node->name == time_name) { - if (current_func_name == vertex_name) { - r_gen_code.uses_vertex_time = true; - } - if (current_func_name == fragment_name || current_func_name == light_name) { - r_gen_code.uses_fragment_time = true; - } - } - } break; - case SL::Node::TYPE_ARRAY_CONSTRUCT: { - SL::ArrayConstructNode *arr_con_node = (SL::ArrayConstructNode *)p_node; - int sz = arr_con_node->initializer.size(); - if (acnode->datatype == SL::TYPE_STRUCT) { - code += _mkid(arr_con_node->struct_name); - } else { - code += _typestr(arr_con_node->datatype); - } - code += "["; - code += itos(arr_con_node->initializer.size()); - code += "]"; - code += "("; - for (int i = 0; i < sz; i++) { - code += _dump_node_code(arr_con_node->initializer[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - if (i != sz - 1) { - code += ", "; - } - } - code += ")"; - } break; - case SL::Node::TYPE_ARRAY_DECLARATION: { - - SL::ArrayDeclarationNode *arr_dec_node = (SL::ArrayDeclarationNode *)p_node; - - StringBuffer<> declaration; - if (arr_dec_node->datatype == SL::TYPE_STRUCT) { - declaration += _mkid(arr_dec_node->struct_name); - } else { - declaration += _prestr(arr_dec_node->precision); - declaration += _typestr(arr_dec_node->datatype); - } - for (int i = 0; i < arr_dec_node->declarations.size(); i++) { - - if (i > 0) { - declaration += ","; - } - - declaration += " "; - - declaration += _mkid(arr_dec_node->declarations[i].name); - declaration += "["; - declaration += itos(arr_dec_node->declarations[i].size); - declaration += "]"; - } - - code += declaration.as_string(); - } break; - case SL::Node::TYPE_ARRAY: { - SL::ArrayNode *arr_node = (SL::ArrayNode *)p_node; - - if (p_assigning && p_actions.write_flag_pointers.has(arr_node->name)) { - *p_actions.write_flag_pointers[arr_node->name] = true; - } - - if (p_default_actions.usage_defines.has(arr_node->name) && !used_name_defines.has(arr_node->name)) { - String define = p_default_actions.usage_defines[arr_node->name]; - - if (define.begins_with("@")) { - define = p_default_actions.usage_defines[define.substr(1, define.length())]; - } - - r_gen_code.custom_defines.push_back(define.utf8()); - used_name_defines.insert(arr_node->name); - } - - if (p_actions.usage_flag_pointers.has(arr_node->name) && !used_flag_pointers.has(arr_node->name)) { - *p_actions.usage_flag_pointers[arr_node->name] = true; - used_flag_pointers.insert(arr_node->name); - } - - if (p_default_actions.renames.has(arr_node->name)) { - code += p_default_actions.renames[arr_node->name]; - } else { - code += _mkid(arr_node->name); - } - - if (arr_node->call_expression != nullptr) { - code += "."; - code += _dump_node_code(arr_node->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - } - - if (arr_node->index_expression != nullptr) { - code += "["; - code += _dump_node_code(arr_node->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "]"; - } - - if (arr_node->name == time_name) { - if (current_func_name == vertex_name) { - r_gen_code.uses_vertex_time = true; - } - if (current_func_name == fragment_name || current_func_name == light_name) { - r_gen_code.uses_fragment_time = true; - } - } - - } break; - case SL::Node::TYPE_CONSTANT: { - SL::ConstantNode *const_node = (SL::ConstantNode *)p_node; - - return get_constant_text(const_node->datatype, const_node->values); - } break; - - case SL::Node::TYPE_OPERATOR: { - SL::OperatorNode *op_node = (SL::OperatorNode *)p_node; - - switch (op_node->op) { - case SL::OP_ASSIGN: - case SL::OP_ASSIGN_ADD: - case SL::OP_ASSIGN_SUB: - case SL::OP_ASSIGN_MUL: - case SL::OP_ASSIGN_DIV: - case SL::OP_ASSIGN_SHIFT_LEFT: - case SL::OP_ASSIGN_SHIFT_RIGHT: - case SL::OP_ASSIGN_BIT_AND: - case SL::OP_ASSIGN_BIT_OR: - case SL::OP_ASSIGN_BIT_XOR: { - code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, true); - code += " "; - code += _opstr(op_node->op); - code += " "; - code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - } break; - - case SL::OP_ASSIGN_MOD: { - code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, true); - code += " = "; - code += "mod("; - code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, true); - code += ", "; - code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ")"; - } break; - - case SL::OP_BIT_INVERT: - case SL::OP_NEGATE: - case SL::OP_NOT: - case SL::OP_DECREMENT: - case SL::OP_INCREMENT: { - code += _opstr(op_node->op); - code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - } break; - - case SL::OP_POST_DECREMENT: - case SL::OP_POST_INCREMENT: { - code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += _opstr(op_node->op); - } break; - - case SL::OP_CALL: - case SL::OP_STRUCT: - case SL::OP_CONSTRUCT: { - ERR_FAIL_COND_V(op_node->arguments[0]->type != SL::Node::TYPE_VARIABLE, String()); - - SL::VariableNode *var_node = (SL::VariableNode *)op_node->arguments[0]; - if (op_node->op == SL::OP_STRUCT) { - code += _mkid(var_node->name); - } else if (op_node->op == SL::OP_CONSTRUCT) { - code += var_node->name; - } else { - - if (var_node->name == "texture") { - // emit texture call - - if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER2D) { - code += "texture2D"; - } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLERCUBE) { - code += "textureCube"; - } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER3D) { - code += "texture3D"; - } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER2DARRAY) { - code += "texture2DArray"; - } - - } else if (var_node->name == "textureLod") { - // emit texture call - - if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER2D) { - code += "texture2DLod"; - } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLERCUBE) { - code += "textureCubeLod"; - } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER3D) { - code += "texture3DLod"; - } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER2DARRAY) { - code += "texture2DArrayLod"; - } - - } else if (var_node->name == "mix") { - - switch (op_node->arguments[3]->get_datatype()) { - - case SL::TYPE_BVEC2: { - code += "select2"; - } break; - - case SL::TYPE_BVEC3: { - code += "select3"; - } break; - - case SL::TYPE_BVEC4: { - code += "select4"; - } break; - - case SL::TYPE_VEC2: - case SL::TYPE_VEC3: - case SL::TYPE_VEC4: - case SL::TYPE_FLOAT: { - - code += "mix"; - } break; - - default: { - SL::DataType type = op_node->arguments[3]->get_datatype(); - // FIXME: Proper error print or graceful handling - print_line(String("uhhhh invalid mix with type: ") + itos(type)); - } break; - } - - } else if (p_default_actions.renames.has(var_node->name)) { - code += p_default_actions.renames[var_node->name]; - } else if (internal_functions.has(var_node->name)) { - code += var_node->name; - } else { - code += _mkid(var_node->name); - } - } - - code += "("; - - for (int i = 1; i < op_node->arguments.size(); i++) { - if (i > 1) { - code += ", "; - } - - code += _dump_node_code(op_node->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - } - - code += ")"; - - if (p_default_actions.usage_defines.has(var_node->name) && !used_name_defines.has(var_node->name)) { - String define = p_default_actions.usage_defines[var_node->name]; - - if (define.begins_with("@")) { - define = p_default_actions.usage_defines[define.substr(1, define.length())]; - } - - r_gen_code.custom_defines.push_back(define.utf8()); - used_name_defines.insert(var_node->name); - } - - } break; - - case SL::OP_INDEX: { - code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "["; - code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "]"; - } break; - - case SL::OP_SELECT_IF: { - code += "("; - code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += " ? "; - code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += " : "; - code += _dump_node_code(op_node->arguments[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ")"; - } break; - - case SL::OP_MOD: { - - code += "mod(float("; - code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "), float("; - code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "))"; - } break; - - default: { - code += "("; - code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += " "; - code += _opstr(op_node->op); - code += " "; - code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ")"; - } break; - } - } break; - - case SL::Node::TYPE_CONTROL_FLOW: { - SL::ControlFlowNode *cf_node = (SL::ControlFlowNode *)p_node; - - if (cf_node->flow_op == SL::FLOW_OP_IF) { - - code += _mktab(p_level); - code += "if ("; - code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ")\n"; - code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - - if (cf_node->blocks.size() == 2) { - code += _mktab(p_level); - code += "else\n"; - code += _dump_node_code(cf_node->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - } - } else if (cf_node->flow_op == SL::FLOW_OP_DO) { - code += _mktab(p_level); - code += "do"; - code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - code += _mktab(p_level); - code += "while ("; - code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ");"; - } else if (cf_node->flow_op == SL::FLOW_OP_WHILE) { - code += _mktab(p_level); - code += "while ("; - code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ")\n"; - code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - } else if (cf_node->flow_op == SL::FLOW_OP_FOR) { - - code += _mktab(p_level); - code += "for ("; - code += _dump_node_code(cf_node->blocks[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "; "; - code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "; "; - code += _dump_node_code(cf_node->expressions[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ")\n"; - - code += _dump_node_code(cf_node->blocks[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - - } else if (cf_node->flow_op == SL::FLOW_OP_RETURN) { - code += _mktab(p_level); - code += "return"; - - if (cf_node->expressions.size()) { - code += " "; - code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - } - code += ";\n"; - } else if (cf_node->flow_op == SL::FLOW_OP_DISCARD) { - if (p_actions.usage_flag_pointers.has("DISCARD") && !used_flag_pointers.has("DISCARD")) { - *p_actions.usage_flag_pointers["DISCARD"] = true; - used_flag_pointers.insert("DISCARD"); - } - code += "discard;"; - } else if (cf_node->flow_op == SL::FLOW_OP_CONTINUE) { - code += "continue;"; - } else if (cf_node->flow_op == SL::FLOW_OP_BREAK) { - code += "break;"; - } - } break; - - case SL::Node::TYPE_MEMBER: { - SL::MemberNode *member_node = (SL::MemberNode *)p_node; - code += _dump_node_code(member_node->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "."; - code += member_node->name; - if (member_node->index_expression != nullptr) { - code += "["; - code += _dump_node_code(member_node->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "]"; - } - } break; - } - - return code.as_string(); -} - -Error ShaderCompilerGLES2::compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) { - - Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderTypes::get_singleton()->get_types()); - - if (err != OK) { - - Vector<String> shader = p_code.split("\n"); - for (int i = 0; i < shader.size(); i++) { - print_line(itos(i + 1) + " " + shader[i]); - } - - _err_print_error(nullptr, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), ERR_HANDLER_SHADER); - return err; - } - - r_gen_code.custom_defines.clear(); - r_gen_code.uniforms.clear(); - r_gen_code.texture_uniforms.clear(); - r_gen_code.texture_hints.clear(); - r_gen_code.texture_types.clear(); - r_gen_code.vertex = String(); - r_gen_code.vertex_global = String(); - r_gen_code.fragment = String(); - r_gen_code.fragment_global = String(); - r_gen_code.light = String(); - r_gen_code.uses_fragment_time = false; - r_gen_code.uses_vertex_time = false; - - used_name_defines.clear(); - used_rmode_defines.clear(); - used_flag_pointers.clear(); - - _dump_node_code(parser.get_shader(), 1, r_gen_code, *p_actions, actions[p_mode], false); - - return OK; -} - -ShaderCompilerGLES2::ShaderCompilerGLES2() { - - /** CANVAS ITEM SHADER **/ - - actions[RS::SHADER_CANVAS_ITEM].renames["VERTEX"] = "outvec.xy"; - actions[RS::SHADER_CANVAS_ITEM].renames["UV"] = "uv"; - actions[RS::SHADER_CANVAS_ITEM].renames["POINT_SIZE"] = "point_size"; - - actions[RS::SHADER_CANVAS_ITEM].renames["WORLD_MATRIX"] = "modelview_matrix"; - actions[RS::SHADER_CANVAS_ITEM].renames["PROJECTION_MATRIX"] = "projection_matrix"; - actions[RS::SHADER_CANVAS_ITEM].renames["EXTRA_MATRIX"] = "extra_matrix_instance"; - actions[RS::SHADER_CANVAS_ITEM].renames["TIME"] = "time"; - actions[RS::SHADER_CANVAS_ITEM].renames["AT_LIGHT_PASS"] = "at_light_pass"; - actions[RS::SHADER_CANVAS_ITEM].renames["INSTANCE_CUSTOM"] = "instance_custom"; - - actions[RS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color"; - actions[RS::SHADER_CANVAS_ITEM].renames["NORMAL"] = "normal"; - actions[RS::SHADER_CANVAS_ITEM].renames["NORMALMAP"] = "normal_map"; - actions[RS::SHADER_CANVAS_ITEM].renames["NORMALMAP_DEPTH"] = "normal_depth"; - actions[RS::SHADER_CANVAS_ITEM].renames["TEXTURE"] = "color_texture"; - actions[RS::SHADER_CANVAS_ITEM].renames["TEXTURE_PIXEL_SIZE"] = "color_texpixel_size"; - actions[RS::SHADER_CANVAS_ITEM].renames["NORMAL_TEXTURE"] = "normal_texture"; - actions[RS::SHADER_CANVAS_ITEM].renames["SCREEN_UV"] = "screen_uv"; - actions[RS::SHADER_CANVAS_ITEM].renames["SCREEN_TEXTURE"] = "screen_texture"; - actions[RS::SHADER_CANVAS_ITEM].renames["SCREEN_PIXEL_SIZE"] = "screen_pixel_size"; - actions[RS::SHADER_CANVAS_ITEM].renames["FRAGCOORD"] = "gl_FragCoord"; - actions[RS::SHADER_CANVAS_ITEM].renames["POINT_COORD"] = "gl_PointCoord"; - - actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT_VEC"] = "light_vec"; - actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT_HEIGHT"] = "light_height"; - actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT_COLOR"] = "light_color"; - actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT_UV"] = "light_uv"; - actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT"] = "light"; - actions[RS::SHADER_CANVAS_ITEM].renames["SHADOW_COLOR"] = "shadow_color"; - actions[RS::SHADER_CANVAS_ITEM].renames["SHADOW_VEC"] = "shadow_vec"; - - actions[RS::SHADER_CANVAS_ITEM].usage_defines["COLOR"] = "#define COLOR_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["NORMAL"] = "#define NORMAL_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - actions[RS::SHADER_CANVAS_ITEM].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["SHADOW_VEC"] = "#define SHADOW_VEC_USED\n"; - - // Ported from GLES3 - - actions[RS::SHADER_CANVAS_ITEM].usage_defines["sinh"] = "#define SINH_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["cosh"] = "#define COSH_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["tanh"] = "#define TANH_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["asinh"] = "#define ASINH_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["acosh"] = "#define ACOSH_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["atanh"] = "#define ATANH_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["determinant"] = "#define DETERMINANT_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["transpose"] = "#define TRANSPOSE_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["outerProduct"] = "#define OUTER_PRODUCT_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["round"] = "#define ROUND_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["roundEven"] = "#define ROUND_EVEN_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["inverse"] = "#define INVERSE_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["isinf"] = "#define IS_INF_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["isnan"] = "#define IS_NAN_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["trunc"] = "#define TRUNC_USED\n"; - - /** SPATIAL SHADER **/ - - actions[RS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform"; - actions[RS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_inverse_matrix"; - actions[RS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_matrix"; - actions[RS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix"; - actions[RS::SHADER_SPATIAL].renames["INV_PROJECTION_MATRIX"] = "projection_inverse_matrix"; - actions[RS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview"; - - actions[RS::SHADER_SPATIAL].renames["VERTEX"] = "vertex.xyz"; - actions[RS::SHADER_SPATIAL].renames["NORMAL"] = "normal"; - actions[RS::SHADER_SPATIAL].renames["TANGENT"] = "tangent"; - actions[RS::SHADER_SPATIAL].renames["BINORMAL"] = "binormal"; - actions[RS::SHADER_SPATIAL].renames["POSITION"] = "position"; - actions[RS::SHADER_SPATIAL].renames["UV"] = "uv_interp"; - actions[RS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp"; - actions[RS::SHADER_SPATIAL].renames["COLOR"] = "color_interp"; - actions[RS::SHADER_SPATIAL].renames["POINT_SIZE"] = "point_size"; - // gl_InstanceID is not available in OpenGL ES 2.0 - actions[RS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "0"; - - //builtins - - actions[RS::SHADER_SPATIAL].renames["TIME"] = "time"; - actions[RS::SHADER_SPATIAL].renames["VIEWPORT_SIZE"] = "viewport_size"; - - 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["ALBEDO"] = "albedo"; - actions[RS::SHADER_SPATIAL].renames["ALPHA"] = "alpha"; - actions[RS::SHADER_SPATIAL].renames["METALLIC"] = "metallic"; - actions[RS::SHADER_SPATIAL].renames["SPECULAR"] = "specular"; - actions[RS::SHADER_SPATIAL].renames["ROUGHNESS"] = "roughness"; - actions[RS::SHADER_SPATIAL].renames["RIM"] = "rim"; - actions[RS::SHADER_SPATIAL].renames["RIM_TINT"] = "rim_tint"; - actions[RS::SHADER_SPATIAL].renames["CLEARCOAT"] = "clearcoat"; - actions[RS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; - actions[RS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy"; - actions[RS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; - actions[RS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength"; - actions[RS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission"; - actions[RS::SHADER_SPATIAL].renames["AO"] = "ao"; - actions[RS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect"; - actions[RS::SHADER_SPATIAL].renames["EMISSION"] = "emission"; - actions[RS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord"; - actions[RS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom"; - actions[RS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv"; - actions[RS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture"; - actions[RS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_texture"; - // Defined in GLES3, but not available in GLES2 - //actions[RS::SHADER_SPATIAL].renames["DEPTH"] = "gl_FragDepth"; - actions[RS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor"; - actions[RS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; - - //for light - actions[RS::SHADER_SPATIAL].renames["VIEW"] = "view"; - actions[RS::SHADER_SPATIAL].renames["LIGHT_COLOR"] = "light_color"; - actions[RS::SHADER_SPATIAL].renames["LIGHT"] = "light"; - actions[RS::SHADER_SPATIAL].renames["ATTENUATION"] = "attenuation"; - actions[RS::SHADER_SPATIAL].renames["DIFFUSE_LIGHT"] = "diffuse_light"; - actions[RS::SHADER_SPATIAL].renames["SPECULAR_LIGHT"] = "specular_light"; - - actions[RS::SHADER_SPATIAL].usage_defines["TANGENT"] = "#define ENABLE_TANGENT_INTERP\n"; - actions[RS::SHADER_SPATIAL].usage_defines["BINORMAL"] = "@TANGENT"; - actions[RS::SHADER_SPATIAL].usage_defines["RIM"] = "#define LIGHT_USE_RIM\n"; - actions[RS::SHADER_SPATIAL].usage_defines["RIM_TINT"] = "@RIM"; - actions[RS::SHADER_SPATIAL].usage_defines["CLEARCOAT"] = "#define LIGHT_USE_CLEARCOAT\n"; - actions[RS::SHADER_SPATIAL].usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT"; - actions[RS::SHADER_SPATIAL].usage_defines["ANISOTROPY"] = "#define LIGHT_USE_ANISOTROPY\n"; - actions[RS::SHADER_SPATIAL].usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY"; - actions[RS::SHADER_SPATIAL].usage_defines["AO"] = "#define ENABLE_AO\n"; - 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["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"; - actions[RS::SHADER_SPATIAL].usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; - - actions[RS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; - actions[RS::SHADER_SPATIAL].usage_defines["TRANSMISSION"] = "#define TRANSMISSION_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["DEPTH_TEXTURE"] = "#define DEPTH_TEXTURE_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; - - actions[RS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - actions[RS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - - // Ported from GLES3 - - actions[RS::SHADER_SPATIAL].usage_defines["sinh"] = "#define SINH_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["cosh"] = "#define COSH_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["tanh"] = "#define TANH_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["asinh"] = "#define ASINH_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["acosh"] = "#define ACOSH_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["atanh"] = "#define ATANH_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["determinant"] = "#define DETERMINANT_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["transpose"] = "#define TRANSPOSE_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["outerProduct"] = "#define OUTER_PRODUCT_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["round"] = "#define ROUND_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["roundEven"] = "#define ROUND_EVEN_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["inverse"] = "#define INVERSE_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["isinf"] = "#define IS_INF_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["isnan"] = "#define IS_NAN_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["trunc"] = "#define TRUNC_USED\n"; - - actions[RS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; - - // Defined in GLES3, could be implemented in GLES2 too if there's a need for it - //actions[RS::SHADER_SPATIAL].render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; - // Defined in GLES3, might not be possible in GLES2 as gl_FrontFacing is not available - //actions[RS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; - //actions[RS::SHADER_SPATIAL].render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; - - bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley"); - - if (!force_lambert) { - actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; - } - - actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; - - bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx"); - - if (!force_blinn) { - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; - } else { - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; - } - - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; - - // No defines for particle shaders in GLES2, there are no GPU particles - - vertex_name = "vertex"; - fragment_name = "fragment"; - light_name = "light"; - time_name = "TIME"; - - List<String> func_list; - - ShaderLanguage::get_builtin_funcs(&func_list); - - for (List<String>::Element *E = func_list.front(); E; E = E->next()) { - internal_functions.insert(E->get()); - } -} diff --git a/drivers/gles2/shader_compiler_gles2.h b/drivers/gles2/shader_compiler_gles2.h deleted file mode 100644 index 757dcdd4f2..0000000000 --- a/drivers/gles2/shader_compiler_gles2.h +++ /dev/null @@ -1,102 +0,0 @@ -/*************************************************************************/ -/* shader_compiler_gles2.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 SHADERCOMPILERGLES2_H -#define SHADERCOMPILERGLES2_H - -#include "core/pair.h" -#include "core/string_builder.h" -#include "servers/rendering/shader_language.h" -#include "servers/rendering/shader_types.h" -#include "servers/rendering_server.h" - -class ShaderCompilerGLES2 { -public: - struct IdentifierActions { - - Map<StringName, Pair<int *, int>> render_mode_values; - Map<StringName, bool *> render_mode_flags; - Map<StringName, bool *> usage_flag_pointers; - Map<StringName, bool *> write_flag_pointers; - - Map<StringName, ShaderLanguage::ShaderNode::Uniform> *uniforms; - }; - - struct GeneratedCode { - - Vector<CharString> custom_defines; - Vector<StringName> uniforms; - Vector<StringName> texture_uniforms; - Vector<ShaderLanguage::DataType> texture_types; - Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints; - - String vertex_global; - String vertex; - String fragment_global; - String fragment; - String light; - - bool uses_fragment_time; - bool uses_vertex_time; - }; - -private: - ShaderLanguage parser; - - struct DefaultIdentifierActions { - - Map<StringName, String> renames; - Map<StringName, String> render_mode_defines; - Map<StringName, String> usage_defines; - }; - - void _dump_function_deps(ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, StringBuilder &r_to_add, Set<StringName> &r_added); - String _dump_node_code(ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning); - - StringName current_func_name; - StringName vertex_name; - StringName fragment_name; - StringName light_name; - StringName time_name; - - Set<StringName> used_name_defines; - Set<StringName> used_flag_pointers; - Set<StringName> used_rmode_defines; - Set<StringName> internal_functions; - - DefaultIdentifierActions actions[RS::SHADER_MAX]; - -public: - Error compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code); - - ShaderCompilerGLES2(); -}; - -#endif // SHADERCOMPILERGLES2_H diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp deleted file mode 100644 index 2c335c6c5a..0000000000 --- a/drivers/gles2/shader_gles2.cpp +++ /dev/null @@ -1,1103 +0,0 @@ -/*************************************************************************/ -/* shader_gles2.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 "shader_gles2.h" - -#include "core/os/memory.h" -#include "core/print_string.h" -#include "core/string_builder.h" -#include "rasterizer_gles2.h" -#include "rasterizer_storage_gles2.h" - -// #define DEBUG_OPENGL - -// #include "shaders/copy.glsl.gen.h" - -#ifdef DEBUG_OPENGL - -#define DEBUG_TEST_ERROR(m_section) \ - { \ - uint32_t err = glGetError(); \ - if (err) { \ - print_line("OpenGL Error #" + itos(err) + " at: " + m_section); \ - } \ - } -#else - -#define DEBUG_TEST_ERROR(m_section) - -#endif - -ShaderGLES2 *ShaderGLES2::active = nullptr; - -//#define DEBUG_SHADER - -#ifdef DEBUG_SHADER - -#define DEBUG_PRINT(m_text) print_line(m_text); - -#else - -#define DEBUG_PRINT(m_text) - -#endif - -GLint ShaderGLES2::get_uniform_location(int p_index) const { - - ERR_FAIL_COND_V(!version, -1); - - return version->uniform_location[p_index]; -} - -bool ShaderGLES2::bind() { - - if (active != this || !version || new_conditional_version.key != conditional_version.key) { - conditional_version = new_conditional_version; - version = get_current_version(); - } else { - return false; - } - - ERR_FAIL_COND_V(!version, false); - - if (!version->ok) { //broken, unable to bind (do not throw error, you saw it before already when it failed compilation). - glUseProgram(0); - return false; - } - - glUseProgram(version->id); - - DEBUG_TEST_ERROR("use program"); - - active = this; - uniforms_dirty = true; - - return true; -} - -void ShaderGLES2::unbind() { - version = nullptr; - glUseProgram(0); - uniforms_dirty = true; - active = nullptr; -} - -static void _display_error_with_code(const String &p_error, const Vector<const char *> &p_code) { - - int line = 1; - String total_code; - - for (int i = 0; i < p_code.size(); i++) { - total_code += String(p_code[i]); - } - - Vector<String> lines = String(total_code).split("\n"); - - for (int j = 0; j < lines.size(); j++) { - - print_line(itos(line) + ": " + lines[j]); - line++; - } - - ERR_PRINT(p_error); -} - -static String _mkid(const String &p_id) { - - String id = "m_" + p_id; - return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl -} - -ShaderGLES2::Version *ShaderGLES2::get_current_version() { - - Version *_v = version_map.getptr(conditional_version); - - if (_v) { - if (conditional_version.code_version != 0) { - CustomCode *cc = custom_code_map.getptr(conditional_version.code_version); - ERR_FAIL_COND_V(!cc, _v); - if (cc->version == _v->code_version) - return _v; - } else { - return _v; - } - } - - if (!_v) - version_map[conditional_version] = Version(); - - Version &v = version_map[conditional_version]; - - if (!_v) { - v.uniform_location = memnew_arr(GLint, uniform_count); - } else { - if (v.ok) { - glDeleteShader(v.vert_id); - glDeleteShader(v.frag_id); - glDeleteProgram(v.id); - v.id = 0; - } - } - - v.ok = false; - - Vector<const char *> strings; - -#ifdef GLES_OVER_GL - strings.push_back("#version 120\n"); - strings.push_back("#define USE_GLES_OVER_GL\n"); -#else - strings.push_back("#version 100\n"); -//angle does not like -#ifdef JAVASCRIPT_ENABLED - strings.push_back("#define USE_HIGHP_PRECISION\n"); -#endif - -#endif - - for (int j = 0; j < conditional_count; j++) { - bool enable = (conditional_version.version & (1 << j)) > 0; - - if (enable) { - strings.push_back(conditional_defines[j]); - DEBUG_PRINT(conditional_defines[j]); - } - } - - // keep them around during the function - CharString code_string; - CharString code_string2; - CharString code_globals; - - CustomCode *cc = nullptr; - - if (conditional_version.code_version > 0) { - cc = custom_code_map.getptr(conditional_version.code_version); - - ERR_FAIL_COND_V(!cc, nullptr); - v.code_version = cc->version; - } - - // program - - v.id = glCreateProgram(); - ERR_FAIL_COND_V(v.id == 0, nullptr); - - if (cc) { - for (int i = 0; i < cc->custom_defines.size(); i++) { - strings.push_back(cc->custom_defines.write[i]); - DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i].get_data())); - } - } - - // vertex shader - - int string_base_size = strings.size(); - - strings.push_back(vertex_code0.get_data()); - - if (cc) { - code_globals = cc->vertex_globals.ascii(); - strings.push_back(code_globals.get_data()); - } - - strings.push_back(vertex_code1.get_data()); - - if (cc) { - code_string = cc->vertex.ascii(); - strings.push_back(code_string.get_data()); - } - - strings.push_back(vertex_code2.get_data()); - -#ifdef DEBUG_SHADER - - DEBUG_PRINT("\nVertex Code:\n\n" + String(code_string.get_data())); - -#endif - - v.vert_id = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(v.vert_id, strings.size(), &strings[0], nullptr); - glCompileShader(v.vert_id); - - GLint status; - - glGetShaderiv(v.vert_id, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { - GLsizei iloglen; - glGetShaderiv(v.vert_id, GL_INFO_LOG_LENGTH, &iloglen); - - if (iloglen < 0) { - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - - ERR_PRINT("No OpenGL vertex shader compiler log. What the frick?"); - } else { - if (iloglen == 0) { - iloglen = 4096; // buggy driver (Adreno 220+) - } - - char *ilogmem = (char *)Memory::alloc_static(iloglen + 1); - ilogmem[iloglen] = '\0'; - glGetShaderInfoLog(v.vert_id, iloglen, &iloglen, ilogmem); - - String err_string = get_shader_name() + ": Vertex shader compilation failed:\n"; - - err_string += ilogmem; - - _display_error_with_code(err_string, strings); - - Memory::free_static(ilogmem); - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - } - - ERR_FAIL_V(nullptr); - } - - strings.resize(string_base_size); - - // fragment shader - - strings.push_back(fragment_code0.get_data()); - - if (cc) { - code_globals = cc->fragment_globals.ascii(); - strings.push_back(code_globals.get_data()); - } - - strings.push_back(fragment_code1.get_data()); - - if (cc) { - code_string = cc->light.ascii(); - strings.push_back(code_string.get_data()); - } - - strings.push_back(fragment_code2.get_data()); - - if (cc) { - code_string2 = cc->fragment.ascii(); - strings.push_back(code_string2.get_data()); - } - - strings.push_back(fragment_code3.get_data()); - -#ifdef DEBUG_SHADER - - if (cc) { - DEBUG_PRINT("\nFragment Code:\n\n" + String(cc->fragment_globals)); - } - DEBUG_PRINT("\nFragment Code:\n\n" + String(code_string.get_data())); -#endif - - v.frag_id = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(v.frag_id, strings.size(), &strings[0], nullptr); - glCompileShader(v.frag_id); - - glGetShaderiv(v.frag_id, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { - GLsizei iloglen; - glGetShaderiv(v.frag_id, GL_INFO_LOG_LENGTH, &iloglen); - - if (iloglen < 0) { - glDeleteShader(v.frag_id); - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - - ERR_PRINT("No OpenGL fragment shader compiler log. What the frick?"); - } else { - if (iloglen == 0) { - iloglen = 4096; // buggy driver (Adreno 220+) - } - - char *ilogmem = (char *)Memory::alloc_static(iloglen + 1); - ilogmem[iloglen] = '\0'; - glGetShaderInfoLog(v.frag_id, iloglen, &iloglen, ilogmem); - - String err_string = get_shader_name() + ": Fragment shader compilation failed:\n"; - - err_string += ilogmem; - - _display_error_with_code(err_string, strings); - - Memory::free_static(ilogmem); - glDeleteShader(v.frag_id); - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - } - - ERR_FAIL_V(nullptr); - } - - glAttachShader(v.id, v.frag_id); - glAttachShader(v.id, v.vert_id); - - // bind the attribute locations. This has to be done before linking so that the - // linker doesn't assign some random indices - - for (int i = 0; i < attribute_pair_count; i++) { - glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name); - } - - glLinkProgram(v.id); - - glGetProgramiv(v.id, GL_LINK_STATUS, &status); - if (status == GL_FALSE) { - GLsizei iloglen; - glGetProgramiv(v.id, GL_INFO_LOG_LENGTH, &iloglen); - - if (iloglen < 0) { - glDeleteShader(v.frag_id); - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - - ERR_PRINT("No OpenGL program link log. What the frick?"); - ERR_FAIL_V(nullptr); - } - - if (iloglen == 0) { - iloglen = 4096; // buggy driver (Adreno 220+) - } - - char *ilogmem = (char *)Memory::alloc_static(iloglen + 1); - ilogmem[iloglen] = '\0'; - glGetProgramInfoLog(v.id, iloglen, &iloglen, ilogmem); - - String err_string = get_shader_name() + ": Program linking failed:\n"; - - err_string += ilogmem; - - _display_error_with_code(err_string, strings); - - Memory::free_static(ilogmem); - glDeleteShader(v.frag_id); - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - - ERR_FAIL_V(nullptr); - } - - // get uniform locations - - glUseProgram(v.id); - - for (int i = 0; i < uniform_count; i++) { - v.uniform_location[i] = glGetUniformLocation(v.id, uniform_names[i]); - } - - for (int i = 0; i < texunit_pair_count; i++) { - GLint loc = glGetUniformLocation(v.id, texunit_pairs[i].name); - if (loc >= 0) { - if (texunit_pairs[i].index < 0) { - glUniform1i(loc, max_image_units + texunit_pairs[i].index); - } else { - glUniform1i(loc, texunit_pairs[i].index); - } - } - } - - if (cc) { - // uniforms - for (int i = 0; i < cc->custom_uniforms.size(); i++) { - String native_uniform_name = _mkid(cc->custom_uniforms[i]); - GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data()); - v.custom_uniform_locations[cc->custom_uniforms[i]] = location; - } - - // textures - for (int i = 0; i < cc->texture_uniforms.size(); i++) { - String native_uniform_name = _mkid(cc->texture_uniforms[i]); - GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data()); - v.custom_uniform_locations[cc->texture_uniforms[i]] = location; - glUniform1i(location, i); - } - } - - glUseProgram(0); - v.ok = true; - - if (cc) { - cc->versions.insert(conditional_version.version); - } - - return &v; -} - -GLint ShaderGLES2::get_uniform_location(const String &p_name) const { - - ERR_FAIL_COND_V(!version, -1); - return glGetUniformLocation(version->id, p_name.ascii().get_data()); -} - -void ShaderGLES2::setup( - const char **p_conditional_defines, - int p_conditional_count, - const char **p_uniform_names, - int p_uniform_count, - const AttributePair *p_attribute_pairs, - int p_attribute_count, - const TexUnitPair *p_texunit_pairs, - int p_texunit_pair_count, - const char *p_vertex_code, - const char *p_fragment_code, - int p_vertex_code_start, - int p_fragment_code_start) { - - ERR_FAIL_COND(version); - - conditional_version.key = 0; - new_conditional_version.key = 0; - uniform_count = p_uniform_count; - conditional_count = p_conditional_count; - conditional_defines = p_conditional_defines; - uniform_names = p_uniform_names; - vertex_code = p_vertex_code; - fragment_code = p_fragment_code; - texunit_pairs = p_texunit_pairs; - texunit_pair_count = p_texunit_pair_count; - vertex_code_start = p_vertex_code_start; - fragment_code_start = p_fragment_code_start; - attribute_pairs = p_attribute_pairs; - attribute_pair_count = p_attribute_count; - - { - String globals_tag = "\nVERTEX_SHADER_GLOBALS"; - String code_tag = "\nVERTEX_SHADER_CODE"; - String code = vertex_code; - int cpos = code.find(globals_tag); - if (cpos == -1) { - vertex_code0 = code.ascii(); - } else { - vertex_code0 = code.substr(0, cpos).ascii(); - code = code.substr(cpos + globals_tag.length(), code.length()); - - cpos = code.find(code_tag); - - if (cpos == -1) { - vertex_code1 = code.ascii(); - } else { - vertex_code1 = code.substr(0, cpos).ascii(); - vertex_code2 = code.substr(cpos + code_tag.length(), code.length()).ascii(); - } - } - } - - { - String globals_tag = "\nFRAGMENT_SHADER_GLOBALS"; - String code_tag = "\nFRAGMENT_SHADER_CODE"; - String light_code_tag = "\nLIGHT_SHADER_CODE"; - String code = fragment_code; - int cpos = code.find(globals_tag); - if (cpos == -1) { - fragment_code0 = code.ascii(); - } else { - fragment_code0 = code.substr(0, cpos).ascii(); - code = code.substr(cpos + globals_tag.length(), code.length()); - - cpos = code.find(light_code_tag); - - String code2; - - if (cpos != -1) { - - fragment_code1 = code.substr(0, cpos).ascii(); - code2 = code.substr(cpos + light_code_tag.length(), code.length()); - } else { - code2 = code; - } - - cpos = code2.find(code_tag); - if (cpos == -1) { - fragment_code2 = code2.ascii(); - } else { - fragment_code2 = code2.substr(0, cpos).ascii(); - fragment_code3 = code2.substr(cpos + code_tag.length(), code2.length()).ascii(); - } - } - } - - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_image_units); -} - -void ShaderGLES2::finish() { - const VersionKey *V = nullptr; - - while ((V = version_map.next(V))) { - Version &v = version_map[*V]; - glDeleteShader(v.vert_id); - glDeleteShader(v.frag_id); - glDeleteProgram(v.id); - memdelete_arr(v.uniform_location); - } -} - -void ShaderGLES2::clear_caches() { - const VersionKey *V = nullptr; - - while ((V = version_map.next(V))) { - Version &v = version_map[*V]; - glDeleteShader(v.vert_id); - glDeleteShader(v.frag_id); - glDeleteProgram(v.id); - memdelete_arr(v.uniform_location); - } - - version_map.clear(); - - custom_code_map.clear(); - version = nullptr; - last_custom_code = 1; - uniforms_dirty = true; -} - -uint32_t ShaderGLES2::create_custom_shader() { - custom_code_map[last_custom_code] = CustomCode(); - custom_code_map[last_custom_code].version = 1; - return last_custom_code++; -} - -void ShaderGLES2::set_custom_shader_code(uint32_t p_code_id, - const String &p_vertex, - const String &p_vertex_globals, - const String &p_fragment, - const String &p_light, - const String &p_fragment_globals, - const Vector<StringName> &p_uniforms, - const Vector<StringName> &p_texture_uniforms, - const Vector<CharString> &p_custom_defines) { - CustomCode *cc = custom_code_map.getptr(p_code_id); - ERR_FAIL_COND(!cc); - - cc->vertex = p_vertex; - cc->vertex_globals = p_vertex_globals; - cc->fragment = p_fragment; - cc->fragment_globals = p_fragment_globals; - cc->light = p_light; - cc->custom_uniforms = p_uniforms; - cc->custom_defines = p_custom_defines; - cc->texture_uniforms = p_texture_uniforms; - cc->version++; -} - -void ShaderGLES2::set_custom_shader(uint32_t p_code_id) { - new_conditional_version.code_version = p_code_id; -} - -void ShaderGLES2::free_custom_shader(uint32_t p_code_id) { - - ERR_FAIL_COND(!custom_code_map.has(p_code_id)); - if (conditional_version.code_version == p_code_id) { - conditional_version.code_version = 0; //do not keep using a version that is going away - unbind(); - } - - VersionKey key; - key.code_version = p_code_id; - for (Set<uint32_t>::Element *E = custom_code_map[p_code_id].versions.front(); E; E = E->next()) { - key.version = E->get(); - ERR_CONTINUE(!version_map.has(key)); - Version &v = version_map[key]; - - glDeleteShader(v.vert_id); - glDeleteShader(v.frag_id); - glDeleteProgram(v.id); - memdelete_arr(v.uniform_location); - v.id = 0; - - version_map.erase(key); - } - - custom_code_map.erase(p_code_id); -} - -void ShaderGLES2::use_material(void *p_material) { - RasterizerStorageGLES2::Material *material = (RasterizerStorageGLES2::Material *)p_material; - - if (!material) { - return; - } - - if (!material->shader) { - return; - } - - Version *v = version_map.getptr(conditional_version); - - // bind uniforms - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = material->shader->uniforms.front(); E; E = E->next()) { - - if (E->get().texture_order >= 0) - continue; // this is a texture, doesn't go here - - Map<StringName, GLint>::Element *L = v->custom_uniform_locations.find(E->key()); - if (!L || L->get() < 0) - continue; //uniform not valid - - GLuint location = L->get(); - - Map<StringName, Variant>::Element *V = material->params.find(E->key()); - - if (V) { - switch (E->get().type) { - case ShaderLanguage::TYPE_BOOL: { - - bool boolean = V->get(); - glUniform1i(location, boolean ? 1 : 0); - } break; - - case ShaderLanguage::TYPE_BVEC2: { - int flags = V->get(); - glUniform2i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0); - } break; - - case ShaderLanguage::TYPE_BVEC3: { - - int flags = V->get(); - glUniform3i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0, (flags & 4) ? 1 : 0); - - } break; - - case ShaderLanguage::TYPE_BVEC4: { - int flags = V->get(); - glUniform4i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0, (flags & 4) ? 1 : 0, (flags & 8) ? 1 : 0); - - } break; - - case ShaderLanguage::TYPE_INT: - case ShaderLanguage::TYPE_UINT: { - int value = V->get(); - glUniform1i(location, value); - } break; - - case ShaderLanguage::TYPE_IVEC2: - case ShaderLanguage::TYPE_UVEC2: { - - Array r = V->get(); - const int count = 2; - if (r.size() == count) { - int values[count]; - for (int i = 0; i < count; i++) { - values[i] = r[i]; - } - glUniform2i(location, values[0], values[1]); - } - - } break; - - case ShaderLanguage::TYPE_IVEC3: - case ShaderLanguage::TYPE_UVEC3: { - Array r = V->get(); - const int count = 3; - if (r.size() == count) { - int values[count]; - for (int i = 0; i < count; i++) { - values[i] = r[i]; - } - glUniform3i(location, values[0], values[1], values[2]); - } - - } break; - - case ShaderLanguage::TYPE_IVEC4: - case ShaderLanguage::TYPE_UVEC4: { - Array r = V->get(); - const int count = 4; - if (r.size() == count) { - int values[count]; - for (int i = 0; i < count; i++) { - values[i] = r[i]; - } - glUniform4i(location, values[0], values[1], values[2], values[3]); - } - - } break; - - case ShaderLanguage::TYPE_FLOAT: { - float value = V->get(); - glUniform1f(location, value); - - } break; - - case ShaderLanguage::TYPE_VEC2: { - Vector2 value = V->get(); - glUniform2f(location, value.x, value.y); - } break; - - case ShaderLanguage::TYPE_VEC3: { - Vector3 value = V->get(); - glUniform3f(location, value.x, value.y, value.z); - } break; - - case ShaderLanguage::TYPE_VEC4: { - if (V->get().get_type() == Variant::COLOR) { - Color value = V->get(); - glUniform4f(location, value.r, value.g, value.b, value.a); - } else if (V->get().get_type() == Variant::QUAT) { - Quat value = V->get(); - glUniform4f(location, value.x, value.y, value.z, value.w); - } else { - Plane value = V->get(); - glUniform4f(location, value.normal.x, value.normal.y, value.normal.z, value.d); - } - - } break; - - case ShaderLanguage::TYPE_MAT2: { - - Transform2D tr = V->get(); - GLfloat matrix[4] = { - /* build a 16x16 matrix */ - tr.elements[0][0], - tr.elements[0][1], - tr.elements[1][0], - tr.elements[1][1], - }; - glUniformMatrix2fv(location, 1, GL_FALSE, matrix); - - } break; - - case ShaderLanguage::TYPE_MAT3: { - Basis val = V->get(); - - GLfloat mat[9] = { - val.elements[0][0], - val.elements[1][0], - val.elements[2][0], - val.elements[0][1], - val.elements[1][1], - val.elements[2][1], - val.elements[0][2], - val.elements[1][2], - val.elements[2][2], - }; - - glUniformMatrix3fv(location, 1, GL_FALSE, mat); - - } break; - - case ShaderLanguage::TYPE_MAT4: { - - Transform2D tr = V->get(); - GLfloat matrix[16] = { /* build a 16x16 matrix */ - tr.elements[0][0], - tr.elements[0][1], - 0, - 0, - tr.elements[1][0], - tr.elements[1][1], - 0, - 0, - 0, - 0, - 1, - 0, - tr.elements[2][0], - tr.elements[2][1], - 0, - 1 - }; - - glUniformMatrix4fv(location, 1, GL_FALSE, matrix); - - } break; - - default: { - ERR_PRINT("ShaderNode type missing, bug?"); - } break; - } - } else if (E->get().default_value.size()) { - const Vector<ShaderLanguage::ConstantNode::Value> &values = E->get().default_value; - switch (E->get().type) { - case ShaderLanguage::TYPE_BOOL: { - glUniform1i(location, values[0].boolean); - } break; - - case ShaderLanguage::TYPE_BVEC2: { - glUniform2i(location, values[0].boolean, values[1].boolean); - } break; - - case ShaderLanguage::TYPE_BVEC3: { - glUniform3i(location, values[0].boolean, values[1].boolean, values[2].boolean); - } break; - - case ShaderLanguage::TYPE_BVEC4: { - glUniform4i(location, values[0].boolean, values[1].boolean, values[2].boolean, values[3].boolean); - } break; - - case ShaderLanguage::TYPE_INT: { - glUniform1i(location, values[0].sint); - } break; - - case ShaderLanguage::TYPE_IVEC2: { - glUniform2i(location, values[0].sint, values[1].sint); - } break; - - case ShaderLanguage::TYPE_IVEC3: { - glUniform3i(location, values[0].sint, values[1].sint, values[2].sint); - } break; - - case ShaderLanguage::TYPE_IVEC4: { - glUniform4i(location, values[0].sint, values[1].sint, values[2].sint, values[3].sint); - } break; - - case ShaderLanguage::TYPE_UINT: { - glUniform1i(location, values[0].uint); - } break; - - case ShaderLanguage::TYPE_UVEC2: { - glUniform2i(location, values[0].uint, values[1].uint); - } break; - - case ShaderLanguage::TYPE_UVEC3: { - glUniform3i(location, values[0].uint, values[1].uint, values[2].uint); - } break; - - case ShaderLanguage::TYPE_UVEC4: { - glUniform4i(location, values[0].uint, values[1].uint, values[2].uint, values[3].uint); - } break; - - case ShaderLanguage::TYPE_FLOAT: { - glUniform1f(location, values[0].real); - } break; - - case ShaderLanguage::TYPE_VEC2: { - glUniform2f(location, values[0].real, values[1].real); - } break; - - case ShaderLanguage::TYPE_VEC3: { - glUniform3f(location, values[0].real, values[1].real, values[2].real); - } break; - - case ShaderLanguage::TYPE_VEC4: { - glUniform4f(location, values[0].real, values[1].real, values[2].real, values[3].real); - } break; - - case ShaderLanguage::TYPE_MAT2: { - GLfloat mat[4]; - - for (int i = 0; i < 4; i++) { - mat[i] = values[i].real; - } - - glUniformMatrix2fv(location, 1, GL_FALSE, mat); - } break; - - case ShaderLanguage::TYPE_MAT3: { - GLfloat mat[9]; - - for (int i = 0; i < 9; i++) { - mat[i] = values[i].real; - } - - glUniformMatrix3fv(location, 1, GL_FALSE, mat); - - } break; - - case ShaderLanguage::TYPE_MAT4: { - GLfloat mat[16]; - - for (int i = 0; i < 16; i++) { - mat[i] = values[i].real; - } - - glUniformMatrix4fv(location, 1, GL_FALSE, mat); - - } break; - - case ShaderLanguage::TYPE_SAMPLER2D: { - - } break; - - case ShaderLanguage::TYPE_ISAMPLER2D: { - - } break; - - case ShaderLanguage::TYPE_USAMPLER2D: { - - } break; - - case ShaderLanguage::TYPE_SAMPLERCUBE: { - - } break; - - case ShaderLanguage::TYPE_SAMPLER2DARRAY: - case ShaderLanguage::TYPE_ISAMPLER2DARRAY: - case ShaderLanguage::TYPE_USAMPLER2DARRAY: - case ShaderLanguage::TYPE_SAMPLER3D: - case ShaderLanguage::TYPE_ISAMPLER3D: - case ShaderLanguage::TYPE_USAMPLER3D: { - // Not implemented in GLES2 - } break; - - case ShaderLanguage::TYPE_VOID: { - // Nothing to do? - } break; - default: { - ERR_PRINT("ShaderNode type missing, bug?"); - } break; - } - } else { //zero - - switch (E->get().type) { - case ShaderLanguage::TYPE_BOOL: { - glUniform1i(location, GL_FALSE); - } break; - - case ShaderLanguage::TYPE_BVEC2: { - glUniform2i(location, GL_FALSE, GL_FALSE); - } break; - - case ShaderLanguage::TYPE_BVEC3: { - glUniform3i(location, GL_FALSE, GL_FALSE, GL_FALSE); - } break; - - case ShaderLanguage::TYPE_BVEC4: { - glUniform4i(location, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - } break; - - case ShaderLanguage::TYPE_INT: { - glUniform1i(location, 0); - } break; - - case ShaderLanguage::TYPE_IVEC2: { - glUniform2i(location, 0, 0); - } break; - - case ShaderLanguage::TYPE_IVEC3: { - glUniform3i(location, 0, 0, 0); - } break; - - case ShaderLanguage::TYPE_IVEC4: { - glUniform4i(location, 0, 0, 0, 0); - } break; - - case ShaderLanguage::TYPE_UINT: { - glUniform1i(location, 0); - } break; - - case ShaderLanguage::TYPE_UVEC2: { - glUniform2i(location, 0, 0); - } break; - - case ShaderLanguage::TYPE_UVEC3: { - glUniform3i(location, 0, 0, 0); - } break; - - case ShaderLanguage::TYPE_UVEC4: { - glUniform4i(location, 0, 0, 0, 0); - } break; - - case ShaderLanguage::TYPE_FLOAT: { - glUniform1f(location, 0); - } break; - - case ShaderLanguage::TYPE_VEC2: { - glUniform2f(location, 0, 0); - } break; - - case ShaderLanguage::TYPE_VEC3: { - glUniform3f(location, 0, 0, 0); - } break; - - case ShaderLanguage::TYPE_VEC4: { - glUniform4f(location, 0, 0, 0, 0); - } break; - - case ShaderLanguage::TYPE_MAT2: { - GLfloat mat[4] = { 0, 0, 0, 0 }; - - glUniformMatrix2fv(location, 1, GL_FALSE, mat); - } break; - - case ShaderLanguage::TYPE_MAT3: { - GLfloat mat[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - glUniformMatrix3fv(location, 1, GL_FALSE, mat); - - } break; - - case ShaderLanguage::TYPE_MAT4: { - GLfloat mat[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - glUniformMatrix4fv(location, 1, GL_FALSE, mat); - - } break; - - case ShaderLanguage::TYPE_SAMPLER2D: { - - } break; - - case ShaderLanguage::TYPE_ISAMPLER2D: { - - } break; - - case ShaderLanguage::TYPE_USAMPLER2D: { - - } break; - - case ShaderLanguage::TYPE_SAMPLERCUBE: { - - } break; - - case ShaderLanguage::TYPE_SAMPLER2DARRAY: - case ShaderLanguage::TYPE_ISAMPLER2DARRAY: - case ShaderLanguage::TYPE_USAMPLER2DARRAY: - case ShaderLanguage::TYPE_SAMPLER3D: - case ShaderLanguage::TYPE_ISAMPLER3D: - case ShaderLanguage::TYPE_USAMPLER3D: { - // Not implemented in GLES2 - } break; - - case ShaderLanguage::TYPE_VOID: { - // Nothing to do? - } break; - default: { - ERR_PRINT("ShaderNode type missing, bug?"); - } break; - } - } - } -} - -ShaderGLES2::ShaderGLES2() { - version = nullptr; - last_custom_code = 1; - uniforms_dirty = true; -} - -ShaderGLES2::~ShaderGLES2() { - finish(); -} diff --git a/drivers/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h deleted file mode 100644 index d20d5bc585..0000000000 --- a/drivers/gles2/shader_gles2.h +++ /dev/null @@ -1,270 +0,0 @@ -/*************************************************************************/ -/* shader_gles2.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 SHADER_GLES2_H -#define SHADER_GLES2_H - -// This must come first to avoid windows.h mess -#include "platform_config.h" -#ifndef GLES2_INCLUDE_H -#include <GLES2/gl2.h> -#else -#include GLES2_INCLUDE_H -#endif - -#include "core/hash_map.h" -#include "core/map.h" -#include "core/math/camera_matrix.h" -#include "core/pair.h" -#include "core/variant.h" -#include "servers/rendering/shader_language.h" - -#include <stdio.h> - -class RasterizerStorageGLES2; - -class ShaderGLES2 { -protected: - struct Enum { - - uint64_t mask; - uint64_t shift; - const char *defines[16]; - }; - - struct EnumValue { - - uint64_t set_mask; - uint64_t clear_mask; - }; - - struct AttributePair { - - const char *name; - int index; - }; - - struct UniformPair { - const char *name; - Variant::Type type_hint; - }; - - struct TexUnitPair { - - const char *name; - int index; - }; - - bool uniforms_dirty; - -private: - //@TODO Optimize to a fixed set of shader pools and use a LRU - int uniform_count; - int texunit_pair_count; - int conditional_count; - int vertex_code_start; - int fragment_code_start; - int attribute_pair_count; - - struct CustomCode { - - String vertex; - String vertex_globals; - String fragment; - String fragment_globals; - String light; - uint32_t version; - Vector<StringName> texture_uniforms; - Vector<StringName> custom_uniforms; - Vector<CharString> custom_defines; - Set<uint32_t> versions; - }; - - struct Version { - - GLuint id; - GLuint vert_id; - GLuint frag_id; - GLint *uniform_location; - Vector<GLint> texture_uniform_locations; - Map<StringName, GLint> custom_uniform_locations; - uint32_t code_version; - bool ok; - Version() { - id = 0; - vert_id = 0; - frag_id = 0; - uniform_location = nullptr; - code_version = 0; - ok = false; - } - }; - - Version *version; - - union VersionKey { - - struct { - uint32_t version; - uint32_t code_version; - }; - uint64_t key; - bool operator==(const VersionKey &p_key) const { return key == p_key.key; } - bool operator<(const VersionKey &p_key) const { return key < p_key.key; } - }; - - struct VersionKeyHash { - - static _FORCE_INLINE_ uint32_t hash(const VersionKey &p_key) { return HashMapHasherDefault::hash(p_key.key); } - }; - - //this should use a way more cachefriendly version.. - HashMap<VersionKey, Version, VersionKeyHash> version_map; - - HashMap<uint32_t, CustomCode> custom_code_map; - uint32_t last_custom_code; - - VersionKey conditional_version; - VersionKey new_conditional_version; - - virtual String get_shader_name() const = 0; - - const char **conditional_defines; - const char **uniform_names; - const AttributePair *attribute_pairs; - const TexUnitPair *texunit_pairs; - const char *vertex_code; - const char *fragment_code; - CharString fragment_code0; - CharString fragment_code1; - CharString fragment_code2; - CharString fragment_code3; - - CharString vertex_code0; - CharString vertex_code1; - CharString vertex_code2; - - Vector<CharString> custom_defines; - - Version *get_current_version(); - - static ShaderGLES2 *active; - - int max_image_units; - - Map<StringName, Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value>>> uniform_values; - -protected: - _FORCE_INLINE_ int _get_uniform(int p_which) const; - _FORCE_INLINE_ void _set_conditional(int p_which, bool p_value); - - void setup(const char **p_conditional_defines, - int p_conditional_count, - const char **p_uniform_names, - int p_uniform_count, - const AttributePair *p_attribute_pairs, - int p_attribute_count, - const TexUnitPair *p_texunit_pairs, - int p_texunit_pair_count, - const char *p_vertex_code, - const char *p_fragment_code, - int p_vertex_code_start, - int p_fragment_code_start); - - ShaderGLES2(); - -public: - enum { - CUSTOM_SHADER_DISABLED = 0 - }; - - GLint get_uniform_location(const String &p_name) const; - GLint get_uniform_location(int p_index) const; - - static _FORCE_INLINE_ ShaderGLES2 *get_active() { return active; } - bool bind(); - void unbind(); - - inline GLuint get_program() const { return version ? version->id : 0; } - - void clear_caches(); - - uint32_t create_custom_shader(); - void set_custom_shader_code(uint32_t p_code_id, - const String &p_vertex, - const String &p_vertex_globals, - const String &p_fragment, - const String &p_light, - const String &p_fragment_globals, - const Vector<StringName> &p_uniforms, - const Vector<StringName> &p_texture_uniforms, - const Vector<CharString> &p_custom_defines); - - void set_custom_shader(uint32_t p_code_id); - void free_custom_shader(uint32_t p_code_id); - - uint32_t get_version_key() const { return conditional_version.version; } - - // this void* is actually a RasterizerStorageGLES2::Material, but C++ doesn't - // like forward declared nested classes. - void use_material(void *p_material); - - _FORCE_INLINE_ uint32_t get_version() const { return new_conditional_version.version; } - _FORCE_INLINE_ bool is_version_valid() const { return version && version->ok; } - - virtual void init() = 0; - void finish(); - - void add_custom_define(const String &p_define) { - custom_defines.push_back(p_define.utf8()); - } - - virtual ~ShaderGLES2(); -}; - -// called a lot, made inline - -int ShaderGLES2::_get_uniform(int p_which) const { - - ERR_FAIL_INDEX_V(p_which, uniform_count, -1); - ERR_FAIL_COND_V(!version, -1); - return version->uniform_location[p_which]; -} - -void ShaderGLES2::_set_conditional(int p_which, bool p_value) { - - ERR_FAIL_INDEX(p_which, conditional_count); - if (p_value) - new_conditional_version.version |= (1 << p_which); - else - new_conditional_version.version &= ~(1 << p_which); -} - -#endif diff --git a/drivers/gles2/shaders/SCsub b/drivers/gles2/shaders/SCsub deleted file mode 100644 index bcd6ea79fb..0000000000 --- a/drivers/gles2/shaders/SCsub +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python - -Import("env") - -if "GLES2_GLSL" in env["BUILDERS"]: - env.GLES2_GLSL("copy.glsl") - # env.GLES2_GLSL('resolve.glsl'); - env.GLES2_GLSL("canvas.glsl") - env.GLES2_GLSL("canvas_shadow.glsl") - env.GLES2_GLSL("scene.glsl") - env.GLES2_GLSL("cubemap_filter.glsl") - env.GLES2_GLSL("cube_to_dp.glsl") - # env.GLES2_GLSL('blend_shape.glsl'); - # env.GLES2_GLSL('screen_space_reflection.glsl'); - env.GLES2_GLSL("effect_blur.glsl") - # env.GLES2_GLSL('subsurf_scattering.glsl'); - # env.GLES2_GLSL('ssao.glsl'); - # env.GLES2_GLSL('ssao_minify.glsl'); - # env.GLES2_GLSL('ssao_blur.glsl'); - # env.GLES2_GLSL('exposure.glsl'); - env.GLES2_GLSL("tonemap.glsl") - # env.GLES2_GLSL('particles.glsl'); - env.GLES2_GLSL("lens_distorted.glsl") diff --git a/drivers/gles2/shaders/blend_shape.glsl b/drivers/gles2/shaders/blend_shape.glsl deleted file mode 100644 index 0d0b3e24e4..0000000000 --- a/drivers/gles2/shaders/blend_shape.glsl +++ /dev/null @@ -1,194 +0,0 @@ -/* clang-format off */ -[vertex] - -/* -from RenderingServer: - -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, -*/ - -#ifdef USE_2D_VERTEX -#define VFORMAT vec2 -#else -#define VFORMAT vec3 -#endif - -/* INPUT ATTRIBS */ - -layout(location = 0) in highp VFORMAT vertex_attrib; -/* clang-format on */ -layout(location = 1) in vec3 normal_attrib; - -#ifdef ENABLE_TANGENT -layout(location = 2) in vec4 tangent_attrib; -#endif - -#ifdef ENABLE_COLOR -layout(location = 3) in vec4 color_attrib; -#endif - -#ifdef ENABLE_UV -layout(location = 4) in vec2 uv_attrib; -#endif - -#ifdef ENABLE_UV2 -layout(location = 5) in vec2 uv2_attrib; -#endif - -#ifdef ENABLE_SKELETON -layout(location = 6) in ivec4 bone_attrib; -layout(location = 7) in vec4 weight_attrib; -#endif - -/* BLEND ATTRIBS */ - -#ifdef ENABLE_BLEND - -layout(location = 8) in highp VFORMAT vertex_attrib_blend; -layout(location = 9) in vec3 normal_attrib_blend; - -#ifdef ENABLE_TANGENT -layout(location = 10) in vec4 tangent_attrib_blend; -#endif - -#ifdef ENABLE_COLOR -layout(location = 11) in vec4 color_attrib_blend; -#endif - -#ifdef ENABLE_UV -layout(location = 12) in vec2 uv_attrib_blend; -#endif - -#ifdef ENABLE_UV2 -layout(location = 13) in vec2 uv2_attrib_blend; -#endif - -#ifdef ENABLE_SKELETON -layout(location = 14) in ivec4 bone_attrib_blend; -layout(location = 15) in vec4 weight_attrib_blend; -#endif - -#endif - -/* OUTPUTS */ - -out VFORMAT vertex_out; //tfb: - -#ifdef ENABLE_NORMAL -out vec3 normal_out; //tfb:ENABLE_NORMAL -#endif - -#ifdef ENABLE_TANGENT -out vec4 tangent_out; //tfb:ENABLE_TANGENT -#endif - -#ifdef ENABLE_COLOR -out vec4 color_out; //tfb:ENABLE_COLOR -#endif - -#ifdef ENABLE_UV -out vec2 uv_out; //tfb:ENABLE_UV -#endif - -#ifdef ENABLE_UV2 -out vec2 uv2_out; //tfb:ENABLE_UV2 -#endif - -#ifdef ENABLE_SKELETON -out ivec4 bone_out; //tfb:ENABLE_SKELETON -out vec4 weight_out; //tfb:ENABLE_SKELETON -#endif - -uniform float blend_amount; - -void main() { - -#ifdef ENABLE_BLEND - - vertex_out = vertex_attrib_blend + vertex_attrib * blend_amount; - -#ifdef ENABLE_NORMAL - normal_out = normal_attrib_blend + normal_attrib * blend_amount; -#endif - -#ifdef ENABLE_TANGENT - - tangent_out.xyz = tangent_attrib_blend.xyz + tangent_attrib.xyz * blend_amount; - tangent_out.w = tangent_attrib_blend.w; //just copy, no point in blending his -#endif - -#ifdef ENABLE_COLOR - - color_out = color_attrib_blend + color_attrib * blend_amount; -#endif - -#ifdef ENABLE_UV - - uv_out = uv_attrib_blend + uv_attrib * blend_amount; -#endif - -#ifdef ENABLE_UV2 - - uv2_out = uv2_attrib_blend + uv2_attrib * blend_amount; -#endif - -#ifdef ENABLE_SKELETON - - bone_out = bone_attrib_blend; - weight_out = weight_attrib_blend + weight_attrib * blend_amount; -#endif - -#else //ENABLE_BLEND - - vertex_out = vertex_attrib * blend_amount; - -#ifdef ENABLE_NORMAL - normal_out = normal_attrib * blend_amount; -#endif - -#ifdef ENABLE_TANGENT - - tangent_out.xyz = tangent_attrib.xyz * blend_amount; - tangent_out.w = tangent_attrib.w; //just copy, no point in blending his -#endif - -#ifdef ENABLE_COLOR - - color_out = color_attrib * blend_amount; -#endif - -#ifdef ENABLE_UV - - uv_out = uv_attrib * blend_amount; -#endif - -#ifdef ENABLE_UV2 - - uv2_out = uv2_attrib * blend_amount; -#endif - -#ifdef ENABLE_SKELETON - - bone_out = bone_attrib; - weight_out = weight_attrib * blend_amount; -#endif - -#endif - gl_Position = vec4(0.0); -} - -/* clang-format off */ -[fragment] - -void main() { - -} -/* clang-format on */ diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl deleted file mode 100644 index 3b685b3f0b..0000000000 --- a/drivers/gles2/shaders/canvas.glsl +++ /dev/null @@ -1,624 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -#ifndef USE_GLES_OVER_GL -#extension GL_OES_texture_3D : enable -#else -#extension GL_EXT_texture_array : enable -#endif - -uniform highp mat4 projection_matrix; -/* clang-format on */ - -#include "stdlib.glsl" - -uniform highp mat4 modelview_matrix; -uniform highp mat4 extra_matrix; -attribute highp vec2 vertex; // attrib:0 -attribute vec4 color_attrib; // attrib:3 -attribute vec2 uv_attrib; // attrib:4 - -#ifdef USE_SKELETON -attribute highp vec4 bone_indices; // attrib:6 -attribute highp vec4 bone_weights; // attrib:7 -#endif - -#ifdef USE_INSTANCING - -attribute highp vec4 instance_xform0; //attrib:8 -attribute highp vec4 instance_xform1; //attrib:9 -attribute highp vec4 instance_xform2; //attrib:10 -attribute highp vec4 instance_color; //attrib:11 - -#ifdef USE_INSTANCE_CUSTOM -attribute highp vec4 instance_custom_data; //attrib:12 -#endif - -#endif - -#ifdef USE_SKELETON -uniform highp sampler2D skeleton_texture; // texunit:-3 -uniform highp ivec2 skeleton_texture_size; -uniform highp mat4 skeleton_transform; -uniform highp mat4 skeleton_transform_inverse; -#endif - -varying vec2 uv_interp; -varying vec4 color_interp; - -uniform highp vec2 color_texpixel_size; - -#ifdef USE_TEXTURE_RECT - -uniform vec4 dst_rect; -uniform vec4 src_rect; - -#endif - -uniform highp float time; - -#ifdef USE_LIGHTING - -// light matrices -uniform highp mat4 light_matrix; -uniform highp mat4 light_matrix_inverse; -uniform highp mat4 light_local_matrix; -uniform highp mat4 shadow_matrix; -uniform highp vec4 light_color; -uniform highp vec4 light_shadow_color; -uniform highp vec2 light_pos; -uniform highp float shadowpixel_size; -uniform highp float shadow_gradient; -uniform highp float light_height; -uniform highp float light_outside_alpha; -uniform highp float shadow_distance_mult; - -varying vec4 light_uv_interp; -varying vec2 transformed_light_uv; -varying vec4 local_rot; - -#ifdef USE_SHADOWS -varying highp vec2 pos; -#endif - -const bool at_light_pass = true; -#else -const bool at_light_pass = false; -#endif - -/* clang-format off */ - -VERTEX_SHADER_GLOBALS - -/* clang-format on */ - -vec2 select(vec2 a, vec2 b, bvec2 c) { - vec2 ret; - - ret.x = c.x ? b.x : a.x; - ret.y = c.y ? b.y : a.y; - - return ret; -} - -void main() { - - vec4 color = color_attrib; - vec2 uv; - -#ifdef USE_INSTANCING - mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0))); - color *= instance_color; - -#ifdef USE_INSTANCE_CUSTOM - vec4 instance_custom = instance_custom_data; -#else - vec4 instance_custom = vec4(0.0); -#endif - -#else - mat4 extra_matrix_instance = extra_matrix; - vec4 instance_custom = vec4(0.0); -#endif - -#ifdef USE_TEXTURE_RECT - - if (dst_rect.z < 0.0) { // Transpose is encoded as negative dst_rect.z - uv = src_rect.xy + abs(src_rect.zw) * vertex.yx; - } else { - uv = src_rect.xy + abs(src_rect.zw) * vertex; - } - - vec4 outvec = vec4(0.0, 0.0, 0.0, 1.0); - - // This is what is done in the GLES 3 bindings and should - // take care of flipped rects. - // - // But it doesn't. - // I don't know why, will need to investigate further. - - outvec.xy = dst_rect.xy + abs(dst_rect.zw) * select(vertex, vec2(1.0, 1.0) - vertex, lessThan(src_rect.zw, vec2(0.0, 0.0))); - - // outvec.xy = dst_rect.xy + abs(dst_rect.zw) * vertex; -#else - vec4 outvec = vec4(vertex.xy, 0.0, 1.0); - - uv = uv_attrib; -#endif - - float point_size = 1.0; - - { - vec2 src_vtx = outvec.xy; - /* clang-format off */ - -VERTEX_SHADER_CODE - - /* clang-format on */ - } - - gl_PointSize = point_size; - -#if !defined(SKIP_TRANSFORM_USED) - outvec = extra_matrix_instance * outvec; - outvec = modelview_matrix * outvec; -#endif - - color_interp = color; - -#ifdef USE_PIXEL_SNAP - outvec.xy = floor(outvec + 0.5).xy; - // precision issue on some hardware creates artifacts within texture - // offset uv by a small amount to avoid - uv += 1e-5; -#endif - -#ifdef USE_SKELETON - - // look up transform from the "pose texture" - if (bone_weights != vec4(0.0)) { - - highp mat4 bone_transform = mat4(0.0); - - for (int i = 0; i < 4; i++) { - ivec2 tex_ofs = ivec2(int(bone_indices[i]) * 2, 0); - - highp mat4 b = mat4( - texel2DFetch(skeleton_texture, skeleton_texture_size, tex_ofs + ivec2(0, 0)), - texel2DFetch(skeleton_texture, skeleton_texture_size, tex_ofs + ivec2(1, 0)), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(0.0, 0.0, 0.0, 1.0)); - - bone_transform += b * bone_weights[i]; - } - - mat4 bone_matrix = skeleton_transform * transpose(bone_transform) * skeleton_transform_inverse; - - outvec = bone_matrix * outvec; - } - -#endif - - uv_interp = uv; - gl_Position = projection_matrix * outvec; - -#ifdef USE_LIGHTING - - light_uv_interp.xy = (light_matrix * outvec).xy; - light_uv_interp.zw = (light_local_matrix * outvec).xy; - - transformed_light_uv = (mat3(light_matrix_inverse) * vec3(light_uv_interp.zw, 0.0)).xy; //for normal mapping - -#ifdef USE_SHADOWS - pos = outvec.xy; -#endif - - local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(1.0, 0.0, 0.0, 0.0))).xy); - local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(0.0, 1.0, 0.0, 0.0))).xy); -#ifdef USE_TEXTURE_RECT - local_rot.xy *= sign(src_rect.z); - local_rot.zw *= sign(src_rect.w); -#endif - -#endif -} - -/* clang-format off */ -[fragment] - -#ifndef USE_GLES_OVER_GL -#extension GL_OES_texture_3D : enable -#else -#extension GL_EXT_texture_array : enable -#endif - -// texture2DLodEXT and textureCubeLodEXT are fragment shader specific. -// Do not copy these defines in the vertex section. -#ifndef USE_GLES_OVER_GL -#ifdef GL_EXT_shader_texture_lod -#extension GL_EXT_shader_texture_lod : enable -#define texture2DLod(img, coord, lod) texture2DLodEXT(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCubeLodEXT(img, coord, lod) -#endif -#endif // !USE_GLES_OVER_GL - -#ifdef GL_ARB_shader_texture_lod -#extension GL_ARB_shader_texture_lod : enable -#endif - -#if !defined(GL_EXT_shader_texture_lod) && !defined(GL_ARB_shader_texture_lod) -#define texture2DLod(img, coord, lod) texture2D(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCube(img, coord, lod) -#endif - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -#include "stdlib.glsl" - -uniform sampler2D color_texture; // texunit:-1 -/* clang-format on */ -uniform highp vec2 color_texpixel_size; -uniform mediump sampler2D normal_texture; // texunit:-2 - -varying mediump vec2 uv_interp; -varying mediump vec4 color_interp; - -uniform highp float time; - -uniform vec4 final_modulate; - -#ifdef SCREEN_TEXTURE_USED - -uniform sampler2D screen_texture; // texunit:-4 - -#endif - -#ifdef SCREEN_UV_USED - -uniform vec2 screen_pixel_size; - -#endif - -#ifdef USE_LIGHTING - -uniform highp mat4 light_matrix; -uniform highp mat4 light_local_matrix; -uniform highp mat4 shadow_matrix; -uniform highp vec4 light_color; -uniform highp vec4 light_shadow_color; -uniform highp vec2 light_pos; -uniform highp float shadowpixel_size; -uniform highp float shadow_gradient; -uniform highp float light_height; -uniform highp float light_outside_alpha; -uniform highp float shadow_distance_mult; - -uniform lowp sampler2D light_texture; // texunit:-4 -varying vec4 light_uv_interp; -varying vec2 transformed_light_uv; - -varying vec4 local_rot; - -#ifdef USE_SHADOWS - -uniform highp sampler2D shadow_texture; // texunit:-5 -varying highp vec2 pos; - -#endif - -const bool at_light_pass = true; -#else -const bool at_light_pass = false; -#endif - -uniform bool use_default_normal; - -/* clang-format off */ - -FRAGMENT_SHADER_GLOBALS - -/* clang-format on */ - -void light_compute( - inout vec4 light, - inout vec2 light_vec, - inout float light_height, - inout vec4 light_color, - vec2 light_uv, - inout vec4 shadow_color, - inout vec2 shadow_vec, - vec3 normal, - vec2 uv, -#if defined(SCREEN_UV_USED) - vec2 screen_uv, -#endif - vec4 color) { - -#if defined(USE_LIGHT_SHADER_CODE) - - /* clang-format off */ - -LIGHT_SHADER_CODE - - /* clang-format on */ - -#endif -} - -void main() { - - vec4 color = color_interp; - vec2 uv = uv_interp; -#ifdef USE_FORCE_REPEAT - //needs to use this to workaround GLES2/WebGL1 forcing tiling that textures that don't support it - uv = mod(uv, vec2(1.0, 1.0)); -#endif - -#if !defined(COLOR_USED) - //default behavior, texture by color - color *= texture2D(color_texture, uv); -#endif - -#ifdef SCREEN_UV_USED - vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; -#endif - - vec3 normal; - -#if defined(NORMAL_USED) - - bool normal_used = true; -#else - bool normal_used = false; -#endif - - if (use_default_normal) { - normal.xy = texture2D(normal_texture, uv).xy * 2.0 - 1.0; - normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); - normal_used = true; - } else { - normal = vec3(0.0, 0.0, 1.0); - } - - { - float normal_depth = 1.0; - -#if defined(NORMALMAP_USED) - vec3 normal_map = vec3(0.0, 0.0, 1.0); - normal_used = true; -#endif - - /* clang-format off */ - -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); -#endif - } - color *= final_modulate; - -#ifdef USE_LIGHTING - - vec2 light_vec = transformed_light_uv; - vec2 shadow_vec = transformed_light_uv; - - if (normal_used) { - normal.xy = mat2(local_rot.xy, local_rot.zw) * normal.xy; - } - - float att = 1.0; - - vec2 light_uv = light_uv_interp.xy; - vec4 light = texture2D(light_texture, light_uv); - - if (any(lessThan(light_uv_interp.xy, vec2(0.0, 0.0))) || any(greaterThanEqual(light_uv_interp.xy, vec2(1.0, 1.0)))) { - color.a *= light_outside_alpha; //invisible - - } else { - float real_light_height = light_height; - vec4 real_light_color = light_color; - vec4 real_light_shadow_color = light_shadow_color; - -#if defined(USE_LIGHT_SHADER_CODE) - //light is written by the light shader - light_compute( - light, - light_vec, - real_light_height, - real_light_color, - light_uv, - real_light_shadow_color, - shadow_vec, - normal, - uv, -#if defined(SCREEN_UV_USED) - screen_uv, -#endif - color); -#endif - - light *= real_light_color; - - if (normal_used) { - vec3 light_normal = normalize(vec3(light_vec, -real_light_height)); - light *= max(dot(-light_normal, normal), 0.0); - } - - color *= light; - -#ifdef USE_SHADOWS - -#ifdef SHADOW_VEC_USED - mat3 inverse_light_matrix = mat3(light_matrix); - inverse_light_matrix[0] = normalize(inverse_light_matrix[0]); - inverse_light_matrix[1] = normalize(inverse_light_matrix[1]); - inverse_light_matrix[2] = normalize(inverse_light_matrix[2]); - shadow_vec = (inverse_light_matrix * vec3(shadow_vec, 0.0)).xy; -#else - shadow_vec = light_uv_interp.zw; -#endif - - float angle_to_light = -atan(shadow_vec.x, shadow_vec.y); - float PI = 3.14159265358979323846264; - /*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays - float ang*/ - - float su, sz; - - float abs_angle = abs(angle_to_light); - vec2 point; - float sh; - if (abs_angle < 45.0 * PI / 180.0) { - point = shadow_vec; - sh = 0.0 + (1.0 / 8.0); - } else if (abs_angle > 135.0 * PI / 180.0) { - point = -shadow_vec; - sh = 0.5 + (1.0 / 8.0); - } else if (angle_to_light > 0.0) { - - point = vec2(shadow_vec.y, -shadow_vec.x); - sh = 0.25 + (1.0 / 8.0); - } else { - - point = vec2(-shadow_vec.y, shadow_vec.x); - sh = 0.75 + (1.0 / 8.0); - } - - highp vec4 s = shadow_matrix * vec4(point, 0.0, 1.0); - s.xyz /= s.w; - su = s.x * 0.5 + 0.5; - sz = s.z * 0.5 + 0.5; - //sz=lightlength(light_vec); - - highp float shadow_attenuation = 0.0; - -#ifdef USE_RGBA_SHADOWS -#define SHADOW_DEPTH(m_tex, m_uv) dot(texture2D((m_tex), (m_uv)), vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) - -#else - -#define SHADOW_DEPTH(m_tex, m_uv) (texture2D((m_tex), (m_uv)).r) - -#endif - -#ifdef SHADOW_USE_GRADIENT - - /* clang-format off */ - /* GLSL es 100 doesn't support line continuation characters(backslashes) */ -#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); shadow_attenuation += 1.0 - smoothstep(sd, sd + shadow_gradient, sz); } - -#else - -#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); shadow_attenuation += step(sz, sd); } - /* clang-format on */ - -#endif - -#ifdef SHADOW_FILTER_NEAREST - - SHADOW_TEST(su); - -#endif - -#ifdef SHADOW_FILTER_PCF3 - - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - shadow_attenuation /= 3.0; - -#endif - -#ifdef SHADOW_FILTER_PCF5 - - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - shadow_attenuation /= 5.0; - -#endif - -#ifdef SHADOW_FILTER_PCF7 - - SHADOW_TEST(su + shadowpixel_size * 3.0); - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - SHADOW_TEST(su - shadowpixel_size * 3.0); - shadow_attenuation /= 7.0; - -#endif - -#ifdef SHADOW_FILTER_PCF9 - - SHADOW_TEST(su + shadowpixel_size * 4.0); - SHADOW_TEST(su + shadowpixel_size * 3.0); - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - SHADOW_TEST(su - shadowpixel_size * 3.0); - SHADOW_TEST(su - shadowpixel_size * 4.0); - shadow_attenuation /= 9.0; - -#endif - -#ifdef SHADOW_FILTER_PCF13 - - SHADOW_TEST(su + shadowpixel_size * 6.0); - SHADOW_TEST(su + shadowpixel_size * 5.0); - SHADOW_TEST(su + shadowpixel_size * 4.0); - SHADOW_TEST(su + shadowpixel_size * 3.0); - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - SHADOW_TEST(su - shadowpixel_size * 3.0); - SHADOW_TEST(su - shadowpixel_size * 4.0); - SHADOW_TEST(su - shadowpixel_size * 5.0); - SHADOW_TEST(su - shadowpixel_size * 6.0); - shadow_attenuation /= 13.0; - -#endif - - //color *= shadow_attenuation; - color = mix(real_light_shadow_color, color, shadow_attenuation); -//use shadows -#endif - } - -//use lighting -#endif - - gl_FragColor = color; -} diff --git a/drivers/gles2/shaders/canvas_shadow.glsl b/drivers/gles2/shaders/canvas_shadow.glsl deleted file mode 100644 index 7a5ba4f571..0000000000 --- a/drivers/gles2/shaders/canvas_shadow.glsl +++ /dev/null @@ -1,62 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -attribute highp vec3 vertex; // attrib:0 - -uniform highp mat4 projection_matrix; -/* clang-format on */ -uniform highp mat4 light_matrix; -uniform highp mat4 world_matrix; -uniform highp float distance_norm; - -varying highp vec4 position_interp; - -void main() { - - gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex, 1.0))); - position_interp = gl_Position; -} - -/* clang-format off */ -[fragment] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -varying highp vec4 position_interp; -/* clang-format on */ - -void main() { - - highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias - -#ifdef USE_RGBA_SHADOWS - - highp vec4 comp = fract(depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0)); - comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0); - gl_FragColor = comp; -#else - - gl_FragColor = vec4(depth); -#endif -} diff --git a/drivers/gles2/shaders/copy.glsl b/drivers/gles2/shaders/copy.glsl deleted file mode 100644 index aa967115da..0000000000 --- a/drivers/gles2/shaders/copy.glsl +++ /dev/null @@ -1,194 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -attribute highp vec4 vertex_attrib; // attrib:0 -/* clang-format on */ - -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) -attribute vec3 cube_in; // attrib:4 -#else -attribute vec2 uv_in; // attrib:4 -#endif - -attribute vec2 uv2_in; // attrib:5 - -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) -varying vec3 cube_interp; -#else -varying vec2 uv_interp; -#endif -varying vec2 uv2_interp; - -// These definitions are here because the shader-wrapper builder does -// not understand `#elif defined()` -#ifdef USE_DISPLAY_TRANSFORM -#endif - -#ifdef USE_COPY_SECTION -uniform highp vec4 copy_section; -#elif defined(USE_DISPLAY_TRANSFORM) -uniform highp mat4 display_transform; -#endif - -void main() { - -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) - cube_interp = cube_in; -#elif defined(USE_ASYM_PANO) - uv_interp = vertex_attrib.xy; -#else - uv_interp = uv_in; -#endif - - uv2_interp = uv2_in; - gl_Position = vertex_attrib; - -#ifdef USE_COPY_SECTION - uv_interp = copy_section.xy + uv_interp * copy_section.zw; - gl_Position.xy = (copy_section.xy + (gl_Position.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0; -#elif defined(USE_DISPLAY_TRANSFORM) - uv_interp = (display_transform * vec4(uv_in, 1.0, 1.0)).xy; -#endif -} - -/* clang-format off */ -[fragment] - -#define M_PI 3.14159265359 - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) -varying vec3 cube_interp; -#else -varying vec2 uv_interp; -#endif -/* clang-format on */ - -#ifdef USE_ASYM_PANO -uniform highp mat4 pano_transform; -uniform highp vec4 asym_proj; -#endif - -#ifdef USE_CUBEMAP -uniform samplerCube source_cube; // texunit:0 -#else -uniform sampler2D source; // texunit:0 -#endif - -#ifdef SEP_CBCR_TEXTURE -uniform sampler2D CbCr; //texunit:1 -#endif - -varying vec2 uv2_interp; - -#ifdef USE_MULTIPLIER -uniform float multiplier; -#endif - -#ifdef USE_CUSTOM_ALPHA -uniform float custom_alpha; -#endif - -#if defined(USE_PANORAMA) || defined(USE_ASYM_PANO) -uniform highp mat4 sky_transform; - -vec4 texturePanorama(sampler2D pano, vec3 normal) { - - vec2 st = vec2( - atan(normal.x, normal.z), - acos(normal.y)); - - if (st.x < 0.0) - st.x += M_PI * 2.0; - - st /= vec2(M_PI * 2.0, M_PI); - - return texture2D(pano, st); -} - -#endif - -void main() { - -#ifdef USE_PANORAMA - - vec3 cube_normal = normalize(cube_interp); - cube_normal.z = -cube_normal.z; - cube_normal = mat3(sky_transform) * cube_normal; - cube_normal.z = -cube_normal.z; - - vec4 color = texturePanorama(source, cube_normal); - -#elif defined(USE_ASYM_PANO) - - // When an asymmetrical projection matrix is used (applicable for stereoscopic rendering i.e. VR) we need to do this calculation per fragment to get a perspective correct result. - // Asymmetrical projection means the center of projection is no longer in the center of the screen but shifted. - // The Matrix[2][0] (= asym_proj.x) and Matrix[2][1] (= asym_proj.z) values are what provide the right shift in the image. - - vec3 cube_normal; - cube_normal.z = -1.0; - cube_normal.x = (cube_normal.z * (-uv_interp.x - asym_proj.x)) / asym_proj.y; - cube_normal.y = (cube_normal.z * (-uv_interp.y - asym_proj.z)) / asym_proj.a; - cube_normal = mat3(sky_transform) * mat3(pano_transform) * cube_normal; - cube_normal.z = -cube_normal.z; - - vec4 color = texturePanorama(source, normalize(cube_normal.xyz)); - -#elif defined(USE_CUBEMAP) - vec4 color = textureCube(source_cube, normalize(cube_interp)); -#elif defined(SEP_CBCR_TEXTURE) - vec4 color; - color.r = texture2D(source, uv_interp).r; - color.gb = texture2D(CbCr, uv_interp).rg - vec2(0.5, 0.5); - color.a = 1.0; -#else - vec4 color = texture2D(source, uv_interp); -#endif - -#ifdef YCBCR_TO_RGB - // YCbCr -> RGB conversion - - // Using BT.601, which is the standard for SDTV is provided as a reference - color.rgb = mat3( - vec3(1.00000, 1.00000, 1.00000), - vec3(0.00000, -0.34413, 1.77200), - vec3(1.40200, -0.71414, 0.00000)) * - color.rgb; -#endif - -#ifdef USE_NO_ALPHA - color.a = 1.0; -#endif - -#ifdef USE_CUSTOM_ALPHA - color.a = custom_alpha; -#endif - -#ifdef USE_MULTIPLIER - color.rgb *= multiplier; -#endif - - gl_FragColor = color; -} diff --git a/drivers/gles2/shaders/cube_to_dp.glsl b/drivers/gles2/shaders/cube_to_dp.glsl deleted file mode 100644 index 769908c3b4..0000000000 --- a/drivers/gles2/shaders/cube_to_dp.glsl +++ /dev/null @@ -1,102 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision mediump float; -precision mediump int; -#endif - -attribute highp vec4 vertex_attrib; // attrib:0 -/* clang-format on */ -attribute vec2 uv_in; // attrib:4 - -varying vec2 uv_interp; - -void main() { - - uv_interp = uv_in; - gl_Position = vertex_attrib; -} - -/* clang-format off */ -[fragment] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -uniform highp samplerCube source_cube; //texunit:0 -/* clang-format on */ -varying vec2 uv_interp; - -uniform bool z_flip; -uniform highp float z_far; -uniform highp float z_near; -uniform highp float bias; - -void main() { - - highp vec3 normal = vec3(uv_interp * 2.0 - 1.0, 0.0); - /* - if (z_flip) { - normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); - } else { - normal.z = -0.5 + 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); - } - */ - - //normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); - //normal.xy *= 1.0 + normal.z; - - normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); - normal = normalize(normal); - /* - normal.z = 0.5; - normal = normalize(normal); - */ - - if (!z_flip) { - normal.z = -normal.z; - } - - //normal = normalize(vec3( uv_interp * 2.0 - 1.0, 1.0 )); - float depth = textureCube(source_cube, normal).r; - - // absolute values for direction cosines, bigger value equals closer to basis axis - vec3 unorm = abs(normal); - - if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) { - // x code - unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0); - } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) { - // y code - unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0); - } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) { - // z code - unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0); - } else { - // oh-no we messed up code - // has to be - unorm = vec3(1.0, 0.0, 0.0); - } - - float depth_fix = 1.0 / dot(normal, unorm); - - depth = 2.0 * depth - 1.0; - float linear_depth = 2.0 * z_near * z_far / (z_far + z_near - depth * (z_far - z_near)); - gl_FragDepth = (linear_depth * depth_fix + bias) / z_far; -} diff --git a/drivers/gles2/shaders/cubemap_filter.glsl b/drivers/gles2/shaders/cubemap_filter.glsl deleted file mode 100644 index db3d8b3a1b..0000000000 --- a/drivers/gles2/shaders/cubemap_filter.glsl +++ /dev/null @@ -1,235 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -attribute highp vec2 vertex; // attrib:0 -/* clang-format on */ -attribute highp vec2 uv; // attrib:4 - -varying highp vec2 uv_interp; - -void main() { - - uv_interp = uv; - gl_Position = vec4(vertex, 0, 1); -} - -/* clang-format off */ -[fragment] - -// texture2DLodEXT and textureCubeLodEXT are fragment shader specific. -// Do not copy these defines in the vertex section. -#ifndef USE_GLES_OVER_GL -#ifdef GL_EXT_shader_texture_lod -#extension GL_EXT_shader_texture_lod : enable -#define texture2DLod(img, coord, lod) texture2DLodEXT(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCubeLodEXT(img, coord, lod) -#endif -#endif // !USE_GLES_OVER_GL - -#ifdef GL_ARB_shader_texture_lod -#extension GL_ARB_shader_texture_lod : enable -#endif - -#if !defined(GL_EXT_shader_texture_lod) && !defined(GL_ARB_shader_texture_lod) -#define texture2DLod(img, coord, lod) texture2D(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCube(img, coord, lod) -#endif - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif - -#endif - -#ifdef USE_SOURCE_PANORAMA -uniform sampler2D source_panorama; //texunit:0 -#else -uniform samplerCube source_cube; //texunit:0 -#endif -/* clang-format on */ - -uniform int face_id; -uniform float roughness; -varying highp vec2 uv_interp; - -uniform sampler2D radical_inverse_vdc_cache; // texunit:1 - -#define M_PI 3.14159265359 - -#ifdef LOW_QUALITY - -#define SAMPLE_COUNT 64 - -#else - -#define SAMPLE_COUNT 512 - -#endif - -#ifdef USE_SOURCE_PANORAMA - -vec4 texturePanorama(sampler2D pano, vec3 normal) { - - vec2 st = vec2( - atan(normal.x, normal.z), - acos(normal.y)); - - if (st.x < 0.0) - st.x += M_PI * 2.0; - - st /= vec2(M_PI * 2.0, M_PI); - - return texture2DLod(pano, st, 0.0); -} - -#endif - -vec3 texelCoordToVec(vec2 uv, int faceID) { - mat3 faceUvVectors[6]; - - // -x - faceUvVectors[0][0] = vec3(0.0, 0.0, 1.0); // u -> +z - faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[0][2] = vec3(-1.0, 0.0, 0.0); // -x face - - // +x - faceUvVectors[1][0] = vec3(0.0, 0.0, -1.0); // u -> -z - faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[1][2] = vec3(1.0, 0.0, 0.0); // +x face - - // -y - faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[2][1] = vec3(0.0, 0.0, -1.0); // v -> -z - faceUvVectors[2][2] = vec3(0.0, -1.0, 0.0); // -y face - - // +y - faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[3][1] = vec3(0.0, 0.0, 1.0); // v -> +z - faceUvVectors[3][2] = vec3(0.0, 1.0, 0.0); // +y face - - // -z - faceUvVectors[4][0] = vec3(-1.0, 0.0, 0.0); // u -> -x - faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[4][2] = vec3(0.0, 0.0, -1.0); // -z face - - // +z - faceUvVectors[5][0] = vec3(1.0, 0.0, 0.0); // u -> +x - faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y - faceUvVectors[5][2] = vec3(0.0, 0.0, 1.0); // +z face - - // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2]. - vec3 result; - for (int i = 0; i < 6; i++) { - if (i == faceID) { - result = (faceUvVectors[i][0] * uv.x) + (faceUvVectors[i][1] * uv.y) + faceUvVectors[i][2]; - break; - } - } - return normalize(result); -} - -vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) { - float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph] - - // Compute distribution direction - float Phi = 2.0 * M_PI * Xi.x; - float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y)); - float SinTheta = sqrt(1.0 - CosTheta * CosTheta); - - // Convert to spherical direction - vec3 H; - H.x = SinTheta * cos(Phi); - H.y = SinTheta * sin(Phi); - H.z = CosTheta; - - vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); - vec3 TangentX = normalize(cross(UpVector, N)); - vec3 TangentY = cross(N, TangentX); - - // Tangent to world space - return TangentX * H.x + TangentY * H.y + N * H.z; -} - -float radical_inverse_VdC(int i) { - return texture2D(radical_inverse_vdc_cache, vec2(float(i) / 512.0, 0.0)).x; -} - -vec2 Hammersley(int i, int N) { - return vec2(float(i) / float(N), radical_inverse_VdC(i)); -} - -uniform bool z_flip; - -void main() { - - vec3 color = vec3(0.0); - - vec2 uv = (uv_interp * 2.0) - 1.0; - vec3 N = texelCoordToVec(uv, face_id); - -#ifdef USE_DIRECT_WRITE - -#ifdef USE_SOURCE_PANORAMA - - gl_FragColor = vec4(texturePanorama(source_panorama, N).rgb, 1.0); -#else - - gl_FragColor = vec4(textureCube(source_cube, N).rgb, 1.0); -#endif //USE_SOURCE_PANORAMA - -#else - - vec4 sum = vec4(0.0); - - for (int sample_num = 0; sample_num < SAMPLE_COUNT; sample_num++) { - - vec2 xi = Hammersley(sample_num, SAMPLE_COUNT); - - vec3 H = ImportanceSampleGGX(xi, roughness, N); - vec3 V = N; - vec3 L = (2.0 * dot(V, H) * H - V); - - float NdotL = clamp(dot(N, L), 0.0, 1.0); - - if (NdotL > 0.0) { - -#ifdef USE_SOURCE_PANORAMA - vec3 val = texturePanorama(source_panorama, L).rgb; -#else - vec3 val = textureCubeLod(source_cube, L, 0.0).rgb; -#endif - //mix using Linear, to approximate high end back-end - val = mix(pow((val + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), val * (1.0 / 12.92), vec3(lessThan(val, vec3(0.04045)))); - - sum.rgb += val * NdotL; - - sum.a += NdotL; - } - } - - sum /= sum.a; - - vec3 a = vec3(0.055); - sum.rgb = mix((vec3(1.0) + a) * pow(sum.rgb, vec3(1.0 / 2.4)) - a, 12.92 * sum.rgb, vec3(lessThan(sum.rgb, vec3(0.0031308)))); - - gl_FragColor = vec4(sum.rgb, 1.0); -#endif -} diff --git a/drivers/gles2/shaders/effect_blur.glsl b/drivers/gles2/shaders/effect_blur.glsl deleted file mode 100644 index b28d78a6ca..0000000000 --- a/drivers/gles2/shaders/effect_blur.glsl +++ /dev/null @@ -1,312 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -attribute vec2 vertex_attrib; // attrib:0 -/* clang-format on */ -attribute vec2 uv_in; // attrib:4 - -varying vec2 uv_interp; - -#ifdef USE_BLUR_SECTION - -uniform vec4 blur_section; - -#endif - -void main() { - - uv_interp = uv_in; - gl_Position = vec4(vertex_attrib, 0.0, 1.0); -#ifdef USE_BLUR_SECTION - - uv_interp = blur_section.xy + uv_interp * blur_section.zw; - gl_Position.xy = (blur_section.xy + (gl_Position.xy * 0.5 + 0.5) * blur_section.zw) * 2.0 - 1.0; -#endif -} - -/* clang-format off */ -[fragment] - -// texture2DLodEXT and textureCubeLodEXT are fragment shader specific. -// Do not copy these defines in the vertex section. -#ifndef USE_GLES_OVER_GL -#ifdef GL_EXT_shader_texture_lod -#extension GL_EXT_shader_texture_lod : enable -#define texture2DLod(img, coord, lod) texture2DLodEXT(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCubeLodEXT(img, coord, lod) -#endif -#endif // !USE_GLES_OVER_GL - -#ifdef GL_ARB_shader_texture_lod -#extension GL_ARB_shader_texture_lod : enable -#endif - -#if !defined(GL_EXT_shader_texture_lod) && !defined(GL_ARB_shader_texture_lod) -#define texture2DLod(img, coord, lod) texture2D(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCube(img, coord, lod) -#endif - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -varying vec2 uv_interp; -/* clang-format on */ -uniform sampler2D source_color; //texunit:0 - -uniform float lod; -uniform vec2 pixel_size; - -#if defined(GLOW_GAUSSIAN_HORIZONTAL) || defined(GLOW_GAUSSIAN_VERTICAL) - -uniform float glow_strength; - -#endif - -#if defined(DOF_FAR_BLUR) || defined(DOF_NEAR_BLUR) - -#ifdef USE_GLES_OVER_GL -#ifdef DOF_QUALITY_LOW -const int dof_kernel_size = 5; -const int dof_kernel_from = 2; -const float dof_kernel[5] = float[](0.153388, 0.221461, 0.250301, 0.221461, 0.153388); -#endif - -#ifdef DOF_QUALITY_MEDIUM -const int dof_kernel_size = 11; -const int dof_kernel_from = 5; -const float dof_kernel[11] = float[](0.055037, 0.072806, 0.090506, 0.105726, 0.116061, 0.119726, 0.116061, 0.105726, 0.090506, 0.072806, 0.055037); - -#endif - -#ifdef DOF_QUALITY_HIGH -const int dof_kernel_size = 21; -const int dof_kernel_from = 10; -const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.046421, 0.050582, 0.054261, 0.057307, 0.059587, 0.060998, 0.061476, 0.060998, 0.059587, 0.057307, 0.054261, 0.050582, 0.046421, 0.041944, 0.037311, 0.032676, 0.028174); -#endif -#endif - -uniform sampler2D dof_source_depth; //texunit:1 -uniform float dof_begin; -uniform float dof_end; -uniform vec2 dof_dir; -uniform float dof_radius; - -#endif - -#ifdef GLOW_FIRST_PASS - -uniform highp float luminance_cap; - -uniform float glow_bloom; -uniform float glow_hdr_threshold; -uniform float glow_hdr_scale; - -#endif - -uniform float camera_z_far; -uniform float camera_z_near; - -void main() { - -#ifdef GLOW_GAUSSIAN_HORIZONTAL - vec2 pix_size = pixel_size; - pix_size *= 0.5; //reading from larger buffer, so use more samples - vec4 color = texture2DLod(source_color, uv_interp + vec2(0.0, 0.0) * pix_size, lod) * 0.174938; - color += texture2DLod(source_color, uv_interp + vec2(1.0, 0.0) * pix_size, lod) * 0.165569; - color += texture2DLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.140367; - color += texture2DLod(source_color, uv_interp + vec2(3.0, 0.0) * pix_size, lod) * 0.106595; - color += texture2DLod(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size, lod) * 0.165569; - color += texture2DLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.140367; - color += texture2DLod(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size, lod) * 0.106595; - color *= glow_strength; - gl_FragColor = color; -#endif - -#ifdef GLOW_GAUSSIAN_VERTICAL - vec4 color = texture2DLod(source_color, uv_interp + vec2(0.0, 0.0) * pixel_size, lod) * 0.288713; - color += texture2DLod(source_color, uv_interp + vec2(0.0, 1.0) * pixel_size, lod) * 0.233062; - color += texture2DLod(source_color, uv_interp + vec2(0.0, 2.0) * pixel_size, lod) * 0.122581; - color += texture2DLod(source_color, uv_interp + vec2(0.0, -1.0) * pixel_size, lod) * 0.233062; - color += texture2DLod(source_color, uv_interp + vec2(0.0, -2.0) * pixel_size, lod) * 0.122581; - color *= glow_strength; - gl_FragColor = color; -#endif - -#ifndef USE_GLES_OVER_GL -#if defined(DOF_FAR_BLUR) || defined(DOF_NEAR_BLUR) - -#ifdef DOF_QUALITY_LOW - const int dof_kernel_size = 5; - const int dof_kernel_from = 2; - float dof_kernel[5]; - dof_kernel[0] = 0.153388; - dof_kernel[1] = 0.221461; - dof_kernel[2] = 0.250301; - dof_kernel[3] = 0.221461; - dof_kernel[4] = 0.153388; -#endif - -#ifdef DOF_QUALITY_MEDIUM - const int dof_kernel_size = 11; - const int dof_kernel_from = 5; - float dof_kernel[11]; - dof_kernel[0] = 0.055037; - dof_kernel[1] = 0.072806; - dof_kernel[2] = 0.090506; - dof_kernel[3] = 0.105726; - dof_kernel[4] = 0.116061; - dof_kernel[5] = 0.119726; - dof_kernel[6] = 0.116061; - dof_kernel[7] = 0.105726; - dof_kernel[8] = 0.090506; - dof_kernel[9] = 0.072806; - dof_kernel[10] = 0.055037; -#endif - -#ifdef DOF_QUALITY_HIGH - const int dof_kernel_size = 21; - const int dof_kernel_from = 10; - float dof_kernel[21]; - dof_kernel[0] = 0.028174; - dof_kernel[1] = 0.032676; - dof_kernel[2] = 0.037311; - dof_kernel[3] = 0.041944; - dof_kernel[4] = 0.046421; - dof_kernel[5] = 0.050582; - dof_kernel[6] = 0.054261; - dof_kernel[7] = 0.057307; - dof_kernel[8] = 0.059587; - dof_kernel[9] = 0.060998; - dof_kernel[10] = 0.061476; - dof_kernel[11] = 0.060998; - dof_kernel[12] = 0.059587; - dof_kernel[13] = 0.057307; - dof_kernel[14] = 0.054261; - dof_kernel[15] = 0.050582; - dof_kernel[16] = 0.046421; - dof_kernel[17] = 0.041944; - dof_kernel[18] = 0.037311; - dof_kernel[19] = 0.032676; - dof_kernel[20] = 0.028174; -#endif -#endif -#endif //!USE_GLES_OVER_GL - -#ifdef DOF_FAR_BLUR - - vec4 color_accum = vec4(0.0); - - float depth = texture2DLod(dof_source_depth, uv_interp, 0.0).r; - depth = depth * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - depth = ((depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near)); -#endif - - float amount = smoothstep(dof_begin, dof_end, depth); - float k_accum = 0.0; - - for (int i = 0; i < dof_kernel_size; i++) { - - int int_ofs = i - dof_kernel_from; - vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * amount * dof_radius; - - float tap_k = dof_kernel[i]; - - float tap_depth = texture2D(dof_source_depth, tap_uv, 0.0).r; - tap_depth = tap_depth * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near)); -#endif - float tap_amount = int_ofs == 0 ? 1.0 : smoothstep(dof_begin, dof_end, tap_depth); - tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect - - vec4 tap_color = texture2DLod(source_color, tap_uv, 0.0) * tap_k; - - k_accum += tap_k * tap_amount; - color_accum += tap_color * tap_amount; - } - - if (k_accum > 0.0) { - color_accum /= k_accum; - } - - gl_FragColor = color_accum; ///k_accum; - -#endif - -#ifdef DOF_NEAR_BLUR - - vec4 color_accum = vec4(0.0); - - float max_accum = 0.0; - - for (int i = 0; i < dof_kernel_size; i++) { - - int int_ofs = i - dof_kernel_from; - vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * dof_radius; - float ofs_influence = max(0.0, 1.0 - abs(float(int_ofs)) / float(dof_kernel_from)); - - float tap_k = dof_kernel[i]; - - vec4 tap_color = texture2DLod(source_color, tap_uv, 0.0); - - float tap_depth = texture2D(dof_source_depth, tap_uv, 0.0).r; - tap_depth = tap_depth * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near)); -#endif - float tap_amount = 1.0 - smoothstep(dof_end, dof_begin, tap_depth); - tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect - -#ifdef DOF_NEAR_FIRST_TAP - - tap_color.a = 1.0 - smoothstep(dof_end, dof_begin, tap_depth); - -#endif - - max_accum = max(max_accum, tap_amount * ofs_influence); - - color_accum += tap_color * tap_k; - } - - color_accum.a = max(color_accum.a, sqrt(max_accum)); - - gl_FragColor = color_accum; - -#endif - -#ifdef GLOW_FIRST_PASS - - float luminance = max(gl_FragColor.r, max(gl_FragColor.g, gl_FragColor.b)); - float feedback = max(smoothstep(glow_hdr_threshold, glow_hdr_threshold + glow_hdr_scale, luminance), glow_bloom); - - gl_FragColor = min(gl_FragColor * feedback, vec4(luminance_cap)); - -#endif -} diff --git a/drivers/gles2/shaders/exposure.glsl b/drivers/gles2/shaders/exposure.glsl deleted file mode 100644 index 759adcda06..0000000000 --- a/drivers/gles2/shaders/exposure.glsl +++ /dev/null @@ -1,88 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ - -void main() { - - gl_Position = vertex_attrib; -} - -/* clang-format off */ -[fragment] - -uniform highp sampler2D source_exposure; //texunit:0 -/* clang-format on */ - -#ifdef EXPOSURE_BEGIN - -uniform highp ivec2 source_render_size; -uniform highp ivec2 target_size; - -#endif - -#ifdef EXPOSURE_END - -uniform highp sampler2D prev_exposure; //texunit:1 -uniform highp float exposure_adjust; -uniform highp float min_luminance; -uniform highp float max_luminance; - -#endif - -layout(location = 0) out highp float exposure; - -void main() { - -#ifdef EXPOSURE_BEGIN - - ivec2 src_pos = ivec2(gl_FragCoord.xy) * source_render_size / target_size; - -#if 1 - //more precise and expensive, but less jittery - ivec2 next_pos = ivec2(gl_FragCoord.xy + ivec2(1)) * source_render_size / target_size; - next_pos = max(next_pos, src_pos + ivec2(1)); //so it at least reads one pixel - highp vec3 source_color = vec3(0.0); - for (int i = src_pos.x; i < next_pos.x; i++) { - for (int j = src_pos.y; j < next_pos.y; j++) { - source_color += texelFetch(source_exposure, ivec2(i, j), 0).rgb; - } - } - - source_color /= float((next_pos.x - src_pos.x) * (next_pos.y - src_pos.y)); -#else - highp vec3 source_color = texelFetch(source_exposure, src_pos, 0).rgb; - -#endif - - exposure = max(source_color.r, max(source_color.g, source_color.b)); - -#else - - ivec2 coord = ivec2(gl_FragCoord.xy); - exposure = texelFetch(source_exposure, coord * 3 + ivec2(0, 0), 0).r; - exposure += texelFetch(source_exposure, coord * 3 + ivec2(1, 0), 0).r; - exposure += texelFetch(source_exposure, coord * 3 + ivec2(2, 0), 0).r; - exposure += texelFetch(source_exposure, coord * 3 + ivec2(0, 1), 0).r; - exposure += texelFetch(source_exposure, coord * 3 + ivec2(1, 1), 0).r; - exposure += texelFetch(source_exposure, coord * 3 + ivec2(2, 1), 0).r; - exposure += texelFetch(source_exposure, coord * 3 + ivec2(0, 2), 0).r; - exposure += texelFetch(source_exposure, coord * 3 + ivec2(1, 2), 0).r; - exposure += texelFetch(source_exposure, coord * 3 + ivec2(2, 2), 0).r; - exposure *= (1.0 / 9.0); - -#ifdef EXPOSURE_END - -#ifdef EXPOSURE_FORCE_SET - //will stay as is -#else - highp float prev_lum = texelFetch(prev_exposure, ivec2(0, 0), 0).r; //1 pixel previous exposure - exposure = clamp(prev_lum + (exposure - prev_lum) * exposure_adjust, min_luminance, max_luminance); - -#endif //EXPOSURE_FORCE_SET - -#endif //EXPOSURE_END - -#endif //EXPOSURE_BEGIN -} diff --git a/drivers/gles2/shaders/lens_distorted.glsl b/drivers/gles2/shaders/lens_distorted.glsl deleted file mode 100644 index f4ff80ba9a..0000000000 --- a/drivers/gles2/shaders/lens_distorted.glsl +++ /dev/null @@ -1,85 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -attribute highp vec2 vertex; // attrib:0 -/* clang-format on */ - -uniform vec2 offset; -uniform vec2 scale; - -varying vec2 uv_interp; - -void main() { - - uv_interp = vertex.xy * 2.0 - 1.0; - - vec2 v = vertex.xy * scale + offset; - gl_Position = vec4(v, 0.0, 1.0); -} - -/* clang-format off */ -[fragment] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -uniform sampler2D source; //texunit:0 -/* clang-format on */ - -uniform vec2 eye_center; -uniform float k1; -uniform float k2; -uniform float upscale; -uniform float aspect_ratio; - -varying vec2 uv_interp; - -void main() { - vec2 coords = uv_interp; - vec2 offset = coords - eye_center; - - // take aspect ratio into account - offset.y /= aspect_ratio; - - // distort - vec2 offset_sq = offset * offset; - float radius_sq = offset_sq.x + offset_sq.y; - float radius_s4 = radius_sq * radius_sq; - float distortion_scale = 1.0 + (k1 * radius_sq) + (k2 * radius_s4); - offset *= distortion_scale; - - // reapply aspect ratio - offset.y *= aspect_ratio; - - // add our eye center back in - coords = offset + eye_center; - coords /= upscale; - - // and check our color - if (coords.x < -1.0 || coords.y < -1.0 || coords.x > 1.0 || coords.y > 1.0) { - gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); - } else { - coords = (coords + vec2(1.0)) / vec2(2.0); - gl_FragColor = texture2D(source, coords); - } -} diff --git a/drivers/gles2/shaders/particles.glsl b/drivers/gles2/shaders/particles.glsl deleted file mode 100644 index 5974050fc1..0000000000 --- a/drivers/gles2/shaders/particles.glsl +++ /dev/null @@ -1,266 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 color; -/* clang-format on */ -layout(location = 1) in highp vec4 velocity_active; -layout(location = 2) in highp vec4 custom; -layout(location = 3) in highp vec4 xform_1; -layout(location = 4) in highp vec4 xform_2; -layout(location = 5) in highp vec4 xform_3; - -struct Attractor { - - vec3 pos; - vec3 dir; - float radius; - float eat_radius; - float strength; - float attenuation; -}; - -#define MAX_ATTRACTORS 64 - -uniform bool emitting; -uniform float system_phase; -uniform float prev_system_phase; -uniform int total_particles; -uniform float explosiveness; -uniform float randomness; -uniform float time; -uniform float delta; - -uniform int attractor_count; -uniform Attractor attractors[MAX_ATTRACTORS]; -uniform bool clear; -uniform uint cycle; -uniform float lifetime; -uniform mat4 emission_transform; -uniform uint random_seed; - -out highp vec4 out_color; //tfb: -out highp vec4 out_velocity_active; //tfb: -out highp vec4 out_custom; //tfb: -out highp vec4 out_xform_1; //tfb: -out highp vec4 out_xform_2; //tfb: -out highp vec4 out_xform_3; //tfb: - -#if defined(USE_MATERIAL) - -/* clang-format off */ -layout(std140) uniform UniformData { //ubo:0 - -MATERIAL_UNIFORMS - -}; -/* clang-format on */ - -#endif - -/* clang-format off */ - -VERTEX_SHADER_GLOBALS - -/* clang-format on */ - -uint hash(uint x) { - - x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b); - x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b); - x = (x >> uint(16)) ^ x; - return x; -} - -void main() { - -#ifdef PARTICLES_COPY - - out_color = color; - out_velocity_active = velocity_active; - out_custom = custom; - out_xform_1 = xform_1; - out_xform_2 = xform_2; - out_xform_3 = xform_3; - -#else - - bool apply_forces = true; - bool apply_velocity = true; - float local_delta = delta; - - float mass = 1.0; - - float restart_phase = float(gl_VertexID) / float(total_particles); - - if (randomness > 0.0) { - uint seed = cycle; - if (restart_phase >= system_phase) { - seed -= uint(1); - } - seed *= uint(total_particles); - seed += uint(gl_VertexID); - float random = float(hash(seed) % uint(65536)) / 65536.0; - restart_phase += randomness * random * 1.0 / float(total_particles); - } - - restart_phase *= (1.0 - explosiveness); - bool restart = false; - bool shader_active = velocity_active.a > 0.5; - - if (system_phase > prev_system_phase) { - // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed - - if (restart_phase >= prev_system_phase && restart_phase < system_phase) { - restart = true; -#ifdef USE_FRACTIONAL_DELTA - local_delta = (system_phase - restart_phase) * lifetime; -#endif - } - - } else { - if (restart_phase >= prev_system_phase) { - restart = true; -#ifdef USE_FRACTIONAL_DELTA - local_delta = (1.0 - restart_phase + system_phase) * lifetime; -#endif - } else if (restart_phase < system_phase) { - restart = true; -#ifdef USE_FRACTIONAL_DELTA - local_delta = (system_phase - restart_phase) * lifetime; -#endif - } - } - - uint current_cycle = cycle; - - if (system_phase < restart_phase) { - current_cycle -= uint(1); - } - - uint particle_number = current_cycle * uint(total_particles) + uint(gl_VertexID); - int index = int(gl_VertexID); - - if (restart) { - shader_active = emitting; - } - - mat4 xform; - -#if defined(ENABLE_KEEP_DATA) - if (clear) { -#else - if (clear || restart) { -#endif - out_color = vec4(1.0); - out_velocity_active = vec4(0.0); - out_custom = vec4(0.0); - if (!restart) - shader_active = false; - - xform = mat4( - vec4(1.0, 0.0, 0.0, 0.0), - vec4(0.0, 1.0, 0.0, 0.0), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(0.0, 0.0, 0.0, 1.0)); - } else { - out_color = color; - out_velocity_active = velocity_active; - out_custom = custom; - xform = transpose(mat4(xform_1, xform_2, xform_3, vec4(vec3(0.0), 1.0))); - } - - if (shader_active) { - //execute shader - - { - /* clang-format off */ - -VERTEX_SHADER_CODE - - /* clang-format on */ - } - -#if !defined(DISABLE_FORCE) - - if (false) { - - vec3 force = vec3(0.0); - for (int i = 0; i < attractor_count; i++) { - - vec3 rel_vec = xform[3].xyz - attractors[i].pos; - float dist = length(rel_vec); - if (attractors[i].radius < dist) - continue; - if (attractors[i].eat_radius > 0.0 && attractors[i].eat_radius > dist) { - out_velocity_active.a = 0.0; - } - - rel_vec = normalize(rel_vec); - - float attenuation = pow(dist / attractors[i].radius, attractors[i].attenuation); - - if (attractors[i].dir == vec3(0.0)) { - //towards center - force += attractors[i].strength * rel_vec * attenuation * mass; - } else { - force += attractors[i].strength * attractors[i].dir * attenuation * mass; - } - } - - out_velocity_active.xyz += force * local_delta; - } -#endif - -#if !defined(DISABLE_VELOCITY) - - if (true) { - - xform[3].xyz += out_velocity_active.xyz * local_delta; - } -#endif - } else { - xform = mat4(0.0); - } - - xform = transpose(xform); - - out_velocity_active.a = mix(0.0, 1.0, shader_active); - - out_xform_1 = xform[0]; - out_xform_2 = xform[1]; - out_xform_3 = xform[2]; - -#endif //PARTICLES_COPY -} - -/* clang-format off */ -[fragment] - -//any code here is never executed, stuff is filled just so it works - -#if defined(USE_MATERIAL) - -layout(std140) uniform UniformData { - -MATERIAL_UNIFORMS - -}; - -#endif - -FRAGMENT_SHADER_GLOBALS - -void main() { - { - -LIGHT_SHADER_CODE - - } - - { - -FRAGMENT_SHADER_CODE - - } -} -/* clang-format on */ diff --git a/drivers/gles2/shaders/resolve.glsl b/drivers/gles2/shaders/resolve.glsl deleted file mode 100644 index 5c6f5d6561..0000000000 --- a/drivers/gles2/shaders/resolve.glsl +++ /dev/null @@ -1,44 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ -layout(location = 4) in vec2 uv_in; - -out vec2 uv_interp; - -void main() { - - uv_interp = uv_in; - gl_Position = vertex_attrib; -} - -/* clang-format off */ -[fragment] - -#if !defined(GLES_OVER_GL) -precision mediump float; -#endif - -in vec2 uv_interp; -/* clang-format on */ -uniform sampler2D source_specular; //texunit:0 -uniform sampler2D source_ssr; //texunit:1 - -uniform vec2 pixel_size; - -in vec2 uv2_interp; - -layout(location = 0) out vec4 frag_color; - -void main() { - - vec4 specular = texture(source_specular, uv_interp); - -#ifdef USE_SSR - vec4 ssr = textureLod(source_ssr, uv_interp, 0.0); - specular.rgb = mix(specular.rgb, ssr.rgb * specular.a, ssr.a); -#endif - - frag_color = vec4(specular.rgb, 1.0); -} diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl deleted file mode 100644 index 84aadcbbc3..0000000000 --- a/drivers/gles2/shaders/scene.glsl +++ /dev/null @@ -1,2210 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -#ifndef USE_GLES_OVER_GL -#extension GL_OES_texture_3D : enable -#else -#extension GL_EXT_texture_array : enable -#endif - -/* clang-format on */ -#include "stdlib.glsl" -/* clang-format off */ - -#define SHADER_IS_SRGB true - -#define M_PI 3.14159265359 - - -// -// attributes -// - -attribute highp vec4 vertex_attrib; // attrib:0 -/* clang-format on */ -attribute vec3 normal_attrib; // attrib:1 - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) -attribute vec4 tangent_attrib; // attrib:2 -#endif - -#if defined(ENABLE_COLOR_INTERP) -attribute vec4 color_attrib; // attrib:3 -#endif - -#if defined(ENABLE_UV_INTERP) -attribute vec2 uv_attrib; // attrib:4 -#endif - -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) -attribute vec2 uv2_attrib; // attrib:5 -#endif - -#ifdef USE_SKELETON - -#ifdef USE_SKELETON_SOFTWARE - -attribute highp vec4 bone_transform_row_0; // attrib:13 -attribute highp vec4 bone_transform_row_1; // attrib:14 -attribute highp vec4 bone_transform_row_2; // attrib:15 - -#else - -attribute vec4 bone_ids; // attrib:6 -attribute highp vec4 bone_weights; // attrib:7 - -uniform highp sampler2D bone_transforms; // texunit:-1 -uniform ivec2 skeleton_texture_size; - -#endif - -#endif - -#ifdef USE_INSTANCING - -attribute highp vec4 instance_xform_row_0; // attrib:8 -attribute highp vec4 instance_xform_row_1; // attrib:9 -attribute highp vec4 instance_xform_row_2; // attrib:10 - -attribute highp vec4 instance_color; // attrib:11 -attribute highp vec4 instance_custom_data; // attrib:12 - -#endif - -// -// uniforms -// - -uniform highp mat4 camera_matrix; -uniform highp mat4 camera_inverse_matrix; -uniform highp mat4 projection_matrix; -uniform highp mat4 projection_inverse_matrix; - -uniform highp mat4 world_transform; - -uniform highp float time; - -uniform highp vec2 viewport_size; - -#ifdef RENDER_DEPTH -uniform float light_bias; -uniform float light_normal_bias; -#endif - -// -// varyings -// - -#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) -varying highp vec4 position_interp; -#endif - -varying highp vec3 vertex_interp; -varying vec3 normal_interp; - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) -varying vec3 tangent_interp; -varying vec3 binormal_interp; -#endif - -#if defined(ENABLE_COLOR_INTERP) -varying vec4 color_interp; -#endif - -#if defined(ENABLE_UV_INTERP) -varying vec2 uv_interp; -#endif - -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) -varying vec2 uv2_interp; -#endif - -/* clang-format off */ - -VERTEX_SHADER_GLOBALS - -/* clang-format on */ - -#ifdef RENDER_DEPTH_DUAL_PARABOLOID - -varying highp float dp_clip; -uniform highp float shadow_dual_paraboloid_render_zfar; -uniform highp float shadow_dual_paraboloid_render_side; - -#endif - -#if defined(USE_SHADOW) && defined(USE_LIGHTING) - -uniform highp mat4 light_shadow_matrix; -varying highp vec4 shadow_coord; - -#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) -uniform highp mat4 light_shadow_matrix2; -varying highp vec4 shadow_coord2; -#endif - -#if defined(LIGHT_USE_PSSM4) - -uniform highp mat4 light_shadow_matrix3; -uniform highp mat4 light_shadow_matrix4; -varying highp vec4 shadow_coord3; -varying highp vec4 shadow_coord4; - -#endif - -#endif - -#if defined(USE_VERTEX_LIGHTING) && defined(USE_LIGHTING) - -varying highp vec3 diffuse_interp; -varying highp vec3 specular_interp; - -// general for all lights -uniform highp vec4 light_color; -uniform highp vec4 shadow_color; -uniform highp float light_specular; - -// directional -uniform highp vec3 light_direction; - -// omni -uniform highp vec3 light_position; - -uniform highp float light_range; -uniform highp float light_attenuation; - -// spot -uniform highp float light_spot_attenuation; -uniform highp float light_spot_range; -uniform highp float light_spot_angle; - -void light_compute( - vec3 N, - vec3 L, - vec3 V, - vec3 light_color, - vec3 attenuation, - float roughness) { - -//this makes lights behave closer to linear, but then addition of lights looks bad -//better left disabled - -//#define SRGB_APPROX(m_var) m_var = pow(m_var,0.4545454545); -/* -#define SRGB_APPROX(m_var) {\ - float S1 = sqrt(m_var);\ - float S2 = sqrt(S1);\ - float S3 = sqrt(S2);\ - m_var = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.0225411470 * m_var;\ - } -*/ -#define SRGB_APPROX(m_var) - - float NdotL = dot(N, L); - float cNdotL = max(NdotL, 0.0); // clamped NdotL - float NdotV = dot(N, V); - float cNdotV = max(NdotV, 0.0); - -#if defined(DIFFUSE_OREN_NAYAR) - vec3 diffuse_brdf_NL; -#else - float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance -#endif - -#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); - } -#else - // lambert by default for everything else - diffuse_brdf_NL = cNdotL * (1.0 / M_PI); -#endif - - SRGB_APPROX(diffuse_brdf_NL) - - diffuse_interp += light_color * diffuse_brdf_NL * attenuation; - - if (roughness > 0.0) { - - // D - float specular_brdf_NL = 0.0; - -#if !defined(SPECULAR_DISABLED) - //normalized blinn always unless disabled - vec3 H = normalize(V + L); - float cNdotH = max(dot(N, H), 0.0); - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float blinn = pow(cNdotH, shininess) * cNdotL; - blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - specular_brdf_NL = blinn; -#endif - - SRGB_APPROX(specular_brdf_NL) - specular_interp += specular_brdf_NL * light_color * attenuation * (1.0 / M_PI); - } -} - -#endif - -#ifdef USE_VERTEX_LIGHTING - -#ifdef USE_REFLECTION_PROBE1 - -uniform highp mat4 refprobe1_local_matrix; -varying mediump vec4 refprobe1_reflection_normal_blend; -uniform highp vec3 refprobe1_box_extents; - -#ifndef USE_LIGHTMAP -varying mediump vec3 refprobe1_ambient_normal; -#endif - -#endif //reflection probe1 - -#ifdef USE_REFLECTION_PROBE2 - -uniform highp mat4 refprobe2_local_matrix; -varying mediump vec4 refprobe2_reflection_normal_blend; -uniform highp vec3 refprobe2_box_extents; - -#ifndef USE_LIGHTMAP -varying mediump vec3 refprobe2_ambient_normal; -#endif - -#endif //reflection probe2 - -#endif //vertex lighting for refprobes - -#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) - -varying vec4 fog_interp; - -uniform mediump vec4 fog_color_base; -#ifdef LIGHT_MODE_DIRECTIONAL -uniform mediump vec4 fog_sun_color_amount; -#endif - -uniform bool fog_transmit_enabled; -uniform mediump float fog_transmit_curve; - -#ifdef FOG_DEPTH_ENABLED -uniform highp float fog_depth_begin; -uniform mediump float fog_depth_curve; -uniform mediump float fog_max_distance; -#endif - -#ifdef FOG_HEIGHT_ENABLED -uniform highp float fog_height_min; -uniform highp float fog_height_max; -uniform mediump float fog_height_curve; -#endif - -#endif //fog - -void main() { - - highp vec4 vertex = vertex_attrib; - - mat4 world_matrix = world_transform; - -#ifdef USE_INSTANCING - { - highp mat4 m = mat4( - instance_xform_row_0, - instance_xform_row_1, - instance_xform_row_2, - vec4(0.0, 0.0, 0.0, 1.0)); - world_matrix = world_matrix * transpose(m); - } - -#endif - - vec3 normal = normal_attrib; - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - vec3 tangent = tangent_attrib.xyz; - float binormalf = tangent_attrib.a; - vec3 binormal = normalize(cross(normal, tangent) * binormalf); -#endif - -#if defined(ENABLE_COLOR_INTERP) - color_interp = color_attrib; -#ifdef USE_INSTANCING - color_interp *= instance_color; -#endif -#endif - -#if defined(ENABLE_UV_INTERP) - uv_interp = uv_attrib; -#endif - -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) - uv2_interp = uv2_attrib; -#endif - -#if defined(OVERRIDE_POSITION) - highp vec4 position; -#endif - -#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) - vertex = world_matrix * vertex; - normal = normalize((world_matrix * vec4(normal, 0.0)).xyz); -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - - tangent = normalize((world_matrix * vec4(tangent, 0.0)).xyz); - binormal = normalize((world_matrix * vec4(binormal, 0.0)).xyz); -#endif -#endif - -#ifdef USE_SKELETON - - highp mat4 bone_transform = mat4(0.0); - -#ifdef USE_SKELETON_SOFTWARE - // passing the transform as attributes - - bone_transform[0] = vec4(bone_transform_row_0.x, bone_transform_row_1.x, bone_transform_row_2.x, 0.0); - bone_transform[1] = vec4(bone_transform_row_0.y, bone_transform_row_1.y, bone_transform_row_2.y, 0.0); - bone_transform[2] = vec4(bone_transform_row_0.z, bone_transform_row_1.z, bone_transform_row_2.z, 0.0); - bone_transform[3] = vec4(bone_transform_row_0.w, bone_transform_row_1.w, bone_transform_row_2.w, 1.0); - -#else - // look up transform from the "pose texture" - { - - for (int i = 0; i < 4; i++) { - ivec2 tex_ofs = ivec2(int(bone_ids[i]) * 3, 0); - - highp mat4 b = mat4( - texel2DFetch(bone_transforms, skeleton_texture_size, tex_ofs + ivec2(0, 0)), - texel2DFetch(bone_transforms, skeleton_texture_size, tex_ofs + ivec2(1, 0)), - texel2DFetch(bone_transforms, skeleton_texture_size, tex_ofs + ivec2(2, 0)), - vec4(0.0, 0.0, 0.0, 1.0)); - - bone_transform += transpose(b) * bone_weights[i]; - } - } - -#endif - - world_matrix = world_matrix * bone_transform; - -#endif - -#ifdef USE_INSTANCING - vec4 instance_custom = instance_custom_data; -#else - vec4 instance_custom = vec4(0.0); - -#endif - - mat4 local_projection_matrix = projection_matrix; - - mat4 modelview = camera_inverse_matrix * world_matrix; - float roughness = 1.0; - -#define projection_matrix local_projection_matrix -#define world_transform world_matrix - - float point_size = 1.0; - - { - /* clang-format off */ - -VERTEX_SHADER_CODE - - /* clang-format on */ - } - - gl_PointSize = point_size; - vec4 outvec = vertex; - - // use local coordinates -#if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED) - vertex = modelview * vertex; - normal = normalize((modelview * vec4(normal, 0.0)).xyz); - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - tangent = normalize((modelview * vec4(tangent, 0.0)).xyz); - binormal = normalize((modelview * vec4(binormal, 0.0)).xyz); -#endif -#endif - -#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) - vertex = camera_inverse_matrix * vertex; - normal = normalize((camera_inverse_matrix * vec4(normal, 0.0)).xyz); -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - tangent = normalize((camera_inverse_matrix * vec4(tangent, 0.0)).xyz); - binormal = normalize((camera_inverse_matrix * vec4(binormal, 0.0)).xyz); -#endif -#endif - - vertex_interp = vertex.xyz; - normal_interp = normal; - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - tangent_interp = tangent; - binormal_interp = binormal; -#endif - -#ifdef RENDER_DEPTH - -#ifdef RENDER_DEPTH_DUAL_PARABOLOID - - vertex_interp.z *= shadow_dual_paraboloid_render_side; - normal_interp.z *= shadow_dual_paraboloid_render_side; - - dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias - - //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges - - highp vec3 vtx = vertex_interp + normalize(vertex_interp) * light_bias; - highp float distance = length(vtx); - vtx = normalize(vtx); - vtx.xy /= 1.0 - vtx.z; - vtx.z = (distance / shadow_dual_paraboloid_render_zfar); - vtx.z = vtx.z * 2.0 - 1.0; - - vertex_interp = vtx; - -#else - float z_ofs = light_bias; - z_ofs += (1.0 - abs(normal_interp.z)) * light_normal_bias; - - vertex_interp.z -= z_ofs; -#endif //dual parabolloid - -#endif //depth - -//vertex lighting -#if defined(USE_VERTEX_LIGHTING) && defined(USE_LIGHTING) - //vertex shaded version of lighting (more limited) - vec3 L; - vec3 light_att; - -#ifdef LIGHT_MODE_OMNI - vec3 light_vec = light_position - vertex_interp; - float light_length = length(light_vec); - - float normalized_distance = light_length / light_range; - - if (normalized_distance < 1.0) { - - float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation); - - vec3 attenuation = vec3(omni_attenuation); - light_att = vec3(omni_attenuation); - } else { - light_att = vec3(0.0); - } - - L = normalize(light_vec); - -#endif - -#ifdef LIGHT_MODE_SPOT - - vec3 light_rel_vec = light_position - vertex_interp; - float light_length = length(light_rel_vec); - float normalized_distance = light_length / light_range; - - if (normalized_distance < 1.0) { - - float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation); - vec3 spot_dir = light_direction; - - float spot_cutoff = light_spot_angle; - - float angle = dot(-normalize(light_rel_vec), spot_dir); - - if (angle > spot_cutoff) { - - float scos = max(angle, spot_cutoff); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); - - spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); - - light_att = vec3(spot_attenuation); - } else { - light_att = vec3(0.0); - } - } else { - light_att = vec3(0.0); - } - - L = normalize(light_rel_vec); - -#endif - -#ifdef LIGHT_MODE_DIRECTIONAL - vec3 light_vec = -light_direction; - light_att = vec3(1.0); //no base attenuation - L = normalize(light_vec); -#endif - - diffuse_interp = vec3(0.0); - specular_interp = vec3(0.0); - light_compute(normal_interp, L, -normalize(vertex_interp), light_color.rgb, light_att, roughness); - -#endif - -//shadows (for both vertex and fragment) -#if defined(USE_SHADOW) && defined(USE_LIGHTING) - - vec4 vi4 = vec4(vertex_interp, 1.0); - shadow_coord = light_shadow_matrix * vi4; - -#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) - shadow_coord2 = light_shadow_matrix2 * vi4; -#endif - -#if defined(LIGHT_USE_PSSM4) - shadow_coord3 = light_shadow_matrix3 * vi4; - shadow_coord4 = light_shadow_matrix4 * vi4; - -#endif - -#endif //use shadow and use lighting - -#ifdef USE_VERTEX_LIGHTING - -#ifdef USE_REFLECTION_PROBE1 - { - vec3 ref_normal = normalize(reflect(vertex_interp, normal_interp)); - vec3 local_pos = (refprobe1_local_matrix * vec4(vertex_interp, 1.0)).xyz; - vec3 inner_pos = abs(local_pos / refprobe1_box_extents); - float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - - { - vec3 local_ref_vec = (refprobe1_local_matrix * vec4(ref_normal, 0.0)).xyz; - refprobe1_reflection_normal_blend.xyz = local_ref_vec; - refprobe1_reflection_normal_blend.a = blend; - } -#ifndef USE_LIGHTMAP - - refprobe1_ambient_normal = (refprobe1_local_matrix * vec4(normal_interp, 0.0)).xyz; -#endif - } - -#endif //USE_REFLECTION_PROBE1 - -#ifdef USE_REFLECTION_PROBE2 - { - vec3 ref_normal = normalize(reflect(vertex_interp, normal_interp)); - vec3 local_pos = (refprobe2_local_matrix * vec4(vertex_interp, 1.0)).xyz; - vec3 inner_pos = abs(local_pos / refprobe2_box_extents); - float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - - { - vec3 local_ref_vec = (refprobe2_local_matrix * vec4(ref_normal, 0.0)).xyz; - refprobe2_reflection_normal_blend.xyz = local_ref_vec; - refprobe2_reflection_normal_blend.a = blend; - } -#ifndef USE_LIGHTMAP - - refprobe2_ambient_normal = (refprobe2_local_matrix * vec4(normal_interp, 0.0)).xyz; -#endif - } - -#endif //USE_REFLECTION_PROBE2 - -#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) - - float fog_amount = 0.0; - -#ifdef LIGHT_MODE_DIRECTIONAL - - vec3 fog_color = mix(fog_color_base.rgb, fog_sun_color_amount.rgb, fog_sun_color_amount.a * pow(max(dot(normalize(vertex_interp), light_direction), 0.0), 8.0)); -#else - vec3 fog_color = fog_color_base.rgb; -#endif - -#ifdef FOG_DEPTH_ENABLED - - { - - float fog_z = smoothstep(fog_depth_begin, fog_max_distance, length(vertex)); - - fog_amount = pow(fog_z, fog_depth_curve) * fog_color_base.a; - } -#endif - -#ifdef FOG_HEIGHT_ENABLED - { - float y = (camera_matrix * vec4(vertex_interp, 1.0)).y; - fog_amount = max(fog_amount, pow(smoothstep(fog_height_min, fog_height_max, y), fog_height_curve)); - } -#endif - fog_interp = vec4(fog_color, fog_amount); - -#endif //fog - -#endif //use vertex lighting - -#if defined(OVERRIDE_POSITION) - gl_Position = position; -#else - gl_Position = projection_matrix * vec4(vertex_interp, 1.0); -#endif - -#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) - position_interp = gl_Position; -#endif -} - -/* clang-format off */ -[fragment] - -#ifndef USE_GLES_OVER_GL -#extension GL_OES_texture_3D : enable -#else -#extension GL_EXT_texture_array : enable -#endif - -// texture2DLodEXT and textureCubeLodEXT are fragment shader specific. -// Do not copy these defines in the vertex section. -#ifndef USE_GLES_OVER_GL -#ifdef GL_EXT_shader_texture_lod -#extension GL_EXT_shader_texture_lod : enable -#define texture2DLod(img, coord, lod) texture2DLodEXT(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCubeLodEXT(img, coord, lod) -#endif -#endif // !USE_GLES_OVER_GL - -#ifdef GL_ARB_shader_texture_lod -#extension GL_ARB_shader_texture_lod : enable -#endif - -#if !defined(GL_EXT_shader_texture_lod) && !defined(GL_ARB_shader_texture_lod) -#define texture2DLod(img, coord, lod) texture2D(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCube(img, coord, lod) -#endif - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -#include "stdlib.glsl" - -#define M_PI 3.14159265359 -#define SHADER_IS_SRGB true - -// -// uniforms -// - -uniform highp mat4 camera_matrix; -/* clang-format on */ -uniform highp mat4 camera_inverse_matrix; -uniform highp mat4 projection_matrix; -uniform highp mat4 projection_inverse_matrix; - -uniform highp mat4 world_transform; - -uniform highp float time; - -uniform highp vec2 viewport_size; - -#if defined(SCREEN_UV_USED) -uniform vec2 screen_pixel_size; -#endif - -#if defined(SCREEN_TEXTURE_USED) -uniform highp sampler2D screen_texture; //texunit:-4 -#endif -#if defined(DEPTH_TEXTURE_USED) -uniform highp sampler2D depth_texture; //texunit:-4 -#endif - -#ifdef USE_REFLECTION_PROBE1 - -#ifdef USE_VERTEX_LIGHTING - -varying mediump vec4 refprobe1_reflection_normal_blend; -#ifndef USE_LIGHTMAP -varying mediump vec3 refprobe1_ambient_normal; -#endif - -#else - -uniform bool refprobe1_use_box_project; -uniform highp vec3 refprobe1_box_extents; -uniform vec3 refprobe1_box_offset; -uniform highp mat4 refprobe1_local_matrix; - -#endif //use vertex lighting - -uniform bool refprobe1_exterior; - -uniform highp samplerCube reflection_probe1; //texunit:-5 - -uniform float refprobe1_intensity; -uniform vec4 refprobe1_ambient; - -#endif //USE_REFLECTION_PROBE1 - -#ifdef USE_REFLECTION_PROBE2 - -#ifdef USE_VERTEX_LIGHTING - -varying mediump vec4 refprobe2_reflection_normal_blend; -#ifndef USE_LIGHTMAP -varying mediump vec3 refprobe2_ambient_normal; -#endif - -#else - -uniform bool refprobe2_use_box_project; -uniform highp vec3 refprobe2_box_extents; -uniform vec3 refprobe2_box_offset; -uniform highp mat4 refprobe2_local_matrix; - -#endif //use vertex lighting - -uniform bool refprobe2_exterior; - -uniform highp samplerCube reflection_probe2; //texunit:-6 - -uniform float refprobe2_intensity; -uniform vec4 refprobe2_ambient; - -#endif //USE_REFLECTION_PROBE2 - -#define RADIANCE_MAX_LOD 6.0 - -#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) - -void reflection_process(samplerCube reflection_map, -#ifdef USE_VERTEX_LIGHTING - vec3 ref_normal, -#ifndef USE_LIGHTMAP - vec3 amb_normal, -#endif - float ref_blend, - -#else //no vertex lighting - vec3 normal, vec3 vertex, - mat4 local_matrix, - bool use_box_project, vec3 box_extents, vec3 box_offset, -#endif //vertex lighting - bool exterior, float intensity, vec4 ref_ambient, float roughness, vec3 ambient, vec3 skybox, inout highp vec4 reflection_accum, inout highp vec4 ambient_accum) { - - vec4 reflection; - -#ifdef USE_VERTEX_LIGHTING - - reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb; - - float blend = ref_blend; //crappier blend formula for vertex - blend *= blend; - blend = max(0.0, 1.0 - blend); - -#else //fragment lighting - - vec3 local_pos = (local_matrix * vec4(vertex, 1.0)).xyz; - - if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box - return; - } - - vec3 inner_pos = abs(local_pos / box_extents); - float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - blend = mix(length(inner_pos), blend, blend); - blend *= blend; - blend = max(0.0, 1.0 - blend); - - //reflect and make local - vec3 ref_normal = normalize(reflect(vertex, normal)); - ref_normal = (local_matrix * vec4(ref_normal, 0.0)).xyz; - - if (use_box_project) { //box project - - vec3 nrdir = normalize(ref_normal); - vec3 rbmax = (box_extents - local_pos) / nrdir; - vec3 rbmin = (-box_extents - local_pos) / nrdir; - - vec3 rbminmax = mix(rbmin, rbmax, vec3(greaterThan(nrdir, vec3(0.0, 0.0, 0.0)))); - - float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); - vec3 posonbox = local_pos + nrdir * fa; - ref_normal = posonbox - box_offset.xyz; - } - - reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb; -#endif - - if (exterior) { - reflection.rgb = mix(skybox, reflection.rgb, blend); - } - reflection.rgb *= intensity; - reflection.a = blend; - reflection.rgb *= blend; - - reflection_accum += reflection; - -#ifndef USE_LIGHTMAP - - vec4 ambient_out; -#ifndef USE_VERTEX_LIGHTING - - vec3 amb_normal = (local_matrix * vec4(normal, 0.0)).xyz; -#endif - - ambient_out.rgb = textureCubeLod(reflection_map, amb_normal, RADIANCE_MAX_LOD).rgb; - ambient_out.rgb = mix(ref_ambient.rgb, ambient_out.rgb, ref_ambient.a); - if (exterior) { - ambient_out.rgb = mix(ambient, ambient_out.rgb, blend); - } - - ambient_out.a = blend; - ambient_out.rgb *= blend; - ambient_accum += ambient_out; - -#endif -} - -#endif //use refprobe 1 or 2 - -#ifdef USE_LIGHTMAP -uniform mediump sampler2D lightmap; //texunit:-4 -uniform mediump float lightmap_energy; -#endif - -#ifdef USE_LIGHTMAP_CAPTURE -uniform mediump vec4[12] lightmap_captures; -uniform bool lightmap_capture_sky; - -#endif - -#ifdef USE_RADIANCE_MAP - -uniform samplerCube radiance_map; // texunit:-2 - -uniform mat4 radiance_inverse_xform; - -#endif - -uniform vec4 bg_color; -uniform float bg_energy; - -uniform float ambient_sky_contribution; -uniform vec4 ambient_color; -uniform float ambient_energy; - -#ifdef USE_LIGHTING - -uniform highp vec4 shadow_color; - -#ifdef USE_VERTEX_LIGHTING - -//get from vertex -varying highp vec3 diffuse_interp; -varying highp vec3 specular_interp; - -uniform highp vec3 light_direction; //may be used by fog, so leave here - -#else -//done in fragment -// general for all lights -uniform highp vec4 light_color; - -uniform highp float light_specular; - -// directional -uniform highp vec3 light_direction; -// omni -uniform highp vec3 light_position; - -uniform highp float light_attenuation; - -// spot -uniform highp float light_spot_attenuation; -uniform highp float light_spot_range; -uniform highp float light_spot_angle; -#endif - -//this is needed outside above if because dual paraboloid wants it -uniform highp float light_range; - -#ifdef USE_SHADOW - -uniform highp vec2 shadow_pixel_size; - -#if defined(LIGHT_MODE_OMNI) || defined(LIGHT_MODE_SPOT) -uniform highp sampler2D light_shadow_atlas; //texunit:-3 -#endif - -#ifdef LIGHT_MODE_DIRECTIONAL -uniform highp sampler2D light_directional_shadow; // texunit:-3 -uniform highp vec4 light_split_offsets; -#endif - -varying highp vec4 shadow_coord; - -#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) -varying highp vec4 shadow_coord2; -#endif - -#if defined(LIGHT_USE_PSSM4) - -varying highp vec4 shadow_coord3; -varying highp vec4 shadow_coord4; - -#endif - -uniform vec4 light_clamp; - -#endif // light shadow - -// directional shadow - -#endif - -// -// varyings -// - -#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) -varying highp vec4 position_interp; -#endif - -varying highp vec3 vertex_interp; -varying vec3 normal_interp; - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) -varying vec3 tangent_interp; -varying vec3 binormal_interp; -#endif - -#if defined(ENABLE_COLOR_INTERP) -varying vec4 color_interp; -#endif - -#if defined(ENABLE_UV_INTERP) -varying vec2 uv_interp; -#endif - -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) -varying vec2 uv2_interp; -#endif - -varying vec3 view_interp; - -vec3 F0(float metallic, float specular, vec3 albedo) { - float dielectric = 0.16 * specular * specular; - // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials; - // see https://google.github.io/filament/Filament.md.html - return mix(vec3(dielectric), albedo, vec3(metallic)); -} - -/* clang-format off */ - -FRAGMENT_SHADER_GLOBALS - -/* clang-format on */ - -#ifdef RENDER_DEPTH_DUAL_PARABOLOID - -varying highp float dp_clip; - -#endif - -#ifdef USE_LIGHTING - -// 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): -// -// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V) -// -// We're basically regouping this as -// -// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)] -// -// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V. -// -// The contents of the D and G (G1) functions (GGX) are taken from -// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014). -// Eqns 71-72 and 85-86 (see also Eqns 43 and 80). - -/* -float G_GGX_2cos(float cos_theta_m, float alpha) { - // Schlick's approximation - // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994) - // Eq. (19), although see Heitz (2014) the about the problems with his derivation. - // It nevertheless approximates GGX well with k = alpha/2. - float k = 0.5 * alpha; - return 0.5 / (cos_theta_m * (1.0 - k) + k); - - // float cos2 = cos_theta_m * cos_theta_m; - // float sin2 = (1.0 - cos2); - // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2)); -} -*/ - -// This approximates G_GGX_2cos(cos_theta_l, alpha) * G_GGX_2cos(cos_theta_v, alpha) -// See Filament docs, Specular G section. -float V_GGX(float cos_theta_l, float cos_theta_v, float alpha) { - return 0.5 / mix(2.0 * cos_theta_l * cos_theta_v, cos_theta_l + cos_theta_v, alpha); -} - -float D_GGX(float cos_theta_m, float alpha) { - float alpha2 = alpha * alpha; - float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m; - return alpha2 / (M_PI * d * d); -} - -/* -float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { - float cos2 = cos_theta_m * cos_theta_m; - float sin2 = (1.0 - cos2); - float s_x = alpha_x * cos_phi; - float s_y = alpha_y * sin_phi; - return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001); -} -*/ - -// This approximates G_GGX_anisotropic_2cos(cos_theta_l, ...) * G_GGX_anisotropic_2cos(cos_theta_v, ...) -// See Filament docs, Anisotropic specular BRDF section. -float V_GGX_anisotropic(float alpha_x, float alpha_y, float TdotV, float TdotL, float BdotV, float BdotL, float NdotV, float NdotL) { - float Lambda_V = NdotL * length(vec3(alpha_x * TdotV, alpha_y * BdotV, NdotV)); - float Lambda_L = NdotV * length(vec3(alpha_x * TdotL, alpha_y * BdotL, NdotL)); - return 0.5 / (Lambda_V + Lambda_L); -} - -float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi, float NdotH) { - float alpha2 = alpha_x * alpha_y; - highp vec3 v = vec3(alpha_y * cos_phi, alpha_x * sin_phi, alpha2 * NdotH); - highp float v2 = dot(v, v); - float w2 = alpha2 / v2; - float D = alpha2 * w2 * w2 * (1.0 / M_PI); - return D; - - /* float cos2 = cos_theta_m * cos_theta_m; - float sin2 = (1.0 - cos2); - float r_x = cos_phi / alpha_x; - float r_y = sin_phi / alpha_y; - float d = cos2 + sin2 * (r_x * r_x + r_y * r_y); - return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); */ -} - -float SchlickFresnel(float u) { - float m = 1.0 - u; - float m2 = m * m; - return m2 * m2 * m; // pow(m,5) -} - -float GTR1(float NdotH, float a) { - if (a >= 1.0) return 1.0 / M_PI; - float a2 = a * a; - float t = 1.0 + (a2 - 1.0) * NdotH * NdotH; - return (a2 - 1.0) / (M_PI * log(a2) * t); -} - -void light_compute( - vec3 N, - vec3 L, - vec3 V, - vec3 B, - vec3 T, - vec3 light_color, - vec3 attenuation, - vec3 diffuse_color, - vec3 transmission, - float specular_blob_intensity, - float roughness, - float metallic, - float specular, - float rim, - float rim_tint, - float clearcoat, - float clearcoat_gloss, - float anisotropy, - inout vec3 diffuse_light, - inout vec3 specular_light, - inout float alpha) { - -//this makes lights behave closer to linear, but then addition of lights looks bad -//better left disabled - -//#define SRGB_APPROX(m_var) m_var = pow(m_var,0.4545454545); -/* -#define SRGB_APPROX(m_var) {\ - float S1 = sqrt(m_var);\ - float S2 = sqrt(S1);\ - float S3 = sqrt(S2);\ - m_var = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.0225411470 * m_var;\ - } -*/ -#define SRGB_APPROX(m_var) - -#if defined(USE_LIGHT_SHADER_CODE) - // light is written by the light shader - - vec3 normal = N; - vec3 albedo = diffuse_color; - vec3 light = L; - vec3 view = V; - - /* clang-format off */ - -LIGHT_SHADER_CODE - - /* clang-format on */ - -#else - float NdotL = dot(N, L); - float cNdotL = max(NdotL, 0.0); // clamped NdotL - float NdotV = dot(N, V); - float cNdotV = max(abs(NdotV), 1e-6); - -#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) - vec3 H = normalize(V + L); -#endif - -#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) - float cNdotH = max(dot(N, H), 0.0); -#endif - -#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) - float cLdotH = max(dot(L, H), 0.0); -#endif - - if (metallic < 1.0) { -#if defined(DIFFUSE_OREN_NAYAR) - vec3 diffuse_brdf_NL; -#else - float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance -#endif - -#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); - -#elif defined(DIFFUSE_BURLEY) - - { - float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5; - float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV); - float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL); - diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; - /* - float energyBias = mix(roughness, 0.0, 0.5); - float energyFactor = mix(roughness, 1.0, 1.0 / 1.51); - float fd90 = energyBias + 2.0 * VoH * VoH * roughness; - float f0 = 1.0; - float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0); - float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0); - - diffuse_brdf_NL = lightScatter * viewScatter * energyFactor; - */ - } -#else - // lambert - diffuse_brdf_NL = cNdotL * (1.0 / M_PI); -#endif - - SRGB_APPROX(diffuse_brdf_NL) - - diffuse_light += light_color * diffuse_color * diffuse_brdf_NL * attenuation; - -#if defined(TRANSMISSION_USED) - diffuse_light += light_color * diffuse_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * transmission * attenuation; -#endif - -#if defined(LIGHT_USE_RIM) - 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; -#endif - } - - if (roughness > 0.0) { - -#if defined(SPECULAR_SCHLICK_GGX) - vec3 specular_brdf_NL = vec3(0.0); -#else - float specular_brdf_NL = 0.0; -#endif - -#if defined(SPECULAR_BLINN) - - //normalized blinn - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float blinn = pow(cNdotH, shininess) * cNdotL; - blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - specular_brdf_NL = blinn; - -#elif defined(SPECULAR_PHONG) - - vec3 R = normalize(-reflect(L, N)); - float cRdotV = max(0.0, dot(R, V)); - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float phong = pow(cRdotV, shininess); - phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - specular_brdf_NL = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); - -#elif defined(SPECULAR_TOON) - - vec3 R = normalize(-reflect(L, N)); - float RdotV = dot(R, V); - float mid = 1.0 - roughness; - mid *= mid; - specular_brdf_NL = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; - -#elif defined(SPECULAR_DISABLED) - // none.. -#elif defined(SPECULAR_SCHLICK_GGX) - // shlick+ggx as default - -#if defined(LIGHT_USE_ANISOTROPY) - float alpha_ggx = roughness * roughness; - float aspect = sqrt(1.0 - anisotropy * 0.9); - float ax = alpha_ggx / aspect; - float ay = alpha_ggx * aspect; - float XdotH = dot(T, H); - float YdotH = dot(B, H); - float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH, cNdotH); - //float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); - float G = V_GGX_anisotropic(ax, ay, dot(T, V), dot(T, L), dot(B, V), dot(B, L), cNdotV, cNdotL); - -#else - float alpha_ggx = roughness * roughness; - float D = D_GGX(cNdotH, alpha_ggx); - //float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); - float G = V_GGX(cNdotL, 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); - - specular_brdf_NL = cNdotL * D * F * G; - -#endif - - SRGB_APPROX(specular_brdf_NL) - specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; - -#if defined(LIGHT_USE_CLEARCOAT) - -#if !defined(SPECULAR_SCHLICK_GGX) - float cLdotH5 = SchlickFresnel(cLdotH); -#endif - float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); - float Fr = mix(.04, 1.0, cLdotH5); - //float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); - float Gr = V_GGX(cNdotL, cNdotV, 0.25); - - float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; - - specular_light += clearcoat_specular_brdf_NL * light_color * specular_blob_intensity * attenuation; -#endif - } - -#ifdef USE_SHADOW_TO_OPACITY - alpha = min(alpha, clamp(1.0 - length(attenuation), 0.0, 1.0)); -#endif - -#endif //defined(USE_LIGHT_SHADER_CODE) -} - -#endif -// shadows - -#ifdef USE_SHADOW - -#ifdef USE_RGBA_SHADOWS - -#define SHADOW_DEPTH(m_val) dot(m_val, vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) - -#else - -#define SHADOW_DEPTH(m_val) (m_val).r - -#endif - -#define SAMPLE_SHADOW_TEXEL(p_shadow, p_pos, p_depth) step(p_depth, SHADOW_DEPTH(texture2D(p_shadow, p_pos))) -#define SAMPLE_SHADOW_TEXEL_PROJ(p_shadow, p_pos) step(p_pos.z, SHADOW_DEPTH(texture2DProj(p_shadow, p_pos))) - -float sample_shadow(highp sampler2D shadow, highp vec4 spos) { - -#ifdef SHADOW_MODE_PCF_13 - - spos.xyz /= spos.w; - vec2 pos = spos.xy; - float depth = spos.z; - - float avg = SAMPLE_SHADOW_TEXEL(shadow, pos, depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, -shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, -shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x * 2.0, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x * 2.0, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y * 2.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y * 2.0), depth); - return avg * (1.0 / 13.0); -#endif - -#ifdef SHADOW_MODE_PCF_5 - - spos.xyz /= spos.w; - vec2 pos = spos.xy; - float depth = spos.z; - - float avg = SAMPLE_SHADOW_TEXEL(shadow, pos, depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y), depth); - return avg * (1.0 / 5.0); - -#endif - -#if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13) - - return SAMPLE_SHADOW_TEXEL_PROJ(shadow, spos); -#endif -} - -#endif - -#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) - -#if defined(USE_VERTEX_LIGHTING) - -varying vec4 fog_interp; - -#else -uniform mediump vec4 fog_color_base; -#ifdef LIGHT_MODE_DIRECTIONAL -uniform mediump vec4 fog_sun_color_amount; -#endif - -uniform bool fog_transmit_enabled; -uniform mediump float fog_transmit_curve; - -#ifdef FOG_DEPTH_ENABLED -uniform highp float fog_depth_begin; -uniform mediump float fog_depth_curve; -uniform mediump float fog_max_distance; -#endif - -#ifdef FOG_HEIGHT_ENABLED -uniform highp float fog_height_min; -uniform highp float fog_height_max; -uniform mediump float fog_height_curve; -#endif - -#endif //vertex lit -#endif //fog - -void main() { - -#ifdef RENDER_DEPTH_DUAL_PARABOLOID - - if (dp_clip > 0.0) - discard; -#endif - highp vec3 vertex = vertex_interp; - vec3 view = -normalize(vertex_interp); - vec3 albedo = vec3(1.0); - vec3 transmission = vec3(0.0); - float metallic = 0.0; - float specular = 0.5; - vec3 emission = vec3(0.0); - float roughness = 1.0; - float rim = 0.0; - float rim_tint = 0.0; - float clearcoat = 0.0; - float clearcoat_gloss = 0.0; - float anisotropy = 0.0; - vec2 anisotropy_flow = vec2(1.0, 0.0); - float sss_strength = 0.0; //unused - // gl_FragDepth is not available in GLES2, so writing to DEPTH is not converted to gl_FragDepth by Godot compiler resulting in a - // compile error because DEPTH is not a variable. - float m_DEPTH = 0.0; - - float alpha = 1.0; - float side = 1.0; - - float specular_blob_intensity = 1.0; -#if defined(SPECULAR_TOON) - specular_blob_intensity *= specular * 2.0; -#endif - -#if defined(ENABLE_AO) - float ao = 1.0; - float ao_light_affect = 0.0; -#endif - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - vec3 binormal = normalize(binormal_interp) * side; - vec3 tangent = normalize(tangent_interp) * side; -#else - vec3 binormal = vec3(0.0); - vec3 tangent = vec3(0.0); -#endif - vec3 normal = normalize(normal_interp) * side; - -#if defined(ENABLE_NORMALMAP) - vec3 normalmap = vec3(0.5); -#endif - float normaldepth = 1.0; - -#if defined(ALPHA_SCISSOR_USED) - float alpha_scissor = 0.5; -#endif - -#if defined(SCREEN_UV_USED) - vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; -#endif - - { - /* clang-format off */ - -FRAGMENT_SHADER_CODE - - /* clang-format on */ - } - -#if defined(ENABLE_NORMALMAP) - normalmap.xy = normalmap.xy * 2.0 - 1.0; - normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); - - normal = normalize(mix(normal_interp, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)) * side; - //normal = normalmap; -#endif - - normal = normalize(normal); - - vec3 N = normal; - - vec3 specular_light = vec3(0.0, 0.0, 0.0); - vec3 diffuse_light = vec3(0.0, 0.0, 0.0); - vec3 ambient_light = vec3(0.0, 0.0, 0.0); - - vec3 eye_position = view; - -#if !defined(USE_SHADOW_TO_OPACITY) - -#if defined(ALPHA_SCISSOR_USED) - if (alpha < alpha_scissor) { - discard; - } -#endif // ALPHA_SCISSOR_USED - -#ifdef USE_DEPTH_PREPASS - if (alpha < 0.1) { - discard; - } -#endif // USE_DEPTH_PREPASS - -#endif // !USE_SHADOW_TO_OPACITY - -#ifdef BASE_PASS - - // IBL precalculations - float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0); - vec3 f0 = F0(metallic, specular, albedo); - vec3 F = f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(1.0 - ndotv, 5.0); - -#ifdef AMBIENT_LIGHT_DISABLED - ambient_light = vec3(0.0, 0.0, 0.0); -#else - -#ifdef USE_RADIANCE_MAP - - vec3 ref_vec = reflect(-eye_position, N); - ref_vec = normalize((radiance_inverse_xform * vec4(ref_vec, 0.0)).xyz); - - ref_vec.z *= -1.0; - - specular_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).xyz * bg_energy; -#ifndef USE_LIGHTMAP - { - vec3 ambient_dir = normalize((radiance_inverse_xform * vec4(normal, 0.0)).xyz); - vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, 4.0).xyz * bg_energy; - env_ambient *= 1.0 - F; - - ambient_light = mix(ambient_color.rgb, env_ambient, ambient_sky_contribution); - } -#endif - -#else - - ambient_light = ambient_color.rgb; - specular_light = bg_color.rgb * bg_energy; - -#endif -#endif // AMBIENT_LIGHT_DISABLED - ambient_light *= ambient_energy; - -#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) - - vec4 ambient_accum = vec4(0.0); - vec4 reflection_accum = vec4(0.0); - -#ifdef USE_REFLECTION_PROBE1 - - reflection_process(reflection_probe1, -#ifdef USE_VERTEX_LIGHTING - refprobe1_reflection_normal_blend.rgb, -#ifndef USE_LIGHTMAP - refprobe1_ambient_normal, -#endif - refprobe1_reflection_normal_blend.a, -#else - normal_interp, vertex_interp, refprobe1_local_matrix, - refprobe1_use_box_project, refprobe1_box_extents, refprobe1_box_offset, -#endif - refprobe1_exterior, refprobe1_intensity, refprobe1_ambient, roughness, - ambient_light, specular_light, reflection_accum, ambient_accum); - -#endif // USE_REFLECTION_PROBE1 - -#ifdef USE_REFLECTION_PROBE2 - - reflection_process(reflection_probe2, -#ifdef USE_VERTEX_LIGHTING - refprobe2_reflection_normal_blend.rgb, -#ifndef USE_LIGHTMAP - refprobe2_ambient_normal, -#endif - refprobe2_reflection_normal_blend.a, -#else - normal_interp, vertex_interp, refprobe2_local_matrix, - refprobe2_use_box_project, refprobe2_box_extents, refprobe2_box_offset, -#endif - refprobe2_exterior, refprobe2_intensity, refprobe2_ambient, roughness, - ambient_light, specular_light, reflection_accum, ambient_accum); - -#endif // USE_REFLECTION_PROBE2 - - if (reflection_accum.a > 0.0) { - specular_light = reflection_accum.rgb / reflection_accum.a; - } - -#ifndef USE_LIGHTMAP - if (ambient_accum.a > 0.0) { - ambient_light = ambient_accum.rgb / ambient_accum.a; - } -#endif - -#endif // defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) - - // environment BRDF approximation - { - -#if defined(DIFFUSE_TOON) - //simplify for toon, as - specular_light *= specular * metallic * albedo * 2.0; -#else - - // scales the specular reflections, needs to be be computed before lighting happens, - // but after environment and reflection probes are added - //TODO: this curve is not really designed for gammaspace, should be adjusted - const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); - const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); - vec4 r = roughness * c0 + c1; - 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; - specular_light *= env.x * F + env.y; - -#endif - } - -#ifdef USE_LIGHTMAP - //ambient light will come entirely from lightmap is lightmap is used - ambient_light = texture2D(lightmap, uv2_interp).rgb * lightmap_energy; -#endif - -#ifdef USE_LIGHTMAP_CAPTURE - { - vec3 cone_dirs[12]; - cone_dirs[0] = vec3(0.0, 0.0, 1.0); - cone_dirs[1] = vec3(0.866025, 0.0, 0.5); - cone_dirs[2] = vec3(0.267617, 0.823639, 0.5); - cone_dirs[3] = vec3(-0.700629, 0.509037, 0.5); - cone_dirs[4] = vec3(-0.700629, -0.509037, 0.5); - cone_dirs[5] = vec3(0.267617, -0.823639, 0.5); - cone_dirs[6] = vec3(0.0, 0.0, -1.0); - cone_dirs[7] = vec3(0.866025, 0.0, -0.5); - cone_dirs[8] = vec3(0.267617, 0.823639, -0.5); - cone_dirs[9] = vec3(-0.700629, 0.509037, -0.5); - cone_dirs[10] = vec3(-0.700629, -0.509037, -0.5); - cone_dirs[11] = vec3(0.267617, -0.823639, -0.5); - - vec3 local_normal = normalize(camera_matrix * vec4(normal, 0.0)).xyz; - vec4 captured = vec4(0.0); - float sum = 0.0; - for (int i = 0; i < 12; i++) { - float amount = max(0.0, dot(local_normal, cone_dirs[i])); //not correct, but creates a nice wrap around effect - captured += lightmap_captures[i] * amount; - sum += amount; - } - - captured /= sum; - - if (lightmap_capture_sky) { - ambient_light = mix(ambient_light, captured.rgb, captured.a); - } else { - ambient_light = captured.rgb; - } - } -#endif - -#endif //BASE PASS - -// -// Lighting -// -#ifdef USE_LIGHTING - -#ifndef USE_VERTEX_LIGHTING - vec3 L; -#endif - vec3 light_att = vec3(1.0); - -#ifdef LIGHT_MODE_OMNI - -#ifndef USE_VERTEX_LIGHTING - vec3 light_vec = light_position - vertex; - float light_length = length(light_vec); - - float normalized_distance = light_length / light_range; - if (normalized_distance < 1.0) { - - float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation); - - light_att = vec3(omni_attenuation); - } else { - light_att = vec3(0.0); - } - L = normalize(light_vec); - -#endif - -#if !defined(SHADOWS_DISABLED) - -#ifdef USE_SHADOW - { - highp vec4 splane = shadow_coord; - float shadow_len = length(splane.xyz); - - splane.xyz = normalize(splane.xyz); - - vec4 clamp_rect = light_clamp; - - if (splane.z >= 0.0) { - splane.z += 1.0; - - clamp_rect.y += clamp_rect.w; - } else { - splane.z = 1.0 - splane.z; - } - - splane.xy /= splane.z; - splane.xy = splane.xy * 0.5 + 0.5; - splane.z = shadow_len / light_range; - - splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; - splane.w = 1.0; - - float shadow = sample_shadow(light_shadow_atlas, splane); - - light_att *= mix(shadow_color.rgb, vec3(1.0), shadow); - } -#endif - -#endif //SHADOWS_DISABLED - -#endif //type omni - -#ifdef LIGHT_MODE_DIRECTIONAL - -#ifndef USE_VERTEX_LIGHTING - vec3 light_vec = -light_direction; - L = normalize(light_vec); -#endif - float depth_z = -vertex.z; - -#if !defined(SHADOWS_DISABLED) - -#ifdef USE_SHADOW - -#ifdef USE_VERTEX_LIGHTING - //compute shadows in a mobile friendly way - -#ifdef LIGHT_USE_PSSM4 - //take advantage of prefetch - float shadow1 = sample_shadow(light_directional_shadow, shadow_coord); - float shadow2 = sample_shadow(light_directional_shadow, shadow_coord2); - float shadow3 = sample_shadow(light_directional_shadow, shadow_coord3); - float shadow4 = sample_shadow(light_directional_shadow, shadow_coord4); - - if (depth_z < light_split_offsets.w) { - float pssm_fade = 0.0; - float shadow_att = 1.0; -#ifdef LIGHT_USE_PSSM_BLEND - float shadow_att2 = 1.0; - float pssm_blend = 0.0; - bool use_blend = true; -#endif - if (depth_z < light_split_offsets.y) { - if (depth_z < light_split_offsets.x) { - shadow_att = shadow1; - -#ifdef LIGHT_USE_PSSM_BLEND - shadow_att2 = shadow2; - - pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); -#endif - } else { - shadow_att = shadow2; - -#ifdef LIGHT_USE_PSSM_BLEND - shadow_att2 = shadow3; - - pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); -#endif - } - } else { - if (depth_z < light_split_offsets.z) { - - shadow_att = shadow3; - -#if defined(LIGHT_USE_PSSM_BLEND) - shadow_att2 = shadow4; - pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z); -#endif - - } else { - - shadow_att = shadow4; - pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z); - -#if defined(LIGHT_USE_PSSM_BLEND) - use_blend = false; -#endif - } - } -#if defined(LIGHT_USE_PSSM_BLEND) - if (use_blend) { - shadow_att = mix(shadow_att, shadow_att2, pssm_blend); - } -#endif - light_att *= mix(shadow_color.rgb, vec3(1.0), shadow_att); - } - -#endif //LIGHT_USE_PSSM4 - -#ifdef LIGHT_USE_PSSM2 - - //take advantage of prefetch - float shadow1 = sample_shadow(light_directional_shadow, shadow_coord); - float shadow2 = sample_shadow(light_directional_shadow, shadow_coord2); - - if (depth_z < light_split_offsets.y) { - float shadow_att = 1.0; - float pssm_fade = 0.0; - -#ifdef LIGHT_USE_PSSM_BLEND - float shadow_att2 = 1.0; - float pssm_blend = 0.0; - bool use_blend = true; -#endif - if (depth_z < light_split_offsets.x) { - float pssm_fade = 0.0; - shadow_att = shadow1; - -#ifdef LIGHT_USE_PSSM_BLEND - shadow_att2 = shadow2; - pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); -#endif - } else { - - shadow_att = shadow2; - pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); -#ifdef LIGHT_USE_PSSM_BLEND - use_blend = false; -#endif - } -#ifdef LIGHT_USE_PSSM_BLEND - if (use_blend) { - shadow_att = mix(shadow_att, shadow_att2, pssm_blend); - } -#endif - light_att *= mix(shadow_color.rgb, vec3(1.0), shadow_att); - } - -#endif //LIGHT_USE_PSSM2 - -#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) - - light_att *= mix(shadow_color.rgb, vec3(1.0), sample_shadow(light_directional_shadow, shadow_coord)); -#endif //orthogonal - -#else //fragment version of pssm - - { -#ifdef LIGHT_USE_PSSM4 - if (depth_z < light_split_offsets.w) { -#elif defined(LIGHT_USE_PSSM2) - if (depth_z < light_split_offsets.y) { -#else - if (depth_z < light_split_offsets.x) { -#endif //pssm2 - - highp vec4 pssm_coord; - float pssm_fade = 0.0; - -#ifdef LIGHT_USE_PSSM_BLEND - float pssm_blend; - highp vec4 pssm_coord2; - bool use_blend = true; -#endif - -#ifdef LIGHT_USE_PSSM4 - - if (depth_z < light_split_offsets.y) { - if (depth_z < light_split_offsets.x) { - pssm_coord = shadow_coord; - -#ifdef LIGHT_USE_PSSM_BLEND - pssm_coord2 = shadow_coord2; - - pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); -#endif - } else { - pssm_coord = shadow_coord2; - -#ifdef LIGHT_USE_PSSM_BLEND - pssm_coord2 = shadow_coord3; - - pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); -#endif - } - } else { - if (depth_z < light_split_offsets.z) { - - pssm_coord = shadow_coord3; - -#if defined(LIGHT_USE_PSSM_BLEND) - pssm_coord2 = shadow_coord4; - pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z); -#endif - - } else { - - pssm_coord = shadow_coord4; - pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z); - -#if defined(LIGHT_USE_PSSM_BLEND) - use_blend = false; -#endif - } - } - -#endif // LIGHT_USE_PSSM4 - -#ifdef LIGHT_USE_PSSM2 - if (depth_z < light_split_offsets.x) { - - pssm_coord = shadow_coord; - -#ifdef LIGHT_USE_PSSM_BLEND - pssm_coord2 = shadow_coord2; - pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); -#endif - } else { - - pssm_coord = shadow_coord2; - pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); -#ifdef LIGHT_USE_PSSM_BLEND - use_blend = false; -#endif - } - -#endif // LIGHT_USE_PSSM2 - -#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) - { - pssm_coord = shadow_coord; - } -#endif - - float shadow = sample_shadow(light_directional_shadow, pssm_coord); - -#ifdef LIGHT_USE_PSSM_BLEND - if (use_blend) { - shadow = mix(shadow, sample_shadow(light_directional_shadow, pssm_coord2), pssm_blend); - } -#endif - - light_att *= mix(shadow_color.rgb, vec3(1.0), shadow); - } - } -#endif //use vertex lighting - -#endif //use shadow - -#endif // SHADOWS_DISABLED - -#endif - -#ifdef LIGHT_MODE_SPOT - - light_att = vec3(1.0); - -#ifndef USE_VERTEX_LIGHTING - - vec3 light_rel_vec = light_position - vertex; - float light_length = length(light_rel_vec); - float normalized_distance = light_length / light_range; - - if (normalized_distance < 1.0) { - float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation); - vec3 spot_dir = light_direction; - - float spot_cutoff = light_spot_angle; - float angle = dot(-normalize(light_rel_vec), spot_dir); - - if (angle > spot_cutoff) { - float scos = max(angle, spot_cutoff); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); - spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); - - light_att = vec3(spot_attenuation); - } else { - light_att = vec3(0.0); - } - } else { - light_att = vec3(0.0); - } - - L = normalize(light_rel_vec); - -#endif - -#if !defined(SHADOWS_DISABLED) - -#ifdef USE_SHADOW - { - highp vec4 splane = shadow_coord; - - float shadow = sample_shadow(light_shadow_atlas, splane); - light_att *= mix(shadow_color.rgb, vec3(1.0), shadow); - } -#endif - -#endif // SHADOWS_DISABLED - -#endif // LIGHT_MODE_SPOT - -#ifdef USE_VERTEX_LIGHTING - //vertex lighting - - specular_light += specular_interp * specular_blob_intensity * light_att; - diffuse_light += diffuse_interp * albedo * light_att; - -#else - //fragment lighting - light_compute( - normal, - L, - eye_position, - binormal, - tangent, - light_color.xyz, - light_att, - albedo, - transmission, - specular_blob_intensity * light_specular, - roughness, - metallic, - specular, - rim, - rim_tint, - clearcoat, - clearcoat_gloss, - anisotropy, - diffuse_light, - specular_light, - alpha); - -#endif //vertex lighting - -#endif //USE_LIGHTING - //compute and merge - -#ifdef USE_SHADOW_TO_OPACITY - - alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); - -#if defined(ALPHA_SCISSOR_USED) - if (alpha < alpha_scissor) { - discard; - } -#endif // ALPHA_SCISSOR_USED - -#ifdef USE_DEPTH_PREPASS - if (alpha < 0.1) { - discard; - } -#endif // USE_DEPTH_PREPASS - -#endif // !USE_SHADOW_TO_OPACITY - -#ifndef RENDER_DEPTH - -#ifdef SHADELESS - - gl_FragColor = vec4(albedo, alpha); -#else - - ambient_light *= albedo; - -#if defined(ENABLE_AO) - ambient_light *= ao; - ao_light_affect = mix(1.0, ao, ao_light_affect); - specular_light *= ao_light_affect; - diffuse_light *= ao_light_affect; -#endif - - diffuse_light *= 1.0 - metallic; - ambient_light *= 1.0 - metallic; - - gl_FragColor = vec4(ambient_light + diffuse_light + specular_light, alpha); - - //add emission if in base pass -#ifdef BASE_PASS - gl_FragColor.rgb += emission; -#endif - // gl_FragColor = vec4(normal, 1.0); - -//apply fog -#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) - -#if defined(USE_VERTEX_LIGHTING) - -#if defined(BASE_PASS) - gl_FragColor.rgb = mix(gl_FragColor.rgb, fog_interp.rgb, fog_interp.a); -#else - gl_FragColor.rgb *= (1.0 - fog_interp.a); -#endif // BASE_PASS - -#else //pixel based fog - float fog_amount = 0.0; - -#ifdef LIGHT_MODE_DIRECTIONAL - - vec3 fog_color = mix(fog_color_base.rgb, fog_sun_color_amount.rgb, fog_sun_color_amount.a * pow(max(dot(eye_position, light_direction), 0.0), 8.0)); -#else - vec3 fog_color = fog_color_base.rgb; -#endif - -#ifdef FOG_DEPTH_ENABLED - - { - - float fog_z = smoothstep(fog_depth_begin, fog_max_distance, length(vertex)); - - fog_amount = pow(fog_z, fog_depth_curve) * fog_color_base.a; - - if (fog_transmit_enabled) { - vec3 total_light = gl_FragColor.rgb; - float transmit = pow(fog_z, fog_transmit_curve); - fog_color = mix(max(total_light, fog_color), fog_color, transmit); - } - } -#endif - -#ifdef FOG_HEIGHT_ENABLED - { - float y = (camera_matrix * vec4(vertex, 1.0)).y; - fog_amount = max(fog_amount, pow(smoothstep(fog_height_min, fog_height_max, y), fog_height_curve)); - } -#endif - -#if defined(BASE_PASS) - gl_FragColor.rgb = mix(gl_FragColor.rgb, fog_color, fog_amount); -#else - gl_FragColor.rgb *= (1.0 - fog_amount); -#endif // BASE_PASS - -#endif //use vertex lit - -#endif // defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) - -#endif //unshaded - -#else // not RENDER_DEPTH -//depth render -#ifdef USE_RGBA_SHADOWS - - highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias - highp vec4 comp = fract(depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0)); - comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0); - gl_FragColor = comp; - -#endif -#endif -} diff --git a/drivers/gles2/shaders/screen_space_reflection.glsl b/drivers/gles2/shaders/screen_space_reflection.glsl deleted file mode 100644 index a11da10b61..0000000000 --- a/drivers/gles2/shaders/screen_space_reflection.glsl +++ /dev/null @@ -1,289 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ -layout(location = 4) in vec2 uv_in; - -out vec2 uv_interp; -out vec2 pos_interp; - -void main() { - - uv_interp = uv_in; - gl_Position = vertex_attrib; - pos_interp.xy = gl_Position.xy; -} - -/* clang-format off */ -[fragment] - -in vec2 uv_interp; -/* clang-format on */ -in vec2 pos_interp; - -uniform sampler2D source_diffuse; //texunit:0 -uniform sampler2D source_normal_roughness; //texunit:1 -uniform sampler2D source_depth; //texunit:2 - -uniform float camera_z_near; -uniform float camera_z_far; - -uniform vec2 viewport_size; -uniform vec2 pixel_size; - -uniform float filter_mipmap_levels; - -uniform mat4 inverse_projection; -uniform mat4 projection; - -uniform int num_steps; -uniform float depth_tolerance; -uniform float distance_fade; -uniform float curve_fade_in; - -layout(location = 0) out vec4 frag_color; - -vec2 view_to_screen(vec3 view_pos, out float w) { - vec4 projected = projection * vec4(view_pos, 1.0); - projected.xyz /= projected.w; - projected.xy = projected.xy * 0.5 + 0.5; - w = projected.w; - return projected.xy; -} - -#define M_PI 3.14159265359 - -void main() { - - vec4 diffuse = texture(source_diffuse, uv_interp); - vec4 normal_roughness = texture(source_normal_roughness, uv_interp); - - vec3 normal; - - normal = normal_roughness.xyz * 2.0 - 1.0; - - float roughness = normal_roughness.w; - - float depth_tex = texture(source_depth, uv_interp).r; - - vec4 world_pos = inverse_projection * vec4(uv_interp * 2.0 - 1.0, depth_tex * 2.0 - 1.0, 1.0); - vec3 vertex = world_pos.xyz / world_pos.w; - - vec3 view_dir = normalize(vertex); - vec3 ray_dir = normalize(reflect(view_dir, normal)); - - if (dot(ray_dir, normal) < 0.001) { - frag_color = vec4(0.0); - return; - } - //ray_dir = normalize(view_dir - normal * dot(normal,view_dir) * 2.0); - - //ray_dir = normalize(vec3(1,1,-1)); - - //////////////// - - //make ray length and clip it against the near plane (don't want to trace beyond visible) - float ray_len = (vertex.z + ray_dir.z * camera_z_far) > -camera_z_near ? (-camera_z_near - vertex.z) / ray_dir.z : camera_z_far; - vec3 ray_end = vertex + ray_dir * ray_len; - - float w_begin; - vec2 vp_line_begin = view_to_screen(vertex, w_begin); - float w_end; - vec2 vp_line_end = view_to_screen(ray_end, w_end); - vec2 vp_line_dir = vp_line_end - vp_line_begin; - - //we need to interpolate w along the ray, to generate perspective correct reflections - - w_begin = 1.0 / w_begin; - w_end = 1.0 / w_end; - - float z_begin = vertex.z * w_begin; - float z_end = ray_end.z * w_end; - - vec2 line_begin = vp_line_begin / pixel_size; - vec2 line_dir = vp_line_dir / pixel_size; - float z_dir = z_end - z_begin; - float w_dir = w_end - w_begin; - - // clip the line to the viewport edges - - float scale_max_x = min(1.0, 0.99 * (1.0 - vp_line_begin.x) / max(1e-5, vp_line_dir.x)); - float scale_max_y = min(1.0, 0.99 * (1.0 - vp_line_begin.y) / max(1e-5, vp_line_dir.y)); - float scale_min_x = min(1.0, 0.99 * vp_line_begin.x / max(1e-5, -vp_line_dir.x)); - float scale_min_y = min(1.0, 0.99 * vp_line_begin.y / max(1e-5, -vp_line_dir.y)); - float line_clip = min(scale_max_x, scale_max_y) * min(scale_min_x, scale_min_y); - line_dir *= line_clip; - z_dir *= line_clip; - w_dir *= line_clip; - - //clip z and w advance to line advance - vec2 line_advance = normalize(line_dir); //down to pixel - float step_size = length(line_advance) / length(line_dir); - float z_advance = z_dir * step_size; // adapt z advance to line advance - float w_advance = w_dir * step_size; // adapt w advance to line advance - - //make line advance faster if direction is closer to pixel edges (this avoids sampling the same pixel twice) - float advance_angle_adj = 1.0 / max(abs(line_advance.x), abs(line_advance.y)); - line_advance *= advance_angle_adj; // adapt z advance to line advance - z_advance *= advance_angle_adj; - w_advance *= advance_angle_adj; - - vec2 pos = line_begin; - float z = z_begin; - float w = w_begin; - float z_from = z / w; - float z_to = z_from; - float depth; - vec2 prev_pos = pos; - - bool found = false; - - float steps_taken = 0.0; - - for (int i = 0; i < num_steps; i++) { - - pos += line_advance; - z += z_advance; - w += w_advance; - - //convert to linear depth - - depth = texture(source_depth, pos * pixel_size).r * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - depth = ((depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near)); -#endif - depth = -depth; - - z_from = z_to; - z_to = z / w; - - if (depth > z_to) { - //if depth was surpassed - if (depth <= max(z_to, z_from) + depth_tolerance) { - //check the depth tolerance - found = true; - } - break; - } - - steps_taken += 1.0; - prev_pos = pos; - } - - if (found) { - - float margin_blend = 1.0; - - vec2 margin = vec2((viewport_size.x + viewport_size.y) * 0.5 * 0.05); //make a uniform margin - if (any(bvec4(lessThan(pos, -margin), greaterThan(pos, viewport_size + margin)))) { - //clip outside screen + margin - frag_color = vec4(0.0); - return; - } - - { - //blend fading out towards external margin - vec2 margin_grad = mix(pos - viewport_size, -pos, lessThan(pos, vec2(0.0))); - margin_blend = 1.0 - smoothstep(0.0, margin.x, max(margin_grad.x, margin_grad.y)); - //margin_blend=1.0; - } - - vec2 final_pos; - float grad; - grad = steps_taken / float(num_steps); - float initial_fade = curve_fade_in == 0.0 ? 1.0 : pow(clamp(grad, 0.0, 1.0), curve_fade_in); - float fade = pow(clamp(1.0 - grad, 0.0, 1.0), distance_fade) * initial_fade; - final_pos = pos; - -#ifdef REFLECT_ROUGHNESS - - vec4 final_color; - //if roughness is enabled, do screen space cone tracing - if (roughness > 0.001) { - /////////////////////////////////////////////////////////////////////////////////////// - //use a blurred version (in consecutive mipmaps) of the screen to simulate roughness - - float gloss = 1.0 - roughness; - float cone_angle = roughness * M_PI * 0.5; - vec2 cone_dir = final_pos - line_begin; - float cone_len = length(cone_dir); - cone_dir = normalize(cone_dir); //will be used normalized from now on - float max_mipmap = filter_mipmap_levels - 1.0; - float gloss_mult = gloss; - - float rem_alpha = 1.0; - final_color = vec4(0.0); - - for (int i = 0; i < 7; i++) { - - float op_len = 2.0 * tan(cone_angle) * cone_len; //opposite side of iso triangle - float radius; - { - //fit to sphere inside cone (sphere ends at end of cone), something like this: - // ___ - // \O/ - // V - // - // as it avoids bleeding from beyond the reflection as much as possible. As a plus - // it also makes the rough reflection more elongated. - float a = op_len; - float h = cone_len; - float a2 = a * a; - float fh2 = 4.0f * h * h; - radius = (a * (sqrt(a2 + fh2) - a)) / (4.0f * h); - } - - //find the place where screen must be sampled - vec2 sample_pos = (line_begin + cone_dir * (cone_len - radius)) * pixel_size; - //radius is in pixels, so it's natural that log2(radius) maps to the right mipmap for the amount of pixels - float mipmap = clamp(log2(radius), 0.0, max_mipmap); - - //mipmap = max(mipmap-1.0,0.0); - //do sampling - - vec4 sample_color; - { - sample_color = textureLod(source_diffuse, sample_pos, mipmap); - } - - //multiply by gloss - sample_color.rgb *= gloss_mult; - sample_color.a = gloss_mult; - - rem_alpha -= sample_color.a; - if (rem_alpha < 0.0) { - sample_color.rgb *= (1.0 - abs(rem_alpha)); - } - - final_color += sample_color; - - if (final_color.a >= 0.95) { - // This code of accumulating gloss and aborting on near one - // makes sense when you think of cone tracing. - // Think of it as if roughness was 0, then we could abort on the first - // iteration. For lesser roughness values, we need more iterations, but - // each needs to have less influence given the sphere is smaller - break; - } - - cone_len -= radius * 2.0; //go to next (smaller) circle. - - gloss_mult *= gloss; - } - } else { - final_color = textureLod(source_diffuse, final_pos * pixel_size, 0.0); - } - - frag_color = vec4(final_color.rgb, fade * margin_blend); - -#else - frag_color = vec4(textureLod(source_diffuse, final_pos * pixel_size, 0.0).rgb, fade * margin_blend); -#endif - - } else { - frag_color = vec4(0.0, 0.0, 0.0, 0.0); - } -} diff --git a/drivers/gles2/shaders/ssao.glsl b/drivers/gles2/shaders/ssao.glsl deleted file mode 100644 index 82eea8f274..0000000000 --- a/drivers/gles2/shaders/ssao.glsl +++ /dev/null @@ -1,285 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ - -void main() { - - gl_Position = vertex_attrib; - gl_Position.z = 1.0; -} - -/* clang-format off */ -[fragment] - -#define TWO_PI 6.283185307179586476925286766559 - -#ifdef SSAO_QUALITY_HIGH - -#define NUM_SAMPLES (80) - -#endif - -#ifdef SSAO_QUALITY_LOW - -#define NUM_SAMPLES (15) - -#endif - -#if !defined(SSAO_QUALITY_LOW) && !defined(SSAO_QUALITY_HIGH) - -#define NUM_SAMPLES (40) - -#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); -/* clang-format on */ - -//#define NUM_SPIRAL_TURNS (7) -const int NUM_SPIRAL_TURNS = ROTATIONS[NUM_SAMPLES - 1]; - -uniform sampler2D source_depth; //texunit:0 -uniform highp usampler2D source_depth_mipmaps; //texunit:1 -uniform sampler2D source_normal; //texunit:2 - -uniform ivec2 screen_size; -uniform float camera_z_far; -uniform float camera_z_near; - -uniform float intensity_div_r6; -uniform float radius; - -#ifdef ENABLE_RADIUS2 -uniform float intensity_div_r62; -uniform float radius2; -#endif - -uniform float bias; -uniform float proj_scale; - -layout(location = 0) out float visibility; - -uniform vec4 proj_info; - -vec3 reconstructCSPosition(vec2 S, float z) { -#ifdef USE_ORTHOGONAL_PROJECTION - return vec3((S.xy * proj_info.xy + proj_info.zw), z); -#else - return vec3((S.xy * proj_info.xy + proj_info.zw) * z, z); - -#endif -} - -vec3 getPosition(ivec2 ssP) { - vec3 P; - P.z = texelFetch(source_depth, ssP, 0).r; - - P.z = P.z * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - P.z = ((P.z + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near)); -#endif - P.z = -P.z; - - // Offset to pixel center - P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z); - return P; -} - -/** Reconstructs screen-space unit normal from screen-space position */ -vec3 reconstructCSFaceNormal(vec3 C) { - return normalize(cross(dFdy(C), dFdx(C))); -} - -/** 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 ssC, vec2 unitOffset, float ssR) { - // Derivation: - // mipLevel = floor(log(ssR / MAX_OFFSET)); - int mipLevel = clamp(int(floor(log2(ssR))) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); - - ivec2 ssP = ivec2(ssR * unitOffset) + ssC; - - 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), (screen_size >> mipLevel) - ivec2(1)); - - if (mipLevel < 1) { - //read from depth buffer - P.z = texelFetch(source_depth, mipP, 0).r; - P.z = P.z * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - P.z = ((P.z + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near)); - -#endif - P.z = -P.z; - - } else { - //read from mipmaps - uint d = texelFetch(source_depth_mipmaps, mipP, mipLevel - 1).r; - P.z = -(float(d) / 65535.0) * camera_z_far; - } - - // 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; - - // The occluding point in camera space - vec3 Q = getOffsetPosition(ssC, unitOffset, 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 - 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_FragCoord.xy); - - // World space point being shaded - vec3 C = getPosition(ssC); - - /* - if (C.z <= -camera_z_far*0.999) { - // We're on the skybox - visibility=1.0; - return; - } - */ - - //visibility=-C.z/camera_z_far; - //return; -#if 0 - vec3 n_C = texelFetch(source_normal,ssC,0).rgb * 2.0 - 1.0; -#else - vec3 n_C = reconstructCSFaceNormal(C); - n_C = -n_C; -#endif - - // 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 -#ifdef USE_ORTHOGONAL_PROJECTION - float ssDiskRadius = -proj_scale * radius; -#else - float ssDiskRadius = -proj_scale * radius / C.z; -#endif - float sum = 0.0; - for (int i = 0; i < NUM_SAMPLES; ++i) { - sum += sampleAO(ssC, C, n_C, ssDiskRadius, radius, i, randomPatternRotationAngle); - } - - float A = max(0.0, 1.0 - sum * intensity_div_r6 * (5.0 / float(NUM_SAMPLES))); - -#ifdef ENABLE_RADIUS2 - - //go again for radius2 - randomPatternRotationAngle = mod(float((5 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 11), 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 - ssDiskRadius = -proj_scale * radius2 / C.z; - - sum = 0.0; - for (int i = 0; i < NUM_SAMPLES; ++i) { - sum += sampleAO(ssC, C, n_C, ssDiskRadius, radius2, i, randomPatternRotationAngle); - } - - A = min(A, max(0.0, 1.0 - sum * intensity_div_r62 * (5.0 / float(NUM_SAMPLES)))); -#endif - // Bilateral box-filter over a quad for free, respecting depth edges - // (the difference that this makes is subtle) - if (abs(dFdx(C.z)) < 0.02) { - A -= dFdx(A) * (float(ssC.x & 1) - 0.5); - } - if (abs(dFdy(C.z)) < 0.02) { - A -= dFdy(A) * (float(ssC.y & 1) - 0.5); - } - - visibility = A; -} diff --git a/drivers/gles2/shaders/ssao_blur.glsl b/drivers/gles2/shaders/ssao_blur.glsl deleted file mode 100644 index e4133ad534..0000000000 --- a/drivers/gles2/shaders/ssao_blur.glsl +++ /dev/null @@ -1,119 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ - -void main() { - - gl_Position = vertex_attrib; - gl_Position.z = 1.0; -} - -/* clang-format off */ -[fragment] - -uniform sampler2D source_ssao; //texunit:0 -/* clang-format on */ -uniform sampler2D source_depth; //texunit:1 -uniform sampler2D source_normal; //texunit:3 - -layout(location = 0) out float visibility; - -////////////////////////////////////////////////////////////////////////////////////////////// -// Tunable Parameters: - -/** Increase to make depth edges crisper. Decrease to reduce flicker. */ -uniform float edge_sharpness; - -/** Step in 2-pixel intervals since we already blurred against neighbors in the - first AO pass. This constant can be increased while R decreases to improve - performance at the expense of some dithering artifacts. - - Morgan found that a scale of 3 left a 1-pixel checkerboard grid that was - unobjectionable after shading was applied but eliminated most temporal incoherence - from using small numbers of sample taps. - */ - -uniform int filter_scale; - -/** 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 - -/** (1, 0) or (0, 1)*/ -uniform ivec2 axis; - -uniform float camera_z_far; -uniform float camera_z_near; - -uniform ivec2 screen_size; - -void main() { - - ivec2 ssC = ivec2(gl_FragCoord.xy); - - float depth = texelFetch(source_depth, ssC, 0).r; - //vec3 normal = texelFetch(source_normal,ssC,0).rgb * 2.0 - 1.0; - - depth = depth * 2.0 - 1.0; - depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near)); - - float depth_divide = 1.0 / camera_z_far; - - //depth *= depth_divide; - - /* - if (depth > camera_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 = 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 + axis * (r * 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; - //vec3 temp_normal = texelFetch(source_normal, rpos, 0).rgb * 2.0 - 1.0; - - temp_depth = temp_depth * 2.0 - 1.0; - temp_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - temp_depth * (camera_z_far - camera_z_near)); - // temp_depth *= depth_divide; - - // 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 - edge_sharpness * abs(temp_depth - depth)); - - sum += value * weight; - totalWeight += weight; - } - } - - const float epsilon = 0.0001; - visibility = sum / (totalWeight + epsilon); -} diff --git a/drivers/gles2/shaders/ssao_minify.glsl b/drivers/gles2/shaders/ssao_minify.glsl deleted file mode 100644 index 272f3e236e..0000000000 --- a/drivers/gles2/shaders/ssao_minify.glsl +++ /dev/null @@ -1,56 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ - -void main() { - - gl_Position = vertex_attrib; -} - -/* clang-format off */ -[fragment] - -#ifdef MINIFY_START - -#define SDEPTH_TYPE highp sampler2D -uniform float camera_z_far; -uniform float camera_z_near; -/* clang-format on */ - -#else - -#define SDEPTH_TYPE mediump usampler2D - -#endif - -uniform SDEPTH_TYPE source_depth; //texunit:0 - -uniform ivec2 from_size; -uniform int source_mipmap; - -layout(location = 0) out mediump uint depth; - -void main() { - - ivec2 ssP = ivec2(gl_FragCoord.xy); - - // Rotated grid subsampling to avoid XY directional bias or Z precision bias while downsampling. - // On DX9, the bit-and can be implemented with floating-point modulo - -#ifdef MINIFY_START - float fdepth = texelFetch(source_depth, clamp(ssP * 2 + ivec2(ssP.y & 1, ssP.x & 1), ivec2(0), from_size - ivec2(1)), source_mipmap).r; - fdepth = fdepth * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - fdepth = ((fdepth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - fdepth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - fdepth * (camera_z_far - camera_z_near)); -#endif - fdepth /= camera_z_far; - depth = uint(clamp(fdepth * 65535.0, 0.0, 65535.0)); - -#else - depth = texelFetch(source_depth, clamp(ssP * 2 + ivec2(ssP.y & 1, ssP.x & 1), ivec2(0), from_size - ivec2(1)), source_mipmap).r; -#endif -} diff --git a/drivers/gles2/shaders/stdlib.glsl b/drivers/gles2/shaders/stdlib.glsl deleted file mode 100644 index 9c74418743..0000000000 --- a/drivers/gles2/shaders/stdlib.glsl +++ /dev/null @@ -1,420 +0,0 @@ - -vec2 select2(vec2 a, vec2 b, bvec2 c) { - vec2 ret; - - ret.x = c.x ? b.x : a.x; - ret.y = c.y ? b.y : a.y; - - return ret; -} - -vec3 select3(vec3 a, vec3 b, bvec3 c) { - vec3 ret; - - ret.x = c.x ? b.x : a.x; - ret.y = c.y ? b.y : a.y; - ret.z = c.z ? b.z : a.z; - - return ret; -} - -vec4 select4(vec4 a, vec4 b, bvec4 c) { - vec4 ret; - - ret.x = c.x ? b.x : a.x; - ret.y = c.y ? b.y : a.y; - ret.z = c.z ? b.z : a.z; - ret.w = c.w ? b.w : a.w; - - return ret; -} - -highp vec4 texel2DFetch(highp sampler2D tex, ivec2 size, ivec2 coord) { - float x_coord = float(2 * coord.x + 1) / float(size.x * 2); - float y_coord = float(2 * coord.y + 1) / float(size.y * 2); - - return texture2DLod(tex, vec2(x_coord, y_coord), 0.0); -} - -#if defined(SINH_USED) - -highp float sinh(highp float x) { - return 0.5 * (exp(x) - exp(-x)); -} - -highp vec2 sinh(highp vec2 x) { - return 0.5 * vec2(exp(x.x) - exp(-x.x), exp(x.y) - exp(-x.y)); -} - -highp vec3 sinh(highp vec3 x) { - return 0.5 * vec3(exp(x.x) - exp(-x.x), exp(x.y) - exp(-x.y), exp(x.z) - exp(-x.z)); -} - -highp vec4 sinh(highp vec4 x) { - return 0.5 * vec4(exp(x.x) - exp(-x.x), exp(x.y) - exp(-x.y), exp(x.z) - exp(-x.z), exp(x.w) - exp(-x.w)); -} - -#endif - -#if defined(COSH_USED) - -highp float cosh(highp float x) { - return 0.5 * (exp(x) + exp(-x)); -} - -highp vec2 cosh(highp vec2 x) { - return 0.5 * vec2(exp(x.x) + exp(-x.x), exp(x.y) + exp(-x.y)); -} - -highp vec3 cosh(highp vec3 x) { - return 0.5 * vec3(exp(x.x) + exp(-x.x), exp(x.y) + exp(-x.y), exp(x.z) + exp(-x.z)); -} - -highp vec4 cosh(highp vec4 x) { - return 0.5 * vec4(exp(x.x) + exp(-x.x), exp(x.y) + exp(-x.y), exp(x.z) + exp(-x.z), exp(x.w) + exp(-x.w)); -} - -#endif - -#if defined(TANH_USED) - -highp float tanh(highp float x) { - highp float exp2x = exp(2.0 * x); - return (exp2x - 1.0) / (exp2x + 1.0); -} - -highp vec2 tanh(highp vec2 x) { - highp float exp2x = exp(2.0 * x.x); - highp float exp2y = exp(2.0 * x.y); - return vec2((exp2x - 1.0) / (exp2x + 1.0), (exp2y - 1.0) / (exp2y + 1.0)); -} - -highp vec3 tanh(highp vec3 x) { - highp float exp2x = exp(2.0 * x.x); - highp float exp2y = exp(2.0 * x.y); - highp float exp2z = exp(2.0 * x.z); - return vec3((exp2x - 1.0) / (exp2x + 1.0), (exp2y - 1.0) / (exp2y + 1.0), (exp2z - 1.0) / (exp2z + 1.0)); -} - -highp vec4 tanh(highp vec4 x) { - highp float exp2x = exp(2.0 * x.x); - highp float exp2y = exp(2.0 * x.y); - highp float exp2z = exp(2.0 * x.z); - highp float exp2w = exp(2.0 * x.w); - return vec4((exp2x - 1.0) / (exp2x + 1.0), (exp2y - 1.0) / (exp2y + 1.0), (exp2z - 1.0) / (exp2z + 1.0), (exp2w - 1.0) / (exp2w + 1.0)); -} - -#endif - -#if defined(ASINH_USED) - -highp float asinh(highp float x) { - return sign(x) * log(abs(x) + sqrt(1.0 + x * x)); -} - -highp vec2 asinh(highp vec2 x) { - return vec2(sign(x.x) * log(abs(x.x) + sqrt(1.0 + x.x * x.x)), sign(x.y) * log(abs(x.y) + sqrt(1.0 + x.y * x.y))); -} - -highp vec3 asinh(highp vec3 x) { - return vec3(sign(x.x) * log(abs(x.x) + sqrt(1.0 + x.x * x.x)), sign(x.y) * log(abs(x.y) + sqrt(1.0 + x.y * x.y)), sign(x.z) * log(abs(x.z) + sqrt(1.0 + x.z * x.z))); -} - -highp vec4 asinh(highp vec4 x) { - return vec4(sign(x.x) * log(abs(x.x) + sqrt(1.0 + x.x * x.x)), sign(x.y) * log(abs(x.y) + sqrt(1.0 + x.y * x.y)), sign(x.z) * log(abs(x.z) + sqrt(1.0 + x.z * x.z)), sign(x.w) * log(abs(x.w) + sqrt(1.0 + x.w * x.w))); -} - -#endif - -#if defined(ACOSH_USED) - -highp float acosh(highp float x) { - return log(x + sqrt(x * x - 1.0)); -} - -highp vec2 acosh(highp vec2 x) { - return vec2(log(x.x + sqrt(x.x * x.x - 1.0)), log(x.y + sqrt(x.y * x.y - 1.0))); -} - -highp vec3 acosh(highp vec3 x) { - return vec3(log(x.x + sqrt(x.x * x.x - 1.0)), log(x.y + sqrt(x.y * x.y - 1.0)), log(x.z + sqrt(x.z * x.z - 1.0))); -} - -highp vec4 acosh(highp vec4 x) { - return vec4(log(x.x + sqrt(x.x * x.x - 1.0)), log(x.y + sqrt(x.y * x.y - 1.0)), log(x.z + sqrt(x.z * x.z - 1.0)), log(x.w + sqrt(x.w * x.w - 1.0))); -} - -#endif - -#if defined(ATANH_USED) - -highp float atanh(highp float x) { - return 0.5 * log((1.0 + x) / (1.0 - x)); -} - -highp vec2 atanh(highp vec2 x) { - return 0.5 * vec2(log((1.0 + x.x) / (1.0 - x.x)), log((1.0 + x.y) / (1.0 - x.y))); -} - -highp vec3 atanh(highp vec3 x) { - return 0.5 * vec3(log((1.0 + x.x) / (1.0 - x.x)), log((1.0 + x.y) / (1.0 - x.y)), log((1.0 + x.z) / (1.0 - x.z))); -} - -highp vec4 atanh(highp vec4 x) { - return 0.5 * vec4(log((1.0 + x.x) / (1.0 - x.x)), log((1.0 + x.y) / (1.0 - x.y)), log((1.0 + x.z) / (1.0 - x.z)), log((1.0 + x.w) / (1.0 - x.w))); -} - -#endif - -#if defined(ROUND_USED) - -highp float round(highp float x) { - return floor(x + 0.5); -} - -highp vec2 round(highp vec2 x) { - return floor(x + vec2(0.5)); -} - -highp vec3 round(highp vec3 x) { - return floor(x + vec3(0.5)); -} - -highp vec4 round(highp vec4 x) { - return floor(x + vec4(0.5)); -} - -#endif - -#if defined(ROUND_EVEN_USED) - -highp float roundEven(highp float x) { - highp float t = x + 0.5; - highp float f = floor(t); - highp float r; - if (t == f) { - if (x > 0) - r = f - mod(f, 2); - else - r = f + mod(f, 2); - } else - r = f; - return r; -} - -highp vec2 roundEven(highp vec2 x) { - return vec2(roundEven(x.x), roundEven(x.y)); -} - -highp vec3 roundEven(highp vec3 x) { - return vec3(roundEven(x.x), roundEven(x.y), roundEven(x.z)); -} - -highp vec4 roundEven(highp vec4 x) { - return vec4(roundEven(x.x), roundEven(x.y), roundEven(x.z), roundEven(x.w)); -} - -#endif - -#if defined(IS_INF_USED) - -bool isinf(highp float x) { - return (2 * x == x) && (x != 0); -} - -bvec2 isinf(highp vec2 x) { - return bvec2((2 * x.x == x.x) && (x.x != 0), (2 * x.y == x.y) && (x.y != 0)); -} - -bvec3 isinf(highp vec3 x) { - return bvec3((2 * x.x == x.x) && (x.x != 0), (2 * x.y == x.y) && (x.y != 0), (2 * x.z == x.z) && (x.z != 0)); -} - -bvec4 isinf(highp vec4 x) { - return bvec4((2 * x.x == x.x) && (x.x != 0), (2 * x.y == x.y) && (x.y != 0), (2 * x.z == x.z) && (x.z != 0), (2 * x.w == x.w) && (x.w != 0)); -} - -#endif - -#if defined(IS_NAN_USED) - -bool isnan(highp float x) { - return x != x; -} - -bvec2 isnan(highp vec2 x) { - return bvec2(x.x != x.x, x.y != x.y); -} - -bvec3 isnan(highp vec3 x) { - return bvec3(x.x != x.x, x.y != x.y, x.z != x.z); -} - -bvec4 isnan(highp vec4 x) { - return bvec4(x.x != x.x, x.y != x.y, x.z != x.z, x.w != x.w); -} - -#endif - -#if defined(TRUNC_USED) - -highp float trunc(highp float x) { - return x < 0 ? -floor(-x) : floor(x); -} - -highp vec2 trunc(highp vec2 x) { - return vec2(x.x < 0 ? -floor(-x.x) : floor(x.x), x.y < 0 ? -floor(-x.y) : floor(x.y)); -} - -highp vec3 trunc(highp vec3 x) { - return vec3(x.x < 0 ? -floor(-x.x) : floor(x.x), x.y < 0 ? -floor(-x.y) : floor(x.y), x.z < 0 ? -floor(-x.z) : floor(x.z)); -} - -highp vec4 trunc(highp vec4 x) { - return vec4(x.x < 0 ? -floor(-x.x) : floor(x.x), x.y < 0 ? -floor(-x.y) : floor(x.y), x.z < 0 ? -floor(-x.z) : floor(x.z), x.w < 0 ? -floor(-x.w) : floor(x.w)); -} - -#endif - -#if defined(DETERMINANT_USED) - -highp float determinant(highp mat2 m) { - return m[0].x * m[1].y - m[1].x * m[0].y; -} - -highp float determinant(highp mat3 m) { - return m[0].x * (m[1].y * m[2].z - m[2].y * m[1].z) - m[1].x * (m[0].y * m[2].z - m[2].y * m[0].z) + m[2].x * (m[0].y * m[1].z - m[1].y * m[0].z); -} - -highp float determinant(highp mat4 m) { - highp float s00 = m[2].z * m[3].w - m[3].z * m[2].w; - highp float s01 = m[2].y * m[3].w - m[3].y * m[2].w; - highp float s02 = m[2].y * m[3].z - m[3].y * m[2].z; - highp float s03 = m[2].x * m[3].w - m[3].x * m[2].w; - highp float s04 = m[2].x * m[3].z - m[3].x * m[2].z; - highp float s05 = m[2].x * m[3].y - m[3].x * m[2].y; - highp vec4 c = vec4((m[1].y * s00 - m[1].z * s01 + m[1].w * s02), -(m[1].x * s00 - m[1].z * s03 + m[1].w * s04), (m[1].x * s01 - m[1].y * s03 + m[1].w * s05), -(m[1].x * s02 - m[1].y * s04 + m[1].z * s05)); - return m[0].x * c.x + m[0].y * c.y + m[0].z * c.z + m[0].w * c.w; -} - -#endif - -#if defined(INVERSE_USED) - -highp mat2 inverse(highp mat2 m) { - highp float d = 1.0 / (m[0].x * m[1].y - m[1].x * m[0].y); - return mat2( - vec2(m[1].y * d, -m[0].y * d), - vec2(-m[1].x * d, m[0].x * d)); -} - -highp mat3 inverse(highp mat3 m) { - highp float d = 1.0 / (m[0].x * (m[1].y * m[2].z - m[2].y * m[1].z) - m[1].x * (m[0].y * m[2].z - m[2].y * m[0].z) + m[2].x * (m[0].y * m[1].z - m[1].y * m[0].z)); - return mat3( - vec3((m[1].y * m[2].z - m[2].y * m[1].z), -(m[1].x * m[2].z - m[2].x * m[1].z), (m[1].x * m[2].y - m[2].x * m[1].y)) * d, - vec3(-(m[0].y * m[2].z - m[2].y * m[0].z), (m[0].x * m[2].z - m[2].x * m[0].z), -(m[0].x * m[2].y - m[2].x * m[0].y)) * d, - vec3((m[0].y * m[1].z - m[1].y * m[0].z), -(m[0].x * m[1].z - m[1].x * m[0].z), (m[0].x * m[1].y - m[1].x * m[0].y)) * d); -} - -highp mat4 inverse(highp mat4 m) { - highp float c00 = m[2].z * m[3].w - m[3].z * m[2].w; - highp float c02 = m[1].z * m[3].w - m[3].z * m[1].w; - highp float c03 = m[1].z * m[2].w - m[2].z * m[1].w; - - highp float c04 = m[2].y * m[3].w - m[3].y * m[2].w; - highp float c06 = m[1].y * m[3].w - m[3].y * m[1].w; - highp float c07 = m[1].y * m[2].w - m[2].y * m[1].w; - - highp float c08 = m[2].y * m[3].z - m[3].y * m[2].z; - highp float c10 = m[1].y * m[3].z - m[3].y * m[1].z; - highp float c11 = m[1].y * m[2].z - m[2].y * m[1].z; - - highp float c12 = m[2].x * m[3].w - m[3].x * m[2].w; - highp float c14 = m[1].x * m[3].w - m[3].x * m[1].w; - highp float c15 = m[1].x * m[2].w - m[2].x * m[1].w; - - highp float c16 = m[2].x * m[3].z - m[3].x * m[2].z; - highp float c18 = m[1].x * m[3].z - m[3].x * m[1].z; - highp float c19 = m[1].x * m[2].z - m[2].x * m[1].z; - - highp float c20 = m[2].x * m[3].y - m[3].x * m[2].y; - highp float c22 = m[1].x * m[3].y - m[3].x * m[1].y; - highp float c23 = m[1].x * m[2].y - m[2].x * m[1].y; - - vec4 f0 = vec4(c00, c00, c02, c03); - vec4 f1 = vec4(c04, c04, c06, c07); - vec4 f2 = vec4(c08, c08, c10, c11); - vec4 f3 = vec4(c12, c12, c14, c15); - vec4 f4 = vec4(c16, c16, c18, c19); - vec4 f5 = vec4(c20, c20, c22, c23); - - vec4 v0 = vec4(m[1].x, m[0].x, m[0].x, m[0].x); - vec4 v1 = vec4(m[1].y, m[0].y, m[0].y, m[0].y); - vec4 v2 = vec4(m[1].z, m[0].z, m[0].z, m[0].z); - vec4 v3 = vec4(m[1].w, m[0].w, m[0].w, m[0].w); - - vec4 inv0 = vec4(v1 * f0 - v2 * f1 + v3 * f2); - vec4 inv1 = vec4(v0 * f0 - v2 * f3 + v3 * f4); - vec4 inv2 = vec4(v0 * f1 - v1 * f3 + v3 * f5); - vec4 inv3 = vec4(v0 * f2 - v1 * f4 + v2 * f5); - - vec4 sa = vec4(+1, -1, +1, -1); - vec4 sb = vec4(-1, +1, -1, +1); - - mat4 inv = mat4(inv0 * sa, inv1 * sb, inv2 * sa, inv3 * sb); - - vec4 r0 = vec4(inv[0].x, inv[1].x, inv[2].x, inv[3].x); - vec4 d0 = vec4(m[0] * r0); - - highp float d1 = (d0.x + d0.y) + (d0.z + d0.w); - highp float d = 1.0 / d1; - - return inv * d; -} - -#endif - -#ifndef USE_GLES_OVER_GL - -#if defined(TRANSPOSE_USED) - -highp mat2 transpose(highp mat2 m) { - return mat2( - vec2(m[0].x, m[1].x), - vec2(m[0].y, m[1].y)); -} - -highp mat3 transpose(highp mat3 m) { - return mat3( - vec3(m[0].x, m[1].x, m[2].x), - vec3(m[0].y, m[1].y, m[2].y), - vec3(m[0].z, m[1].z, m[2].z)); -} - -#endif - -highp mat4 transpose(highp mat4 m) { - return mat4( - vec4(m[0].x, m[1].x, m[2].x, m[3].x), - vec4(m[0].y, m[1].y, m[2].y, m[3].y), - vec4(m[0].z, m[1].z, m[2].z, m[3].z), - vec4(m[0].w, m[1].w, m[2].w, m[3].w)); -} - -#if defined(OUTER_PRODUCT_USED) - -highp mat2 outerProduct(highp vec2 c, highp vec2 r) { - return mat2(c * r.x, c * r.y); -} - -highp mat3 outerProduct(highp vec3 c, highp vec3 r) { - return mat3(c * r.x, c * r.y, c * r.z); -} - -highp mat4 outerProduct(highp vec4 c, highp vec4 r) { - return mat4(c * r.x, c * r.y, c * r.z, c * r.w); -} - -#endif - -#endif diff --git a/drivers/gles2/shaders/subsurf_scattering.glsl b/drivers/gles2/shaders/subsurf_scattering.glsl deleted file mode 100644 index f40fb3a244..0000000000 --- a/drivers/gles2/shaders/subsurf_scattering.glsl +++ /dev/null @@ -1,174 +0,0 @@ -/* clang-format off */ -[vertex] - -layout(location = 0) in highp vec4 vertex_attrib; -/* clang-format on */ -layout(location = 4) in vec2 uv_in; - -out vec2 uv_interp; - -void main() { - - uv_interp = uv_in; - gl_Position = vertex_attrib; -} - -/* clang-format off */ -[fragment] - -//#define QUALIFIER uniform // some guy on the interweb says it may be faster with this -#define QUALIFIER const - -#ifdef USE_25_SAMPLES -const int kernel_size = 25; -/* clang-format on */ -QUALIFIER vec2 kernel[25] = vec2[]( - vec2(0.530605, 0.0), - vec2(0.000973794, -3.0), - vec2(0.00333804, -2.52083), - vec2(0.00500364, -2.08333), - vec2(0.00700976, -1.6875), - vec2(0.0094389, -1.33333), - vec2(0.0128496, -1.02083), - vec2(0.017924, -0.75), - vec2(0.0263642, -0.520833), - vec2(0.0410172, -0.333333), - vec2(0.0493588, -0.1875), - vec2(0.0402784, -0.0833333), - vec2(0.0211412, -0.0208333), - vec2(0.0211412, 0.0208333), - vec2(0.0402784, 0.0833333), - vec2(0.0493588, 0.1875), - vec2(0.0410172, 0.333333), - vec2(0.0263642, 0.520833), - vec2(0.017924, 0.75), - vec2(0.0128496, 1.02083), - vec2(0.0094389, 1.33333), - vec2(0.00700976, 1.6875), - vec2(0.00500364, 2.08333), - vec2(0.00333804, 2.52083), - vec2(0.000973794, 3.0)); -#endif //USE_25_SAMPLES - -#ifdef USE_17_SAMPLES -const int kernel_size = 17; -QUALIFIER vec2 kernel[17] = vec2[]( - vec2(0.536343, 0.0), - vec2(0.00317394, -2.0), - vec2(0.0100386, -1.53125), - vec2(0.0144609, -1.125), - vec2(0.0216301, -0.78125), - vec2(0.0347317, -0.5), - vec2(0.0571056, -0.28125), - vec2(0.0582416, -0.125), - vec2(0.0324462, -0.03125), - vec2(0.0324462, 0.03125), - vec2(0.0582416, 0.125), - vec2(0.0571056, 0.28125), - vec2(0.0347317, 0.5), - vec2(0.0216301, 0.78125), - vec2(0.0144609, 1.125), - vec2(0.0100386, 1.53125), - vec2(0.00317394, 2.0)); -#endif //USE_17_SAMPLES - -#ifdef USE_11_SAMPLES -const int kernel_size = 11; -QUALIFIER vec2 kernel[11] = vec2[]( - vec2(0.560479, 0.0), - vec2(0.00471691, -2.0), - vec2(0.0192831, -1.28), - vec2(0.03639, -0.72), - vec2(0.0821904, -0.32), - vec2(0.0771802, -0.08), - vec2(0.0771802, 0.08), - vec2(0.0821904, 0.32), - vec2(0.03639, 0.72), - vec2(0.0192831, 1.28), - vec2(0.00471691, 2.0)); -#endif //USE_11_SAMPLES - -uniform float max_radius; -uniform float camera_z_far; -uniform float camera_z_near; -uniform float unit_size; -uniform vec2 dir; -in vec2 uv_interp; - -uniform sampler2D source_diffuse; //texunit:0 -uniform sampler2D source_sss; //texunit:1 -uniform sampler2D source_depth; //texunit:2 - -layout(location = 0) out vec4 frag_color; - -void main() { - - float strength = texture(source_sss, uv_interp).r; - strength *= strength; //stored as sqrt - - // Fetch color of current pixel: - vec4 base_color = texture(source_diffuse, uv_interp); - - if (strength > 0.0) { - - // Fetch linear depth of current pixel: - float depth = texture(source_depth, uv_interp).r * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - depth = ((depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; - float scale = unit_size; //remember depth is negative by default in OpenGL -#else - depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near)); - float scale = unit_size / depth; //remember depth is negative by default in OpenGL -#endif - - // Calculate the final step to fetch the surrounding pixels: - vec2 step = max_radius * scale * dir; - step *= strength; // Modulate it using the alpha channel. - step *= 1.0 / 3.0; // Divide by 3 as the kernels range from -3 to 3. - - // Accumulate the center sample: - vec3 color_accum = base_color.rgb; - color_accum *= kernel[0].x; -#ifdef ENABLE_STRENGTH_WEIGHTING - float color_weight = kernel[0].x; -#endif - - // Accumulate the other samples: - for (int i = 1; i < kernel_size; i++) { - // Fetch color and depth for current sample: - vec2 offset = uv_interp + kernel[i].y * step; - vec3 color = texture(source_diffuse, offset).rgb; - -#ifdef ENABLE_FOLLOW_SURFACE - // If the difference in depth is huge, we lerp color back to "colorM": - float depth_cmp = texture(source_depth, offset).r * 2.0 - 1.0; - -#ifdef USE_ORTHOGONAL_PROJECTION - depth_cmp = ((depth_cmp + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - depth_cmp = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth_cmp * (camera_z_far - camera_z_near)); -#endif - - float s = clamp(300.0f * scale * max_radius * abs(depth - depth_cmp), 0.0, 1.0); - color = mix(color, base_color.rgb, s); -#endif - - // Accumulate: - color *= kernel[i].x; - -#ifdef ENABLE_STRENGTH_WEIGHTING - float color_s = texture(source_sss, offset).r; - color_weight += color_s * kernel[i].x; - color *= color_s; -#endif - color_accum += color; - } - -#ifdef ENABLE_STRENGTH_WEIGHTING - color_accum /= color_weight; -#endif - frag_color = vec4(color_accum, base_color.a); //keep alpha (used for SSAO) - } else { - frag_color = base_color; - } -} diff --git a/drivers/gles2/shaders/tonemap.glsl b/drivers/gles2/shaders/tonemap.glsl deleted file mode 100644 index 585d821626..0000000000 --- a/drivers/gles2/shaders/tonemap.glsl +++ /dev/null @@ -1,289 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -attribute vec2 vertex_attrib; // attrib:0 -/* clang-format on */ -attribute vec2 uv_in; // attrib:4 - -varying vec2 uv_interp; - -void main() { - gl_Position = vec4(vertex_attrib, 0.0, 1.0); - - uv_interp = uv_in; -} - -/* clang-format off */ -[fragment] - - -// texture2DLodEXT and textureCubeLodEXT are fragment shader specific. -// Do not copy these defines in the vertex section. -#ifndef USE_GLES_OVER_GL -#ifdef GL_EXT_shader_texture_lod -#extension GL_EXT_shader_texture_lod : enable -#define texture2DLod(img, coord, lod) texture2DLodEXT(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCubeLodEXT(img, coord, lod) -#endif -#endif // !USE_GLES_OVER_GL - -#ifdef GL_ARB_shader_texture_lod -#extension GL_ARB_shader_texture_lod : enable -#endif - -#if !defined(GL_EXT_shader_texture_lod) && !defined(GL_ARB_shader_texture_lod) -#define texture2DLod(img, coord, lod) texture2D(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCube(img, coord, lod) -#endif - -// Allows the use of bitshift operators for bicubic upscale -#ifdef GL_EXT_gpu_shader4 -#extension GL_EXT_gpu_shader4 : enable -#endif - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -#include "stdlib.glsl" - -varying vec2 uv_interp; -/* clang-format on */ - -uniform highp sampler2D source; //texunit:0 - -#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7) -#define USING_GLOW // only use glow when at least one glow level is selected - -#ifdef USE_MULTI_TEXTURE_GLOW -uniform highp sampler2D source_glow1; //texunit:1 -uniform highp sampler2D source_glow2; //texunit:2 -uniform highp sampler2D source_glow3; //texunit:3 -uniform highp sampler2D source_glow4; //texunit:4 -uniform highp sampler2D source_glow5; //texunit:5 -uniform highp sampler2D source_glow6; //texunit:6 -uniform highp sampler2D source_glow7; //texunit:7 -#else -uniform highp sampler2D source_glow; //texunit:1 -#endif -uniform highp float glow_intensity; -#endif - -#ifdef USE_BCS -uniform vec3 bcs; -#endif - -#ifdef USE_COLOR_CORRECTION -uniform sampler2D color_correction; //texunit:2 -#endif - -#ifdef GL_EXT_gpu_shader4 -#ifdef USE_GLOW_FILTER_BICUBIC -// w0, w1, w2, and w3 are the four cubic B-spline basis functions -float w0(float a) { - return (1.0 / 6.0) * (a * (a * (-a + 3.0) - 3.0) + 1.0); -} - -float w1(float a) { - return (1.0 / 6.0) * (a * a * (3.0 * a - 6.0) + 4.0); -} - -float w2(float a) { - return (1.0 / 6.0) * (a * (a * (-3.0 * a + 3.0) + 3.0) + 1.0); -} - -float w3(float a) { - return (1.0 / 6.0) * (a * a * a); -} - -// g0 and g1 are the two amplitude functions -float g0(float a) { - return w0(a) + w1(a); -} - -float g1(float a) { - return w2(a) + w3(a); -} - -// h0 and h1 are the two offset functions -float h0(float a) { - return -1.0 + w1(a) / (w0(a) + w1(a)); -} - -float h1(float a) { - return 1.0 + w3(a) / (w2(a) + w3(a)); -} - -uniform ivec2 glow_texture_size; - -vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { - float lod = float(p_lod); - vec2 tex_size = vec2(glow_texture_size >> p_lod); - vec2 pixel_size = vec2(1.0) / tex_size; - - uv = uv * tex_size + vec2(0.5); - - vec2 iuv = floor(uv); - vec2 fuv = fract(uv); - - float g0x = g0(fuv.x); - float g1x = g1(fuv.x); - float h0x = h0(fuv.x); - float h1x = h1(fuv.x); - float h0y = h0(fuv.y); - float h1y = h1(fuv.y); - - vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5)) * pixel_size; - vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5)) * pixel_size; - vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5)) * pixel_size; - vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5)) * pixel_size; - - return (g0(fuv.y) * (g0x * texture2DLod(tex, p0, lod) + g1x * texture2DLod(tex, p1, lod))) + - (g1(fuv.y) * (g0x * texture2DLod(tex, p2, lod) + g1x * texture2DLod(tex, p3, lod))); -} - -#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod) -#else //!USE_GLOW_FILTER_BICUBIC -#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2DLod(m_tex, m_uv, float(m_lod)) -#endif //USE_GLOW_FILTER_BICUBIC - -#else //!GL_EXT_gpu_shader4 -#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2DLod(m_tex, m_uv, float(m_lod)) -#endif //GL_EXT_gpu_shader4 - -vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blending mode -#ifdef USE_GLOW_REPLACE - color = glow; -#endif - -#ifdef USE_GLOW_SCREEN - color = max((color + glow) - (color * glow), vec3(0.0)); -#endif - -#ifdef USE_GLOW_SOFTLIGHT - glow = glow * vec3(0.5) + vec3(0.5); - - color.r = (glow.r <= 0.5) ? (color.r - (1.0 - 2.0 * glow.r) * color.r * (1.0 - color.r)) : (((glow.r > 0.5) && (color.r <= 0.25)) ? (color.r + (2.0 * glow.r - 1.0) * (4.0 * color.r * (4.0 * color.r + 1.0) * (color.r - 1.0) + 7.0 * color.r)) : (color.r + (2.0 * glow.r - 1.0) * (sqrt(color.r) - color.r))); - color.g = (glow.g <= 0.5) ? (color.g - (1.0 - 2.0 * glow.g) * color.g * (1.0 - color.g)) : (((glow.g > 0.5) && (color.g <= 0.25)) ? (color.g + (2.0 * glow.g - 1.0) * (4.0 * color.g * (4.0 * color.g + 1.0) * (color.g - 1.0) + 7.0 * color.g)) : (color.g + (2.0 * glow.g - 1.0) * (sqrt(color.g) - color.g))); - color.b = (glow.b <= 0.5) ? (color.b - (1.0 - 2.0 * glow.b) * color.b * (1.0 - color.b)) : (((glow.b > 0.5) && (color.b <= 0.25)) ? (color.b + (2.0 * glow.b - 1.0) * (4.0 * color.b * (4.0 * color.b + 1.0) * (color.b - 1.0) + 7.0 * color.b)) : (color.b + (2.0 * glow.b - 1.0) * (sqrt(color.b) - color.b))); -#endif - -#if !defined(USE_GLOW_SCREEN) && !defined(USE_GLOW_SOFTLIGHT) && !defined(USE_GLOW_REPLACE) // no other selected -> additive - color += glow; -#endif - - return color; -} - -vec3 apply_bcs(vec3 color, vec3 bcs) { - color = mix(vec3(0.0), color, bcs.x); - color = mix(vec3(0.5), color, bcs.y); - color = mix(vec3(dot(vec3(1.0), color) * 0.33333), color, bcs.z); - - return color; -} - -vec3 apply_color_correction(vec3 color, sampler2D correction_tex) { - color.r = texture2D(correction_tex, vec2(color.r, 0.0)).r; - color.g = texture2D(correction_tex, vec2(color.g, 0.0)).g; - color.b = texture2D(correction_tex, vec2(color.b, 0.0)).b; - - return color; -} - -void main() { - vec3 color = texture2DLod(source, uv_interp, 0.0).rgb; - - // Glow - -#ifdef USING_GLOW - vec3 glow = vec3(0.0); -#ifdef USE_MULTI_TEXTURE_GLOW -#ifdef USE_GLOW_LEVEL1 - glow += GLOW_TEXTURE_SAMPLE(source_glow1, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL2 - glow += GLOW_TEXTURE_SAMPLE(source_glow2, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL3 - glow += GLOW_TEXTURE_SAMPLE(source_glow3, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL4 - glow += GLOW_TEXTURE_SAMPLE(source_glow4, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL5 - glow += GLOW_TEXTURE_SAMPLE(source_glow5, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL6 - glow += GLOW_TEXTURE_SAMPLE(source_glow6, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL7 - glow += GLOW_TEXTURE_SAMPLE(source_glow7, uv_interp, 0).rgb; -#endif -#endif -#endif -#endif -#endif -#endif -#endif - -#else - -#ifdef USE_GLOW_LEVEL1 - glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 1).rgb; -#endif - -#ifdef USE_GLOW_LEVEL2 - glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 2).rgb; -#endif - -#ifdef USE_GLOW_LEVEL3 - glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 3).rgb; -#endif - -#ifdef USE_GLOW_LEVEL4 - glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 4).rgb; -#endif - -#ifdef USE_GLOW_LEVEL5 - glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 5).rgb; -#endif - -#ifdef USE_GLOW_LEVEL6 - glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 6).rgb; -#endif - -#ifdef USE_GLOW_LEVEL7 - glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 7).rgb; -#endif -#endif //USE_MULTI_TEXTURE_GLOW - - glow *= glow_intensity; - color = apply_glow(color, glow); -#endif - - // Additional effects - -#ifdef USE_BCS - color = apply_bcs(color, bcs); -#endif - -#ifdef USE_COLOR_CORRECTION - color = apply_color_correction(color, color_correction); -#endif - - gl_FragColor = vec4(color, 1.0); -} diff --git a/drivers/png/SCsub b/drivers/png/SCsub index db08be0c47..26508dc612 100644 --- a/drivers/png/SCsub +++ b/drivers/png/SCsub @@ -5,6 +5,9 @@ Import("env") env_png = env.Clone() # Thirdparty source files + +thirdparty_obj = [] + if env["builtin_libpng"]: thirdparty_dir = "#thirdparty/libpng/" thirdparty_sources = [ @@ -41,7 +44,7 @@ if env["builtin_libpng"]: env_thirdparty = env_png.Clone() env_thirdparty.disable_warnings() - env_thirdparty.add_source_files(env.drivers_sources, thirdparty_sources) + env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) if use_neon: env_neon = env_thirdparty.Clone() @@ -52,9 +55,17 @@ if env["builtin_libpng"]: neon_sources.append(env_neon.Object(thirdparty_dir + "/arm/filter_neon_intrinsics.c")) neon_sources.append(env_neon.Object(thirdparty_dir + "/arm/filter_neon.S")) neon_sources.append(env_neon.Object(thirdparty_dir + "/arm/palette_neon_intrinsics.c")) - env.drivers_sources += neon_sources + thirdparty_obj += neon_sources + + env.drivers_sources += thirdparty_obj + # Godot source files -env_png.add_source_files(env.drivers_sources, "*.cpp") -Export("env") +driver_obj = [] + +env_png.add_source_files(driver_obj, "*.cpp") +env.drivers_sources += driver_obj + +# Needed to force rebuilding the driver files when the thirdparty library is updated. +env.Depends(driver_obj, thirdparty_obj) diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp index 4cb93a821c..854c6706e6 100644 --- a/drivers/png/image_loader_png.cpp +++ b/drivers/png/image_loader_png.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,13 +31,12 @@ #include "image_loader_png.h" #include "core/os/os.h" -#include "core/print_string.h" +#include "core/string/print_string.h" #include "drivers/png/png_driver_common.h" #include <string.h> Error ImageLoaderPNG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { - const size_t buffer_size = f->get_len(); Vector<uint8_t> file_buffer; Error err = file_buffer.resize(buffer_size); @@ -51,27 +50,25 @@ Error ImageLoaderPNG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force f->close(); } const uint8_t *reader = file_buffer.ptr(); - return PNGDriverCommon::png_to_image(reader, buffer_size, p_image); + return PNGDriverCommon::png_to_image(reader, buffer_size, p_force_linear, p_image); } void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("png"); } Ref<Image> ImageLoaderPNG::load_mem_png(const uint8_t *p_png, int p_size) { - Ref<Image> img; img.instance(); - Error err = PNGDriverCommon::png_to_image(p_png, p_size, img); + // the value of p_force_linear does not matter since it only applies to 16 bit + Error err = PNGDriverCommon::png_to_image(p_png, p_size, false, img); ERR_FAIL_COND_V(err, Ref<Image>()); return img; } Ref<Image> ImageLoaderPNG::lossless_unpack_png(const Vector<uint8_t> &p_data) { - const int len = p_data.size(); ERR_FAIL_COND_V(len < 4, Ref<Image>()); const uint8_t *r = p_data.ptr(); @@ -80,7 +77,6 @@ Ref<Image> ImageLoaderPNG::lossless_unpack_png(const Vector<uint8_t> &p_data) { } Vector<uint8_t> ImageLoaderPNG::lossless_pack_png(const Ref<Image> &p_image) { - Vector<uint8_t> out_buffer; // add Godot's own "PNG " prefix @@ -104,7 +100,6 @@ Vector<uint8_t> ImageLoaderPNG::lossless_pack_png(const Ref<Image> &p_image) { } ImageLoaderPNG::ImageLoaderPNG() { - Image::_png_mem_loader_func = load_mem_png; Image::lossless_unpacker = lossless_unpack_png; Image::lossless_packer = lossless_pack_png; diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h index 0154be0398..b4a58616f6 100644 --- a/drivers/png/image_loader_png.h +++ b/drivers/png/image_loader_png.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/drivers/png/png_driver_common.cpp b/drivers/png/png_driver_common.cpp index f17abcb54c..9e848a2253 100644 --- a/drivers/png/png_driver_common.cpp +++ b/drivers/png/png_driver_common.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -58,8 +58,7 @@ static bool check_error(const png_image &image) { return false; } -Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image) { - +Error png_to_image(const uint8_t *p_source, size_t p_size, bool p_force_linear, Ref<Image> p_image) { png_image png_img; zeromem(&png_img, sizeof(png_img)); png_img.version = PNG_IMAGE_VERSION; @@ -100,6 +99,11 @@ Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image) { return ERR_UNAVAILABLE; } + if (!p_force_linear) { + // assume 16 bit pngs without sRGB or gAMA chunks are in sRGB format + png_img.flags |= PNG_IMAGE_FLAG_16BIT_sRGB; + } + const png_uint_32 stride = PNG_IMAGE_ROW_STRIDE(png_img); Vector<uint8_t> buffer; Error err = buffer.resize(PNG_IMAGE_BUFFER_SIZE(png_img, stride)); @@ -115,17 +119,17 @@ Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image) { ERR_FAIL_COND_V(!success, ERR_FILE_CORRUPT); //print_line("png width: "+itos(png_img.width)+" height: "+itos(png_img.height)); - p_image->create(png_img.width, png_img.height, 0, dest_format, buffer); + p_image->create(png_img.width, png_img.height, false, dest_format, buffer); return OK; } Error image_to_png(const Ref<Image> &p_image, Vector<uint8_t> &p_buffer) { - Ref<Image> source_image = p_image->duplicate(); - if (source_image->is_compressed()) + if (source_image->is_compressed()) { source_image->decompress(); + } ERR_FAIL_COND_V(source_image->is_compressed(), FAILED); @@ -179,7 +183,6 @@ Error image_to_png(const Ref<Image> &p_image, Vector<uint8_t> &p_buffer) { ERR_FAIL_COND_V_MSG(check_error(png_img), FAILED, png_img.message); } if (!success) { - // buffer was big enough, must be some other error ERR_FAIL_COND_V(compressed_size <= png_size_estimate, FAILED); @@ -200,5 +203,4 @@ Error image_to_png(const Ref<Image> &p_image, Vector<uint8_t> &p_buffer) { return OK; } - } // namespace PNGDriverCommon diff --git a/drivers/png/png_driver_common.h b/drivers/png/png_driver_common.h index 12129f034e..003b587913 100644 --- a/drivers/png/png_driver_common.h +++ b/drivers/png/png_driver_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 */ @@ -31,17 +31,16 @@ #ifndef PNG_DRIVER_COMMON_H #define PNG_DRIVER_COMMON_H -#include "core/image.h" +#include "core/io/image.h" namespace PNGDriverCommon { // Attempt to load png from buffer (p_source, p_size) into p_image -Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image); +Error png_to_image(const uint8_t *p_source, size_t p_size, bool p_force_linear, Ref<Image> p_image); // Append p_image, as a png, to p_buffer. // Contents of p_buffer is unspecified if error returned. Error image_to_png(const Ref<Image> &p_image, Vector<uint8_t> &p_buffer); - } // namespace PNGDriverCommon #endif diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp index 2380c2685f..f47fc403cc 100644 --- a/drivers/png/resource_saver_png.cpp +++ b/drivers/png/resource_saver_png.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,13 +30,12 @@ #include "resource_saver_png.h" -#include "core/image.h" +#include "core/io/image.h" #include "core/os/file_access.h" #include "drivers/png/png_driver_common.h" #include "scene/resources/texture.h" Error ResourceSaverPNG::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { - Ref<ImageTexture> texture = p_resource; ERR_FAIL_COND_V_MSG(!texture.is_valid(), ERR_INVALID_PARAMETER, "Can't save invalid texture as PNG."); @@ -50,7 +49,6 @@ Error ResourceSaverPNG::save(const String &p_path, const RES &p_resource, uint32 }; Error ResourceSaverPNG::save_image(const String &p_path, const Ref<Image> &p_img) { - Vector<uint8_t> buffer; Error err = PNGDriverCommon::image_to_png(p_img, buffer); ERR_FAIL_COND_V_MSG(err, err, "Can't convert image to PNG."); @@ -72,7 +70,6 @@ Error ResourceSaverPNG::save_image(const String &p_path, const Ref<Image> &p_img } Vector<uint8_t> ResourceSaverPNG::save_image_to_buffer(const Ref<Image> &p_img) { - Vector<uint8_t> buffer; Error err = PNGDriverCommon::image_to_png(p_img, buffer); ERR_FAIL_COND_V_MSG(err, Vector<uint8_t>(), "Can't convert image to PNG."); @@ -80,19 +77,16 @@ Vector<uint8_t> ResourceSaverPNG::save_image_to_buffer(const Ref<Image> &p_img) } bool ResourceSaverPNG::recognize(const RES &p_resource) const { - return (p_resource.is_valid() && p_resource->is_class("ImageTexture")); } void ResourceSaverPNG::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { - if (Object::cast_to<ImageTexture>(*p_resource)) { p_extensions->push_back("png"); } } ResourceSaverPNG::ResourceSaverPNG() { - Image::save_png_func = &save_image; Image::save_png_buffer_func = &save_image_to_buffer; }; diff --git a/drivers/png/resource_saver_png.h b/drivers/png/resource_saver_png.h index c32b383521..c924438224 100644 --- a/drivers/png/resource_saver_png.h +++ b/drivers/png/resource_saver_png.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 RESOURCE_SAVER_PNG_H #define RESOURCE_SAVER_PNG_H -#include "core/image.h" +#include "core/io/image.h" #include "core/io/resource_saver.h" class ResourceSaverPNG : public ResourceFormatSaver { diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index 8a47f6cf96..440b7d7f53 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.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,8 +32,8 @@ #ifdef PULSEAUDIO_ENABLED +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" void AudioDriverPulseAudio::pa_state_cb(pa_context *c, void *userdata) { AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata; @@ -78,7 +78,6 @@ void AudioDriverPulseAudio::pa_source_info_cb(pa_context *c, const pa_source_inf } void AudioDriverPulseAudio::pa_server_info_cb(pa_context *c, const pa_server_info *i, void *userdata) { - ERR_FAIL_COND_MSG(!i, "PulseAudio server info is null."); AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata; @@ -88,7 +87,6 @@ void AudioDriverPulseAudio::pa_server_info_cb(pa_context *c, const pa_server_inf } void AudioDriverPulseAudio::detect_channels(bool capture) { - pa_channel_map_init_stereo(capture ? &pa_rec_map : &pa_map); String device = capture ? capture_device_name : device_name; @@ -145,7 +143,6 @@ void AudioDriverPulseAudio::detect_channels(bool capture) { } Error AudioDriverPulseAudio::init_device() { - // If there is a specified device check that it is really present if (device_name != "Default") { Array list = get_device_list(); @@ -182,7 +179,7 @@ Error AudioDriverPulseAudio::init_device() { break; } - int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY); + int latency = GLOBAL_GET("audio/output_latency"); buffer_frames = closest_power_of_2(latency * mix_rate / 1000); pa_buffer_size = buffer_frames * pa_map.channels; @@ -236,12 +233,11 @@ Error AudioDriverPulseAudio::init_device() { } Error AudioDriverPulseAudio::init() { - active = false; thread_exited = false; exit_thread = false; - mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); + mix_rate = GLOBAL_GET("audio/mix_rate"); pa_ml = pa_mainloop_new(); ERR_FAIL_COND_V(pa_ml == nullptr, ERR_CANT_OPEN); @@ -298,7 +294,6 @@ Error AudioDriverPulseAudio::init() { } float AudioDriverPulseAudio::get_latency() { - if (latency == 0) { //only do this once since it's approximate anyway lock(); @@ -324,14 +319,12 @@ float AudioDriverPulseAudio::get_latency() { } void AudioDriverPulseAudio::thread_func(void *p_udata) { - AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)p_udata; unsigned int write_ofs = 0; size_t avail_bytes = 0; uint32_t default_device_msec = OS::get_singleton()->get_ticks_msec(); while (!ad->exit_thread) { - size_t read_bytes = 0; size_t written_bytes = 0; @@ -421,7 +414,6 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { // If we're using the default device check that the current device is still the default if (ad->device_name == "Default") { - uint32_t msec = OS::get_singleton()->get_ticks_msec(); if (msec > (default_device_msec + 1000)) { String old_default_device = ad->default_device; @@ -524,17 +516,14 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { } void AudioDriverPulseAudio::start() { - active = true; } int AudioDriverPulseAudio::get_mix_rate() const { - return mix_rate; } AudioDriver::SpeakerMode AudioDriverPulseAudio::get_speaker_mode() const { - return get_speaker_mode_by_total_channels(channels); } @@ -551,7 +540,6 @@ void AudioDriverPulseAudio::pa_sinklist_cb(pa_context *c, const pa_sink_info *l, } Array AudioDriverPulseAudio::get_device_list() { - pa_devices.clear(); pa_devices.push_back("Default"); @@ -583,33 +571,30 @@ Array AudioDriverPulseAudio::get_device_list() { } String AudioDriverPulseAudio::get_device() { - return device_name; } void AudioDriverPulseAudio::set_device(String device) { - lock(); new_device = device; unlock(); } void AudioDriverPulseAudio::lock() { - - if (!thread) + if (!thread) { return; + } mutex.lock(); } void AudioDriverPulseAudio::unlock() { - - if (!thread) + if (!thread) { return; + } mutex.unlock(); } void AudioDriverPulseAudio::finish_device() { - if (pa_str) { pa_stream_disconnect(pa_str); pa_stream_unref(pa_str); @@ -618,9 +603,9 @@ void AudioDriverPulseAudio::finish_device() { } void AudioDriverPulseAudio::finish() { - - if (!thread) + if (!thread) { return; + } exit_thread = true; Thread::wait_to_finish(thread); @@ -644,7 +629,6 @@ void AudioDriverPulseAudio::finish() { } Error AudioDriverPulseAudio::capture_init_device() { - // If there is a specified device check that it is really present if (capture_device_name != "Default") { Array list = capture_get_device_list(); @@ -702,7 +686,6 @@ Error AudioDriverPulseAudio::capture_init_device() { } void AudioDriverPulseAudio::capture_finish_device() { - if (pa_rec_str) { int ret = pa_stream_disconnect(pa_rec_str); if (ret != 0) { @@ -714,7 +697,6 @@ void AudioDriverPulseAudio::capture_finish_device() { } Error AudioDriverPulseAudio::capture_start() { - lock(); Error err = capture_init_device(); unlock(); @@ -731,7 +713,6 @@ Error AudioDriverPulseAudio::capture_stop() { } void AudioDriverPulseAudio::capture_set_device(const String &p_name) { - lock(); capture_new_device = p_name; unlock(); @@ -753,7 +734,6 @@ void AudioDriverPulseAudio::pa_sourcelist_cb(pa_context *c, const pa_source_info } Array AudioDriverPulseAudio::capture_get_device_list() { - pa_rec_devices.clear(); pa_rec_devices.push_back("Default"); @@ -785,7 +765,6 @@ Array AudioDriverPulseAudio::capture_get_device_list() { } String AudioDriverPulseAudio::capture_get_device() { - lock(); String name = capture_device_name; unlock(); @@ -793,30 +772,9 @@ String AudioDriverPulseAudio::capture_get_device() { return name; } -AudioDriverPulseAudio::AudioDriverPulseAudio() : - thread(nullptr), - pa_ml(nullptr), - pa_ctx(nullptr), - pa_str(nullptr), - pa_rec_str(nullptr), - device_name("Default"), - new_device("Default"), - default_device(""), - mix_rate(0), - buffer_frames(0), - pa_buffer_size(0), - channels(0), - pa_ready(0), - pa_status(0), - active(false), - thread_exited(false), - exit_thread(false), - latency(0) { +AudioDriverPulseAudio::AudioDriverPulseAudio() { samples_in.clear(); samples_out.clear(); } -AudioDriverPulseAudio::~AudioDriverPulseAudio() { -} - -#endif +#endif // PULSEAUDIO_ENABLED diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h index 1ece332a8a..71ab2ef1c8 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.h +++ b/drivers/pulseaudio/audio_driver_pulseaudio.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 */ @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef PULSEAUDIO_ENABLED - #ifndef AUDIO_DRIVER_PULSEAUDIO_H #define AUDIO_DRIVER_PULSEAUDIO_H +#ifdef PULSEAUDIO_ENABLED + #include "core/os/mutex.h" #include "core/os/thread.h" #include "servers/audio_server.h" @@ -40,19 +40,18 @@ #include <pulse/pulseaudio.h> class AudioDriverPulseAudio : public AudioDriver { - - Thread *thread; + Thread *thread = nullptr; Mutex mutex; - pa_mainloop *pa_ml; - pa_context *pa_ctx; - pa_stream *pa_str; - pa_stream *pa_rec_str; + pa_mainloop *pa_ml = nullptr; + pa_context *pa_ctx = nullptr; + pa_stream *pa_str = nullptr; + pa_stream *pa_rec_str = nullptr; pa_channel_map pa_map; pa_channel_map pa_rec_map; - String device_name; - String new_device; + String device_name = "Default"; + String new_device = "Default"; String default_device; String capture_device_name; @@ -62,20 +61,20 @@ class AudioDriverPulseAudio : public AudioDriver { Vector<int32_t> samples_in; Vector<int16_t> samples_out; - unsigned int mix_rate; - unsigned int buffer_frames; - unsigned int pa_buffer_size; - int channels; - int pa_ready; - int pa_status; + unsigned int mix_rate = 0; + unsigned int buffer_frames = 0; + unsigned int pa_buffer_size = 0; + int channels = 0; + int pa_ready = 0; + int pa_status = 0; Array pa_devices; Array pa_rec_devices; - bool active; - bool thread_exited; - mutable bool exit_thread; + bool active = false; + bool thread_exited = false; + mutable bool exit_thread = false; - float latency; + float latency = 0; static void pa_state_cb(pa_context *c, void *userdata); static void pa_sink_info_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata); @@ -122,9 +121,9 @@ public: virtual Error capture_stop(); AudioDriverPulseAudio(); - ~AudioDriverPulseAudio(); + ~AudioDriverPulseAudio() {} }; -#endif // AUDIO_DRIVER_PULSEAUDIO_H - #endif // PULSEAUDIO_ENABLED + +#endif // AUDIO_DRIVER_PULSEAUDIO_H diff --git a/drivers/register_driver_types.cpp b/drivers/register_driver_types.cpp index dcc7a5c14d..18262c74c4 100644 --- a/drivers/register_driver_types.cpp +++ b/drivers/register_driver_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 */ @@ -37,7 +37,6 @@ static ImageLoaderPNG *image_loader_png; static Ref<ResourceSaverPNG> resource_saver_png; void register_core_driver_types() { - image_loader_png = memnew(ImageLoaderPNG); ImageLoader::add_image_format_loader(image_loader_png); @@ -46,9 +45,9 @@ void register_core_driver_types() { } void unregister_core_driver_types() { - - if (image_loader_png) + if (image_loader_png) { memdelete(image_loader_png); + } ResourceSaver::remove_resource_format_saver(resource_saver_png); resource_saver_png.unref(); diff --git a/drivers/register_driver_types.h b/drivers/register_driver_types.h index c8dbdbb22d..607aa91cb8 100644 --- a/drivers/register_driver_types.h +++ b/drivers/register_driver_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/drivers/spirv-reflect/SCsub b/drivers/spirv-reflect/SCsub index d0ffaf068d..1e7b3de0e6 100644 --- a/drivers/spirv-reflect/SCsub +++ b/drivers/spirv-reflect/SCsub @@ -2,8 +2,7 @@ Import("env") -env_spirv_reflect = env.Clone() -env_spirv_reflect.disable_warnings() +# Thirdparty source files thirdparty_dir = "#thirdparty/spirv-reflect/" thirdparty_sources = [ @@ -12,6 +11,7 @@ thirdparty_sources = [ thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] -env_spirv_reflect.add_source_files(env.drivers_sources, thirdparty_sources) +env_thirdparty = env.Clone() +env_thirdparty.disable_warnings() -Export("env") +env_thirdparty.add_source_files(env.drivers_sources, thirdparty_sources) diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index 00103684c7..5dc039afd9 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.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,9 +32,9 @@ #if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) -#include "core/list.h" #include "core/os/memory.h" -#include "core/print_string.h" +#include "core/string/print_string.h" +#include "core/templates/list.h" #include <errno.h> #include <stdio.h> @@ -50,12 +50,10 @@ #endif DirAccess *DirAccessUnix::create_fs() { - return memnew(DirAccessUnix); } Error DirAccessUnix::list_dir_begin() { - list_dir_end(); //close any previous dir opening! //char real_current_dir_name[2048]; //is this enough?! @@ -63,18 +61,19 @@ Error DirAccessUnix::list_dir_begin() { //chdir(current_path.utf8().get_data()); dir_stream = opendir(current_dir.utf8().get_data()); //chdir(real_current_dir_name); - if (!dir_stream) + if (!dir_stream) { return ERR_CANT_OPEN; //error! + } return OK; } bool DirAccessUnix::file_exists(String p_file) { - GLOBAL_LOCK_FUNCTION - if (p_file.is_rel_path()) + if (p_file.is_rel_path()) { p_file = current_dir.plus_file(p_file); + } p_file = fix_path(p_file); @@ -89,11 +88,11 @@ bool DirAccessUnix::file_exists(String p_file) { } bool DirAccessUnix::dir_exists(String p_dir) { - GLOBAL_LOCK_FUNCTION - if (p_dir.is_rel_path()) + if (p_dir.is_rel_path()) { p_dir = get_current_dir().plus_file(p_dir); + } p_dir = fix_path(p_dir); @@ -104,9 +103,9 @@ bool DirAccessUnix::dir_exists(String p_dir) { } uint64_t DirAccessUnix::get_modified_time(String p_file) { - - if (p_file.is_rel_path()) + if (p_file.is_rel_path()) { p_file = current_dir.plus_file(p_file); + } p_file = fix_path(p_file); @@ -116,16 +115,15 @@ uint64_t DirAccessUnix::get_modified_time(String p_file) { if (success) { return flags.st_mtime; } else { - ERR_FAIL_V(0); }; return 0; }; String DirAccessUnix::get_next() { - - if (!dir_stream) + if (!dir_stream) { return ""; + } dirent *entry = readdir(dir_stream); @@ -154,25 +152,23 @@ String DirAccessUnix::get_next() { _cisdir = (entry->d_type == DT_DIR); } - _cishidden = (fname != "." && fname != ".." && fname.begins_with(".")); + _cishidden = is_hidden(fname); return fname; } bool DirAccessUnix::current_is_dir() const { - return _cisdir; } bool DirAccessUnix::current_is_hidden() const { - return _cishidden; } void DirAccessUnix::list_dir_end() { - - if (dir_stream) + if (dir_stream) { closedir(dir_stream); + } dir_stream = nullptr; _cisdir = false; } @@ -198,7 +194,6 @@ static bool _filter_drive(struct mntent *mnt) { #endif static void _get_drives(List<String> *list) { - #if defined(HAVE_MNTENT) && defined(X11_ENABLED) // Check /etc/mtab for the list of mounted partitions FILE *mtab = setmntent("/etc/mtab", "r"); @@ -252,7 +247,6 @@ static void _get_drives(List<String> *list) { } int DirAccessUnix::get_drive_count() { - List<String> list; _get_drives(&list); @@ -260,7 +254,6 @@ int DirAccessUnix::get_drive_count() { } String DirAccessUnix::get_drive(int p_drive) { - List<String> list; _get_drives(&list); @@ -270,16 +263,15 @@ String DirAccessUnix::get_drive(int p_drive) { } bool DirAccessUnix::drives_are_shortcuts() { - return true; } Error DirAccessUnix::make_dir(String p_dir) { - GLOBAL_LOCK_FUNCTION - if (p_dir.is_rel_path()) + if (p_dir.is_rel_path()) { p_dir = get_current_dir().plus_file(p_dir); + } p_dir = fix_path(p_dir); @@ -298,7 +290,6 @@ Error DirAccessUnix::make_dir(String p_dir) { } Error DirAccessUnix::change_dir(String p_dir) { - GLOBAL_LOCK_FUNCTION p_dir = fix_path(p_dir); @@ -307,8 +298,9 @@ Error DirAccessUnix::change_dir(String p_dir) { String prev_dir; char real_current_dir_name[2048]; ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == nullptr, ERR_BUG); - if (prev_dir.parse_utf8(real_current_dir_name)) + if (prev_dir.parse_utf8(real_current_dir_name)) { prev_dir = real_current_dir_name; //no utf8, maybe latin? + } // try_dir is the directory we are trying to change into String try_dir = ""; @@ -343,28 +335,28 @@ Error DirAccessUnix::change_dir(String p_dir) { } String DirAccessUnix::get_current_dir(bool p_include_drive) { - String base = _get_root_path(); if (base != "") { - String bd = current_dir.replace_first(base, ""); - if (bd.begins_with("/")) + if (bd.begins_with("/")) { return _get_root_string() + bd.substr(1, bd.length()); - else + } else { return _get_root_string() + bd; + } } return current_dir; } Error DirAccessUnix::rename(String p_path, String p_new_path) { - - if (p_path.is_rel_path()) + if (p_path.is_rel_path()) { p_path = get_current_dir().plus_file(p_path); + } p_path = fix_path(p_path); - if (p_new_path.is_rel_path()) + if (p_new_path.is_rel_path()) { p_new_path = get_current_dir().plus_file(p_new_path); + } p_new_path = fix_path(p_new_path); @@ -372,28 +364,28 @@ Error DirAccessUnix::rename(String p_path, String p_new_path) { } Error DirAccessUnix::remove(String p_path) { - - if (p_path.is_rel_path()) + if (p_path.is_rel_path()) { p_path = get_current_dir().plus_file(p_path); + } p_path = fix_path(p_path); struct stat flags; - if ((stat(p_path.utf8().get_data(), &flags) != 0)) + if ((stat(p_path.utf8().get_data(), &flags) != 0)) { return FAILED; + } - if (S_ISDIR(flags.st_mode)) + if (S_ISDIR(flags.st_mode)) { return ::rmdir(p_path.utf8().get_data()) == 0 ? OK : FAILED; - else + } else { return ::unlink(p_path.utf8().get_data()) == 0 ? OK : FAILED; + } } size_t DirAccessUnix::get_space_left() { - #ifndef NO_STATVFS struct statvfs vfs; if (statvfs(current_dir.utf8().get_data(), &vfs) != 0) { - return 0; }; @@ -408,8 +400,11 @@ String DirAccessUnix::get_filesystem_type() const { return ""; //TODO this should be implemented } -DirAccessUnix::DirAccessUnix() { +bool DirAccessUnix::is_hidden(const String &p_name) { + return p_name != "." && p_name != ".." && p_name.begins_with("."); +} +DirAccessUnix::DirAccessUnix() { dir_stream = nullptr; _cisdir = false; @@ -418,14 +413,14 @@ DirAccessUnix::DirAccessUnix() { // set current directory to an absolute path of the current directory char real_current_dir_name[2048]; ERR_FAIL_COND(getcwd(real_current_dir_name, 2048) == nullptr); - if (current_dir.parse_utf8(real_current_dir_name)) + if (current_dir.parse_utf8(real_current_dir_name)) { current_dir = real_current_dir_name; + } change_dir(current_dir); } DirAccessUnix::~DirAccessUnix() { - list_dir_end(); } diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h index b403d8e356..b70df1ca02 100644 --- a/drivers/unix/dir_access_unix.h +++ b/drivers/unix/dir_access_unix.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 @@ #include <unistd.h> class DirAccessUnix : public DirAccess { - DIR *dir_stream; static DirAccess *create_fs(); @@ -52,6 +51,7 @@ class DirAccessUnix : public DirAccess { protected: virtual String fix_unicode_name(const char *p_name) const { return String::utf8(p_name); } + virtual bool is_hidden(const String &p_name); public: virtual Error list_dir_begin(); ///< This starts dir listing diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index 4aa408a1f0..6b24a85ff6 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,7 +33,7 @@ #if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) #include "core/os/os.h" -#include "core/print_string.h" +#include "core/string/print_string.h" #include <sys/stat.h> #include <sys/types.h> @@ -63,38 +63,37 @@ #endif void FileAccessUnix::check_errors() const { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); if (feof(f)) { - last_error = ERR_FILE_EOF; } } Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) { - - if (f) + if (f) { fclose(f); + } f = nullptr; path_src = p_path; path = fix_path(p_path); - //printf("opening %ls, %i\n", path.c_str(), Memory::get_static_mem_usage()); + //printf("opening %s, %i\n", path.utf8().get_data(), Memory::get_static_mem_usage()); ERR_FAIL_COND_V_MSG(f, ERR_ALREADY_IN_USE, "File is already in use."); const char *mode_string; - if (p_mode_flags == READ) + if (p_mode_flags == READ) { mode_string = "rb"; - else if (p_mode_flags == WRITE) + } else if (p_mode_flags == WRITE) { mode_string = "wb"; - else if (p_mode_flags == READ_WRITE) + } else if (p_mode_flags == READ_WRITE) { mode_string = "rb+"; - else if (p_mode_flags == WRITE_READ) + } else if (p_mode_flags == WRITE_READ) { mode_string = "wb+"; - else + } else { return ERR_INVALID_PARAMETER; + } /* pretty much every implementation that uses fopen as primary backend (unix-compatible mostly) supports utf8 encoding */ @@ -150,9 +149,9 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) { } void FileAccessUnix::close() { - - if (!f) + if (!f) { return; + } fclose(f); f = nullptr; @@ -174,39 +173,35 @@ void FileAccessUnix::close() { } bool FileAccessUnix::is_open() const { - return (f != nullptr); } String FileAccessUnix::get_path() const { - return path_src; } String FileAccessUnix::get_path_absolute() const { - return path; } void FileAccessUnix::seek(size_t p_position) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); last_error = OK; - if (fseek(f, p_position, SEEK_SET)) + if (fseek(f, p_position, SEEK_SET)) { check_errors(); + } } void FileAccessUnix::seek_end(int64_t p_position) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); - if (fseek(f, p_position, SEEK_END)) + if (fseek(f, p_position, SEEK_END)) { check_errors(); + } } size_t FileAccessUnix::get_position() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); long pos = ftell(f); @@ -218,7 +213,6 @@ size_t FileAccessUnix::get_position() const { } size_t FileAccessUnix::get_len() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); long pos = ftell(f); @@ -232,12 +226,10 @@ size_t FileAccessUnix::get_len() const { } bool FileAccessUnix::eof_reached() const { - return last_error == ERR_FILE_EOF; } uint8_t FileAccessUnix::get_8() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); uint8_t b; if (fread(&b, 1, 1, f) == 0) { @@ -248,7 +240,6 @@ uint8_t FileAccessUnix::get_8() const { } int FileAccessUnix::get_buffer(uint8_t *p_dst, int p_length) const { - ERR_FAIL_COND_V_MSG(!f, -1, "File must be opened before use."); int read = fread(p_dst, 1, p_length, f); check_errors(); @@ -256,44 +247,41 @@ int FileAccessUnix::get_buffer(uint8_t *p_dst, int p_length) const { }; Error FileAccessUnix::get_error() const { - return last_error; } void FileAccessUnix::flush() { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); fflush(f); } void FileAccessUnix::store_8(uint8_t p_dest) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); ERR_FAIL_COND(fwrite(&p_dest, 1, 1, f) != 1); } void FileAccessUnix::store_buffer(const uint8_t *p_src, int p_length) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); ERR_FAIL_COND(!p_src); ERR_FAIL_COND((int)fwrite(p_src, 1, p_length, f) != p_length); } bool FileAccessUnix::file_exists(const String &p_path) { - int err; struct stat st; String filename = fix_path(p_path); // Does the name exist at all? err = stat(filename.utf8().get_data(), &st); - if (err) + if (err) { return false; + } #ifdef UNIX_ENABLED // See if we have access to the file - if (access(filename.utf8().get_data(), F_OK)) + if (access(filename.utf8().get_data(), F_OK)) { return false; + } #else if (_access(filename.utf8().get_data(), 4) == -1) return false; @@ -310,7 +298,6 @@ bool FileAccessUnix::file_exists(const String &p_path) { } uint64_t FileAccessUnix::_get_modified_time(const String &p_file) { - String file = fix_path(p_file); struct stat flags; int err = stat(file.utf8().get_data(), &flags); @@ -323,7 +310,6 @@ uint64_t FileAccessUnix::_get_modified_time(const String &p_file) { } uint32_t FileAccessUnix::_get_unix_permissions(const String &p_file) { - String file = fix_path(p_file); struct stat flags; int err = stat(file.utf8().get_data(), &flags); @@ -336,7 +322,6 @@ uint32_t FileAccessUnix::_get_unix_permissions(const String &p_file) { } Error FileAccessUnix::_set_unix_permissions(const String &p_file, uint32_t p_permissions) { - String file = fix_path(p_file); int err = chmod(file.utf8().get_data(), p_permissions); @@ -348,20 +333,12 @@ Error FileAccessUnix::_set_unix_permissions(const String &p_file, uint32_t p_per } FileAccess *FileAccessUnix::create_libc() { - return memnew(FileAccessUnix); } CloseNotificationFunc FileAccessUnix::close_notification_func = nullptr; -FileAccessUnix::FileAccessUnix() : - f(nullptr), - flags(0), - last_error(OK) { -} - FileAccessUnix::~FileAccessUnix() { - close(); } diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index 8116f72345..998fad7909 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.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,11 +41,10 @@ typedef void (*CloseNotificationFunc)(const String &p_file, int p_flags); class FileAccessUnix : public FileAccess { - - FILE *f; - int flags; + FILE *f = nullptr; + int flags = 0; void check_errors() const; - mutable Error last_error; + mutable Error last_error = OK; String save_path; String path; String path_src; @@ -84,7 +83,7 @@ public: virtual uint32_t _get_unix_permissions(const String &p_file); virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions); - FileAccessUnix(); + FileAccessUnix() {} virtual ~FileAccessUnix(); }; diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index 5e3dedfc2f..8ec1de4386 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.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 */ @@ -76,7 +76,6 @@ #endif static IP_Address _sockaddr2ip(struct sockaddr *p_addr) { - IP_Address ip; if (p_addr->sa_family == AF_INET) { @@ -91,9 +90,8 @@ static IP_Address _sockaddr2ip(struct sockaddr *p_addr) { }; IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) { - struct addrinfo hints; - struct addrinfo *result; + struct addrinfo *result = nullptr; memset(&hints, 0, sizeof(struct addrinfo)); if (p_type == TYPE_IPV4) { @@ -115,8 +113,9 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) { if (result == nullptr || result->ai_addr == nullptr) { ERR_PRINT("Invalid response from getaddrinfo"); - if (result) + if (result) { freeaddrinfo(result); + } return IP_Address(); }; @@ -132,7 +131,6 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) { #if defined(UWP_ENABLED) void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const { - using namespace Windows::Networking; using namespace Windows::Networking::Connectivity; @@ -140,7 +138,6 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co auto hostnames = NetworkInformation::GetHostNames(); for (int i = 0; i < hostnames->Size; i++) { - auto hostname = hostnames->GetAt(i); if (hostname->Type != HostNameType::Ipv4 && hostname->Type != HostNameType::Ipv6) @@ -167,12 +164,10 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co #else void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const { - ULONG buf_size = 1024; IP_ADAPTER_ADDRESSES *addrs; while (true) { - addrs = (IP_ADAPTER_ADDRESSES *)memalloc(buf_size); int err = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, nullptr, addrs, &buf_size); @@ -190,7 +185,6 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co IP_ADAPTER_ADDRESSES *adapter = addrs; while (adapter != nullptr) { - Interface_Info info; info.name = adapter->AdapterName; info.name_friendly = adapter->FriendlyName; @@ -218,7 +212,6 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co #else // UNIX void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const { - struct ifaddrs *ifAddrStruct = nullptr; struct ifaddrs *ifa = nullptr; int family; @@ -226,13 +219,15 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co getifaddrs(&ifAddrStruct); for (ifa = ifAddrStruct; ifa != nullptr; ifa = ifa->ifa_next) { - if (!ifa->ifa_addr) + if (!ifa->ifa_addr) { continue; + } family = ifa->ifa_addr->sa_family; - if (family != AF_INET && family != AF_INET6) + if (family != AF_INET && family != AF_INET6) { continue; + } Map<String, Interface_Info>::Element *E = r_interfaces->find(ifa->ifa_name); if (!E) { @@ -248,17 +243,17 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co info.ip_addresses.push_front(_sockaddr2ip(ifa->ifa_addr)); } - if (ifAddrStruct != nullptr) freeifaddrs(ifAddrStruct); + if (ifAddrStruct != nullptr) { + freeifaddrs(ifAddrStruct); + } } #endif void IP_Unix::make_default() { - _create = _create_unix; } IP *IP_Unix::_create_unix() { - return memnew(IP_Unix); } diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h index 0580facac2..ca2ee17f4e 100644 --- a/drivers/unix/ip_unix.h +++ b/drivers/unix/ip_unix.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 */ @@ -38,12 +38,12 @@ class IP_Unix : public IP { GDCLASS(IP_Unix, IP); - virtual IP_Address _resolve_hostname(const String &p_hostname, IP::Type p_type); + virtual IP_Address _resolve_hostname(const String &p_hostname, IP::Type p_type) override; static IP *_create_unix(); public: - virtual void get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const; + virtual void get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const override; static void make_default(); IP_Unix(); diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp index 7c6543c3a2..19753943c8 100644 --- a/drivers/unix/net_socket_posix.cpp +++ b/drivers/unix/net_socket_posix.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 */ @@ -96,7 +96,6 @@ #endif size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type) { - memset(p_addr, 0, sizeof(struct sockaddr_storage)); if (p_ip_type == IP::TYPE_IPV6 || p_ip_type == IP::TYPE_ANY) { // IPv6 socket @@ -132,16 +131,13 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const } void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port) { - if (p_addr->ss_family == AF_INET) { - struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; r_ip.set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr)); r_port = ntohs(addr4->sin_port); } else if (p_addr->ss_family == AF_INET6) { - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; r_ip.set_ipv6(addr6->sin6_addr.s6_addr); @@ -173,9 +169,7 @@ void NetSocketPosix::cleanup() { } NetSocketPosix::NetSocketPosix() : - _sock(SOCK_EMPTY), - _ip_type(IP::TYPE_NONE), - _is_stream(false) { + _sock(SOCK_EMPTY) { } NetSocketPosix::~NetSocketPosix() { @@ -202,12 +196,15 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const { print_verbose("Socket error: " + itos(err)); return ERR_NET_OTHER; #else - if (errno == EISCONN) + if (errno == EISCONN) { return ERR_NET_IS_CONNECTED; - if (errno == EINPROGRESS || errno == EALREADY) + } + if (errno == EINPROGRESS || errno == EALREADY) { return ERR_NET_IN_PROGRESS; - if (errno == EAGAIN || errno == EWOULDBLOCK) + } + if (errno == EAGAIN || errno == EWOULDBLOCK) { return ERR_NET_WOULD_BLOCK; + } print_verbose("Socket error: " + itos(errno)); return ERR_NET_OTHER; #endif @@ -218,7 +215,6 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const { #endif bool NetSocketPosix::_can_use_ip(const IP_Address &p_ip, const bool p_for_bind) const { - if (p_for_bind && !(p_ip.is_valid() || p_ip.is_wildcard())) { return false; } else if (!p_for_bind && !p_ip.is_valid()) { @@ -230,7 +226,6 @@ bool NetSocketPosix::_can_use_ip(const IP_Address &p_ip, const bool p_for_bind) } _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add) { - ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); ERR_FAIL_COND_V(!_can_use_ip(p_ip, false), ERR_INVALID_PARAMETER); @@ -246,16 +241,19 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, St IP::get_singleton()->get_local_interfaces(&if_info); for (Map<String, IP::Interface_Info>::Element *E = if_info.front(); E; E = E->next()) { IP::Interface_Info &c = E->get(); - if (c.name != p_if_name) + if (c.name != p_if_name) { continue; + } - if_v6id = (uint32_t)c.index.to_int64(); - if (type == IP::TYPE_IPV6) + if_v6id = (uint32_t)c.index.to_int(); + if (type == IP::TYPE_IPV6) { break; // IPv6 uses index. + } for (List<IP_Address>::Element *F = c.ip_addresses.front(); F; F = F->next()) { - if (!F->get().is_ipv4()) + if (!F->get().is_ipv4()) { continue; // Wrong IP type + } if_ip = F->get(); break; } @@ -350,11 +348,11 @@ Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) { // recv/recvfrom and an ICMP reply was received from a previous send/sendto. unsigned long disable = 0; if (ioctlsocket(_sock, SIO_UDP_CONNRESET, &disable) == SOCKET_ERROR) { - print_verbose("Unable to turn off UDP WSAECONNRESET behaviour on Windows"); + print_verbose("Unable to turn off UDP WSAECONNRESET behavior on Windows"); } if (ioctlsocket(_sock, SIO_UDP_NETRESET, &disable) == SOCKET_ERROR) { // This feature seems not to be supported on wine. - print_verbose("Unable to turn off UDP WSAENETRESET behaviour on Windows"); + print_verbose("Unable to turn off UDP WSAENETRESET behavior on Windows"); } } #endif @@ -369,9 +367,9 @@ Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) { } void NetSocketPosix::close() { - - if (_sock != SOCK_EMPTY) + if (_sock != SOCK_EMPTY) { SOCK_CLOSE(_sock); + } _sock = SOCK_EMPTY; _ip_type = IP::TYPE_NONE; @@ -379,7 +377,6 @@ void NetSocketPosix::close() { } Error NetSocketPosix::bind(IP_Address p_addr, uint16_t p_port) { - ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); ERR_FAIL_COND_V(!_can_use_ip(p_addr, true), ERR_INVALID_PARAMETER); @@ -410,7 +407,6 @@ Error NetSocketPosix::listen(int p_max_pending) { } Error NetSocketPosix::connect_to_host(IP_Address p_host, uint16_t p_port) { - ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); ERR_FAIL_COND_V(!_can_use_ip(p_host, false), ERR_INVALID_PARAMETER); @@ -418,7 +414,6 @@ Error NetSocketPosix::connect_to_host(IP_Address p_host, uint16_t p_port) { size_t addr_size = _set_addr_storage(&addr, p_host, p_port, _ip_type); if (SOCK_CONNECT(_sock, (struct sockaddr *)&addr, addr_size) != 0) { - NetError err = _get_socket_error(); switch (err) { @@ -440,7 +435,6 @@ Error NetSocketPosix::connect_to_host(IP_Address p_host, uint16_t p_port) { } Error NetSocketPosix::poll(PollType p_type, int p_timeout) const { - ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); #if defined(WINDOWS_ENABLED) @@ -521,8 +515,9 @@ Error NetSocketPosix::poll(PollType p_type, int p_timeout) const { return FAILED; } - if (ret == 0) + if (ret == 0) { return ERR_BUSY; + } return OK; #endif @@ -535,8 +530,9 @@ Error NetSocketPosix::recv(uint8_t *p_buffer, int p_len, int &r_read) { if (r_read < 0) { NetError err = _get_socket_error(); - if (err == ERR_NET_WOULD_BLOCK) + if (err == ERR_NET_WOULD_BLOCK) { return ERR_BUSY; + } return FAILED; } @@ -555,8 +551,9 @@ Error NetSocketPosix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Add if (r_read < 0) { NetError err = _get_socket_error(); - if (err == ERR_NET_WOULD_BLOCK) + if (err == ERR_NET_WOULD_BLOCK) { return ERR_BUSY; + } return FAILED; } @@ -582,15 +579,17 @@ Error NetSocketPosix::send(const uint8_t *p_buffer, int p_len, int &r_sent) { int flags = 0; #ifdef MSG_NOSIGNAL - if (_is_stream) + if (_is_stream) { flags = MSG_NOSIGNAL; + } #endif r_sent = ::send(_sock, SOCK_CBUF(p_buffer), p_len, flags); if (r_sent < 0) { NetError err = _get_socket_error(); - if (err == ERR_NET_WOULD_BLOCK) + if (err == ERR_NET_WOULD_BLOCK) { return ERR_BUSY; + } return FAILED; } @@ -607,8 +606,9 @@ Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP if (r_sent < 0) { NetError err = _get_socket_error(); - if (err == ERR_NET_WOULD_BLOCK) + if (err == ERR_NET_WOULD_BLOCK) { return ERR_BUSY; + } return FAILED; } @@ -619,8 +619,9 @@ Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP Error NetSocketPosix::set_broadcasting_enabled(bool p_enabled) { ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); // IPv6 has no broadcast support. - if (_ip_type == IP::TYPE_IPV6) + if (_ip_type == IP::TYPE_IPV6) { return ERR_UNAVAILABLE; + } int par = p_enabled ? 1 : 0; if (setsockopt(_sock, SOL_SOCKET, SO_BROADCAST, SOCK_CBUF(&par), sizeof(int)) != 0) { @@ -639,14 +640,16 @@ void NetSocketPosix::set_blocking_enabled(bool p_enabled) { ret = SOCK_IOCTL(_sock, FIONBIO, &par); #else int opts = fcntl(_sock, F_GETFL); - if (p_enabled) + if (p_enabled) { ret = fcntl(_sock, F_SETFL, opts & ~O_NONBLOCK); - else + } else { ret = fcntl(_sock, F_SETFL, opts | O_NONBLOCK); + } #endif - if (ret != 0) + if (ret != 0) { WARN_PRINT("Unable to change non-block mode"); + } } void NetSocketPosix::set_ipv6_only_enabled(bool p_enabled) { @@ -701,7 +704,6 @@ bool NetSocketPosix::is_open() const { } int NetSocketPosix::get_available_bytes() const { - ERR_FAIL_COND_V(!is_open(), -1); unsigned long len; @@ -715,7 +717,6 @@ int NetSocketPosix::get_available_bytes() const { } Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) { - Ref<NetSocket> out; ERR_FAIL_COND_V(!is_open(), out); diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h index 0a19967265..cc6af661c8 100644 --- a/drivers/unix/net_socket_posix.h +++ b/drivers/unix/net_socket_posix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -45,11 +45,10 @@ #endif class NetSocketPosix : public NetSocket { - private: - SOCKET_TYPE _sock; - IP::Type _ip_type; - bool _is_stream; + SOCKET_TYPE _sock; // NOLINT - the default value is defined in the .cpp + IP::Type _ip_type = IP::TYPE_NONE; + bool _is_stream = false; enum NetError { ERR_NET_WOULD_BLOCK, diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 53c60951b7..d94c2126ef 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.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,10 +32,10 @@ #ifdef UNIX_ENABLED +#include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" #include "core/debugger/script_debugger.h" #include "core/os/thread_dummy.h" -#include "core/project_settings.h" #include "drivers/unix/dir_access_unix.h" #include "drivers/unix/file_access_unix.h" #include "drivers/unix/net_socket_posix.h" @@ -48,7 +48,7 @@ #include <mach/mach_time.h> #endif -#if defined(__FreeBSD__) || defined(__OpenBSD__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) #include <sys/param.h> #include <sys/sysctl.h> #endif @@ -91,20 +91,19 @@ static void _setup_clock() { #endif void OS_Unix::debug_break() { - assert(false); }; static void handle_interrupt(int sig) { - if (!EngineDebugger::is_active()) + if (!EngineDebugger::is_active()) { return; + } EngineDebugger::get_script_debugger()->set_depth(-1); EngineDebugger::get_script_debugger()->set_lines_left(1); } void OS_Unix::initialize_debugging() { - if (EngineDebugger::is_active()) { struct sigaction action; memset(&action, 0, sizeof(action)); @@ -114,12 +113,10 @@ void OS_Unix::initialize_debugging() { } int OS_Unix::unix_initialize_audio(int p_audio_driver) { - return 0; } void OS_Unix::initialize_core() { - #ifdef NO_THREADS ThreadDummy::make_default(); RWLockDummy::make_default(); @@ -130,7 +127,6 @@ void OS_Unix::initialize_core() { FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES); FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA); FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM); - //FileAccessBufferedFA<FileAccessUnix>::make_default(); DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_RESOURCES); DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA); DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM); @@ -144,17 +140,14 @@ void OS_Unix::initialize_core() { } void OS_Unix::finalize_core() { - NetSocketPosix::cleanup(); } void OS_Unix::alert(const String &p_alert, const String &p_title) { - fprintf(stderr, "ERROR: %s\n", p_alert.utf8().get_data()); } String OS_Unix::get_stdin_string(bool p_block) { - if (p_block) { char buff[1024]; String ret = stdin_buf + fgets(buff, 1024, stdin); @@ -166,74 +159,64 @@ String OS_Unix::get_stdin_string(bool p_block) { } String OS_Unix::get_name() const { - return "Unix"; } -uint64_t OS_Unix::get_unix_time() const { - - return time(nullptr); -}; - -uint64_t OS_Unix::get_system_time_secs() const { - struct timeval tv_now; - gettimeofday(&tv_now, nullptr); - return uint64_t(tv_now.tv_sec); -} - -uint64_t OS_Unix::get_system_time_msecs() const { +double OS_Unix::get_unix_time() const { struct timeval tv_now; gettimeofday(&tv_now, nullptr); - return uint64_t(tv_now.tv_sec) * 1000 + uint64_t(tv_now.tv_usec) / 1000; -} + return (double)tv_now.tv_sec + double(tv_now.tv_usec) / 1000000; +}; OS::Date OS_Unix::get_date(bool utc) const { - time_t t = time(nullptr); - struct tm *lt; - if (utc) - lt = gmtime(&t); - else - lt = localtime(&t); + struct tm lt; + if (utc) { + gmtime_r(&t, <); + } else { + localtime_r(&t, <); + } Date ret; - ret.year = 1900 + lt->tm_year; + ret.year = 1900 + lt.tm_year; // Index starting at 1 to match OS_Unix::get_date // and Windows SYSTEMTIME and tm_mon follows the typical structure // of 0-11, noted here: http://www.cplusplus.com/reference/ctime/tm/ - ret.month = (Month)(lt->tm_mon + 1); - ret.day = lt->tm_mday; - ret.weekday = (Weekday)lt->tm_wday; - ret.dst = lt->tm_isdst; + ret.month = (Month)(lt.tm_mon + 1); + ret.day = lt.tm_mday; + ret.weekday = (Weekday)lt.tm_wday; + ret.dst = lt.tm_isdst; return ret; } OS::Time OS_Unix::get_time(bool utc) const { time_t t = time(nullptr); - struct tm *lt; - if (utc) - lt = gmtime(&t); - else - lt = localtime(&t); + struct tm lt; + if (utc) { + gmtime_r(&t, <); + } else { + localtime_r(&t, <); + } Time ret; - ret.hour = lt->tm_hour; - ret.min = lt->tm_min; - ret.sec = lt->tm_sec; + ret.hour = lt.tm_hour; + ret.min = lt.tm_min; + ret.sec = lt.tm_sec; get_time_zone_info(); return ret; } OS::TimeZoneInfo OS_Unix::get_time_zone_info() const { time_t t = time(nullptr); - struct tm *lt = localtime(&t); + struct tm lt; + localtime_r(&t, <); char name[16]; - strftime(name, 16, "%Z", lt); + strftime(name, 16, "%Z", <); name[15] = 0; TimeZoneInfo ret; ret.name = name; char bias_buf[16]; - strftime(bias_buf, 16, "%z", lt); + strftime(bias_buf, 16, "%z", <); int bias; bias_buf[15] = 0; sscanf(bias_buf, "%d", &bias); @@ -241,22 +224,25 @@ OS::TimeZoneInfo OS_Unix::get_time_zone_info() const { // convert from ISO 8601 (1 minute=1, 1 hour=100) to minutes int hour = (int)bias / 100; int minutes = bias % 100; - if (bias < 0) + if (bias < 0) { ret.bias = hour * 60 - minutes; - else + } else { ret.bias = hour * 60 + minutes; + } return ret; } void OS_Unix::delay_usec(uint32_t p_usec) const { - - struct timespec rem = { static_cast<time_t>(p_usec / 1000000), (static_cast<long>(p_usec) % 1000000) * 1000 }; - while (nanosleep(&rem, &rem) == EINTR) { + struct timespec requested = { static_cast<time_t>(p_usec / 1000000), (static_cast<long>(p_usec) % 1000000) * 1000 }; + struct timespec remaining; + while (nanosleep(&requested, &remaining) == -1 && errno == EINTR) { + requested.tv_sec = remaining.tv_sec; + requested.tv_nsec = remaining.tv_nsec; } } -uint64_t OS_Unix::get_ticks_usec() const { +uint64_t OS_Unix::get_ticks_usec() const { #if defined(__APPLE__) uint64_t longtime = mach_absolute_time() * _clock_scale; #else @@ -271,36 +257,27 @@ uint64_t OS_Unix::get_ticks_usec() const { return longtime; } -Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) { - +Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) { #ifdef __EMSCRIPTEN__ // Don't compile this code at all to avoid undefined references. // Actual virtual call goes to OS_JavaScript. ERR_FAIL_V(ERR_BUG); #else - if (p_blocking && r_pipe) { - - String argss; - argss = "\"" + p_path + "\""; - + if (r_pipe) { + String command = "\"" + p_path + "\""; for (int i = 0; i < p_arguments.size(); i++) { - - argss += String(" \"") + p_arguments[i] + "\""; + command += String(" \"") + p_arguments[i] + "\""; } - if (read_stderr) { - argss += " 2>&1"; // Read stderr too + command += " 2>&1"; // Include stderr } else { - argss += " 2>/dev/null"; //silence stderr + command += " 2>/dev/null"; // Silence stderr } - FILE *f = popen(argss.utf8().get_data(), "r"); - - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot pipe stream from process running with following arguments '" + argss + "'."); + FILE *f = popen(command.utf8().get_data(), "r"); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot create pipe from command: " + command); char buf[65535]; - while (fgets(buf, 65535, f)) { - if (p_pipe_mutex) { p_pipe_mutex->lock(); } @@ -310,9 +287,10 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo } } int rv = pclose(f); - if (r_exitcode) - *r_exitcode = WEXITSTATUS(rv); + if (r_exitcode) { + *r_exitcode = WEXITSTATUS(rv); + } return OK; } @@ -320,49 +298,75 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo ERR_FAIL_COND_V(pid < 0, ERR_CANT_FORK); if (pid == 0) { - // is child - - if (!p_blocking) { - // For non blocking calls, create a new session-ID so parent won't wait for it. - // This ensures the process won't go zombie at end. - setsid(); - } - + // The child process Vector<CharString> cs; cs.push_back(p_path.utf8()); - for (int i = 0; i < p_arguments.size(); i++) + for (int i = 0; i < p_arguments.size(); i++) { cs.push_back(p_arguments[i].utf8()); + } Vector<char *> args; - for (int i = 0; i < cs.size(); i++) + for (int i = 0; i < cs.size(); i++) { args.push_back((char *)cs[i].get_data()); + } args.push_back(0); execvp(p_path.utf8().get_data(), &args[0]); - // still alive? something failed.. - fprintf(stderr, "**ERROR** OS_Unix::execute - Could not create child process while executing: %s\n", p_path.utf8().get_data()); - abort(); + // The execvp() function only returns if an error occurs. + ERR_PRINT("Could not create child process: " + p_path); + raise(SIGKILL); + } + + int status; + waitpid(pid, &status, 0); + if (r_exitcode) { + *r_exitcode = WIFEXITED(status) ? WEXITSTATUS(status) : status; } + return OK; +#endif +} + +Error OS_Unix::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) { +#ifdef __EMSCRIPTEN__ + // Don't compile this code at all to avoid undefined references. + // Actual virtual call goes to OS_JavaScript. + ERR_FAIL_V(ERR_BUG); +#else + pid_t pid = fork(); + ERR_FAIL_COND_V(pid < 0, ERR_CANT_FORK); - if (p_blocking) { + if (pid == 0) { + // The new process + // Create a new session-ID so parent won't wait for it. + // This ensures the process won't go zombie at the end. + setsid(); - int status; - waitpid(pid, &status, 0); - if (r_exitcode) - *r_exitcode = WEXITSTATUS(status); + Vector<CharString> cs; + cs.push_back(p_path.utf8()); + for (int i = 0; i < p_arguments.size(); i++) { + cs.push_back(p_arguments[i].utf8()); + } - } else { + Vector<char *> args; + for (int i = 0; i < cs.size(); i++) { + args.push_back((char *)cs[i].get_data()); + } + args.push_back(0); - if (r_child_id) - *r_child_id = pid; + execvp(p_path.utf8().get_data(), &args[0]); + // The execvp() function only returns if an error occurs. + ERR_PRINT("Could not create child process: " + p_path); + raise(SIGKILL); } + if (r_child_id) { + *r_child_id = pid; + } return OK; #endif } Error OS_Unix::kill(const ProcessID &p_pid) { - int ret = ::kill(p_pid, SIGKILL); if (!ret) { //avoid zombie process @@ -373,29 +377,27 @@ Error OS_Unix::kill(const ProcessID &p_pid) { } int OS_Unix::get_process_id() const { - return getpid(); }; bool OS_Unix::has_environment(const String &p_var) const { - return getenv(p_var.utf8().get_data()) != nullptr; } String OS_Unix::get_locale() const { - - if (!has_environment("LANG")) + if (!has_environment("LANG")) { return "en"; + } String locale = get_environment("LANG"); int tp = locale.find("."); - if (tp != -1) + if (tp != -1) { locale = locale.substr(0, tp); + } return locale; } Error OS_Unix::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { - String path = p_path; if (FileAccess::exists(path) && path.is_rel_path()) { @@ -442,32 +444,29 @@ Error OS_Unix::get_dynamic_library_symbol_handle(void *p_library_handle, const S } Error OS_Unix::set_cwd(const String &p_cwd) { - - if (chdir(p_cwd.utf8().get_data()) != 0) + if (chdir(p_cwd.utf8().get_data()) != 0) { return ERR_CANT_OPEN; + } return OK; } String OS_Unix::get_environment(const String &p_var) const { - - if (getenv(p_var.utf8().get_data())) + if (getenv(p_var.utf8().get_data())) { return getenv(p_var.utf8().get_data()); + } return ""; } bool OS_Unix::set_environment(const String &p_var, const String &p_value) const { - return setenv(p_var.utf8().get_data(), p_value.utf8().get_data(), /* overwrite: */ true) == 0; } int OS_Unix::get_processor_count() const { - return sysconf(_SC_NPROCESSORS_CONF); } String OS_Unix::get_user_data_dir() const { - String appname = get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/name")); if (appname != "") { bool use_custom_dir = ProjectSettings::get_singleton()->get("application/config/use_custom_user_dir"); @@ -486,7 +485,6 @@ String OS_Unix::get_user_data_dir() const { } String OS_Unix::get_executable_path() const { - #ifdef __linux__ //fix for running from a symlink char buf[256]; @@ -501,7 +499,7 @@ String OS_Unix::get_executable_path() const { return OS::get_executable_path(); } return b; -#elif defined(__OpenBSD__) +#elif defined(__OpenBSD__) || defined(__NetBSD__) char resolved_path[MAXPATHLEN]; realpath(OS::get_executable_path().utf8().get_data(), resolved_path); @@ -544,10 +542,11 @@ void UnixTerminalLogger::log_error(const char *p_function, const char *p_file, i } const char *err_details; - if (p_rationale && p_rationale[0]) + if (p_rationale && p_rationale[0]) { err_details = p_rationale; - else + } else { err_details = p_code; + } // Disable color codes if stdout is not a TTY. // This prevents Godot from writing ANSI escape codes when redirecting diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index 90679ddf1d..6c79d984e9 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -37,7 +37,6 @@ #include "drivers/unix/ip_unix.h" class OS_Unix : public OS { - protected: // UNIX only handles the core functions. // inheriting platforms under unix (eg. X11) should handle the rest @@ -46,7 +45,7 @@ protected: virtual int unix_initialize_audio(int p_audio_driver); //virtual Error initialize(int p_video_driver,int p_audio_driver); - virtual void finalize_core(); + virtual void finalize_core() override; String stdin_buf; @@ -54,7 +53,7 @@ public: OS_Unix(); virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); - virtual String get_stdin_string(bool p_block); + virtual String get_stdin_string(bool p_block) override; //virtual void set_mouse_show(bool p_show); //virtual void set_mouse_grab(bool p_grab); @@ -66,41 +65,40 @@ public: //virtual VideoMode get_video_mode() const; //virtual void get_fullscreen_mode_list(List<VideoMode> *p_list) const; - virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false); - virtual Error close_dynamic_library(void *p_library_handle); - virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false); + virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override; + virtual Error close_dynamic_library(void *p_library_handle) override; + virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override; - virtual Error set_cwd(const String &p_cwd); + virtual Error set_cwd(const String &p_cwd) override; - virtual String get_name() const; + virtual String get_name() const override; - virtual Date get_date(bool utc) const; - virtual Time get_time(bool utc) const; - virtual TimeZoneInfo get_time_zone_info() const; + virtual Date get_date(bool utc) const override; + virtual Time get_time(bool utc) const override; + virtual TimeZoneInfo get_time_zone_info() const override; - virtual uint64_t get_unix_time() const; - virtual uint64_t get_system_time_secs() const; - virtual uint64_t get_system_time_msecs() const; + virtual double get_unix_time() const override; - virtual void delay_usec(uint32_t p_usec) const; - virtual uint64_t get_ticks_usec() const; + virtual void delay_usec(uint32_t p_usec) const override; + virtual uint64_t get_ticks_usec() const override; - virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr); - virtual Error kill(const ProcessID &p_pid); - virtual int get_process_id() const; + virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) override; + virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override; + virtual Error kill(const ProcessID &p_pid) override; + virtual int get_process_id() const override; - virtual bool has_environment(const String &p_var) const; - virtual String get_environment(const String &p_var) const; - virtual bool set_environment(const String &p_var, const String &p_value) const; - virtual String get_locale() const; + virtual bool has_environment(const String &p_var) const override; + virtual String get_environment(const String &p_var) const override; + virtual bool set_environment(const String &p_var, const String &p_value) const override; + virtual String get_locale() const override; - virtual int get_processor_count() const; + virtual int get_processor_count() const override; - virtual void debug_break(); - virtual void initialize_debugging(); + virtual void debug_break() override; + virtual void initialize_debugging() override; - virtual String get_executable_path() const; - virtual String get_user_data_dir() const; + virtual String get_executable_path() const override; + virtual String get_user_data_dir() const override; }; class UnixTerminalLogger : public StdLogger { diff --git a/drivers/unix/rw_lock_posix.cpp b/drivers/unix/rw_lock_posix.cpp index f219a0905c..af3ca3a597 100644 --- a/drivers/unix/rw_lock_posix.cpp +++ b/drivers/unix/rw_lock_posix.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,12 +32,11 @@ #include "rw_lock_posix.h" -#include "core/error_macros.h" +#include "core/error/error_macros.h" #include "core/os/memory.h" #include <stdio.h> void RWLockPosix::read_lock() { - int err = pthread_rwlock_rdlock(&rwlock); if (err != 0) { perror("Acquiring lock failed"); @@ -46,12 +45,10 @@ void RWLockPosix::read_lock() { } void RWLockPosix::read_unlock() { - pthread_rwlock_unlock(&rwlock); } Error RWLockPosix::read_try_lock() { - if (pthread_rwlock_tryrdlock(&rwlock) != 0) { return ERR_BUSY; } else { @@ -60,13 +57,11 @@ Error RWLockPosix::read_try_lock() { } void RWLockPosix::write_lock() { - int err = pthread_rwlock_wrlock(&rwlock); ERR_FAIL_COND(err != 0); } void RWLockPosix::write_unlock() { - pthread_rwlock_unlock(&rwlock); } @@ -79,23 +74,19 @@ Error RWLockPosix::write_try_lock() { } RWLock *RWLockPosix::create_func_posix() { - return memnew(RWLockPosix); } void RWLockPosix::make_default() { - create_func = create_func_posix; } RWLockPosix::RWLockPosix() { - //rwlock=PTHREAD_RWLOCK_INITIALIZER; fails on OSX pthread_rwlock_init(&rwlock, nullptr); } RWLockPosix::~RWLockPosix() { - pthread_rwlock_destroy(&rwlock); } diff --git a/drivers/unix/rw_lock_posix.h b/drivers/unix/rw_lock_posix.h index b12d373db5..aecb2e18ab 100644 --- a/drivers/unix/rw_lock_posix.h +++ b/drivers/unix/rw_lock_posix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -37,7 +37,6 @@ #include <pthread.h> class RWLockPosix : public RWLock { - pthread_rwlock_t rwlock; static RWLock *create_func_posix(); diff --git a/drivers/unix/syslog_logger.cpp b/drivers/unix/syslog_logger.cpp index dc9112bf14..423ddac793 100644 --- a/drivers/unix/syslog_logger.cpp +++ b/drivers/unix/syslog_logger.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 @@ #ifdef UNIX_ENABLED #include "syslog_logger.h" -#include "core/print_string.h" +#include "core/string/print_string.h" #include <syslog.h> void SyslogLogger::logv(const char *p_format, va_list p_list, bool p_err) { @@ -49,18 +49,29 @@ void SyslogLogger::print_error(const char *p_function, const char *p_file, int p const char *err_type = "**ERROR**"; switch (p_type) { - case ERR_ERROR: err_type = "**ERROR**"; break; - case ERR_WARNING: err_type = "**WARNING**"; break; - case ERR_SCRIPT: err_type = "**SCRIPT ERROR**"; break; - case ERR_SHADER: err_type = "**SHADER ERROR**"; break; - default: ERR_PRINT("Unknown error type"); break; + case ERR_ERROR: + err_type = "**ERROR**"; + break; + case ERR_WARNING: + err_type = "**WARNING**"; + break; + case ERR_SCRIPT: + err_type = "**SCRIPT ERROR**"; + break; + case ERR_SHADER: + err_type = "**SHADER ERROR**"; + break; + default: + ERR_PRINT("Unknown error type"); + break; } const char *err_details; - if (p_rationale && *p_rationale) + if (p_rationale && *p_rationale) { err_details = p_rationale; - else + } else { err_details = p_code; + } syslog(p_type == ERR_WARNING ? LOG_WARNING : LOG_ERR, "%s: %s\n At: %s:%i:%s() - %s", err_type, err_details, p_file, p_line, p_function, p_code); } diff --git a/drivers/unix/syslog_logger.h b/drivers/unix/syslog_logger.h index 52da12481f..d9f7f2ff99 100644 --- a/drivers/unix/syslog_logger.h +++ b/drivers/unix/syslog_logger.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/drivers/unix/thread_posix.cpp b/drivers/unix/thread_posix.cpp index c227aec6d6..5c7a546b29 100644 --- a/drivers/unix/thread_posix.cpp +++ b/drivers/unix/thread_posix.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,17 +29,17 @@ /*************************************************************************/ #include "thread_posix.h" -#include "core/script_language.h" #if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(NO_THREADS) +#include "core/object/script_language.h" +#include "core/os/memory.h" +#include "core/templates/safe_refcount.h" + #ifdef PTHREAD_BSD_SET_NAME #include <pthread_np.h> #endif -#include "core/os/memory.h" -#include "core/safe_refcount.h" - static void _thread_id_key_destr_callback(void *p_value) { memdelete(static_cast<Thread::ID *>(p_value)); } @@ -54,17 +54,14 @@ pthread_key_t ThreadPosix::thread_id_key = _create_thread_id_key(); Thread::ID ThreadPosix::next_thread_id = 0; Thread::ID ThreadPosix::get_id() const { - return id; } Thread *ThreadPosix::create_thread_posix() { - return memnew(ThreadPosix); } void *ThreadPosix::thread_callback(void *userdata) { - ThreadPosix *t = reinterpret_cast<ThreadPosix *>(userdata); t->id = atomic_increment(&next_thread_id); pthread_setspecific(thread_id_key, (void *)memnew(ID(t->id))); @@ -79,7 +76,6 @@ void *ThreadPosix::thread_callback(void *userdata) { } Thread *ThreadPosix::create_func_posix(ThreadCreateCallback p_callback, void *p_user, const Settings &) { - ThreadPosix *tr = memnew(ThreadPosix); tr->callback = p_callback; tr->user = p_user; @@ -91,19 +87,20 @@ Thread *ThreadPosix::create_func_posix(ThreadCreateCallback p_callback, void *p_ return tr; } -Thread::ID ThreadPosix::get_thread_id_func_posix() { +Thread::ID ThreadPosix::get_thread_id_func_posix() { void *value = pthread_getspecific(thread_id_key); - if (value) + if (value) { return *static_cast<ID *>(value); + } ID new_id = atomic_increment(&next_thread_id); pthread_setspecific(thread_id_key, (void *)memnew(ID(new_id))); return new_id; } -void ThreadPosix::wait_to_finish_func_posix(Thread *p_thread) { +void ThreadPosix::wait_to_finish_func_posix(Thread *p_thread) { ThreadPosix *tp = static_cast<ThreadPosix *>(p_thread); ERR_FAIL_COND(!tp); ERR_FAIL_COND(tp->pthread == 0); @@ -113,7 +110,6 @@ void ThreadPosix::wait_to_finish_func_posix(Thread *p_thread) { } Error ThreadPosix::set_name_func_posix(const String &p_name) { - #ifdef PTHREAD_NO_RENAME return ERR_UNAVAILABLE; @@ -130,6 +126,8 @@ Error ThreadPosix::set_name_func_posix(const String &p_name) { #ifdef PTHREAD_BSD_SET_NAME pthread_set_name_np(running_thread, p_name.utf8().get_data()); int err = 0; // Open/FreeBSD ignore errors in this function +#elif defined(PTHREAD_NETBSD_SET_NAME) + int err = pthread_setname_np(running_thread, "%s", const_cast<char *>(p_name.utf8().get_data())); #else int err = pthread_setname_np(running_thread, p_name.utf8().get_data()); #endif // PTHREAD_BSD_SET_NAME @@ -142,7 +140,6 @@ Error ThreadPosix::set_name_func_posix(const String &p_name) { }; void ThreadPosix::make_default() { - create_func = create_func_posix; get_thread_id_func = get_thread_id_func_posix; wait_to_finish_func = wait_to_finish_func_posix; @@ -150,7 +147,6 @@ void ThreadPosix::make_default() { } ThreadPosix::ThreadPosix() { - pthread = 0; } diff --git a/drivers/unix/thread_posix.h b/drivers/unix/thread_posix.h index e852dcf3d5..fa2037e1a2 100644 --- a/drivers/unix/thread_posix.h +++ b/drivers/unix/thread_posix.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 */ @@ -38,7 +38,6 @@ #include <sys/types.h> class ThreadPosix : public Thread { - static pthread_key_t thread_id_key; static ID next_thread_id; diff --git a/drivers/vulkan/SCsub b/drivers/vulkan/SCsub index 91d0e42f80..14b9d63204 100644 --- a/drivers/vulkan/SCsub +++ b/drivers/vulkan/SCsub @@ -2,8 +2,9 @@ Import("env") -env.add_source_files(env.drivers_sources, "*.cpp") +thirdparty_obj = [] +# FIXME: Refactor all this to reduce code duplication. if env["platform"] == "android": # Use NDK Vulkan headers thirdparty_dir = env["ANDROID_NDK_ROOT"] + "/sources/third_party/vulkan/src" @@ -21,7 +22,20 @@ if env["platform"] == "android": thirdparty_dir = "#thirdparty/vulkan" vma_sources = [thirdparty_dir + "/android/vk_mem_alloc.cpp"] - env_thirdparty.add_source_files(env.drivers_sources, vma_sources) + env_thirdparty.add_source_files(thirdparty_obj, vma_sources) + +elif env["platform"] == "iphone": + # Use bundled Vulkan headers + thirdparty_dir = "#thirdparty/vulkan" + env.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "/include", thirdparty_dir + "/loader"]) + + # Build Vulkan memory allocator + env_thirdparty = env.Clone() + env_thirdparty.disable_warnings() + + vma_sources = [thirdparty_dir + "/vk_mem_alloc.cpp"] + env_thirdparty.add_source_files(thirdparty_obj, vma_sources) + elif env["builtin_vulkan"]: # Use bundled Vulkan headers thirdparty_dir = "#thirdparty/vulkan" @@ -47,7 +61,6 @@ elif env["builtin_vulkan"]: if env["platform"] == "windows": loader_sources.append("dirent_on_windows.c") - loader_sources.append("dxgi_loader.c") env_thirdparty.AppendUnique( CPPDEFINES=[ "VK_USE_PLATFORM_WIN32_KHR", @@ -70,16 +83,6 @@ elif env["builtin_vulkan"]: 'FALLBACK_CONFIG_DIRS=\\"%s\\"' % "/etc/xdg", ] ) - elif env["platform"] == "iphone": - env_thirdparty.AppendUnique( - CPPDEFINES=[ - "VK_USE_PLATFORM_IOS_MVK", - "VULKAN_NON_CMAKE_BUILD", - 'SYSCONFDIR=\\"%s\\"' % "/etc", - 'FALLBACK_DATA_DIRS=\\"%s\\"' % "/usr/local/share:/usr/share", - 'FALLBACK_CONFIG_DIRS=\\"%s\\"' % "/etc/xdg", - ] - ) elif env["platform"] == "linuxbsd": env_thirdparty.AppendUnique( CPPDEFINES=[ @@ -97,5 +100,30 @@ elif env["builtin_vulkan"]: env_thirdparty.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"]) loader_sources = [thirdparty_dir + "/loader/" + file for file in loader_sources] - env_thirdparty.add_source_files(env.drivers_sources, loader_sources) - env_thirdparty.add_source_files(env.drivers_sources, vma_sources) + env_thirdparty.add_source_files(thirdparty_obj, loader_sources) + env_thirdparty.add_source_files(thirdparty_obj, vma_sources) + +else: # Always build VMA. + thirdparty_dir = "#thirdparty/vulkan" + env.Prepend(CPPPATH=[thirdparty_dir]) + + # Build Vulkan loader library + env_thirdparty = env.Clone() + env_thirdparty.disable_warnings() + vma_sources = [thirdparty_dir + "/vk_mem_alloc.cpp"] + + env_thirdparty.add_source_files(thirdparty_obj, vma_sources) + + +env.drivers_sources += thirdparty_obj + + +# Godot source files + +driver_obj = [] + +env.add_source_files(driver_obj, "*.cpp") +env.drivers_sources += driver_obj + +# Needed to force rebuilding the driver files when the thirdparty code is updated. +env.Depends(driver_obj, thirdparty_obj) diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 23e9227a39..0c59310f8d 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.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,17 +30,68 @@ #include "rendering_device_vulkan.h" -#include "core/hashfuncs.h" +#include "core/config/project_settings.h" #include "core/os/file_access.h" #include "core/os/os.h" -#include "core/project_settings.h" +#include "core/templates/hashfuncs.h" #include "drivers/vulkan/vulkan_context.h" + #include "thirdparty/spirv-reflect/spirv_reflect.h" //#define FORCE_FULL_BARRIER -void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) { +// Get the Vulkan object information and possible stage access types (bitwise OR'd with incoming values) +RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID p_buffer, VkPipelineStageFlags &stage_mask, VkAccessFlags &access_mask) { + Buffer *buffer = nullptr; + if (vertex_buffer_owner.owns(p_buffer)) { + stage_mask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + access_mask |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; + buffer = vertex_buffer_owner.getornull(p_buffer); + } else if (index_buffer_owner.owns(p_buffer)) { + stage_mask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + access_mask |= VK_ACCESS_INDEX_READ_BIT; + buffer = index_buffer_owner.getornull(p_buffer); + } else if (uniform_buffer_owner.owns(p_buffer)) { + stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + access_mask |= VK_ACCESS_UNIFORM_READ_BIT; + buffer = uniform_buffer_owner.getornull(p_buffer); + } else if (texture_buffer_owner.owns(p_buffer)) { + stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + access_mask |= VK_ACCESS_SHADER_READ_BIT; + buffer = &texture_buffer_owner.getornull(p_buffer)->buffer; + } else if (storage_buffer_owner.owns(p_buffer)) { + stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + buffer = storage_buffer_owner.getornull(p_buffer); + } + return buffer; +} + +static void update_external_dependency_for_store(VkSubpassDependency &dependency, bool is_sampled, bool is_storage, bool is_depth) { + // Transitioning from write to read, protect the shaders that may use this next + // Allow for copies/image layout transitions + dependency.dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; + dependency.dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT; + + if (is_sampled) { + dependency.dstStageMask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + dependency.dstAccessMask |= VK_ACCESS_SHADER_READ_BIT; + } else if (is_storage) { + dependency.dstStageMask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + dependency.dstAccessMask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + } else { + dependency.dstStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + } + + if (is_depth) { + // Depth resources have addtional stages that may be interested in them + dependency.dstStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + dependency.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + } +} +void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) { if (!dependency_map.has(p_depends_on)) { dependency_map[p_depends_on] = Set<RID>(); } @@ -55,23 +106,20 @@ void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) { } void RenderingDeviceVulkan::_free_dependencies(RID p_id) { - //direct dependencies must be freed Map<RID, Set<RID>>::Element *E = dependency_map.find(p_id); if (E) { - while (E->get().size()) { free(E->get().front()->get()); } dependency_map.erase(E); } - //reverse depenencies must be unreferenced + //reverse dependencies must be unreferenced E = reverse_dependency_map.find(p_id); if (E) { - for (Set<RID>::Element *F = E->get().front(); F; F = F->next()) { Map<RID, Set<RID>>::Element *G = dependency_map.find(F->get()); ERR_CONTINUE(!G); @@ -566,81 +614,98 @@ int RenderingDeviceVulkan::get_format_vertex_size(DataFormat p_format) { case DATA_FORMAT_B8G8R8A8_UNORM: case DATA_FORMAT_B8G8R8A8_SNORM: case DATA_FORMAT_B8G8R8A8_UINT: - case DATA_FORMAT_B8G8R8A8_SINT: return 4; + case DATA_FORMAT_B8G8R8A8_SINT: + case DATA_FORMAT_A2B10G10R10_UNORM_PACK32: + return 4; case DATA_FORMAT_R16_UNORM: case DATA_FORMAT_R16_SNORM: case DATA_FORMAT_R16_UINT: case DATA_FORMAT_R16_SINT: - case DATA_FORMAT_R16_SFLOAT: return 4; + case DATA_FORMAT_R16_SFLOAT: + return 4; case DATA_FORMAT_R16G16_UNORM: case DATA_FORMAT_R16G16_SNORM: case DATA_FORMAT_R16G16_UINT: case DATA_FORMAT_R16G16_SINT: - case DATA_FORMAT_R16G16_SFLOAT: return 4; + case DATA_FORMAT_R16G16_SFLOAT: + return 4; case DATA_FORMAT_R16G16B16_UNORM: case DATA_FORMAT_R16G16B16_SNORM: case DATA_FORMAT_R16G16B16_UINT: case DATA_FORMAT_R16G16B16_SINT: - case DATA_FORMAT_R16G16B16_SFLOAT: return 8; + case DATA_FORMAT_R16G16B16_SFLOAT: + return 8; case DATA_FORMAT_R16G16B16A16_UNORM: case DATA_FORMAT_R16G16B16A16_SNORM: case DATA_FORMAT_R16G16B16A16_UINT: case DATA_FORMAT_R16G16B16A16_SINT: - case DATA_FORMAT_R16G16B16A16_SFLOAT: return 8; + case DATA_FORMAT_R16G16B16A16_SFLOAT: + return 8; case DATA_FORMAT_R32_UINT: case DATA_FORMAT_R32_SINT: - case DATA_FORMAT_R32_SFLOAT: return 4; + case DATA_FORMAT_R32_SFLOAT: + return 4; case DATA_FORMAT_R32G32_UINT: case DATA_FORMAT_R32G32_SINT: - case DATA_FORMAT_R32G32_SFLOAT: return 8; + case DATA_FORMAT_R32G32_SFLOAT: + return 8; case DATA_FORMAT_R32G32B32_UINT: case DATA_FORMAT_R32G32B32_SINT: - case DATA_FORMAT_R32G32B32_SFLOAT: return 12; + case DATA_FORMAT_R32G32B32_SFLOAT: + return 12; case DATA_FORMAT_R32G32B32A32_UINT: case DATA_FORMAT_R32G32B32A32_SINT: - case DATA_FORMAT_R32G32B32A32_SFLOAT: return 16; + case DATA_FORMAT_R32G32B32A32_SFLOAT: + return 16; case DATA_FORMAT_R64_UINT: case DATA_FORMAT_R64_SINT: - case DATA_FORMAT_R64_SFLOAT: return 8; + case DATA_FORMAT_R64_SFLOAT: + return 8; case DATA_FORMAT_R64G64_UINT: case DATA_FORMAT_R64G64_SINT: - case DATA_FORMAT_R64G64_SFLOAT: return 16; + case DATA_FORMAT_R64G64_SFLOAT: + return 16; case DATA_FORMAT_R64G64B64_UINT: case DATA_FORMAT_R64G64B64_SINT: - case DATA_FORMAT_R64G64B64_SFLOAT: return 24; + case DATA_FORMAT_R64G64B64_SFLOAT: + return 24; case DATA_FORMAT_R64G64B64A64_UINT: case DATA_FORMAT_R64G64B64A64_SINT: - case DATA_FORMAT_R64G64B64A64_SFLOAT: return 32; - default: return 0; + case DATA_FORMAT_R64G64B64A64_SFLOAT: + return 32; + default: + return 0; } } uint32_t RenderingDeviceVulkan::get_image_format_pixel_size(DataFormat p_format) { - switch (p_format) { - - case DATA_FORMAT_R4G4_UNORM_PACK8: return 1; + case DATA_FORMAT_R4G4_UNORM_PACK8: + return 1; case DATA_FORMAT_R4G4B4A4_UNORM_PACK16: case DATA_FORMAT_B4G4R4A4_UNORM_PACK16: case DATA_FORMAT_R5G6B5_UNORM_PACK16: case DATA_FORMAT_B5G6R5_UNORM_PACK16: case DATA_FORMAT_R5G5B5A1_UNORM_PACK16: case DATA_FORMAT_B5G5R5A1_UNORM_PACK16: - case DATA_FORMAT_A1R5G5B5_UNORM_PACK16: return 2; + case DATA_FORMAT_A1R5G5B5_UNORM_PACK16: + return 2; case DATA_FORMAT_R8_UNORM: case DATA_FORMAT_R8_SNORM: case DATA_FORMAT_R8_USCALED: case DATA_FORMAT_R8_SSCALED: case DATA_FORMAT_R8_UINT: case DATA_FORMAT_R8_SINT: - case DATA_FORMAT_R8_SRGB: return 1; + case DATA_FORMAT_R8_SRGB: + return 1; case DATA_FORMAT_R8G8_UNORM: case DATA_FORMAT_R8G8_SNORM: case DATA_FORMAT_R8G8_USCALED: case DATA_FORMAT_R8G8_SSCALED: case DATA_FORMAT_R8G8_UINT: case DATA_FORMAT_R8G8_SINT: - case DATA_FORMAT_R8G8_SRGB: return 2; + case DATA_FORMAT_R8G8_SRGB: + return 2; case DATA_FORMAT_R8G8B8_UNORM: case DATA_FORMAT_R8G8B8_SNORM: case DATA_FORMAT_R8G8B8_USCALED: @@ -654,7 +719,8 @@ uint32_t RenderingDeviceVulkan::get_image_format_pixel_size(DataFormat p_format) case DATA_FORMAT_B8G8R8_SSCALED: case DATA_FORMAT_B8G8R8_UINT: case DATA_FORMAT_B8G8R8_SINT: - case DATA_FORMAT_B8G8R8_SRGB: return 3; + case DATA_FORMAT_B8G8R8_SRGB: + return 3; case DATA_FORMAT_R8G8B8A8_UNORM: case DATA_FORMAT_R8G8B8A8_SNORM: case DATA_FORMAT_R8G8B8A8_USCALED: @@ -668,7 +734,8 @@ uint32_t RenderingDeviceVulkan::get_image_format_pixel_size(DataFormat p_format) case DATA_FORMAT_B8G8R8A8_SSCALED: case DATA_FORMAT_B8G8R8A8_UINT: case DATA_FORMAT_B8G8R8A8_SINT: - case DATA_FORMAT_B8G8R8A8_SRGB: return 4; + case DATA_FORMAT_B8G8R8A8_SRGB: + return 4; case DATA_FORMAT_A8B8G8R8_UNORM_PACK32: case DATA_FORMAT_A8B8G8R8_SNORM_PACK32: case DATA_FORMAT_A8B8G8R8_USCALED_PACK32: @@ -687,67 +754,87 @@ uint32_t RenderingDeviceVulkan::get_image_format_pixel_size(DataFormat p_format) case DATA_FORMAT_A2B10G10R10_USCALED_PACK32: case DATA_FORMAT_A2B10G10R10_SSCALED_PACK32: case DATA_FORMAT_A2B10G10R10_UINT_PACK32: - case DATA_FORMAT_A2B10G10R10_SINT_PACK32: return 4; + case DATA_FORMAT_A2B10G10R10_SINT_PACK32: + return 4; case DATA_FORMAT_R16_UNORM: case DATA_FORMAT_R16_SNORM: case DATA_FORMAT_R16_USCALED: case DATA_FORMAT_R16_SSCALED: case DATA_FORMAT_R16_UINT: case DATA_FORMAT_R16_SINT: - case DATA_FORMAT_R16_SFLOAT: return 2; + case DATA_FORMAT_R16_SFLOAT: + return 2; case DATA_FORMAT_R16G16_UNORM: case DATA_FORMAT_R16G16_SNORM: case DATA_FORMAT_R16G16_USCALED: case DATA_FORMAT_R16G16_SSCALED: case DATA_FORMAT_R16G16_UINT: case DATA_FORMAT_R16G16_SINT: - case DATA_FORMAT_R16G16_SFLOAT: return 4; + case DATA_FORMAT_R16G16_SFLOAT: + return 4; case DATA_FORMAT_R16G16B16_UNORM: case DATA_FORMAT_R16G16B16_SNORM: case DATA_FORMAT_R16G16B16_USCALED: case DATA_FORMAT_R16G16B16_SSCALED: case DATA_FORMAT_R16G16B16_UINT: case DATA_FORMAT_R16G16B16_SINT: - case DATA_FORMAT_R16G16B16_SFLOAT: return 6; + case DATA_FORMAT_R16G16B16_SFLOAT: + return 6; case DATA_FORMAT_R16G16B16A16_UNORM: case DATA_FORMAT_R16G16B16A16_SNORM: case DATA_FORMAT_R16G16B16A16_USCALED: case DATA_FORMAT_R16G16B16A16_SSCALED: case DATA_FORMAT_R16G16B16A16_UINT: case DATA_FORMAT_R16G16B16A16_SINT: - case DATA_FORMAT_R16G16B16A16_SFLOAT: return 8; + case DATA_FORMAT_R16G16B16A16_SFLOAT: + return 8; case DATA_FORMAT_R32_UINT: case DATA_FORMAT_R32_SINT: - case DATA_FORMAT_R32_SFLOAT: return 4; + case DATA_FORMAT_R32_SFLOAT: + return 4; case DATA_FORMAT_R32G32_UINT: case DATA_FORMAT_R32G32_SINT: - case DATA_FORMAT_R32G32_SFLOAT: return 8; + case DATA_FORMAT_R32G32_SFLOAT: + return 8; case DATA_FORMAT_R32G32B32_UINT: case DATA_FORMAT_R32G32B32_SINT: - case DATA_FORMAT_R32G32B32_SFLOAT: return 12; + case DATA_FORMAT_R32G32B32_SFLOAT: + return 12; case DATA_FORMAT_R32G32B32A32_UINT: case DATA_FORMAT_R32G32B32A32_SINT: - case DATA_FORMAT_R32G32B32A32_SFLOAT: return 16; + case DATA_FORMAT_R32G32B32A32_SFLOAT: + return 16; case DATA_FORMAT_R64_UINT: case DATA_FORMAT_R64_SINT: - case DATA_FORMAT_R64_SFLOAT: return 8; + case DATA_FORMAT_R64_SFLOAT: + return 8; case DATA_FORMAT_R64G64_UINT: case DATA_FORMAT_R64G64_SINT: - case DATA_FORMAT_R64G64_SFLOAT: return 16; + case DATA_FORMAT_R64G64_SFLOAT: + return 16; case DATA_FORMAT_R64G64B64_UINT: case DATA_FORMAT_R64G64B64_SINT: - case DATA_FORMAT_R64G64B64_SFLOAT: return 24; + case DATA_FORMAT_R64G64B64_SFLOAT: + return 24; case DATA_FORMAT_R64G64B64A64_UINT: case DATA_FORMAT_R64G64B64A64_SINT: - case DATA_FORMAT_R64G64B64A64_SFLOAT: return 32; + case DATA_FORMAT_R64G64B64A64_SFLOAT: + return 32; case DATA_FORMAT_B10G11R11_UFLOAT_PACK32: - case DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32: return 4; - case DATA_FORMAT_D16_UNORM: return 2; - case DATA_FORMAT_X8_D24_UNORM_PACK32: return 4; - case DATA_FORMAT_D32_SFLOAT: return 4; - case DATA_FORMAT_S8_UINT: return 1; - case DATA_FORMAT_D16_UNORM_S8_UINT: return 4; - case DATA_FORMAT_D24_UNORM_S8_UINT: return 4; + case DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32: + return 4; + case DATA_FORMAT_D16_UNORM: + return 2; + case DATA_FORMAT_X8_D24_UNORM_PACK32: + return 4; + case DATA_FORMAT_D32_SFLOAT: + return 4; + case DATA_FORMAT_S8_UINT: + return 1; + case DATA_FORMAT_D16_UNORM_S8_UINT: + return 4; + case DATA_FORMAT_D24_UNORM_S8_UINT: + return 4; case DATA_FORMAT_D32_SFLOAT_S8_UINT: return 5; //? case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: @@ -765,17 +852,20 @@ uint32_t RenderingDeviceVulkan::get_image_format_pixel_size(DataFormat p_format) case DATA_FORMAT_BC6H_UFLOAT_BLOCK: case DATA_FORMAT_BC6H_SFLOAT_BLOCK: case DATA_FORMAT_BC7_UNORM_BLOCK: - case DATA_FORMAT_BC7_SRGB_BLOCK: return 1; + case DATA_FORMAT_BC7_SRGB_BLOCK: + return 1; case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: - case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: return 1; + case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: + return 1; case DATA_FORMAT_EAC_R11_UNORM_BLOCK: case DATA_FORMAT_EAC_R11_SNORM_BLOCK: case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK: - case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK: return 1; + case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK: + return 1; case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: @@ -803,14 +893,17 @@ uint32_t RenderingDeviceVulkan::get_image_format_pixel_size(DataFormat p_format) case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK: case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK: case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK: - case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK: return 1; + case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK: + return 1; case DATA_FORMAT_G8B8G8R8_422_UNORM: - case DATA_FORMAT_B8G8R8G8_422_UNORM: return 4; + case DATA_FORMAT_B8G8R8G8_422_UNORM: + return 4; case DATA_FORMAT_G8_B8_R8_3PLANE_420_UNORM: case DATA_FORMAT_G8_B8R8_2PLANE_420_UNORM: case DATA_FORMAT_G8_B8_R8_3PLANE_422_UNORM: case DATA_FORMAT_G8_B8R8_2PLANE_422_UNORM: - case DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM: return 4; + case DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM: + return 4; case DATA_FORMAT_R10X6_UNORM_PACK16: case DATA_FORMAT_R10X6G10X6_UNORM_2PACK16: case DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: @@ -830,14 +923,16 @@ uint32_t RenderingDeviceVulkan::get_image_format_pixel_size(DataFormat p_format) case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: - case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: return 2; + case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: + return 2; case DATA_FORMAT_G16B16G16R16_422_UNORM: case DATA_FORMAT_B16G16R16G16_422_UNORM: case DATA_FORMAT_G16_B16_R16_3PLANE_420_UNORM: case DATA_FORMAT_G16_B16R16_2PLANE_420_UNORM: case DATA_FORMAT_G16_B16_R16_3PLANE_422_UNORM: case DATA_FORMAT_G16_B16R16_2PLANE_422_UNORM: - case DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM: return 8; + case DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM: + return 8; case DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: case DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: case DATA_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: @@ -845,7 +940,8 @@ uint32_t RenderingDeviceVulkan::get_image_format_pixel_size(DataFormat p_format) case DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: case DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: case DATA_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: - case DATA_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: return 1; + case DATA_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: + return 1; default: { ERR_PRINT("Format not handled, bug"); } @@ -857,7 +953,6 @@ uint32_t RenderingDeviceVulkan::get_image_format_pixel_size(DataFormat p_format) // https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.pdf void RenderingDeviceVulkan::get_compressed_image_format_block_dimensions(DataFormat p_format, uint32_t &r_w, uint32_t &r_h) { - switch (p_format) { case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: @@ -938,34 +1033,45 @@ void RenderingDeviceVulkan::get_compressed_image_format_block_dimensions(DataFor } uint32_t RenderingDeviceVulkan::get_compressed_image_format_block_byte_size(DataFormat p_format) { - switch (p_format) { case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK: - case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK: return 8; + case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK: + return 8; case DATA_FORMAT_BC2_UNORM_BLOCK: - case DATA_FORMAT_BC2_SRGB_BLOCK: return 16; + case DATA_FORMAT_BC2_SRGB_BLOCK: + return 16; case DATA_FORMAT_BC3_UNORM_BLOCK: - case DATA_FORMAT_BC3_SRGB_BLOCK: return 16; + case DATA_FORMAT_BC3_SRGB_BLOCK: + return 16; case DATA_FORMAT_BC4_UNORM_BLOCK: - case DATA_FORMAT_BC4_SNORM_BLOCK: return 8; + case DATA_FORMAT_BC4_SNORM_BLOCK: + return 8; case DATA_FORMAT_BC5_UNORM_BLOCK: - case DATA_FORMAT_BC5_SNORM_BLOCK: return 16; + case DATA_FORMAT_BC5_SNORM_BLOCK: + return 16; case DATA_FORMAT_BC6H_UFLOAT_BLOCK: - case DATA_FORMAT_BC6H_SFLOAT_BLOCK: return 16; + case DATA_FORMAT_BC6H_SFLOAT_BLOCK: + return 16; case DATA_FORMAT_BC7_UNORM_BLOCK: - case DATA_FORMAT_BC7_SRGB_BLOCK: return 16; + case DATA_FORMAT_BC7_SRGB_BLOCK: + return 16; case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: - case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: return 8; + case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: + return 8; case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: - case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: return 8; + case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: + return 8; case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: - case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: return 16; + case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: + return 16; case DATA_FORMAT_EAC_R11_UNORM_BLOCK: - case DATA_FORMAT_EAC_R11_SNORM_BLOCK: return 8; + case DATA_FORMAT_EAC_R11_SNORM_BLOCK: + return 8; case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK: - case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK: return 16; + case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK: + return 16; case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: //again, not sure about astc case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: @@ -1011,7 +1117,6 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_block_byte_size(Data } uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFormat p_format) { - switch (p_format) { case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: //these formats are half byte size, so rshift is 1 case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: @@ -1028,11 +1133,13 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFor case DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: case DATA_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: case DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: - case DATA_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: return 1; + case DATA_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: + return 1; case DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: //these formats are quarter byte size, so rshift is 1 case DATA_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: case DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: - case DATA_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: return 2; + case DATA_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: + return 2; default: { } } @@ -1055,7 +1162,6 @@ bool RenderingDeviceVulkan::format_has_stencil(DataFormat p_format) { } uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw, uint32_t *r_blockh, uint32_t *r_depth) { - ERR_FAIL_COND_V(p_mipmaps == 0, 0); uint32_t w = p_width; uint32_t h = p_height; @@ -1095,7 +1201,6 @@ uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_form } uint32_t RenderingDeviceVulkan::get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth) { - //formats and block size don't really matter here since they can all go down to 1px (even if block is larger) int w = p_width; int h = p_height; @@ -1104,7 +1209,6 @@ uint32_t RenderingDeviceVulkan::get_image_required_mipmaps(uint32_t p_width, uin int mipmaps = 1; while (true) { - if (w == 1 && h == 1 && d == 1) { break; } @@ -1258,6 +1362,7 @@ Error RenderingDeviceVulkan::_buffer_allocate(Buffer *p_buffer, uint32_t p_size, p_buffer->buffer_info.buffer = p_buffer->buffer; p_buffer->buffer_info.offset = 0; p_buffer->buffer_info.range = p_size; + p_buffer->usage = p_usage; return OK; } @@ -1274,7 +1379,6 @@ Error RenderingDeviceVulkan::_buffer_free(Buffer *p_buffer) { } Error RenderingDeviceVulkan::_insert_staging_block() { - VkBufferCreateInfo bufferInfo; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.pNext = nullptr; @@ -1312,7 +1416,6 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_ r_alloc_size = p_amount; while (true) { - r_alloc_offset = 0; //see if we can use current block @@ -1368,7 +1471,6 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_ //block_until_next_frame() continue; } else { - //flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands _flush(true); @@ -1413,7 +1515,6 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_ //block_until_next_frame() continue; //and try again } else { - _flush(false); for (int i = 0; i < staging_buffer_blocks.size(); i++) { @@ -1443,13 +1544,11 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_ } Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_buffer, uint32_t p_required_align) { - //submitting may get chunked for various reasons, so convert this to a task size_t to_submit = p_data_size; size_t submit_from = 0; while (to_submit > 0) { - uint32_t block_write_offset; uint32_t block_write_amount; @@ -1490,7 +1589,6 @@ Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, c } void RenderingDeviceVulkan::_memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw) { - VkMemoryBarrier mem_barrier; mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; mem_barrier.pNext = nullptr; @@ -1537,7 +1635,6 @@ void RenderingDeviceVulkan::_full_barrier(bool p_sync_with_draw) { } void RenderingDeviceVulkan::_buffer_memory_barrier(VkBuffer buffer, uint64_t p_from, uint64_t p_size, VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw) { - VkBufferMemoryBarrier buffer_mem_barrier; buffer_mem_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; buffer_mem_barrier.pNext = nullptr; @@ -1557,7 +1654,6 @@ void RenderingDeviceVulkan::_buffer_memory_barrier(VkBuffer buffer, uint64_t p_f /*****************/ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data) { - _THREAD_SAFE_METHOD_ VkImageCreateInfo image_create_info; @@ -1597,16 +1693,16 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T #endif } - if (p_format.type == TEXTURE_TYPE_CUBE || p_format.type == TEXTURE_TYPE_CUBE_ARRAY) { + if (p_format.texture_type == TEXTURE_TYPE_CUBE || p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY) { image_create_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; } /*if (p_format.type == TEXTURE_TYPE_2D || p_format.type == TEXTURE_TYPE_2D_ARRAY) { image_create_info.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; }*/ - ERR_FAIL_INDEX_V(p_format.type, TEXTURE_TYPE_MAX, RID()); + ERR_FAIL_INDEX_V(p_format.texture_type, TEXTURE_TYPE_MAX, RID()); - image_create_info.imageType = vulkan_image_type[p_format.type]; + image_create_info.imageType = vulkan_image_type[p_format.texture_type]; ERR_FAIL_COND_V_MSG(p_format.width < 1, RID(), "Width must be equal or greater than 1 for all textures"); @@ -1631,10 +1727,10 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T image_create_info.mipLevels = p_format.mipmaps; - if (p_format.type == TEXTURE_TYPE_1D_ARRAY || p_format.type == TEXTURE_TYPE_2D_ARRAY || p_format.type == TEXTURE_TYPE_CUBE_ARRAY || p_format.type == TEXTURE_TYPE_CUBE) { + if (p_format.texture_type == TEXTURE_TYPE_1D_ARRAY || p_format.texture_type == TEXTURE_TYPE_2D_ARRAY || p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || p_format.texture_type == TEXTURE_TYPE_CUBE) { ERR_FAIL_COND_V_MSG(p_format.array_layers < 1, RID(), "Amount of layers must be equal or greater than 1 for arrays and cubemaps."); - ERR_FAIL_COND_V_MSG((p_format.type == TEXTURE_TYPE_CUBE_ARRAY || p_format.type == TEXTURE_TYPE_CUBE) && (p_format.array_layers % 6) != 0, RID(), + ERR_FAIL_COND_V_MSG((p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY || p_format.texture_type == TEXTURE_TYPE_CUBE) && (p_format.array_layers % 6) != 0, RID(), "Cubemap and cubemap array textures must provide a layer number that is multiple of 6"); image_create_info.arrayLayers = p_format.array_layers; } else { @@ -1687,7 +1783,6 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T "Too many mipmaps requested for texture format and dimensions (" + itos(image_create_info.mipLevels) + "), maximum allowed: (" + itos(required_mipmaps) + ")."); if (p_data.size()) { - ERR_FAIL_COND_V_MSG(!(p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT), RID(), "Texture needs the TEXTURE_USAGE_CAN_UPDATE_BIT usage flag in order to be updated at initialization or later"); @@ -1765,7 +1860,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T VkResult err = vmaCreateImage(allocator, &image_create_info, &allocInfo, &texture.image, &texture.allocation, &texture.allocation_info); ERR_FAIL_COND_V_MSG(err, RID(), "vmaCreateImage failed with error " + itos(err) + "."); - texture.type = p_format.type; + texture.type = p_format.texture_type; texture.format = p_format.format; texture.width = image_create_info.extent.width; texture.height = image_create_info.extent.height; @@ -1795,7 +1890,6 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T texture.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } else if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - texture.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } else { @@ -1803,7 +1897,6 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T } if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - texture.read_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; texture.barrier_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; @@ -1835,7 +1928,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, }; - image_view_create_info.viewType = view_types[p_format.type]; + image_view_create_info.viewType = view_types[p_format.texture_type]; if (p_view.format_override == DATA_FORMAT_MAX) { image_view_create_info.format = image_create_info.format; } else { @@ -1892,13 +1985,12 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T image_memory_barrier.subresourceRange.baseArrayLayer = 0; image_memory_barrier.subresourceRange.layerCount = image_create_info.arrayLayers; - vkCmdPipelineBarrier(frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + vkCmdPipelineBarrier(frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); } RID id = texture_owner.make_rid(texture); if (p_data.size()) { - for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) { texture_update(id, i, p_data[i]); } @@ -1907,7 +1999,6 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T } RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID p_with_texture) { - _THREAD_SAFE_METHOD_ Texture *src_texture = texture_owner.getornull(p_with_texture); @@ -1987,7 +2078,6 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID } RID RenderingDeviceVulkan::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) { - _THREAD_SAFE_METHOD_ Texture *src_texture = texture_owner.getornull(p_with_texture); @@ -2005,15 +2095,26 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_3D && src_texture->type != TEXTURE_TYPE_3D, RID(), "Can only create a 3D slice from a 3D texture"); + ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_2D_ARRAY && (src_texture->type != TEXTURE_TYPE_2D_ARRAY), RID(), + "Can only create an array slice from a 2D array mipmap"); + //create view ERR_FAIL_UNSIGNED_INDEX_V(p_mipmap, src_texture->mipmaps, RID()); ERR_FAIL_UNSIGNED_INDEX_V(p_layer, src_texture->layers, RID()); + int slice_layers = 1; + if (p_slice_type == TEXTURE_SLICE_2D_ARRAY) { + ERR_FAIL_COND_V_MSG(p_layer != 0, RID(), "layer must be 0 when obtaining a 2D array mipmap slice"); + slice_layers = src_texture->layers; + } else if (p_slice_type == TEXTURE_SLICE_CUBEMAP) { + slice_layers = 6; + } + Texture texture = *src_texture; get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height); texture.mipmaps = 1; - texture.layers = p_slice_type == TEXTURE_SLICE_CUBEMAP ? 6 : 1; + texture.layers = slice_layers; texture.base_mipmap = p_mipmap; texture.base_layer = p_layer; @@ -2033,7 +2134,16 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p VK_IMAGE_VIEW_TYPE_2D, }; - image_view_create_info.viewType = p_slice_type == TEXTURE_SLICE_CUBEMAP ? VK_IMAGE_VIEW_TYPE_CUBE : (p_slice_type == TEXTURE_SLICE_3D ? VK_IMAGE_VIEW_TYPE_3D : view_types[texture.type]); + image_view_create_info.viewType = view_types[texture.type]; + + if (p_slice_type == TEXTURE_SLICE_CUBEMAP) { + image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_CUBE; + } else if (p_slice_type == TEXTURE_SLICE_3D) { + image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_3D; + } else if (p_slice_type == TEXTURE_SLICE_2D_ARRAY) { + image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + } + if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) { image_view_create_info.format = vulkan_formats[texture.format]; } else { @@ -2067,7 +2177,7 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p } image_view_create_info.subresourceRange.baseMipLevel = p_mipmap; image_view_create_info.subresourceRange.levelCount = 1; - image_view_create_info.subresourceRange.layerCount = p_slice_type == TEXTURE_SLICE_CUBEMAP ? 6 : 1; + image_view_create_info.subresourceRange.layerCount = slice_layers; image_view_create_info.subresourceRange.baseArrayLayer = p_layer; if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { @@ -2087,7 +2197,6 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p } Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, bool p_sync_with_draw) { - _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V_MSG(draw_list && p_sync_with_draw, ERR_INVALID_PARAMETER, @@ -2153,12 +2262,11 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; image_memory_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); } uint32_t mipmap_offset = 0; for (uint32_t mm_i = 0; mm_i < texture->mipmaps; mm_i++) { - uint32_t depth; uint32_t image_total = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, mm_i + 1, &width, &height, &depth); @@ -2171,7 +2279,6 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con for (uint32_t x = 0; x < width; x += region_size) { for (uint32_t y = 0; y < height; y += region_size) { - uint32_t region_w = MIN(region_size, width - x); uint32_t region_h = MIN(region_size, height - y); @@ -2232,7 +2339,6 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con uint32_t dst_offset = (yr * region_w + xr) * pixel_size; //copy block for (uint32_t i = 0; i < pixel_size; i++) { - write_ptr[dst_offset + i] = read_ptr[src_offset + i]; } } @@ -2245,8 +2351,8 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con VkBufferImageCopy buffer_image_copy; buffer_image_copy.bufferOffset = alloc_offset; - buffer_image_copy.bufferRowLength = 0; //tigthly packed - buffer_image_copy.bufferImageHeight = 0; //tigthly packed + buffer_image_copy.bufferRowLength = 0; //tightly packed + buffer_image_copy.bufferImageHeight = 0; //tightly packed buffer_image_copy.imageSubresource.aspectMask = texture->read_aspect_mask; buffer_image_copy.imageSubresource.mipLevel = mm_i; @@ -2289,14 +2395,13 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; image_memory_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); } return OK; } Vector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer, bool p_2d) { - uint32_t width, height, depth; uint32_t image_size = get_image_format_required_size(tex->format, tex->width, tex->height, p_2d ? 1 : tex->depth, tex->mipmaps, &width, &height, &depth); @@ -2316,7 +2421,6 @@ Vector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex uint32_t mipmap_offset = 0; for (uint32_t mm_i = 0; mm_i < tex->mipmaps; mm_i++) { - uint32_t image_total = get_image_format_required_size(tex->format, tex->width, tex->height, p_2d ? 1 : tex->depth, mm_i + 1, &width, &height, &depth); uint8_t *write_ptr_mipmap = w + mipmap_offset; @@ -2363,7 +2467,6 @@ Vector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex } Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t p_layer) { - _THREAD_SAFE_METHOD_ Texture *tex = texture_owner.getornull(p_texture); @@ -2384,13 +2487,12 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t //does not need anything fancy, map and read. return _texture_get_data_from_image(tex, tex->image, tex->allocation, p_layer); } else { - //compute total image size uint32_t width, height, depth; uint32_t buffer_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps, &width, &height, &depth); //allocate buffer - VkCommandBuffer command_buffer = frames[frame].setup_command_buffer; + VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; //makes more sense to retrieve Buffer tmp_buffer; _buffer_allocate(&tmp_buffer, buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_CPU_ONLY); @@ -2422,7 +2524,6 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t uint32_t prev_size = 0; uint32_t offset = 0; for (uint32_t i = 0; i < tex->mipmaps; i++) { - VkBufferImageCopy buffer_image_copy; uint32_t image_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, i + 1); @@ -2457,6 +2558,9 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t image_memory_barrier.pNext = nullptr; image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + if (tex->usage_flags & TEXTURE_USAGE_STORAGE_BIT) { + image_memory_barrier.dstAccessMask |= VK_ACCESS_SHADER_WRITE_BIT; + } image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; image_memory_barrier.newLayout = tex->layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -2468,7 +2572,7 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; image_memory_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); } _flush(true); @@ -2479,7 +2583,6 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t Vector<uint8_t> buffer_data; { - buffer_data.resize(buffer_size); uint8_t *w = buffer_data.ptrw(); copymem(w, buffer_mem, buffer_size); @@ -2506,7 +2609,6 @@ bool RenderingDeviceVulkan::texture_is_valid(RID p_texture) { } Error RenderingDeviceVulkan::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) { - _THREAD_SAFE_METHOD_ Texture *src_tex = texture_owner.getornull(p_from_texture); @@ -2557,7 +2659,6 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, VkCommandBuffer command_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; { - //PRE Copy the image { //Source @@ -2604,7 +2705,6 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, //COPY { - VkImageCopy image_copy_region; image_copy_region.srcSubresource.aspectMask = src_tex->read_aspect_mask; image_copy_region.srcSubresource.baseArrayLayer = p_src_layer; @@ -2648,7 +2748,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; image_memory_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); } { //make dst readable @@ -2670,12 +2770,13 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; image_memory_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); } } return OK; } + Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID p_to_texture, bool p_sync_with_draw) { _THREAD_SAFE_METHOD_ @@ -2701,8 +2802,8 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID ERR_FAIL_COND_V_MSG(dst_tex->type != TEXTURE_TYPE_2D, ERR_INVALID_PARAMETER, "Destination texture must be 2D (or a slice of a 3D/Cube texture)."); ERR_FAIL_COND_V_MSG(dst_tex->samples != TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Destination texture must not be multisampled."); - ERR_FAIL_COND_V_MSG(src_tex->format != dst_tex->format, ERR_INVALID_PARAMETER, "Source and Destionation textures must be the same format."); - ERR_FAIL_COND_V_MSG(src_tex->width != dst_tex->width && src_tex->height != dst_tex->height && src_tex->depth != dst_tex->depth, ERR_INVALID_PARAMETER, "Source and Destionation textures must have the same dimensions."); + ERR_FAIL_COND_V_MSG(src_tex->format != dst_tex->format, ERR_INVALID_PARAMETER, "Source and Destination textures must be the same format."); + ERR_FAIL_COND_V_MSG(src_tex->width != dst_tex->width && src_tex->height != dst_tex->height && src_tex->depth != dst_tex->depth, ERR_INVALID_PARAMETER, "Source and Destination textures must have the same dimensions."); ERR_FAIL_COND_V_MSG(src_tex->read_aspect_mask != dst_tex->read_aspect_mask, ERR_INVALID_PARAMETER, "Source and destination texture must be of the same type (color or depth)."); @@ -2710,7 +2811,6 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID VkCommandBuffer command_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; { - //PRE Copy the image { //Source @@ -2731,7 +2831,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer; image_memory_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); } { //Dest VkImageMemoryBarrier image_memory_barrier; @@ -2757,7 +2857,6 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID //COPY { - VkImageResolve image_copy_region; image_copy_region.srcSubresource.aspectMask = src_tex->read_aspect_mask; image_copy_region.srcSubresource.baseArrayLayer = src_tex->base_layer; @@ -2801,7 +2900,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer; image_memory_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); } { //make dst readable @@ -2823,7 +2922,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID image_memory_barrier.subresourceRange.baseArrayLayer = dst_tex->base_layer; image_memory_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); } } @@ -2831,7 +2930,6 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID } Error RenderingDeviceVulkan::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) { - _THREAD_SAFE_METHOD_ Texture *src_tex = texture_owner.getornull(p_texture); @@ -2856,16 +2954,22 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, VkCommandBuffer command_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; - VkImageLayout layout = src_tex->layout; + VkImageLayout clear_layout = (src_tex->layout == VK_IMAGE_LAYOUT_GENERAL) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + // NOTE: Perhaps the valid stages/accesses for a given onwner should be a property of the owner. (Here and places like _get_buffer_from_owner) + const VkPipelineStageFlags valid_texture_stages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + constexpr VkAccessFlags read_access = VK_ACCESS_SHADER_READ_BIT; + constexpr VkAccessFlags read_write_access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + const VkAccessFlags valid_texture_access = (src_tex->usage_flags & TEXTURE_USAGE_STORAGE_BIT) ? read_write_access : read_access; - if (src_tex->layout != VK_IMAGE_LAYOUT_GENERAL) { //storage may be in general state + { // Barrier from previous access with optional layout change (see clear_layout logic above) VkImageMemoryBarrier image_memory_barrier; image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_memory_barrier.pNext = nullptr; - image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.srcAccessMask = valid_texture_access; image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; image_memory_barrier.oldLayout = src_tex->layout; - image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + image_memory_barrier.newLayout = clear_layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -2876,8 +2980,7 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer + p_base_layer; image_memory_barrier.subresourceRange.layerCount = p_layers; - layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + vkCmdPipelineBarrier(command_buffer, valid_texture_stages, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); } VkClearColorValue clear_color; @@ -2893,16 +2996,15 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, range.baseMipLevel = src_tex->base_mipmap + p_base_mipmap; range.levelCount = p_mipmaps; - vkCmdClearColorImage(command_buffer, src_tex->image, layout, &clear_color, 1, &range); - - if (src_tex->layout != VK_IMAGE_LAYOUT_GENERAL) { //storage may be in general state + vkCmdClearColorImage(command_buffer, src_tex->image, clear_layout, &clear_color, 1, &range); + { // Barrier to post clear accesses (changing back the layout if needed) VkImageMemoryBarrier image_memory_barrier; image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_memory_barrier.pNext = nullptr; image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + image_memory_barrier.dstAccessMask = valid_texture_access; + image_memory_barrier.oldLayout = clear_layout; image_memory_barrier.newLayout = src_tex->layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -2914,7 +3016,7 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer + p_base_layer; image_memory_barrier.subresourceRange.layerCount = p_layers; - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, valid_texture_stages, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); } return OK; @@ -2964,35 +3066,49 @@ bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_f /********************/ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, int *r_color_attachment_count) { - Vector<VkAttachmentDescription> attachments; Vector<VkAttachmentReference> color_references; Vector<VkAttachmentReference> depth_stencil_references; Vector<VkAttachmentReference> resolve_references; - for (int i = 0; i < p_format.size(); i++) { + // Set up a dependencies from/to external equivalent to the default (implicit) one, and then amend them + const VkPipelineStageFlags default_access_mask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; // From Section 7.1 of Vulkan API Spec v1.1.148 - VkAttachmentDescription description; + VkPipelineStageFlags reading_stages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT; + VkSubpassDependency dependencies[2] = { { VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, default_access_mask, 0 }, + { 0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, default_access_mask, 0, 0 } }; + VkSubpassDependency &dependency_from_external = dependencies[0]; + VkSubpassDependency &dependency_to_external = dependencies[1]; - description.flags = 0; + for (int i = 0; i < p_format.size(); i++) { ERR_FAIL_INDEX_V(p_format[i].format, DATA_FORMAT_MAX, VK_NULL_HANDLE); - description.format = vulkan_formats[p_format[i].format]; ERR_FAIL_INDEX_V(p_format[i].samples, TEXTURE_SAMPLES_MAX, VK_NULL_HANDLE); + ERR_FAIL_COND_V_MSG(!(p_format[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)), + VK_NULL_HANDLE, "Texture format for index (" + itos(i) + ") requires an attachment (depth, stencil or resolve) bit set."); + + VkAttachmentDescription description = {}; + description.flags = 0; + description.format = vulkan_formats[p_format[i].format]; description.samples = rasterization_sample_count[p_format[i].samples]; - //anything below does not really matter, as vulkan just ignores it when creating a pipeline - ERR_FAIL_COND_V_MSG(!(p_format[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)), VK_NULL_HANDLE, - "Texture format for index (" + itos(i) + ") requires an attachment (depth, stencil or resolve) bit set."); bool is_depth_stencil = p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; bool is_sampled = p_format[i].usage_flags & TEXTURE_USAGE_SAMPLING_BIT; bool is_storage = p_format[i].usage_flags & TEXTURE_USAGE_STORAGE_BIT; + // For each UNDEFINED, assume the prior use was a *read*, as we'd be discarding the output of a write + // Also, each UNDEFINED will do an immediate layout transition (write), s.t. we must ensure execution syncronization vs. + // the read. If this is a performance issue, one could track the actual last accessor of each resource, adding only that + // stage switch (is_depth_stencil ? p_initial_depth_action : p_initial_color_action) { - case INITIAL_ACTION_CLEAR: { description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + dependency_from_external.srcStageMask |= reading_stages; } break; case INITIAL_ACTION_KEEP: { if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { @@ -3003,10 +3119,12 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + dependency_from_external.srcStageMask |= reading_stages; } else { description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + dependency_from_external.srcStageMask |= reading_stages; } } break; case INITIAL_ACTION_DROP: { @@ -3018,10 +3136,12 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + dependency_from_external.srcStageMask |= reading_stages; } else { description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + dependency_from_external.srcStageMask |= reading_stages; } } break; case INITIAL_ACTION_CONTINUE: { @@ -3037,6 +3157,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + dependency_from_external.srcStageMask |= reading_stages; } } break; default: { @@ -3046,20 +3167,21 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF switch (is_depth_stencil ? p_final_depth_action : p_final_color_action) { case FINAL_ACTION_READ: { - if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, false); } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, true); } else { description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + // TODO: What does this mean about the next usage (and thus appropriate dependency masks } } break; case FINAL_ACTION_DISCARD: { @@ -3068,7 +3190,6 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); @@ -3084,7 +3205,6 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; description.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; description.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; @@ -3114,9 +3234,24 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF } else if (p_format[i].usage_flags & TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT) { reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; resolve_references.push_back(reference); + // if resolves are done, we need to ensure the copy is safe + dependency_to_external.dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; + dependency_to_external.dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT; } else { ERR_FAIL_V_MSG(VK_NULL_HANDLE, "Texture index " + itos(i) + " is neither color, depth stencil or resolve so it can't be used as attachment."); } + + // NOTE: Big Mallet Approach -- any layout transition causes a full barrier + if (reference.layout != description.initialLayout) { + // NOTE: this should be smarter based on the textures knowledge of it's previous role + dependency_from_external.srcStageMask |= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + dependency_from_external.srcAccessMask |= VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; + } + if (reference.layout != description.finalLayout) { + // NOTE: this should be smarter based on the textures knowledge of it's subsequent role + dependency_to_external.dstStageMask |= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + dependency_to_external.dstAccessMask |= VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; + } } ERR_FAIL_COND_V_MSG(depth_stencil_references.size() > 1, VK_NULL_HANDLE, @@ -3145,8 +3280,8 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF render_pass_create_info.pAttachments = attachments.ptr(); render_pass_create_info.subpassCount = 1; render_pass_create_info.pSubpasses = &subpass; - render_pass_create_info.dependencyCount = 0; - render_pass_create_info.pDependencies = nullptr; + render_pass_create_info.dependencyCount = 2; + render_pass_create_info.pDependencies = dependencies; VkRenderPass render_pass; VkResult res = vkCreateRenderPass(device, &render_pass_create_info, nullptr, &render_pass); @@ -3159,7 +3294,6 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF } RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create(const Vector<AttachmentFormat> &p_format) { - _THREAD_SAFE_METHOD_ FramebufferFormatKey key; @@ -3172,7 +3306,7 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c } int color_references; - VkRenderPass render_pass = _render_pass_create(p_format, INITIAL_ACTION_CLEAR, FINAL_ACTION_DISCARD, INITIAL_ACTION_CLEAR, FINAL_ACTION_DISCARD, &color_references); //actions don't matter for this use case + VkRenderPass render_pass = _render_pass_create(p_format, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, &color_references); //actions don't matter for this use case if (render_pass == VK_NULL_HANDLE) { //was likely invalid return INVALID_ID; @@ -3189,6 +3323,63 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c return id; } +RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create_empty(const Size2i &p_size) { + ERR_FAIL_COND_V(p_size.width <= 0 || p_size.height <= 0, INVALID_FORMAT_ID); + + FramebufferFormatKey key; + key.empty_size = p_size; + + const Map<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key); + if (E) { + //exists, return + return E->get(); + } + + VkSubpassDescription subpass; + subpass.flags = 0; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = 0; //unsupported for now + subpass.pInputAttachments = nullptr; + subpass.colorAttachmentCount = 0; + subpass.pColorAttachments = nullptr; + subpass.pDepthStencilAttachment = nullptr; + subpass.pResolveAttachments = nullptr; + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = nullptr; + + VkRenderPassCreateInfo render_pass_create_info; + render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + render_pass_create_info.pNext = nullptr; + render_pass_create_info.flags = 0; + render_pass_create_info.attachmentCount = 0; + render_pass_create_info.pAttachments = nullptr; + render_pass_create_info.subpassCount = 1; + render_pass_create_info.pSubpasses = &subpass; + render_pass_create_info.dependencyCount = 0; + render_pass_create_info.pDependencies = nullptr; + + VkRenderPass render_pass; + VkResult res = vkCreateRenderPass(device, &render_pass_create_info, nullptr, &render_pass); + + ERR_FAIL_COND_V_MSG(res, VK_NULL_HANDLE, "vkCreateRenderPass for empty fb failed with error " + itos(res) + "."); + + if (render_pass == VK_NULL_HANDLE) { //was likely invalid + return INVALID_ID; + } + + FramebufferFormatID id = FramebufferFormatID(framebuffer_format_cache.size()) | (FramebufferFormatID(ID_TYPE_FRAMEBUFFER_FORMAT) << FramebufferFormatID(ID_BASE_SHIFT)); + + E = framebuffer_format_cache.insert(key, id); + + FramebufferFormat fb_format; + fb_format.E = E; + fb_format.color_attachments = 0; + fb_format.render_pass = render_pass; + fb_format.samples = TEXTURE_SAMPLES_1; + framebuffer_formats[id] = fb_format; + return id; +} + RenderingDevice::TextureSamples RenderingDeviceVulkan::framebuffer_format_get_texture_samples(FramebufferFormatID p_format) { Map<FramebufferFormatID, FramebufferFormat>::Element *E = framebuffer_formats.find(p_format); ERR_FAIL_COND_V(!E, TEXTURE_SAMPLES_1); @@ -3200,8 +3391,17 @@ RenderingDevice::TextureSamples RenderingDeviceVulkan::framebuffer_format_get_te /**** RENDER TARGET ****/ /***********************/ -RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check) { +RID RenderingDeviceVulkan::framebuffer_create_empty(const Size2i &p_size, FramebufferFormatID p_format_check) { + _THREAD_SAFE_METHOD_ + Framebuffer framebuffer; + framebuffer.format_id = framebuffer_format_create_empty(p_size); + ERR_FAIL_COND_V(p_format_check != INVALID_FORMAT_ID && framebuffer.format_id != p_format_check, RID()); + framebuffer.size = p_size; + + return framebuffer_owner.make_rid(framebuffer); +} +RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check) { _THREAD_SAFE_METHOD_ Vector<AttachmentFormat> attachments; @@ -3249,7 +3449,6 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac } RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_get_format(RID p_framebuffer) { - _THREAD_SAFE_METHOD_ Framebuffer *framebuffer = framebuffer_owner.getornull(p_framebuffer); @@ -3263,7 +3462,6 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_get_form /*****************/ RID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) { - _THREAD_SAFE_METHOD_ VkSamplerCreateInfo sampler_create_info; @@ -3308,14 +3506,21 @@ RID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) { /**** VERTEX ARRAY ****/ /**********************/ -RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data) { - +RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data, bool p_use_as_storage) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID()); + ERR_FAIL_COND_V_MSG(draw_list != nullptr && p_data.size(), RID(), + "Creating buffers with data is forbidden during creation of a draw list"); + ERR_FAIL_COND_V_MSG(compute_list != nullptr && p_data.size(), RID(), + "Creating buffers with data is forbidden during creation of a draw list"); + uint32_t usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + if (p_use_as_storage) { + usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + } Buffer buffer; - _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + _buffer_allocate(&buffer, p_size_bytes, usage, VMA_MEMORY_USAGE_GPU_ONLY); if (p_data.size()) { uint64_t data_size = p_data.size(); const uint8_t *r = p_data.ptr(); @@ -3328,7 +3533,6 @@ RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Vec // Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(const Vector<VertexAttribute> &p_vertex_formats) { - _THREAD_SAFE_METHOD_ VertexDescriptionKey key; @@ -3350,7 +3554,7 @@ RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(cons ERR_FAIL_COND_V(used_locations.has(p_vertex_formats[i].location), INVALID_ID); ERR_FAIL_COND_V_MSG(get_format_vertex_size(p_vertex_formats[i].format) == 0, INVALID_ID, - "Data format for attachment (" + itos(i) + ") is not valid for a vertex array."); + "Data format for attachment (" + itos(i) + "), '" + named_formats[p_vertex_formats[i].format] + "', is not valid for a vertex array."); vdcache.bindings[i].binding = i; vdcache.bindings[i].stride = p_vertex_formats[i].stride; @@ -3380,7 +3584,6 @@ RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(cons } RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers) { - _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID()); @@ -3437,8 +3640,11 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo } RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBufferFormat p_format, const Vector<uint8_t> &p_data, bool p_use_restart_indices) { - _THREAD_SAFE_METHOD_ + ERR_FAIL_COND_V_MSG(draw_list != nullptr && p_data.size(), RID(), + "Creating buffers with data is forbidden during creation of a draw list"); + ERR_FAIL_COND_V_MSG(compute_list != nullptr && p_data.size(), RID(), + "Creating buffers with data is forbidden during creation of a draw list"); ERR_FAIL_COND_V(p_index_count == 0, RID()); @@ -3457,7 +3663,7 @@ RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBuff const uint16_t *index16 = (const uint16_t *)r; for (uint32_t i = 0; i < p_index_count; i++) { if (p_use_restart_indices && index16[i] == 0xFFFF) { - continue; //restart index, ingnore + continue; //restart index, ignore } index_buffer.max_index = MAX(index16[i], index_buffer.max_index); } @@ -3465,7 +3671,7 @@ RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBuff const uint32_t *index32 = (const uint32_t *)r; for (uint32_t i = 0; i < p_index_count; i++) { if (p_use_restart_indices && index32[i] == 0xFFFFFFFF) { - continue; //restart index, ingnore + continue; //restart index, ignore } index_buffer.max_index = MAX(index32[i], index_buffer.max_index); } @@ -3487,7 +3693,6 @@ RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBuff } RID RenderingDeviceVulkan::index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count) { - _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!index_buffer_owner.owns(p_index_buffer), RID()); @@ -3554,13 +3759,11 @@ String RenderingDeviceVulkan::_shader_uniform_debug(RID p_shader, int p_set) { } #if 0 bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLayoutBinding> > &bindings, Vector<Vector<UniformInfo> > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, Shader::PushConstant &push_constant, String *r_error) { - VkDescriptorSetLayoutBinding layout_binding; UniformInfo info; switch (reflection.getType()->getBasicType()) { case glslang::EbtSampler: { - //print_line("DEBUG: IsSampler"); if (reflection.getType()->getSampler().dim == glslang::EsdBuffer) { //texture buffers @@ -3578,7 +3781,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa //print_line("DEBUG: SAMPLER: texel buffer"); } else { if (r_error) { - *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported buffer type."; + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' is of unsupported buffer type."; } return false; } @@ -3601,7 +3804,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa } else { //print_line("DEBUG: sampler unknown"); if (r_error) { - *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported sampler type."; + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' is of unsupported sampler type."; } return false; } @@ -3626,7 +3829,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa if (reflection.getType()->getQualifier().layoutPushConstant) { uint32_t len = reflection.size; if (push_constant.push_constant_size != 0 && push_constant.push_constant_size != len) { - *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' push constants for different stages should all be the same size."; + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' push constants for different stages should all be the same size."; return false; } push_constant.push_constant_size = len; @@ -3642,7 +3845,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa //print_line("DEBUG: Storage buffer"); } else { if (r_error) { - *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported block type: (" + itos(reflection.getType()->getQualifier().storage) + ")."; + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' is of unsupported block type: (" + itos(reflection.getType()->getQualifier().storage) + ")."; } return false; } @@ -3658,20 +3861,17 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa } break; /*case glslang::EbtReference: { - } break;*/ /*case glslang::EbtAtomicUint: { - } break;*/ default: { - if (reflection.getType()->getQualifier().hasOffset() || reflection.name.find(".") != std::string::npos) { //member of uniform block? return true; } if (r_error) { - *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' unsupported uniform type."; + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' unsupported uniform type."; } return false; } @@ -3679,7 +3879,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa if (!reflection.getType()->getQualifier().hasBinding()) { if (r_error) { - *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' lacks a binding number."; + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' lacks a binding number."; } return false; } @@ -3688,14 +3888,14 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa if (set >= MAX_UNIFORM_SETS) { if (r_error) { - *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ")."; + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ")."; } return false; } if (set >= limits.maxBoundDescriptorSets) { if (r_error) { - *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ")."; + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ")."; } return false; } @@ -3709,7 +3909,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa //already exists, verify that it's the same type if (bindings[set][i].descriptorType != layout_binding.descriptorType) { if (r_error) { - *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform type."; + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform type."; } return false; } @@ -3717,7 +3917,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa //also, verify that it's the same size if (bindings[set][i].descriptorCount != layout_binding.descriptorCount || uniform_infos[set][i].length != info.length) { if (r_error) { - *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform size."; + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform size."; } return false; } @@ -3751,7 +3951,6 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa #endif RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages) { - //descriptor layouts Vector<Vector<VkDescriptorSetLayoutBinding>> set_bindings; Vector<Vector<UniformInfo>> uniform_info; @@ -3768,7 +3967,6 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages bool is_compute = false; for (int i = 0; i < p_stages.size(); i++) { - if (p_stages[i].shader_stage == SHADER_STAGE_COMPUTE) { is_compute = true; ERR_FAIL_COND_V_MSG(p_stages.size() != 1, RID(), @@ -3792,7 +3990,6 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages uint32_t stage = p_stages[i].shader_stage; if (binding_count > 0) { - //Parse bindings Vector<SpvReflectDescriptorBinding *> bindings; @@ -3864,6 +4061,10 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; info.type = UNIFORM_TYPE_INPUT_ATTACHMENT; } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: { + ERR_PRINT("Acceleration structure not supported."); + continue; + } break; } if (need_array_dimensions) { @@ -3943,7 +4144,6 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages } if (stage == SHADER_STAGE_VERTEX) { - uint32_t iv_count = 0; result = spvReflectEnumerateInputVariables(&module, &iv_count, nullptr); ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), @@ -3966,7 +4166,6 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages } if (stage == SHADER_STAGE_FRAGMENT) { - uint32_t ov_count = 0; result = spvReflectEnumerateOutputVariables(&module, &ov_count, nullptr); ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), @@ -4079,9 +4278,7 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages //proceed to create descriptor sets if (success) { - for (int i = 0; i < set_bindings.size(); i++) { - //empty ones are fine if they were not used according to spec (binding count will be 0) VkDescriptorSetLayoutCreateInfo layout_create_info; layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; @@ -4140,8 +4337,10 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages } pipeline_layout_create_info.pSetLayouts = layouts.ptr(); + // Needs to be declared in this outer scope, otherwise it may not outlive its assignment + // to pipeline_layout_create_info. + VkPushConstantRange push_constant_range; if (push_constant.push_constant_size) { - VkPushConstantRange push_constant_range; push_constant_range.stageFlags = push_constant.push_constants_vk_stage; push_constant_range.offset = 0; push_constant_range.size = push_constant.push_constant_size; @@ -4190,10 +4389,13 @@ uint32_t RenderingDeviceVulkan::shader_get_vertex_input_attribute_mask(RID p_sha /******************/ RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data) { - _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID()); + ERR_FAIL_COND_V_MSG(draw_list != nullptr && p_data.size(), RID(), + "Creating buffers with data is forbidden during creation of a draw list"); + ERR_FAIL_COND_V_MSG(compute_list != nullptr && p_data.size(), RID(), + "Creating buffers with data is forbidden during creation of a draw list"); Buffer buffer; Error err = _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); @@ -4207,14 +4409,22 @@ RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Ve return uniform_buffer_owner.make_rid(buffer); } -RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data) { - +RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data, uint32_t p_usage) { _THREAD_SAFE_METHOD_ + ERR_FAIL_COND_V_MSG(draw_list != nullptr && p_data.size(), RID(), + "Creating buffers with data is forbidden during creation of a draw list"); + ERR_FAIL_COND_V_MSG(compute_list != nullptr && p_data.size(), RID(), + "Creating buffers with data is forbidden during creation of a draw list"); ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID()); Buffer buffer; - Error err = _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + buffer.usage = p_usage; + uint32_t flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + if (p_usage & STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT) { + flags |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; + } + Error err = _buffer_allocate(&buffer, p_size_bytes, flags, VMA_MEMORY_USAGE_GPU_ONLY); ERR_FAIL_COND_V(err != OK, RID()); if (p_data.size()) { @@ -4227,8 +4437,11 @@ RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Ve } RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data) { - _THREAD_SAFE_METHOD_ + ERR_FAIL_COND_V_MSG(draw_list != nullptr && p_data.size(), RID(), + "Creating buffers with data is forbidden during creation of a draw list"); + ERR_FAIL_COND_V_MSG(compute_list != nullptr && p_data.size(), RID(), + "Creating buffers with data is forbidden during creation of a draw list"); uint32_t element_size = get_format_vertex_size(p_format); ERR_FAIL_COND_V_MSG(element_size == 0, RID(), "Format requested is not supported for texture buffers"); @@ -4377,14 +4590,13 @@ void RenderingDeviceVulkan::_descriptor_pool_free(const DescriptorPoolKey &p_key vkDestroyDescriptorPool(device, p_pool->pool, nullptr); descriptor_pools[p_key].erase(p_pool); memdelete(p_pool); - if (descriptor_pools[p_key].empty()) { + if (descriptor_pools[p_key].is_empty()) { descriptor_pools.erase(p_key); } } } RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) { - _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(p_uniforms.size() == 0, RID()); @@ -4412,7 +4624,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, List<Vector<VkBufferView>> buffer_views; List<Vector<VkDescriptorImageInfo>> image_infos; //used for verification to make sure a uniform set does not use a framebuffer bound texture - Vector<RID> attachable_textures; + LocalVector<UniformSet::AttachableTexture> attachable_textures; Vector<Texture *> mutable_sampled_textures; Vector<Texture *> mutable_storage_textures; @@ -4425,21 +4637,27 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, } } ERR_FAIL_COND_V_MSG(uniform_idx == -1, RID(), - "All the shader bindings for the given set must be covered by the uniforms provided."); + "All the shader bindings for the given set must be covered by the uniforms provided. Binding (" + itos(set_uniform.binding) + "), set (" + itos(p_shader_set) + ") was not provided."); const Uniform &uniform = uniforms[uniform_idx]; - ERR_FAIL_COND_V_MSG(uniform.type != set_uniform.type, RID(), - "Mismatch uniform type for binding (" + itos(set_uniform.binding) + "). Expected '" + shader_uniform_names[set_uniform.type] + "', supplied: '" + shader_uniform_names[uniform.type] + "'."); + ERR_FAIL_COND_V_MSG(uniform.uniform_type != set_uniform.type, RID(), + "Mismatch uniform type for binding (" + itos(set_uniform.binding) + "), set (" + itos(p_shader_set) + "). Expected '" + shader_uniform_names[set_uniform.type] + "', supplied: '" + shader_uniform_names[uniform.uniform_type] + "'."); VkWriteDescriptorSet write; //common header write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write.pNext = nullptr; write.dstSet = VK_NULL_HANDLE; //will assign afterwards when everything is valid write.dstBinding = set_uniform.binding; + write.dstArrayElement = 0; + write.descriptorCount = 0; + write.descriptorType = VK_DESCRIPTOR_TYPE_MAX_ENUM; //Invalid value. + write.pImageInfo = nullptr; + write.pBufferInfo = nullptr; + write.pTexelBufferView = nullptr; uint32_t type_size = 1; - switch (uniform.type) { + switch (uniform.uniform_type) { case UNIFORM_TYPE_SAMPLER: { if (uniform.ids.size() != set_uniform.length) { if (set_uniform.length > 1) { @@ -4474,7 +4692,6 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, } break; case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: { - if (uniform.ids.size() != set_uniform.length * 2) { if (set_uniform.length > 1) { ERR_FAIL_V_MSG(RID(), "SamplerTexture (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler&texture elements, so it should provided twice the amount of IDs (sampler,texture pairs) to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); @@ -4500,7 +4717,10 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, img_info.imageView = texture->view; if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)) { - attachable_textures.push_back(texture->owner.is_valid() ? texture->owner : uniform.ids[j + 1]); + UniformSet::AttachableTexture attachable_texture; + attachable_texture.bind = set_uniform.binding; + attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.ids[j + 1]; + attachable_textures.push_back(attachable_texture); } if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) { @@ -4528,7 +4748,6 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, } break; case UNIFORM_TYPE_TEXTURE: { - if (uniform.ids.size() != set_uniform.length) { if (set_uniform.length > 1) { ERR_FAIL_V_MSG(RID(), "Texture (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); @@ -4551,7 +4770,10 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, img_info.imageView = texture->view; if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)) { - attachable_textures.push_back(texture->owner.is_valid() ? texture->owner : uniform.ids[j]); + UniformSet::AttachableTexture attachable_texture; + attachable_texture.bind = set_uniform.binding; + attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.ids[j]; + attachable_textures.push_back(attachable_texture); } if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) { @@ -4579,7 +4801,6 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, type_size = uniform.ids.size(); } break; case UNIFORM_TYPE_IMAGE: { - if (uniform.ids.size() != set_uniform.length) { if (set_uniform.length > 1) { ERR_FAIL_V_MSG(RID(), "Image (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); @@ -4659,7 +4880,6 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, } break; case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER: { - if (uniform.ids.size() != set_uniform.length * 2) { if (set_uniform.length > 1) { ERR_FAIL_V_MSG(RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler buffer elements, so it should provided twice the amount of IDs (sampler,buffer pairs) to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); @@ -4726,7 +4946,15 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, ERR_FAIL_COND_V_MSG(uniform.ids.size() != 1, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.ids.size()) + " provided)."); - Buffer *buffer = storage_buffer_owner.getornull(uniform.ids[0]); + Buffer *buffer = nullptr; + + if (storage_buffer_owner.owns(uniform.ids[0])) { + buffer = storage_buffer_owner.getornull(uniform.ids[0]); + } else if (vertex_buffer_owner.owns(uniform.ids[0])) { + buffer = vertex_buffer_owner.getornull(uniform.ids[0]); + + ERR_FAIL_COND_V_MSG(!(buffer->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), RID(), "Vertex buffer supplied (binding: " + itos(uniform.binding) + ") was not created with storage flag."); + } ERR_FAIL_COND_V_MSG(!buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid."); //if 0, then its sized on link time @@ -4741,7 +4969,6 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, write.pTexelBufferView = nullptr; } break; case UNIFORM_TYPE_INPUT_ATTACHMENT: { - } break; default: { } @@ -4818,44 +5045,27 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint ERR_FAIL_COND_V_MSG(draw_list && p_sync_with_draw, ERR_INVALID_PARAMETER, "Updating buffers in 'sync to draw' mode is forbidden during creation of a draw list"); + ERR_FAIL_COND_V_MSG(compute_list && p_sync_with_draw, ERR_INVALID_PARAMETER, + "Updating buffers in 'sync to draw' mode is forbidden during creation of a compute list"); - VkPipelineStageFlags dst_stage_mask; - VkAccessFlags dst_access; + // Protect subsequent updates... + VkPipelineStageFlags dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT; + VkAccessFlags dst_access = VK_ACCESS_TRANSFER_WRITE_BIT; - Buffer *buffer = nullptr; - if (vertex_buffer_owner.owns(p_buffer)) { - dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; - dst_access = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; - buffer = vertex_buffer_owner.getornull(p_buffer); - } else if (index_buffer_owner.owns(p_buffer)) { - dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; - dst_access = VK_ACCESS_INDEX_READ_BIT; - buffer = index_buffer_owner.getornull(p_buffer); - } else if (uniform_buffer_owner.owns(p_buffer)) { - dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - dst_access = VK_ACCESS_UNIFORM_READ_BIT; - buffer = uniform_buffer_owner.getornull(p_buffer); - } else if (texture_buffer_owner.owns(p_buffer)) { - dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - dst_access = VK_ACCESS_SHADER_READ_BIT; - buffer = &texture_buffer_owner.getornull(p_buffer)->buffer; - } else if (storage_buffer_owner.owns(p_buffer)) { - dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - dst_access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; - buffer = storage_buffer_owner.getornull(p_buffer); - } else { + Buffer *buffer = _get_buffer_from_owner(p_buffer, dst_stage_mask, dst_access); + if (!buffer) { ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type."); } ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER, "Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end."); + _buffer_memory_barrier(buffer->buffer, p_offset, p_size, dst_stage_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_access, VK_ACCESS_TRANSFER_WRITE_BIT, p_sync_with_draw); Error err = _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, p_sync_with_draw); if (err) { return err; } - _buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, p_sync_with_draw); #ifdef FORCE_FULL_BARRIER _full_barrier(p_sync_with_draw); #else @@ -4865,23 +5075,22 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint } Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { - _THREAD_SAFE_METHOD_ - Buffer *buffer = nullptr; - if (vertex_buffer_owner.owns(p_buffer)) { - buffer = vertex_buffer_owner.getornull(p_buffer); - } else if (index_buffer_owner.owns(p_buffer)) { - buffer = index_buffer_owner.getornull(p_buffer); - } else if (texture_buffer_owner.owns(p_buffer)) { - buffer = &texture_buffer_owner.getornull(p_buffer)->buffer; - } else if (storage_buffer_owner.owns(p_buffer)) { - buffer = storage_buffer_owner.getornull(p_buffer); - } else { + // It could be this buffer was just created + VkPipelineShaderStageCreateFlags src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT; + VkAccessFlags src_access_mask = VK_ACCESS_TRANSFER_WRITE_BIT; + // Get the vulkan buffer and the potential stage/access possible + Buffer *buffer = _get_buffer_from_owner(p_buffer, src_stage_mask, src_access_mask); + if (!buffer) { ERR_FAIL_V_MSG(Vector<uint8_t>(), "Buffer is either invalid or this type of buffer can't be retrieved. Only Index and Vertex buffers allow retrieving."); } + // Make sure no one is using the buffer -- the "false" gets us to the same command buffer as below. + _buffer_memory_barrier(buffer->buffer, 0, buffer->size, src_stage_mask, src_access_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, false); + VkCommandBuffer command_buffer = frames[frame].setup_command_buffer; + Buffer tmp_buffer; _buffer_allocate(&tmp_buffer, buffer->size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_CPU_ONLY); VkBufferCopy region; @@ -4898,7 +5107,6 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { Vector<uint8_t> buffer_data; { - buffer_data.resize(buffer->size); uint8_t *w = buffer_data.ptrw(); copymem(w, buffer_mem, buffer->size); @@ -4916,7 +5124,6 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { /*************************/ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags) { - _THREAD_SAFE_METHOD_ //needs a shader @@ -5003,13 +5210,13 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma input_assembly_create_info.topology = topology_list[p_render_primitive]; input_assembly_create_info.primitiveRestartEnable = (p_render_primitive == RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX); - //tesselation - VkPipelineTessellationStateCreateInfo tesselation_create_info; - tesselation_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; - tesselation_create_info.pNext = nullptr; - tesselation_create_info.flags = 0; + //tessellation + VkPipelineTessellationStateCreateInfo tessellation_create_info; + tessellation_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + tessellation_create_info.pNext = nullptr; + tessellation_create_info.flags = 0; ERR_FAIL_COND_V(p_rasterization_state.patch_control_points < 1 || p_rasterization_state.patch_control_points > limits.maxTessellationPatchSize, RID()); - tesselation_create_info.patchControlPoints = p_rasterization_state.patch_control_points; + tessellation_create_info.patchControlPoints = p_rasterization_state.patch_control_points; VkPipelineViewportStateCreateInfo viewport_state_create_info; viewport_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; @@ -5221,7 +5428,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma graphics_pipeline_create_info.pStages = shader->pipeline_stages.ptr(); graphics_pipeline_create_info.pVertexInputState = &pipeline_vertex_input_state_create_info; graphics_pipeline_create_info.pInputAssemblyState = &input_assembly_create_info; - graphics_pipeline_create_info.pTessellationState = &tesselation_create_info; + graphics_pipeline_create_info.pTessellationState = &tessellation_create_info; graphics_pipeline_create_info.pViewportState = &viewport_state_create_info; graphics_pipeline_create_info.pRasterizationState = &rasterization_state_create_info; graphics_pipeline_create_info.pMultisampleState = &multisample_state_create_info; @@ -5326,7 +5533,6 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader) { } bool RenderingDeviceVulkan::compute_pipeline_is_valid(RID p_pipeline) { - return compute_pipeline_owner.owns(p_pipeline); } @@ -5339,14 +5545,15 @@ int RenderingDeviceVulkan::screen_get_width(DisplayServer::WindowID p_screen) co ERR_FAIL_COND_V_MSG(local_device.is_valid(), -1, "Local devices have no screen"); return context->window_get_width(p_screen); } + int RenderingDeviceVulkan::screen_get_height(DisplayServer::WindowID p_screen) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V_MSG(local_device.is_valid(), -1, "Local devices have no screen"); return context->window_get_height(p_screen); } -RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::screen_get_framebuffer_format() const { +RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::screen_get_framebuffer_format() const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V_MSG(local_device.is_valid(), INVALID_ID, "Local devices have no screen"); @@ -5376,7 +5583,6 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::screen_get_framebuff /*******************/ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(DisplayServer::WindowID p_screen, const Color &p_clear_color) { - _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V_MSG(local_device.is_valid(), INVALID_ID, "Local devices have no screen"); @@ -5436,11 +5642,10 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(Di vkCmdSetScissor(command_buffer, 0, 1, &scissor); - return ID_TYPE_DRAW_LIST; + return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT; } Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass) { - Framebuffer::VersionKey vk; vk.initial_color_action = p_initial_color_action; vk.final_color_action = p_final_color_action; @@ -5484,8 +5689,7 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu return OK; } -Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents) { - +Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents, const Vector<RID> &p_storage_textures) { VkRenderPassBeginInfo render_pass_begin; render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; render_pass_begin.pNext = nullptr; @@ -5530,6 +5734,37 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff render_pass_begin.clearValueCount = clear_values.size(); render_pass_begin.pClearValues = clear_values.ptr(); + for (int i = 0; i < p_storage_textures.size(); i++) { + Texture *texture = texture_owner.getornull(p_storage_textures[i]); + ERR_CONTINUE_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), "Supplied storage texture " + itos(i) + " for draw list is not set to be used for storage."); + + if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) { + //must change layout to general + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = nullptr; + image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.oldLayout = texture->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = texture->image; + image_memory_barrier.subresourceRange.aspectMask = texture->read_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = texture->base_mipmap; + image_memory_barrier.subresourceRange.levelCount = texture->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = texture->base_layer; + image_memory_barrier.subresourceRange.layerCount = texture->layers; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + + texture->layout = VK_IMAGE_LAYOUT_GENERAL; + + draw_list_storage_textures.push_back(p_storage_textures[i]); + } + } + vkCmdBeginRenderPass(command_buffer, &render_pass_begin, subpass_contents); //mark textures as bound @@ -5551,7 +5786,8 @@ void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list, int color_index = 0; for (int i = 0; i < framebuffer->texture_ids.size(); i++) { Texture *texture = texture_owner.getornull(framebuffer->texture_ids[i]); - VkClearAttachment clear_at; + VkClearAttachment clear_at = {}; + if (p_clear_color && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { ERR_FAIL_INDEX(color_index, p_clear_colors.size()); //a bug Color clear_color = p_clear_colors[color_index]; @@ -5562,7 +5798,6 @@ void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list, clear_at.colorAttachment = color_index++; clear_at.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } else if (p_clear_depth && texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - clear_at.clearValue.depthStencil.depth = p_depth; clear_at.clearValue.depthStencil.stencil = p_stencil; clear_at.colorAttachment = 0; @@ -5587,8 +5822,7 @@ void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list, vkCmdClearAttachments(draw_list->command_buffer, clear_attachments.size(), clear_attachments.ptr(), 1, &cr); } -RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, 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) { - +RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, 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) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time."); @@ -5638,7 +5872,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu ERR_FAIL_COND_V(err != OK, INVALID_ID); VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; - err = _draw_list_render_pass_begin(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, viewport_offset, viewport_size, vkframebuffer, render_pass, command_buffer, VK_SUBPASS_CONTENTS_INLINE); + err = _draw_list_render_pass_begin(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, viewport_offset, viewport_size, vkframebuffer, render_pass, command_buffer, VK_SUBPASS_CONTENTS_INLINE, p_storage_textures); if (err != OK) { return INVALID_ID; @@ -5675,11 +5909,10 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu vkCmdSetScissor(command_buffer, 0, 1, &scissor); draw_list->viewport = Rect2i(viewport_offset, viewport_size); - return ID_TYPE_DRAW_LIST; + return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT; } -Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, 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) { - +Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, 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) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(p_splits < 1, ERR_INVALID_DECLARATION); @@ -5726,7 +5959,6 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p uint32_t from = split_draw_list_allocators.size(); split_draw_list_allocators.resize(p_splits); for (uint32_t i = from; i < p_splits; i++) { - VkCommandPoolCreateInfo cmd_pool_info; cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; cmd_pool_info.pNext = nullptr; @@ -5737,7 +5969,6 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p ERR_FAIL_COND_V_MSG(res, ERR_CANT_CREATE, "vkCreateCommandPool failed with error " + itos(res) + "."); for (int j = 0; j < frame_count; j++) { - VkCommandBuffer command_buffer; VkCommandBufferAllocateInfo cmdbuf; @@ -5763,7 +5994,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); VkCommandBuffer frame_command_buffer = frames[frame].draw_command_buffer; - err = _draw_list_render_pass_begin(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, viewport_offset, viewport_size, vkframebuffer, render_pass, frame_command_buffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); + err = _draw_list_render_pass_begin(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, viewport_offset, viewport_size, vkframebuffer, render_pass, frame_command_buffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS, p_storage_textures); if (err != OK) { return ERR_CANT_CREATE; @@ -5774,9 +6005,8 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p draw_list_split = true; for (uint32_t i = 0; i < p_splits; i++) { - //take a command buffer and initialize it - VkCommandBuffer command_buffer = split_draw_list_allocators[p_splits].command_buffers[frame]; + VkCommandBuffer command_buffer = split_draw_list_allocators[i].command_buffers[frame]; VkCommandBufferInheritanceInfo inheritance_info; inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; @@ -5834,7 +6064,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p scissor.extent.height = viewport_size.height; vkCmdSetScissor(command_buffer, 0, 1, &scissor); - r_split_ids[i] = (DrawListID(1) << DrawListID(ID_TYPE_SPLIT_DRAW_LIST)) + i; + r_split_ids[i] = (int64_t(ID_TYPE_SPLIT_DRAW_LIST) << ID_BASE_SHIFT) + i; draw_list[i].viewport = Rect2i(viewport_offset, viewport_size); } @@ -5843,14 +6073,13 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p } RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(DrawListID p_id) { - if (p_id < 0) { return nullptr; } if (!draw_list) { return nullptr; - } else if (p_id == ID_TYPE_DRAW_LIST) { + } else if (p_id == (int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT)) { if (draw_list_split) { return nullptr; } @@ -5873,7 +6102,6 @@ RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(DrawL } void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) { - DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); #ifdef DEBUG_ENABLED @@ -5924,7 +6152,7 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI if (pipeline->push_constant_size) { dl->state.pipeline_push_constant_stages = pipeline->push_constant_stages; #ifdef DEBUG_ENABLED - dl->validation.pipeline_push_constant_suppplied = false; + dl->validation.pipeline_push_constant_supplied = false; #endif } @@ -5944,9 +6172,8 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI } void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) { - #ifdef DEBUG_ENABLED - ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index > MAX_UNIFORM_SETS, + ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index >= MAX_UNIFORM_SETS, "Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(limits.maxBoundDescriptorSets) + ")."); #endif DrawList *dl = _get_draw_list_ptr(p_list); @@ -5971,13 +6198,13 @@ void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_ #ifdef DEBUG_ENABLED { //validate that textures bound are not attached as framebuffer bindings uint32_t attachable_count = uniform_set->attachable_textures.size(); - const RID *attachable_ptr = uniform_set->attachable_textures.ptr(); + const UniformSet::AttachableTexture *attachable_ptr = uniform_set->attachable_textures.ptr(); uint32_t bound_count = draw_list_bound_textures.size(); const RID *bound_ptr = draw_list_bound_textures.ptr(); for (uint32_t i = 0; i < attachable_count; i++) { for (uint32_t j = 0; j < bound_count; j++) { - ERR_FAIL_COND_MSG(attachable_ptr[i] == bound_ptr[j], - "Attempted to use the same texture in framebuffer attachment and a uniform set, this is not allowed."); + ERR_FAIL_COND_MSG(attachable_ptr[i].texture == bound_ptr[j], + "Attempted to use the same texture in framebuffer attachment and a uniform (set: " + itos(p_index) + ", binding: " + itos(attachable_ptr[i].bind) + "), this is not allowed."); } } } @@ -6007,8 +6234,8 @@ void RenderingDeviceVulkan::draw_list_bind_vertex_array(DrawListID p_list, RID p dl->validation.vertex_array_size = vertex_array->vertex_count; vkCmdBindVertexBuffers(dl->command_buffer, 0, vertex_array->buffers.size(), vertex_array->buffers.ptr(), vertex_array->offsets.ptr()); } -void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_index_array) { +void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_index_array) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); #ifdef DEBUG_ENABLED @@ -6033,7 +6260,6 @@ void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_ } void RenderingDeviceVulkan::draw_list_set_line_width(DrawListID p_list, float p_width) { - DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); #ifdef DEBUG_ENABLED @@ -6057,12 +6283,11 @@ void RenderingDeviceVulkan::draw_list_set_push_constant(DrawListID p_list, const #endif vkCmdPushConstants(dl->command_buffer, dl->state.pipeline_layout, dl->state.pipeline_push_constant_stages, 0, p_data_size, p_data); #ifdef DEBUG_ENABLED - dl->validation.pipeline_push_constant_suppplied = true; + dl->validation.pipeline_push_constant_supplied = true; #endif } void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances, uint32_t p_procedural_vertices) { - DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); #ifdef DEBUG_ENABLED @@ -6079,14 +6304,14 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices //make sure format is right ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format != dl->validation.vertex_format, "The vertex format used to create the pipeline does not match the vertex format bound."); - //make sure amount of instances is valid + //make sure number of instances is valid ERR_FAIL_COND_MSG(p_instances > dl->validation.vertex_max_instances_allowed, - "Amount of instances requested (" + itos(p_instances) + " is larger than the maximum amount suported by the bound vertex array (" + itos(dl->validation.vertex_max_instances_allowed) + ")."); + "Number of instances requested (" + itos(p_instances) + " is larger than the maximum number supported by the bound vertex array (" + itos(dl->validation.vertex_max_instances_allowed) + ")."); } if (dl->validation.pipeline_push_constant_size > 0) { //using push constants, check that they were supplied - ERR_FAIL_COND_MSG(!dl->validation.pipeline_push_constant_suppplied, + ERR_FAIL_COND_MSG(!dl->validation.pipeline_push_constant_supplied, "The shader in this pipeline requires a push constant to be set before drawing, but it's not present."); } @@ -6095,13 +6320,11 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices //Bind descriptor sets for (uint32_t i = 0; i < dl->state.set_count; i++) { - if (dl->state.sets[i].pipeline_expected_format == 0) { continue; //nothing expected by this pipeline } #ifdef DEBUG_ENABLED if (dl->state.sets[i].pipeline_expected_format != dl->state.sets[i].uniform_set_format) { - if (dl->state.sets[i].uniform_set_format == 0) { ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline"); } else if (uniform_set_owner.owns(dl->state.sets[i].uniform_set)) { @@ -6120,7 +6343,6 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices } if (p_use_indices) { - #ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(p_procedural_vertices > 0, "Procedural vertices can't be used together with indices."); @@ -6148,7 +6370,6 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices #endif vkCmdDrawIndexed(dl->command_buffer, to_draw, p_instances, dl->validation.index_array_offset, 0, 0); } else { - uint32_t to_draw; if (p_procedural_vertices > 0) { @@ -6158,7 +6379,6 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices #endif to_draw = p_procedural_vertices; } else { - #ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format == INVALID_ID, "Draw command lacks indices, but pipeline format does not use vertices."); @@ -6188,7 +6408,7 @@ void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Re Rect2i rect = p_rect; rect.position += dl->viewport.position; - rect = dl->viewport.clip(rect); + rect = dl->viewport.intersection(rect); if (rect.get_area() == 0) { return; @@ -6201,6 +6421,7 @@ void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Re vkCmdSetScissor(dl->command_buffer, 0, 1, &scissor); } + void RenderingDeviceVulkan::draw_list_disable_scissor(DrawListID p_list) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); @@ -6217,7 +6438,6 @@ void RenderingDeviceVulkan::draw_list_disable_scissor(DrawListID p_list) { } void RenderingDeviceVulkan::draw_list_end() { - _THREAD_SAFE_METHOD_ ERR_FAIL_COND_MSG(!draw_list, "Immediate draw list is already inactive."); @@ -6226,8 +6446,8 @@ void RenderingDeviceVulkan::draw_list_end() { //send all command buffers VkCommandBuffer *command_buffers = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer) * draw_list_count); for (uint32_t i = 0; i < draw_list_count; i++) { - vkEndCommandBuffer(draw_list->command_buffer); - command_buffers[i] = draw_list->command_buffer; + vkEndCommandBuffer(draw_list[i].command_buffer); + command_buffers[i] = draw_list[i].command_buffer; } vkCmdExecuteCommands(frames[frame].draw_command_buffer, draw_list_count, command_buffers); @@ -6255,6 +6475,33 @@ void RenderingDeviceVulkan::draw_list_end() { draw_list_bound_textures.clear(); + for (int i = 0; i < draw_list_storage_textures.size(); i++) { + Texture *texture = texture_owner.getornull(draw_list_storage_textures[i]); + + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = nullptr; + image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.oldLayout = texture->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = texture->image; + image_memory_barrier.subresourceRange.aspectMask = texture->read_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = texture->base_mipmap; + image_memory_barrier.subresourceRange.levelCount = texture->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = texture->base_layer; + image_memory_barrier.subresourceRange.layerCount = texture->layers; + + vkCmdPipelineBarrier(frames[frame].draw_command_buffer, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + + texture->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + + draw_list_storage_textures.clear(); + // To ensure proper synchronization, we must make sure rendering is done before: // * Some buffer is copied // * Another render pass happens (since we may be done @@ -6271,7 +6518,6 @@ void RenderingDeviceVulkan::draw_list_end() { /***********************/ RenderingDevice::ComputeListID RenderingDeviceVulkan::compute_list_begin() { - ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time."); ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time."); @@ -6328,7 +6574,7 @@ void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_l if (pipeline->push_constant_size) { cl->state.pipeline_push_constant_stages = pipeline->push_constant_stages; #ifdef DEBUG_ENABLED - cl->validation.pipeline_push_constant_suppplied = false; + cl->validation.pipeline_push_constant_supplied = false; #endif } @@ -6341,6 +6587,7 @@ void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_l cl->validation.pipeline_push_constant_size = pipeline->push_constant_size; #endif } + void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) { ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); ERR_FAIL_COND(!compute_list); @@ -6348,7 +6595,7 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list, ComputeList *cl = compute_list; #ifdef DEBUG_ENABLED - ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index > MAX_UNIFORM_SETS, + ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index >= MAX_UNIFORM_SETS, "Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(limits.maxBoundDescriptorSets) + ")."); #endif @@ -6373,7 +6620,6 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list, for (uint32_t i = 0; i < textures_to_sampled_count; i++) { if (textures_to_sampled[i]->layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { - VkImageMemoryBarrier image_memory_barrier; image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_memory_barrier.pNext = nullptr; @@ -6391,7 +6637,7 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list, image_memory_barrier.subresourceRange.baseArrayLayer = textures_to_sampled[i]->base_layer; image_memory_barrier.subresourceRange.layerCount = textures_to_sampled[i]->layers; - vkCmdPipelineBarrier(cl->command_buffer, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + vkCmdPipelineBarrier(cl->command_buffer, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); textures_to_sampled[i]->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -6404,7 +6650,6 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list, for (uint32_t i = 0; i < textures_to_storage_count; i++) { if (textures_to_storage[i]->layout != VK_IMAGE_LAYOUT_GENERAL) { - VkImageMemoryBarrier image_memory_barrier; image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_memory_barrier.pNext = nullptr; @@ -6462,9 +6707,10 @@ void RenderingDeviceVulkan::compute_list_set_push_constant(ComputeListID p_list, #endif vkCmdPushConstants(cl->command_buffer, cl->state.pipeline_layout, cl->state.pipeline_push_constant_stages, 0, p_data_size, p_data); #ifdef DEBUG_ENABLED - cl->validation.pipeline_push_constant_suppplied = true; + cl->validation.pipeline_push_constant_supplied = true; #endif } + void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) { ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); ERR_FAIL_COND(!compute_list); @@ -6488,7 +6734,7 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t if (cl->validation.pipeline_push_constant_size > 0) { //using push constants, check that they were supplied - ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_suppplied, + ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_supplied, "The shader in this pipeline requires a push constant to be set before drawing, but it's not present."); } @@ -6497,13 +6743,11 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t //Bind descriptor sets for (uint32_t i = 0; i < cl->state.set_count; i++) { - if (cl->state.sets[i].pipeline_expected_format == 0) { continue; //nothing expected by this pipeline } #ifdef DEBUG_ENABLED if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) { - if (cl->state.sets[i].uniform_set_format == 0) { ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline"); } else if (uniform_set_owner.owns(cl->state.sets[i].uniform_set)) { @@ -6524,6 +6768,62 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t vkCmdDispatch(cl->command_buffer, p_x_groups, p_y_groups, p_z_groups); } +void RenderingDeviceVulkan::compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset) { + ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); + ERR_FAIL_COND(!compute_list); + + ComputeList *cl = compute_list; + Buffer *buffer = storage_buffer_owner.getornull(p_buffer); + ERR_FAIL_COND(!buffer); + + ERR_FAIL_COND_MSG(!(buffer->usage & STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT), "Buffer provided was not created to do indirect dispatch."); + + ERR_FAIL_COND_MSG(p_offset + 12 > buffer->size, "Offset provided (+12) is past the end of buffer."); + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified."); +#endif + +#ifdef DEBUG_ENABLED + + ERR_FAIL_COND_MSG(!cl->validation.pipeline_active, "No compute pipeline was set before attempting to draw."); + + if (cl->validation.pipeline_push_constant_size > 0) { + //using push constants, check that they were supplied + ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_supplied, + "The shader in this pipeline requires a push constant to be set before drawing, but it's not present."); + } + +#endif + + //Bind descriptor sets + + for (uint32_t i = 0; i < cl->state.set_count; i++) { + if (cl->state.sets[i].pipeline_expected_format == 0) { + continue; //nothing expected by this pipeline + } +#ifdef DEBUG_ENABLED + if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) { + if (cl->state.sets[i].uniform_set_format == 0) { + ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline"); + } else if (uniform_set_owner.owns(cl->state.sets[i].uniform_set)) { + UniformSet *us = uniform_set_owner.getornull(cl->state.sets[i].uniform_set); + ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader)); + } else { + ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader)); + } + } +#endif + if (!cl->state.sets[i].bound) { + //All good, see if this requires re-binding + vkCmdBindDescriptorSets(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, cl->state.pipeline_layout, i, 1, &cl->state.sets[i].descriptor_set, 0, nullptr); + cl->state.sets[i].bound = true; + } + } + + vkCmdDispatchIndirect(cl->command_buffer, buffer->buffer, p_offset); +} + void RenderingDeviceVulkan::compute_list_add_barrier(ComputeListID p_list) { #ifdef FORCE_FULL_BARRIER _full_barrier(true); @@ -6534,14 +6834,12 @@ void RenderingDeviceVulkan::compute_list_add_barrier(ComputeListID p_list) { void RenderingDeviceVulkan::compute_list_end() { ERR_FAIL_COND(!compute_list); - for (Set<Texture *>::Element *E = compute_list->state.textures_to_sampled_layout.front(); E; E = E->next()) { - VkImageMemoryBarrier image_memory_barrier; image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_memory_barrier.pNext = nullptr; image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; - image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT; image_memory_barrier.oldLayout = E->get()->layout; image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -6554,7 +6852,8 @@ void RenderingDeviceVulkan::compute_list_end() { image_memory_barrier.subresourceRange.baseArrayLayer = E->get()->base_layer; image_memory_barrier.subresourceRange.layerCount = E->get()->layers; - vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + // TODO: Look at the usages in the compute list and determine tighter dst stage and access masks based on some "final" usage equivalent + vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); E->get()->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; } @@ -6564,13 +6863,19 @@ void RenderingDeviceVulkan::compute_list_end() { #ifdef FORCE_FULL_BARRIER _full_barrier(true); #else - _memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT, true); + _memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT, true); +#endif +} + +void RenderingDeviceVulkan::full_barrier() { +#ifndef DEBUG_ENABLED + ERR_PRINT("Full barrier is debug-only, should not be used in production"); #endif + _full_barrier(true); } #if 0 void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_framebuffer, ID *p_draw_lists, uint32_t p_draw_list_count, InitialAction p_initial_action, FinalAction p_final_action, const Vector<Variant> &p_clear_colors) { - VkCommandBuffer frame_cmdbuf = frames[frame].frame_buffer; ERR_FAIL_COND(!frame_cmdbuf); @@ -6599,7 +6904,6 @@ void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_frame ID screen_format = screen_get_framebuffer_format(); { - VkCommandBuffer *command_buffers = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer) * p_draw_list_count); uint32_t command_buffer_count = 0; @@ -6623,12 +6927,10 @@ void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_frame } vkCmdEndRenderPass(frame_cmdbuf); - } #endif void RenderingDeviceVulkan::_free_internal(RID p_id) { - //push everything so it's disposed of next time this frame index is processed (means, it's safe to do it) if (texture_owner.owns(p_id)) { Texture *texture = texture_owner.getornull(p_id); @@ -6691,8 +6993,8 @@ void RenderingDeviceVulkan::_free_internal(RID p_id) { ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id())); } } -void RenderingDeviceVulkan::free(RID p_id) { +void RenderingDeviceVulkan::free(RID p_id) { _THREAD_SAFE_METHOD_ _free_dependencies(p_id); //recursively erase dependencies first, to avoid potential API problems @@ -6700,7 +7002,6 @@ void RenderingDeviceVulkan::free(RID p_id) { } void RenderingDeviceVulkan::_finalize_command_bufers() { - if (draw_list) { ERR_PRINT("Found open draw list at the end of the frame, this should never happen (further drawing will likely not work)."); } @@ -6716,7 +7017,6 @@ void RenderingDeviceVulkan::_finalize_command_bufers() { } void RenderingDeviceVulkan::_begin_frame() { - //erase pending resources _free_pending_resources(frame); @@ -6763,7 +7063,6 @@ void RenderingDeviceVulkan::_begin_frame() { } void RenderingDeviceVulkan::swap_buffers() { - ERR_FAIL_COND_MSG(local_device.is_valid(), "Local devices can't swap buffers."); _THREAD_SAFE_METHOD_ @@ -6790,12 +7089,12 @@ void RenderingDeviceVulkan::submit() { } void RenderingDeviceVulkan::sync() { - ERR_FAIL_COND_MSG(local_device.is_null(), "Only local devices can submit and sync."); ERR_FAIL_COND_MSG(!local_device_processing, "sync can only be called after a submit"); context->local_device_sync(local_device); _begin_frame(); + local_device_processing = false; } void RenderingDeviceVulkan::_free_pending_resources(int p_frame) { @@ -6895,7 +7194,6 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) { //buffers while (frames[p_frame].buffers_to_dispose_of.front()) { - _buffer_free(&frames[p_frame].buffers_to_dispose_of.front()->get()); frames[p_frame].buffers_to_dispose_of.pop_front(); @@ -6912,8 +7210,13 @@ uint32_t RenderingDeviceVulkan::get_frame_delay() const { return frame_count; } -void RenderingDeviceVulkan::_flush(bool p_current_frame) { +uint64_t RenderingDeviceVulkan::get_memory_usage() const { + VmaStats stats; + vmaCalculateStats(allocator, &stats); + return stats.total.usedBytes; +} +void RenderingDeviceVulkan::_flush(bool p_current_frame) { if (local_device.is_valid() && !p_current_frame) { return; //flushign previous frames has no effect with local device } @@ -6924,7 +7227,6 @@ void RenderingDeviceVulkan::_flush(bool p_current_frame) { } if (local_device.is_valid()) { - VkCommandBuffer command_buffers[2] = { frames[frame].setup_command_buffer, frames[frame].draw_command_buffer }; context->local_device_push_command_buffers(local_device, command_buffers, 2); context->local_device_sync(local_device); @@ -6970,12 +7272,12 @@ void RenderingDeviceVulkan::_flush(bool p_current_frame) { } void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_device) { - context = p_context; device = p_context->get_device(); if (p_local_device) { frame_count = 1; local_device = p_context->local_device_create(); + device = p_context->local_device_get_vk_device(local_device); } else { frame_count = p_context->get_swapchain_image_count() + 1; //always need one extra to ensure it's unused at any time, without having to use a fence for this. } @@ -6995,7 +7297,6 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de frame = 0; //create setup and frame buffers for (int i = 0; i < frame_count; i++) { - frames[i].index = 0; { //create command pool, one per frame is recommended @@ -7119,7 +7420,6 @@ void RenderingDeviceVulkan::_free_rids(T &p_owner, const char *p_type) { } void RenderingDeviceVulkan::capture_timestamp(const String &p_name, bool p_sync_to_draw) { - ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements); { @@ -7199,7 +7499,7 @@ uint64_t RenderingDeviceVulkan::get_captured_timestamp_gpu_time(uint32_t p_index // this sucks because timestampPeriod multiplier is a float, while the timestamp is 64 bits nanosecs. // so, in cases like nvidia which give you enormous numbers and 1 as multiplier, multiplying is next to impossible - // need to do 128 bits fixed point multiplication to get the rigth value + // need to do 128 bits fixed point multiplication to get the right value uint64_t shift_bits = 16; @@ -7211,10 +7511,12 @@ uint64_t RenderingDeviceVulkan::get_captured_timestamp_gpu_time(uint32_t p_index return l; } + uint64_t RenderingDeviceVulkan::get_captured_timestamp_cpu_time(uint32_t p_index) const { ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0); return frames[frame].timestamp_cpu_result_values[p_index]; } + String RenderingDeviceVulkan::get_captured_timestamp_name(uint32_t p_index) const { ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, String()); return frames[frame].timestamp_result_names[p_index]; @@ -7222,49 +7524,83 @@ String RenderingDeviceVulkan::get_captured_timestamp_name(uint32_t p_index) cons int RenderingDeviceVulkan::limit_get(Limit p_limit) { switch (p_limit) { - case LIMIT_MAX_BOUND_UNIFORM_SETS: return limits.maxBoundDescriptorSets; - case LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS: return limits.maxColorAttachments; - case LIMIT_MAX_TEXTURES_PER_UNIFORM_SET: return limits.maxDescriptorSetSampledImages; - case LIMIT_MAX_SAMPLERS_PER_UNIFORM_SET: return limits.maxDescriptorSetSamplers; - case LIMIT_MAX_STORAGE_BUFFERS_PER_UNIFORM_SET: return limits.maxDescriptorSetStorageBuffers; - case LIMIT_MAX_STORAGE_IMAGES_PER_UNIFORM_SET: return limits.maxDescriptorSetStorageImages; - case LIMIT_MAX_UNIFORM_BUFFERS_PER_UNIFORM_SET: return limits.maxDescriptorSetUniformBuffers; - case LIMIT_MAX_DRAW_INDEXED_INDEX: return limits.maxDrawIndexedIndexValue; - case LIMIT_MAX_FRAMEBUFFER_HEIGHT: return limits.maxFramebufferHeight; - case LIMIT_MAX_FRAMEBUFFER_WIDTH: return limits.maxFramebufferWidth; - case LIMIT_MAX_TEXTURE_ARRAY_LAYERS: return limits.maxImageArrayLayers; - case LIMIT_MAX_TEXTURE_SIZE_1D: return limits.maxImageDimension1D; - case LIMIT_MAX_TEXTURE_SIZE_2D: return limits.maxImageDimension2D; - case LIMIT_MAX_TEXTURE_SIZE_3D: return limits.maxImageDimension3D; - case LIMIT_MAX_TEXTURE_SIZE_CUBE: return limits.maxImageDimensionCube; - case LIMIT_MAX_TEXTURES_PER_SHADER_STAGE: return limits.maxPerStageDescriptorSampledImages; - case LIMIT_MAX_SAMPLERS_PER_SHADER_STAGE: return limits.maxPerStageDescriptorSamplers; - case LIMIT_MAX_STORAGE_BUFFERS_PER_SHADER_STAGE: return limits.maxPerStageDescriptorStorageBuffers; - case LIMIT_MAX_STORAGE_IMAGES_PER_SHADER_STAGE: return limits.maxPerStageDescriptorStorageImages; - case LIMIT_MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE: return limits.maxPerStageDescriptorUniformBuffers; - case LIMIT_MAX_PUSH_CONSTANT_SIZE: return limits.maxPushConstantsSize; - case LIMIT_MAX_UNIFORM_BUFFER_SIZE: return limits.maxUniformBufferRange; - case LIMIT_MAX_VERTEX_INPUT_ATTRIBUTE_OFFSET: return limits.maxVertexInputAttributeOffset; - case LIMIT_MAX_VERTEX_INPUT_ATTRIBUTES: return limits.maxVertexInputAttributes; - case LIMIT_MAX_VERTEX_INPUT_BINDINGS: return limits.maxVertexInputBindings; - case LIMIT_MAX_VERTEX_INPUT_BINDING_STRIDE: return limits.maxVertexInputBindingStride; - case LIMIT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT: return limits.minUniformBufferOffsetAlignment; - case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X: return limits.maxComputeWorkGroupCount[0]; - case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y: return limits.maxComputeWorkGroupCount[1]; - case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z: return limits.maxComputeWorkGroupCount[2]; - case LIMIT_MAX_COMPUTE_WORKGROUP_INVOCATIONS: return limits.maxComputeWorkGroupInvocations; - case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X: return limits.maxComputeWorkGroupSize[0]; - case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y: return limits.maxComputeWorkGroupSize[1]; - case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z: return limits.maxComputeWorkGroupSize[2]; - - default: ERR_FAIL_V(0); + case LIMIT_MAX_BOUND_UNIFORM_SETS: + return limits.maxBoundDescriptorSets; + case LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS: + return limits.maxColorAttachments; + case LIMIT_MAX_TEXTURES_PER_UNIFORM_SET: + return limits.maxDescriptorSetSampledImages; + case LIMIT_MAX_SAMPLERS_PER_UNIFORM_SET: + return limits.maxDescriptorSetSamplers; + case LIMIT_MAX_STORAGE_BUFFERS_PER_UNIFORM_SET: + return limits.maxDescriptorSetStorageBuffers; + case LIMIT_MAX_STORAGE_IMAGES_PER_UNIFORM_SET: + return limits.maxDescriptorSetStorageImages; + case LIMIT_MAX_UNIFORM_BUFFERS_PER_UNIFORM_SET: + return limits.maxDescriptorSetUniformBuffers; + case LIMIT_MAX_DRAW_INDEXED_INDEX: + return limits.maxDrawIndexedIndexValue; + case LIMIT_MAX_FRAMEBUFFER_HEIGHT: + return limits.maxFramebufferHeight; + case LIMIT_MAX_FRAMEBUFFER_WIDTH: + return limits.maxFramebufferWidth; + case LIMIT_MAX_TEXTURE_ARRAY_LAYERS: + return limits.maxImageArrayLayers; + case LIMIT_MAX_TEXTURE_SIZE_1D: + return limits.maxImageDimension1D; + case LIMIT_MAX_TEXTURE_SIZE_2D: + return limits.maxImageDimension2D; + case LIMIT_MAX_TEXTURE_SIZE_3D: + return limits.maxImageDimension3D; + case LIMIT_MAX_TEXTURE_SIZE_CUBE: + return limits.maxImageDimensionCube; + case LIMIT_MAX_TEXTURES_PER_SHADER_STAGE: + return limits.maxPerStageDescriptorSampledImages; + case LIMIT_MAX_SAMPLERS_PER_SHADER_STAGE: + return limits.maxPerStageDescriptorSamplers; + case LIMIT_MAX_STORAGE_BUFFERS_PER_SHADER_STAGE: + return limits.maxPerStageDescriptorStorageBuffers; + case LIMIT_MAX_STORAGE_IMAGES_PER_SHADER_STAGE: + return limits.maxPerStageDescriptorStorageImages; + case LIMIT_MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE: + return limits.maxPerStageDescriptorUniformBuffers; + case LIMIT_MAX_PUSH_CONSTANT_SIZE: + return limits.maxPushConstantsSize; + case LIMIT_MAX_UNIFORM_BUFFER_SIZE: + return limits.maxUniformBufferRange; + case LIMIT_MAX_VERTEX_INPUT_ATTRIBUTE_OFFSET: + return limits.maxVertexInputAttributeOffset; + case LIMIT_MAX_VERTEX_INPUT_ATTRIBUTES: + return limits.maxVertexInputAttributes; + case LIMIT_MAX_VERTEX_INPUT_BINDINGS: + return limits.maxVertexInputBindings; + case LIMIT_MAX_VERTEX_INPUT_BINDING_STRIDE: + return limits.maxVertexInputBindingStride; + case LIMIT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT: + return limits.minUniformBufferOffsetAlignment; + case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X: + return limits.maxComputeWorkGroupCount[0]; + case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y: + return limits.maxComputeWorkGroupCount[1]; + case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z: + return limits.maxComputeWorkGroupCount[2]; + case LIMIT_MAX_COMPUTE_WORKGROUP_INVOCATIONS: + return limits.maxComputeWorkGroupInvocations; + case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X: + return limits.maxComputeWorkGroupSize[0]; + case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y: + return limits.maxComputeWorkGroupSize[1]; + case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z: + return limits.maxComputeWorkGroupSize[2]; + + default: + ERR_FAIL_V(0); } return 0; } void RenderingDeviceVulkan::finalize() { - //free all resources _flush(false); @@ -7290,7 +7626,6 @@ void RenderingDeviceVulkan::finalize() { WARN_PRINT(itos(owned.size()) + " RIDs of type 'Texture' were leaked."); //free shared first for (List<RID>::Element *E = owned.front(); E;) { - List<RID>::Element *N = E->next(); if (texture_is_shared(E->get())) { free(E->get()); @@ -7354,7 +7689,6 @@ RenderingDevice *RenderingDeviceVulkan::create_local_device() { } RenderingDeviceVulkan::RenderingDeviceVulkan() { - screen_prepared = false; } RenderingDeviceVulkan::~RenderingDeviceVulkan() { diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index 6432946fbe..a786eca70d 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.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,10 @@ #ifndef RENDERING_DEVICE_VULKAN_H #define RENDERING_DEVICE_VULKAN_H -#include "core/oa_hash_map.h" #include "core/os/thread_safe.h" -#include "core/rid_owner.h" +#include "core/templates/local_vector.h" +#include "core/templates/oa_hash_map.h" +#include "core/templates/rid_owner.h" #include "servers/rendering/rendering_device.h" #ifdef DEBUG_ENABLED @@ -42,16 +43,12 @@ #endif #endif #include "vk_mem_alloc.h" + #include <vulkan/vulkan.h> -//todo: -//compute -//push constants -//views of texture slices class VulkanContext; class RenderingDeviceVulkan : public RenderingDevice { - _THREAD_SAFE_CLASS_ // Miscellaneous tables that map @@ -98,7 +95,7 @@ class RenderingDeviceVulkan : public RenderingDevice { ID_BASE_SHIFT = 58 //5 bits for ID types }; - VkDevice device; + VkDevice device = VK_NULL_HANDLE; Map<RID, Set<RID>> dependency_map; //IDs to IDs that depend on it Map<RID, Set<RID>> reverse_dependency_map; //same as above, but in reverse @@ -111,7 +108,7 @@ class RenderingDeviceVulkan : public RenderingDevice { /*****************/ // In Vulkan, the concept of textures does not exist, - // intead there is the image (the memory prety much, + // instead there is the image (the memory pretty much, // the view (how the memory is interpreted) and the // sampler (how it's sampled from the shader). // @@ -123,36 +120,35 @@ class RenderingDeviceVulkan : public RenderingDevice { // for a framebuffer to render into it. struct Texture { - - VkImage image; - VmaAllocation allocation; + VkImage image = VK_NULL_HANDLE; + VmaAllocation allocation = nullptr; VmaAllocationInfo allocation_info; - VkImageView view; + VkImageView view = VK_NULL_HANDLE; TextureType type; DataFormat format; TextureSamples samples; - uint32_t width; - uint32_t height; - uint32_t depth; - uint32_t layers; - uint32_t mipmaps; - uint32_t usage_flags; - uint32_t base_mipmap; - uint32_t base_layer; + uint32_t width = 0; + uint32_t height = 0; + uint32_t depth = 0; + uint32_t layers = 0; + uint32_t mipmaps = 0; + uint32_t usage_flags = 0; + uint32_t base_mipmap = 0; + uint32_t base_layer = 0; Vector<DataFormat> allowed_shared_formats; VkImageLayout layout; - uint32_t read_aspect_mask; - uint32_t barrier_aspect_mask; - bool bound; //bound to framebffer + uint32_t read_aspect_mask = 0; + uint32_t barrier_aspect_mask = 0; + bool bound = false; //bound to framebffer RID owner; }; RID_Owner<Texture, true> texture_owner; - uint32_t texture_upload_region_size_px; + uint32_t texture_upload_region_size_px = 0; Vector<uint8_t> _texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer, bool p_2d = false); @@ -188,31 +184,28 @@ class RenderingDeviceVulkan : public RenderingDevice { // See the comments in the code to understand better how it works. struct StagingBufferBlock { - VkBuffer buffer; - VmaAllocation allocation; - uint64_t frame_used; - uint32_t fill_amount; + VkBuffer buffer = VK_NULL_HANDLE; + VmaAllocation allocation = nullptr; + uint64_t frame_used = 0; + uint32_t fill_amount = 0; }; Vector<StagingBufferBlock> staging_buffer_blocks; - int staging_buffer_current; - uint32_t staging_buffer_block_size; - uint64_t staging_buffer_max_size; - bool staging_buffer_used; + int staging_buffer_current = 0; + uint32_t staging_buffer_block_size = 0; + uint64_t staging_buffer_max_size = 0; + bool staging_buffer_used = false; Error _staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment = true, bool p_on_draw_command_buffer = false); Error _insert_staging_block(); struct Buffer { - - uint32_t size; - VkBuffer buffer; - VmaAllocation allocation; + uint32_t size = 0; + uint32_t usage = 0; + VkBuffer buffer = VK_NULL_HANDLE; + VmaAllocation allocation = nullptr; VkDescriptorBufferInfo buffer_info; //used for binding Buffer() { - size = 0; - buffer = VK_NULL_HANDLE; - allocation = nullptr; } }; @@ -235,8 +228,12 @@ class RenderingDeviceVulkan : public RenderingDevice { // used for the render pipelines. struct FramebufferFormatKey { + Size2i empty_size; Vector<AttachmentFormat> attachments; bool operator<(const FramebufferFormatKey &p_key) const { + if (empty_size != p_key.empty_size) { + return empty_size < p_key.empty_size; + } int as = attachments.size(); int bs = p_key.attachments.size(); @@ -271,15 +268,15 @@ class RenderingDeviceVulkan : public RenderingDevice { Map<FramebufferFormatKey, FramebufferFormatID> framebuffer_format_cache; struct FramebufferFormat { const Map<FramebufferFormatKey, FramebufferFormatID>::Element *E; - VkRenderPass render_pass; //here for constructing shaders, never used, see section (7.2. Render Pass Compatibility from Vulkan spec) - int color_attachments; //used for pipeline validation + VkRenderPass render_pass = VK_NULL_HANDLE; //here for constructing shaders, never used, see section (7.2. Render Pass Compatibility from Vulkan spec) + int color_attachments = 0; //used for pipeline validation TextureSamples samples; }; Map<FramebufferFormatID, FramebufferFormat> framebuffer_formats; struct Framebuffer { - FramebufferFormatID format_id; + FramebufferFormatID format_id = 0; struct VersionKey { InitialAction initial_color_action; FinalAction final_color_action; @@ -302,12 +299,12 @@ class RenderingDeviceVulkan : public RenderingDevice { } }; - uint32_t storage_mask; + uint32_t storage_mask = 0; Vector<RID> texture_ids; struct Version { - VkFramebuffer framebuffer; - VkRenderPass render_pass; //this one is owned + VkFramebuffer framebuffer = VK_NULL_HANDLE; + VkRenderPass render_pass = VK_NULL_HANDLE; //this one is owned }; Map<VersionKey, Version> framebuffers; @@ -322,7 +319,7 @@ class RenderingDeviceVulkan : public RenderingDevice { // Vertex buffers in Vulkan are similar to how // they work in OpenGL, except that instead of - // an attribtue index, there is a buffer binding + // an attribute index, there is a buffer binding // index (for binding the buffers in real-time) // and a location index (what is used in the shader). // @@ -394,8 +391,8 @@ class RenderingDeviceVulkan : public RenderingDevice { struct VertexDescriptionCache { Vector<VertexAttribute> vertex_formats; - VkVertexInputBindingDescription *bindings; - VkVertexInputAttributeDescription *attributes; + VkVertexInputBindingDescription *bindings = nullptr; + VkVertexInputAttributeDescription *attributes = nullptr; VkPipelineVertexInputStateCreateInfo create_info; }; @@ -403,9 +400,9 @@ class RenderingDeviceVulkan : public RenderingDevice { struct VertexArray { RID buffer; - VertexFormatID description; - int vertex_count; - uint32_t max_instances_allowed; + VertexFormatID description = 0; + int vertex_count = 0; + uint32_t max_instances_allowed = 0; Vector<VkBuffer> buffers; //not owned, just referenced Vector<VkDeviceSize> offsets; @@ -414,21 +411,21 @@ class RenderingDeviceVulkan : public RenderingDevice { RID_Owner<VertexArray, true> vertex_array_owner; struct IndexBuffer : public Buffer { - uint32_t max_index; //used for validation - uint32_t index_count; - VkIndexType index_type; - bool supports_restart_indices; + uint32_t max_index = 0; //used for validation + uint32_t index_count = 0; + VkIndexType index_type = VK_INDEX_TYPE_NONE_NV; + bool supports_restart_indices = false; }; RID_Owner<IndexBuffer, true> index_buffer_owner; struct IndexArray { - uint32_t max_index; //remember the maximum index here too, for validation + uint32_t max_index = 0; //remember the maximum index here too, for validation VkBuffer buffer; //not owned, inherited from index buffer - uint32_t offset; - uint32_t indices; - VkIndexType index_type; - bool supports_restart_indices; + uint32_t offset = 0; + uint32_t indices = 0; + VkIndexType index_type = VK_INDEX_TYPE_NONE_NV; + bool supports_restart_indices = false; }; RID_Owner<IndexArray, true> index_array_owner; @@ -454,10 +451,10 @@ class RenderingDeviceVulkan : public RenderingDevice { }; struct UniformInfo { - UniformType type; - int binding; - uint32_t stages; - int length; //size of arrays (in total elements), or ubos (in bytes * total elements) + UniformType type = UniformType::UNIFORM_TYPE_MAX; + int binding = 0; + uint32_t stages = 0; + int length = 0; //size of arrays (in total elements), or ubos (in bytes * total elements) bool operator!=(const UniformInfo &p_info) const { return (binding != p_info.binding || type != p_info.type || stages != p_info.stages || length != p_info.length); @@ -521,29 +518,27 @@ class RenderingDeviceVulkan : public RenderingDevice { // does not submit something invalid. struct Shader { - struct Set { - Vector<UniformInfo> uniform_info; - VkDescriptorSetLayout descriptor_set_layout; + VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE; }; - uint32_t vertex_input_mask; //inputs used, this is mostly for validation - int fragment_outputs; + uint32_t vertex_input_mask = 0; //inputs used, this is mostly for validation + int fragment_outputs = 0; struct PushConstant { - uint32_t push_constant_size; - uint32_t push_constants_vk_stage; + uint32_t push_constant_size = 0; + uint32_t push_constants_vk_stage = 0; }; PushConstant push_constant; bool is_compute = false; - int max_output; + int max_output = 0; Vector<Set> sets; Vector<uint32_t> set_formats; Vector<VkPipelineShaderStageCreateInfo> pipeline_stages; - VkPipelineLayout pipeline_layout; + VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; }; String _shader_uniform_debug(RID p_shader, int p_set = -1); @@ -576,7 +571,7 @@ class RenderingDeviceVulkan : public RenderingDevice { struct DescriptorPoolKey { union { struct { - uint16_t uniform_type[UNIFORM_TYPE_MAX]; //using 16 bits because, for sending arrays, each element is a pool set. + uint16_t uniform_type[UNIFORM_TYPE_MAX]; // Using 16 bits because, for sending arrays, each element is a pool set. }; struct { uint64_t key1; @@ -607,7 +602,7 @@ class RenderingDeviceVulkan : public RenderingDevice { }; Map<DescriptorPoolKey, Set<DescriptorPool *>> descriptor_pools; - uint32_t max_descriptors_per_pool; + uint32_t max_descriptors_per_pool = 0; DescriptorPool *_descriptor_pool_allocate(const DescriptorPoolKey &p_key); void _descriptor_pool_free(const DescriptorPoolKey &p_key, DescriptorPool *p_pool); @@ -618,7 +613,7 @@ class RenderingDeviceVulkan : public RenderingDevice { //texture buffer needs a view struct TextureBuffer { Buffer buffer; - VkBufferView view; + VkBufferView view = VK_NULL_HANDLE; }; RID_Owner<TextureBuffer, true> texture_buffer_owner; @@ -632,14 +627,19 @@ class RenderingDeviceVulkan : public RenderingDevice { // the above restriction is not too serious. struct UniformSet { - uint32_t format; + uint32_t format = 0; RID shader_id; - uint32_t shader_set; - DescriptorPool *pool; + uint32_t shader_set = 0; + DescriptorPool *pool = nullptr; DescriptorPoolKey pool_key; - VkDescriptorSet descriptor_set; + VkDescriptorSet descriptor_set = VK_NULL_HANDLE; //VkPipelineLayout pipeline_layout; //not owned, inherited from shader - Vector<RID> attachable_textures; //used for validation + struct AttachableTexture { + uint32_t bind; + RID texture; + }; + + LocalVector<AttachableTexture> attachable_textures; //used for validation Vector<Texture *> mutable_sampled_textures; //used for layout change Vector<Texture *> mutable_storage_textures; //used for layout change }; @@ -665,33 +665,32 @@ class RenderingDeviceVulkan : public RenderingDevice { //Cached values for validation #ifdef DEBUG_ENABLED struct Validation { - FramebufferFormatID framebuffer_format; - uint32_t dynamic_state; - VertexFormatID vertex_format; - bool uses_restart_indices; - uint32_t primitive_minimum; - uint32_t primitive_divisor; + FramebufferFormatID framebuffer_format = 0; + uint32_t dynamic_state = 0; + VertexFormatID vertex_format = 0; + bool uses_restart_indices = false; + uint32_t primitive_minimum = 0; + uint32_t primitive_divisor = 0; } validation; #endif //Actual pipeline RID shader; Vector<uint32_t> set_formats; - VkPipelineLayout pipeline_layout; // not owned, needed for push constants - VkPipeline pipeline; - uint32_t push_constant_size; - uint32_t push_constant_stages; + VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; // not owned, needed for push constants + VkPipeline pipeline = VK_NULL_HANDLE; + uint32_t push_constant_size = 0; + uint32_t push_constant_stages = 0; }; RID_Owner<RenderPipeline, true> render_pipeline_owner; struct ComputePipeline { - RID shader; Vector<uint32_t> set_formats; - VkPipelineLayout pipeline_layout; // not owned, needed for push constants - VkPipeline pipeline; - uint32_t push_constant_size; - uint32_t push_constant_stages; + VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; // not owned, needed for push constants + VkPipeline pipeline = VK_NULL_HANDLE; + uint32_t push_constant_size = 0; + uint32_t push_constant_stages = 0; }; RID_Owner<ComputePipeline, true> compute_pipeline_owner; @@ -712,192 +711,130 @@ class RenderingDeviceVulkan : public RenderingDevice { // each needs it's own command pool. struct SplitDrawListAllocator { - VkCommandPool command_pool; + VkCommandPool command_pool = VK_NULL_HANDLE; Vector<VkCommandBuffer> command_buffers; //one for each frame }; Vector<SplitDrawListAllocator> split_draw_list_allocators; struct DrawList { - - VkCommandBuffer command_buffer; //if persistent, this is owned, otherwise it's shared with the ringbuffer + VkCommandBuffer command_buffer = VK_NULL_HANDLE; // If persistent, this is owned, otherwise it's shared with the ringbuffer. Rect2i viewport; struct SetState { - uint32_t pipeline_expected_format; - uint32_t uniform_set_format; - VkDescriptorSet descriptor_set; + uint32_t pipeline_expected_format = 0; + uint32_t uniform_set_format = 0; + VkDescriptorSet descriptor_set = VK_NULL_HANDLE; RID uniform_set; - bool bound; - SetState() { - bound = false; - pipeline_expected_format = 0; - uniform_set_format = 0; - descriptor_set = VK_NULL_HANDLE; - } + bool bound = false; }; struct State { SetState sets[MAX_UNIFORM_SETS]; - uint32_t set_count; + uint32_t set_count = 0; RID pipeline; RID pipeline_shader; - VkPipelineLayout pipeline_layout; + VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; RID vertex_array; RID index_array; - uint32_t pipeline_push_constant_stages; - - State() { - set_count = 0; - pipeline_layout = VK_NULL_HANDLE; - pipeline_push_constant_stages = 0; - } + uint32_t pipeline_push_constant_stages = 0; } state; -#ifdef DEBUG_ENABLED +#ifdef DEBUG_ENABLED struct Validation { - bool active; //means command buffer was not closes, so you can keep adding things - FramebufferFormatID framebuffer_format; - //actual render pass values - uint32_t dynamic_state; - VertexFormatID vertex_format; //INVALID_ID if not set - uint32_t vertex_array_size; //0 if not set - uint32_t vertex_max_instances_allowed; - bool index_buffer_uses_restart_indices; - uint32_t index_array_size; //0 if index buffer not set - uint32_t index_array_max_index; - uint32_t index_array_offset; + bool active = true; // Means command buffer was not closed, so you can keep adding things. + FramebufferFormatID framebuffer_format = INVALID_ID; + // Actual render pass values. + uint32_t dynamic_state = 0; + VertexFormatID vertex_format = INVALID_ID; + uint32_t vertex_array_size = 0; + uint32_t vertex_max_instances_allowed = 0xFFFFFFFF; + bool index_buffer_uses_restart_indices = false; + uint32_t index_array_size = 0; + uint32_t index_array_max_index = 0; + uint32_t index_array_offset = 0; Vector<uint32_t> set_formats; Vector<bool> set_bound; Vector<RID> set_rids; - //last pipeline set values - bool pipeline_active; - uint32_t pipeline_dynamic_state; - VertexFormatID pipeline_vertex_format; + // Last pipeline set values. + bool pipeline_active = false; + uint32_t pipeline_dynamic_state = 0; + VertexFormatID pipeline_vertex_format = INVALID_ID; RID pipeline_shader; - uint32_t invalid_set_from; - bool pipeline_uses_restart_indices; - uint32_t pipeline_primitive_divisor; - uint32_t pipeline_primitive_minimum; + uint32_t invalid_set_from = 0; + bool pipeline_uses_restart_indices = false; + uint32_t pipeline_primitive_divisor = 0; + uint32_t pipeline_primitive_minimum = 0; Vector<uint32_t> pipeline_set_formats; - uint32_t pipeline_push_constant_size; - bool pipeline_push_constant_suppplied; - - Validation() { - active = true; - dynamic_state = 0; - vertex_format = INVALID_ID; - vertex_array_size = 0; - vertex_max_instances_allowed = 0xFFFFFFFF; - framebuffer_format = INVALID_ID; - index_array_size = 0; //not sent - index_array_max_index = 0; //not set - index_buffer_uses_restart_indices = false; - invalid_set_from = 0; - - //pipeline state initalize - pipeline_active = false; - pipeline_dynamic_state = 0; - pipeline_vertex_format = INVALID_ID; - pipeline_uses_restart_indices = false; - pipeline_push_constant_size = 0; - pipeline_push_constant_suppplied = false; - } + uint32_t pipeline_push_constant_size = 0; + bool pipeline_push_constant_supplied = false; } validation; #else struct Validation { - uint32_t vertex_array_size; //0 if not set - uint32_t index_array_size; //0 if index buffer not set + uint32_t vertex_array_size = 0; + uint32_t index_array_size = 0; uint32_t index_array_offset; - - Validation() { - vertex_array_size = 0; - index_array_size = 0; //not sent - } } validation; - #endif }; - DrawList *draw_list; //one for regular draw lists, multiple for split. - uint32_t draw_list_count; - bool draw_list_split; + DrawList *draw_list = nullptr; // One for regular draw lists, multiple for split. + uint32_t draw_list_count = 0; + bool draw_list_split = false; Vector<RID> draw_list_bound_textures; - bool draw_list_unbind_color_textures; - bool draw_list_unbind_depth_textures; + Vector<RID> draw_list_storage_textures; + bool draw_list_unbind_color_textures = false; + bool draw_list_unbind_depth_textures = false; void _draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil); Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass); - Error _draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents); + Error _draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents, const Vector<RID> &p_storage_textures); _FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id); + Buffer *_get_buffer_from_owner(RID p_buffer, VkPipelineStageFlags &dst_stage_mask, VkAccessFlags &dst_access); /**********************/ /**** COMPUTE LIST ****/ /**********************/ struct ComputeList { - - VkCommandBuffer command_buffer; //if persistent, this is owned, otherwise it's shared with the ringbuffer + VkCommandBuffer command_buffer = VK_NULL_HANDLE; // If persistent, this is owned, otherwise it's shared with the ringbuffer. struct SetState { - uint32_t pipeline_expected_format; - uint32_t uniform_set_format; - VkDescriptorSet descriptor_set; + uint32_t pipeline_expected_format = 0; + uint32_t uniform_set_format = 0; + VkDescriptorSet descriptor_set = VK_NULL_HANDLE; RID uniform_set; - bool bound; - SetState() { - bound = false; - pipeline_expected_format = 0; - uniform_set_format = 0; - descriptor_set = VK_NULL_HANDLE; - } + bool bound = false; }; struct State { Set<Texture *> textures_to_sampled_layout; - SetState sets[MAX_UNIFORM_SETS]; - uint32_t set_count; + uint32_t set_count = 0; RID pipeline; RID pipeline_shader; - VkPipelineLayout pipeline_layout; - uint32_t pipeline_push_constant_stages; - - State() { - set_count = 0; - pipeline_layout = VK_NULL_HANDLE; - pipeline_push_constant_stages = 0; - } + VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; + uint32_t pipeline_push_constant_stages = 0; } state; -#ifdef DEBUG_ENABLED +#ifdef DEBUG_ENABLED struct Validation { - bool active; //means command buffer was not closes, so you can keep adding things + bool active = true; // Means command buffer was not closed, so you can keep adding things. Vector<uint32_t> set_formats; Vector<bool> set_bound; Vector<RID> set_rids; - //last pipeline set values - bool pipeline_active; + // Last pipeline set values. + bool pipeline_active = false; RID pipeline_shader; - uint32_t invalid_set_from; + uint32_t invalid_set_from = 0; Vector<uint32_t> pipeline_set_formats; - uint32_t pipeline_push_constant_size; - bool pipeline_push_constant_suppplied; - - Validation() { - active = true; - invalid_set_from = 0; - - //pipeline state initalize - pipeline_active = false; - pipeline_push_constant_size = 0; - pipeline_push_constant_suppplied = false; - } + uint32_t pipeline_push_constant_size = 0; + bool pipeline_push_constant_supplied = false; } validation; #endif }; - ComputeList *compute_list; + ComputeList *compute_list = nullptr; /**************************/ /**** FRAME MANAGEMENT ****/ @@ -929,46 +866,46 @@ class RenderingDeviceVulkan : public RenderingDevice { List<RenderPipeline> render_pipelines_to_dispose_of; List<ComputePipeline> compute_pipelines_to_dispose_of; - VkCommandPool command_pool; - VkCommandBuffer setup_command_buffer; //used at the begining of every frame for set-up - VkCommandBuffer draw_command_buffer; //used at the begining of every frame for set-up + VkCommandPool command_pool = VK_NULL_HANDLE; + VkCommandBuffer setup_command_buffer = VK_NULL_HANDLE; //used at the beginning of every frame for set-up + VkCommandBuffer draw_command_buffer = VK_NULL_HANDLE; //used at the beginning of every frame for set-up struct Timestamp { String description; - uint64_t value; + uint64_t value = 0; }; VkQueryPool timestamp_pool; - String *timestamp_names; - uint64_t *timestamp_cpu_values; - uint32_t timestamp_count; - String *timestamp_result_names; - uint64_t *timestamp_cpu_result_values; - uint64_t *timestamp_result_values; - uint32_t timestamp_result_count; - uint64_t index; + String *timestamp_names = nullptr; + uint64_t *timestamp_cpu_values = nullptr; + uint32_t timestamp_count = 0; + String *timestamp_result_names = nullptr; + uint64_t *timestamp_cpu_result_values = nullptr; + uint64_t *timestamp_result_values = nullptr; + uint32_t timestamp_result_count = 0; + uint64_t index = 0; }; - uint32_t max_timestamp_query_elements; + uint32_t max_timestamp_query_elements = 0; - Frame *frames; //frames available, for main device they are cycled (usually 3), for local devices only 1 - int frame; //current frame - int frame_count; //total amount of frames - uint64_t frames_drawn; + Frame *frames = nullptr; //frames available, for main device they are cycled (usually 3), for local devices only 1 + int frame = 0; //current frame + int frame_count = 0; //total amount of frames + uint64_t frames_drawn = 0; RID local_device; bool local_device_processing = false; void _free_pending_resources(int p_frame); - VmaAllocator allocator; + VmaAllocator allocator = nullptr; - VulkanContext *context; + VulkanContext *context = nullptr; void _free_internal(RID p_id); void _flush(bool p_current_frame); - bool screen_prepared; + bool screen_prepared = false; template <class T> void _free_rids(T &p_owner, const char *p_type); @@ -997,9 +934,11 @@ public: /*********************/ virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format); + virtual FramebufferFormatID framebuffer_format_create_empty(const Size2i &p_size); virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format); virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID); + virtual RID framebuffer_create_empty(const Size2i &p_size, FramebufferFormatID p_format_check = INVALID_ID); virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer); @@ -1013,7 +952,7 @@ public: /**** VERTEX ARRAY ****/ /**********************/ - virtual RID vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>()); + 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); // Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated virtual VertexFormatID vertex_format_create(const Vector<VertexAttribute> &p_vertex_formats); @@ -1035,7 +974,7 @@ public: /*****************/ virtual RID uniform_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>()); - virtual RID storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>()); + virtual RID storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), uint32_t p_usage = 0); virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>()); virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set); @@ -1072,8 +1011,8 @@ public: virtual DrawListID draw_list_begin_for_screen(DisplayServer::WindowID p_screen = 0, const Color &p_clear_color = Color()); - virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, 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()); - virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, 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()); + virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, 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>()); + virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, 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>()); virtual void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline); virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index); @@ -1100,8 +1039,11 @@ public: virtual void compute_list_add_barrier(ComputeListID p_list); virtual void compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups); + virtual void compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset); virtual void compute_list_end(); + virtual void full_barrier(); + /**************/ /**** FREE ****/ /**************/ @@ -1138,6 +1080,8 @@ public: virtual RenderingDevice *create_local_device(); + virtual uint64_t get_memory_usage() const; + RenderingDeviceVulkan(); ~RenderingDeviceVulkan(); }; diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index d293abdee3..4d2bc406e4 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.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 "vulkan_context.h" -#include "core/engine.h" -#include "core/project_settings.h" -#include "core/ustring.h" +#include "core/config/engine.h" +#include "core/config/project_settings.h" +#include "core/string/ustring.h" #include "core/version.h" #include "vk_enum_string_helper.h" @@ -49,7 +49,6 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback( VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData) { - // This error needs to be ignored because the AMD allocator will mix up memory types on IGP processors. if (strstr(pCallbackData->pMessage, "Mapping an image with layout") != nullptr && strstr(pCallbackData->pMessage, "can result in undefined behavior if this memory is used by the device") != nullptr) { @@ -155,7 +154,7 @@ VkBool32 VulkanContext::_check_layers(uint32_t check_count, const char **check_n } } if (!found) { - ERR_PRINT("Cant find layer: " + String(check_names[i])); + WARN_PRINT("Can't find layer: " + String(check_names[i])); return 0; } } @@ -163,7 +162,6 @@ VkBool32 VulkanContext::_check_layers(uint32_t check_count, const char **check_n } Error VulkanContext::_create_validation_layers() { - VkResult err; const char *instance_validation_layers_alt1[] = { "VK_LAYER_KHRONOS_validation" }; const char *instance_validation_layers_alt2[] = { "VK_LAYER_LUNARG_standard_validation" }; @@ -218,8 +216,6 @@ Error VulkanContext::_create_validation_layers() { } Error VulkanContext::_initialize_extensions() { - - VkResult err; uint32_t instance_extension_count = 0; enabled_extension_count = 0; @@ -229,13 +225,13 @@ Error VulkanContext::_initialize_extensions() { VkBool32 platformSurfaceExtFound = 0; memset(extension_names, 0, sizeof(extension_names)); - err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr); - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + VkResult err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr); + ERR_FAIL_COND_V(err != VK_SUCCESS && err != VK_INCOMPLETE, ERR_CANT_CREATE); if (instance_extension_count > 0) { VkExtensionProperties *instance_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * instance_extension_count); err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, instance_extensions); - if (err) { + if (err != VK_SUCCESS && err != VK_INCOMPLETE) { free(instance_extensions); ERR_FAIL_V(ERR_CANT_CREATE); } @@ -275,7 +271,6 @@ Error VulkanContext::_initialize_extensions() { } Error VulkanContext::_create_physical_device() { - /* Look for validation layers */ if (use_validation_layers) { _create_validation_layers(); @@ -306,7 +301,7 @@ Error VulkanContext::_create_physical_device() { /*flags*/ 0, /*pApplicationInfo*/ &app, /*enabledLayerCount*/ enabled_layer_count, - /*ppEnabledLayerNames*/ (const char *const *)instance_validation_layers, + /*ppEnabledLayerNames*/ (const char *const *)enabled_layers, /*enabledExtensionCount*/ enabled_extension_count, /*ppEnabledExtensionNames*/ (const char *const *)extension_names, }; @@ -348,6 +343,8 @@ Error VulkanContext::_create_physical_device() { "Please look at the Getting Started guide for additional information.\n" "vkCreateInstance Failure"); + inst_initialized = true; + /* Make initial call to query gpu_count, then second call for gpu info*/ err = vkEnumeratePhysicalDevices(inst, &gpu_count, nullptr); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); @@ -496,6 +493,8 @@ Error VulkanContext::_create_physical_device() { // features based on this query vkGetPhysicalDeviceFeatures(gpu, &physical_device_features); + physical_device_features.robustBufferAccess = false; //turn off robust buffer access, which can hamper performance on some hardware + #define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \ { \ fp##entrypoint = (PFN_vk##entrypoint)vkGetInstanceProcAddr(inst, "vk" #entrypoint); \ @@ -513,7 +512,6 @@ Error VulkanContext::_create_physical_device() { } Error VulkanContext::_create_device() { - VkResult err; float queue_priorities[1] = { 0.0 }; VkDeviceQueueCreateInfo queues[2]; @@ -552,7 +550,6 @@ Error VulkanContext::_create_device() { } Error VulkanContext::_initialize_queues(VkSurfaceKHR surface) { - // Iterate over each queue to learn whether it supports presenting: VkBool32 *supportsPresent = (VkBool32 *)malloc(queue_family_count * sizeof(VkBool32)); for (uint32_t i = 0; i < queue_family_count; i++) { @@ -601,12 +598,13 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR surface) { _create_device(); static PFN_vkGetDeviceProcAddr g_gdpa = nullptr; -#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \ - { \ - if (!g_gdpa) g_gdpa = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr(inst, "vkGetDeviceProcAddr"); \ - fp##entrypoint = (PFN_vk##entrypoint)g_gdpa(dev, "vk" #entrypoint); \ - ERR_FAIL_COND_V_MSG(fp##entrypoint == nullptr, ERR_CANT_CREATE, \ - "vkGetDeviceProcAddr failed to find vk" #entrypoint); \ +#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \ + { \ + if (!g_gdpa) \ + g_gdpa = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr(inst, "vkGetDeviceProcAddr"); \ + fp##entrypoint = (PFN_vk##entrypoint)g_gdpa(dev, "vk" #entrypoint); \ + ERR_FAIL_COND_V_MSG(fp##entrypoint == nullptr, ERR_CANT_CREATE, \ + "vkGetDeviceProcAddr failed to find vk" #entrypoint); \ } GET_DEVICE_PROC_ADDR(device, CreateSwapchainKHR); @@ -704,14 +702,14 @@ Error VulkanContext::_create_semaphores() { } Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, VkSurfaceKHR p_surface, int p_width, int p_height) { - ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER); if (!queues_initialized) { // We use a single GPU, but we need a surface to initialize the // queues, so this process must be deferred until a surface // is created. - _initialize_queues(p_surface); + Error err = _initialize_queues(p_surface); + ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); } Window window; @@ -765,7 +763,6 @@ void VulkanContext::window_destroy(DisplayServer::WindowID p_window_id) { } Error VulkanContext::_clean_up_swap_chain(Window *window) { - if (!window->swapchain) { return OK; } @@ -1014,7 +1011,6 @@ Error VulkanContext::_update_swap_chain(Window *window) { { const VkAttachmentDescription attachment = { - /*flags*/ 0, /*format*/ format, /*samples*/ VK_SAMPLE_COUNT_1_BIT, @@ -1135,12 +1131,12 @@ Error VulkanContext::_update_swap_chain(Window *window) { } Error VulkanContext::initialize() { - Error err = _create_physical_device(); if (err) { return err; } + device_initialized = true; return OK; } @@ -1149,7 +1145,6 @@ void VulkanContext::set_setup_buffer(const VkCommandBuffer &pCommandBuffer) { } void VulkanContext::append_command_buffer(const VkCommandBuffer &pCommandBuffer) { - if (command_buffer_queue.size() <= command_buffer_count) { command_buffer_queue.resize(command_buffer_count + 1); } @@ -1159,14 +1154,12 @@ void VulkanContext::append_command_buffer(const VkCommandBuffer &pCommandBuffer) } void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) { - // ensure everything else pending is executed vkDeviceWaitIdle(device); //flush the pending setup buffer if (p_flush_setup && command_buffer_queue[0]) { - //use a fence to wait for everything done VkSubmitInfo submit_info; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; @@ -1185,7 +1178,6 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) { } if (p_flush_pending && command_buffer_count > 1) { - //use a fence to wait for everything done VkSubmitInfo submit_info; @@ -1207,7 +1199,6 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) { } Error VulkanContext::prepare_buffers() { - if (!queues_initialized) { return OK; } @@ -1219,7 +1210,6 @@ Error VulkanContext::prepare_buffers() { vkResetFences(device, 1, &fences[frame_index]); for (Map<int, Window>::Element *E = windows.front(); E; E = E->next()) { - Window *w = &E->get(); if (w->swapchain == VK_NULL_HANDLE) { @@ -1255,7 +1245,6 @@ Error VulkanContext::prepare_buffers() { } Error VulkanContext::swap_buffers() { - if (!queues_initialized) { return OK; } @@ -1474,9 +1463,11 @@ VkDevice VulkanContext::get_device() { VkPhysicalDevice VulkanContext::get_physical_device() { return gpu; } + int VulkanContext::get_swapchain_image_count() const { return swapchainImageCount; } + uint32_t VulkanContext::get_graphics_queue() const { return graphics_queue_family_index; } @@ -1489,23 +1480,6 @@ VkPhysicalDeviceLimits VulkanContext::get_device_limits() const { return gpu_props.limits; } -VulkanContext::VulkanContext() { - queue_props = nullptr; - command_buffer_count = 0; - instance_validation_layers = nullptr; - use_validation_layers = true; - VK_KHR_incremental_present_enabled = true; - VK_GOOGLE_display_timing_enabled = true; - - command_buffer_queue.resize(1); //first one is the setup command always - command_buffer_queue.write[0] = nullptr; - command_buffer_count = 1; - queues_initialized = false; - - buffers_prepared = false; - swapchainImageCount = 0; -} - RID VulkanContext::local_device_create() { LocalDevice ld; @@ -1550,7 +1524,6 @@ VkDevice VulkanContext::local_device_get_vk_device(RID p_local_device) { } void VulkanContext::local_device_push_command_buffers(RID p_local_device, const VkCommandBuffer *p_buffers, int p_count) { - LocalDevice *ld = local_device_owner.getornull(p_local_device); ERR_FAIL_COND(ld->waiting); @@ -1566,13 +1539,21 @@ void VulkanContext::local_device_push_command_buffers(RID p_local_device, const submit_info.pSignalSemaphores = nullptr; VkResult err = vkQueueSubmit(ld->queue, 1, &submit_info, VK_NULL_HANDLE); + if (err == VK_ERROR_OUT_OF_HOST_MEMORY) { + print_line("out of host memory"); + } + if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY) { + print_line("out of device memory"); + } + if (err == VK_ERROR_DEVICE_LOST) { + print_line("device lost"); + } ERR_FAIL_COND(err); ld->waiting = true; } void VulkanContext::local_device_sync(RID p_local_device) { - LocalDevice *ld = local_device_owner.getornull(p_local_device); ERR_FAIL_COND(!ld->waiting); @@ -1581,25 +1562,37 @@ void VulkanContext::local_device_sync(RID p_local_device) { } void VulkanContext::local_device_free(RID p_local_device) { - LocalDevice *ld = local_device_owner.getornull(p_local_device); vkDestroyDevice(ld->device, nullptr); local_device_owner.free(p_local_device); } +VulkanContext::VulkanContext() { + use_validation_layers = Engine::get_singleton()->is_validation_layers_enabled(); + + command_buffer_queue.resize(1); // First one is always the setup command. + command_buffer_queue.write[0] = nullptr; +} + VulkanContext::~VulkanContext() { if (queue_props) { free(queue_props); } - for (uint32_t i = 0; i < FRAME_LAG; i++) { - vkDestroyFence(device, fences[i], nullptr); - vkDestroySemaphore(device, image_acquired_semaphores[i], nullptr); - vkDestroySemaphore(device, draw_complete_semaphores[i], nullptr); - if (separate_present_queue) { - vkDestroySemaphore(device, image_ownership_semaphores[i], nullptr); + if (device_initialized) { + for (uint32_t i = 0; i < FRAME_LAG; i++) { + vkDestroyFence(device, fences[i], nullptr); + vkDestroySemaphore(device, image_acquired_semaphores[i], nullptr); + vkDestroySemaphore(device, draw_complete_semaphores[i], nullptr); + if (separate_present_queue) { + vkDestroySemaphore(device, image_ownership_semaphores[i], nullptr); + } } + if (inst_initialized && use_validation_layers) { + DestroyDebugUtilsMessengerEXT(inst, dbg_messenger, nullptr); + } + vkDestroyDevice(device, nullptr); + } + if (inst_initialized) { + vkDestroyInstance(inst, nullptr); } - DestroyDebugUtilsMessengerEXT(inst, dbg_messenger, nullptr); - vkDestroyDevice(device, nullptr); - vkDestroyInstance(inst, nullptr); } diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h index 51c3febb47..2be9903483 100644 --- a/drivers/vulkan/vulkan_context.h +++ b/drivers/vulkan/vulkan_context.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,43 +31,47 @@ #ifndef VULKAN_CONTEXT_H #define VULKAN_CONTEXT_H -#include "core/error_list.h" -#include "core/map.h" +#include "core/error/error_list.h" #include "core/os/mutex.h" -#include "core/rid_owner.h" -#include "core/ustring.h" +#include "core/string/ustring.h" +#include "core/templates/map.h" +#include "core/templates/rid_owner.h" #include "servers/display_server.h" + #include <vulkan/vulkan.h> class VulkanContext { - enum { MAX_EXTENSIONS = 128, MAX_LAYERS = 64, FRAME_LAG = 2 }; - VkInstance inst; - VkSurfaceKHR surface; - VkPhysicalDevice gpu; + VkInstance inst = VK_NULL_HANDLE; + VkSurfaceKHR surface = VK_NULL_HANDLE; + VkPhysicalDevice gpu = VK_NULL_HANDLE; VkPhysicalDeviceProperties gpu_props; - uint32_t queue_family_count; - VkQueueFamilyProperties *queue_props; - VkDevice device; - - //present - bool queues_initialized; - uint32_t graphics_queue_family_index; - uint32_t present_queue_family_index; - bool separate_present_queue; - VkQueue graphics_queue; - VkQueue present_queue; + uint32_t queue_family_count = 0; + VkQueueFamilyProperties *queue_props = nullptr; + VkDevice device = VK_NULL_HANDLE; + bool device_initialized = false; + bool inst_initialized = false; + + bool buffers_prepared = false; + + // Present queue. + bool queues_initialized = false; + uint32_t graphics_queue_family_index = 0; + uint32_t present_queue_family_index = 0; + bool separate_present_queue = false; + VkQueue graphics_queue = VK_NULL_HANDLE; + VkQueue present_queue = VK_NULL_HANDLE; VkColorSpaceKHR color_space; VkFormat format; VkSemaphore image_acquired_semaphores[FRAME_LAG]; VkSemaphore draw_complete_semaphores[FRAME_LAG]; VkSemaphore image_ownership_semaphores[FRAME_LAG]; - int frame_index; + int frame_index = 0; VkFence fences[FRAME_LAG]; VkPhysicalDeviceMemoryProperties memory_properties; VkPhysicalDeviceFeatures physical_device_features; @@ -77,58 +81,46 @@ class VulkanContext { VkCommandBuffer graphics_to_present_cmd; VkImageView view; VkFramebuffer framebuffer; - } SwapchainImageResources; struct Window { - - bool is_minimzed; - VkSurfaceKHR surface; - VkSwapchainKHR swapchain; - SwapchainImageResources *swapchain_image_resources; - VkPresentModeKHR presentMode; - uint32_t current_buffer; - int width; - int height; - VkCommandPool present_cmd_pool; //for separate present queue - - VkRenderPass render_pass; - - Window() { - width = 0; - height = 0; - render_pass = VK_NULL_HANDLE; - current_buffer = 0; - surface = VK_NULL_HANDLE; - swapchain_image_resources = VK_NULL_HANDLE; - swapchain = VK_NULL_HANDLE; - is_minimzed = false; - presentMode = VK_PRESENT_MODE_FIFO_KHR; - } + VkSurfaceKHR surface = VK_NULL_HANDLE; + VkSwapchainKHR swapchain = VK_NULL_HANDLE; + SwapchainImageResources *swapchain_image_resources = VK_NULL_HANDLE; + VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; + uint32_t current_buffer = 0; + int width = 0; + int height = 0; + VkCommandPool present_cmd_pool = VK_NULL_HANDLE; // For separate present queue. + VkRenderPass render_pass = VK_NULL_HANDLE; }; struct LocalDevice { bool waiting = false; - VkDevice device; - VkQueue queue; + VkDevice device = VK_NULL_HANDLE; + VkQueue queue = VK_NULL_HANDLE; }; RID_Owner<LocalDevice, true> local_device_owner; Map<DisplayServer::WindowID, Window> windows; - uint32_t swapchainImageCount; + uint32_t swapchainImageCount = 0; - //commands + // Commands. + + bool prepared = false; + + Vector<VkCommandBuffer> command_buffer_queue; + int command_buffer_count = 1; - bool prepared; + // Extensions. - //extensions - bool VK_KHR_incremental_present_enabled; - bool VK_GOOGLE_display_timing_enabled; - const char **instance_validation_layers; - uint32_t enabled_extension_count; - uint32_t enabled_layer_count; + bool VK_KHR_incremental_present_enabled = true; + bool VK_GOOGLE_display_timing_enabled = true; + uint32_t enabled_extension_count = 0; const char *extension_names[MAX_EXTENSIONS]; + + uint32_t enabled_layer_count = 0; const char *enabled_layers[MAX_LAYERS]; PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT; @@ -150,13 +142,14 @@ class VulkanContext { PFN_vkGetRefreshCycleDurationGOOGLE fpGetRefreshCycleDurationGOOGLE; PFN_vkGetPastPresentationTimingGOOGLE fpGetPastPresentationTimingGOOGLE; - VkDebugUtilsMessengerEXT dbg_messenger; + VkDebugUtilsMessengerEXT dbg_messenger = VK_NULL_HANDLE; Error _create_validation_layers(); Error _initialize_extensions(); VkBool32 _check_layers(uint32_t check_count, const char **check_names, uint32_t layer_count, VkLayerProperties *layers); - static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_messenger_callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_messenger_callback( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData); @@ -174,12 +167,11 @@ class VulkanContext { Error _create_swap_chain(); Error _create_semaphores(); - Vector<VkCommandBuffer> command_buffer_queue; - int command_buffer_count; - protected: virtual const char *_get_platform_surface_extension() const = 0; - // virtual VkResult _create_surface(VkSurfaceKHR *surface, VkInstance p_instance) = 0; + + // Enabled via command line argument. + bool use_validation_layers = false; virtual Error _window_create(DisplayServer::WindowID p_window_id, VkSurfaceKHR p_surface, int p_width, int p_height); @@ -187,10 +179,6 @@ protected: return inst; } - bool buffers_prepared; - - bool use_validation_layers; - public: VkDevice get_device(); VkPhysicalDevice get_physical_device(); diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index ab2976f02c..7d5082d276 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.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,8 +32,8 @@ #include "audio_driver_wasapi.h" +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" #include <functiondiscoverykeys.h> @@ -69,13 +69,11 @@ static bool default_render_device_changed = false; static bool default_capture_device_changed = false; class CMMNotificationClient : public IMMNotificationClient { - LONG _cRef; - IMMDeviceEnumerator *_pEnumerator; + LONG _cRef = 1; + IMMDeviceEnumerator *_pEnumerator = nullptr; public: - CMMNotificationClient() : - _cRef(1), - _pEnumerator(nullptr) {} + CMMNotificationClient() {} virtual ~CMMNotificationClient() { if ((_pEnumerator) != nullptr) { (_pEnumerator)->Release(); @@ -141,7 +139,6 @@ public: static CMMNotificationClient notif_client; Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool reinit) { - WAVEFORMATEX *pwfex; IMMDeviceEnumerator *enumerator = nullptr; IMMDevice *device = nullptr; @@ -313,7 +310,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c } Error AudioDriverWASAPI::init_render_device(bool reinit) { - Error err = audio_device_init(&audio_output, false, reinit); if (err != OK) return err; @@ -352,7 +348,6 @@ Error AudioDriverWASAPI::init_render_device(bool reinit) { } Error AudioDriverWASAPI::init_capture_device(bool reinit) { - Error err = audio_device_init(&audio_input, true, reinit); if (err != OK) return err; @@ -368,7 +363,6 @@ Error AudioDriverWASAPI::init_capture_device(bool reinit) { } Error AudioDriverWASAPI::audio_device_finish(AudioDeviceWASAPI *p_device) { - if (p_device->active) { if (p_device->audio_client) { p_device->audio_client->Stop(); @@ -385,18 +379,15 @@ Error AudioDriverWASAPI::audio_device_finish(AudioDeviceWASAPI *p_device) { } Error AudioDriverWASAPI::finish_render_device() { - return audio_device_finish(&audio_output); } Error AudioDriverWASAPI::finish_capture_device() { - return audio_device_finish(&audio_input); } Error AudioDriverWASAPI::init() { - - mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); + mix_rate = GLOBAL_GET("audio/mix_rate"); Error err = init_render_device(); if (err != OK) { @@ -412,17 +403,14 @@ Error AudioDriverWASAPI::init() { } int AudioDriverWASAPI::get_mix_rate() const { - return mix_rate; } AudioDriver::SpeakerMode AudioDriverWASAPI::get_speaker_mode() const { - return get_speaker_mode_by_total_channels(channels); } Array AudioDriverWASAPI::audio_device_get_list(bool p_capture) { - Array list; IMMDeviceCollection *devices = nullptr; IMMDeviceEnumerator *enumerator = nullptr; @@ -470,12 +458,10 @@ Array AudioDriverWASAPI::audio_device_get_list(bool p_capture) { } Array AudioDriverWASAPI::get_device_list() { - return audio_device_get_list(false); } String AudioDriverWASAPI::get_device() { - lock(); String name = audio_output.device_name; unlock(); @@ -484,7 +470,6 @@ String AudioDriverWASAPI::get_device() { } void AudioDriverWASAPI::set_device(String device) { - lock(); audio_output.new_device = device; unlock(); @@ -552,13 +537,11 @@ void AudioDriverWASAPI::write_sample(WORD format_tag, int bits_per_sample, BYTE } void AudioDriverWASAPI::thread_func(void *p_udata) { - AudioDriverWASAPI *ad = (AudioDriverWASAPI *)p_udata; uint32_t avail_frames = 0; uint32_t write_ofs = 0; while (!ad->exit_thread) { - uint32_t read_frames = 0; uint32_t written_frames = 0; @@ -585,19 +568,16 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { ad->start_counting_ticks(); if (avail_frames > 0 && ad->audio_output.audio_client) { - UINT32 cur_frames; bool invalidated = false; HRESULT hr = ad->audio_output.audio_client->GetCurrentPadding(&cur_frames); if (hr == S_OK) { - // Check how much frames are available on the WASAPI buffer UINT32 write_frames = MIN(ad->buffer_frames - cur_frames, avail_frames); if (write_frames > 0) { BYTE *buffer = nullptr; hr = ad->audio_output.render_client->GetBuffer(write_frames, &buffer); if (hr == S_OK) { - // We're using WASAPI Shared Mode so we must convert the buffer if (ad->channels == ad->audio_output.channels) { for (unsigned int i = 0; i < write_frames * ad->channels; i++) { @@ -768,7 +748,6 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { } void AudioDriverWASAPI::start() { - if (audio_output.audio_client) { HRESULT hr = audio_output.audio_client->Start(); if (hr != S_OK) { @@ -780,17 +759,14 @@ void AudioDriverWASAPI::start() { } void AudioDriverWASAPI::lock() { - mutex.lock(); } void AudioDriverWASAPI::unlock() { - mutex.unlock(); } void AudioDriverWASAPI::finish() { - if (thread) { exit_thread = true; Thread::wait_to_finish(thread); @@ -804,7 +780,6 @@ void AudioDriverWASAPI::finish() { } Error AudioDriverWASAPI::capture_start() { - Error err = init_capture_device(); if (err != OK) { ERR_PRINT("WASAPI: init_capture_device error"); @@ -821,7 +796,6 @@ Error AudioDriverWASAPI::capture_start() { } Error AudioDriverWASAPI::capture_stop() { - if (audio_input.active) { audio_input.audio_client->Stop(); audio_input.active = false; @@ -833,19 +807,16 @@ Error AudioDriverWASAPI::capture_stop() { } void AudioDriverWASAPI::capture_set_device(const String &p_name) { - lock(); audio_input.new_device = p_name; unlock(); } Array AudioDriverWASAPI::capture_get_device_list() { - return audio_device_get_list(true); } String AudioDriverWASAPI::capture_get_device() { - lock(); String name = audio_input.device_name; unlock(); @@ -854,17 +825,7 @@ String AudioDriverWASAPI::capture_get_device() { } AudioDriverWASAPI::AudioDriverWASAPI() { - - thread = nullptr; - samples_in.clear(); - - channels = 0; - mix_rate = 0; - buffer_frames = 0; - - thread_exited = false; - exit_thread = false; } -#endif +#endif // WASAPI_ENABLED diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h index 01a4666812..2df07d16f7 100644 --- a/drivers/wasapi/audio_driver_wasapi.h +++ b/drivers/wasapi/audio_driver_wasapi.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 */ @@ -42,50 +42,38 @@ #include <windows.h> class AudioDriverWASAPI : public AudioDriver { - class AudioDeviceWASAPI { public: - IAudioClient *audio_client; - IAudioRenderClient *render_client; - IAudioCaptureClient *capture_client; - bool active; - - WORD format_tag; - WORD bits_per_sample; - unsigned int channels; - unsigned int frame_size; - - String device_name; - String new_device; - - AudioDeviceWASAPI() : - audio_client(nullptr), - render_client(nullptr), - capture_client(nullptr), - active(false), - format_tag(0), - bits_per_sample(0), - channels(0), - frame_size(0), - device_name("Default"), - new_device("Default") { - } + IAudioClient *audio_client = nullptr; + IAudioRenderClient *render_client = nullptr; + IAudioCaptureClient *capture_client = nullptr; + bool active = false; + + WORD format_tag = 0; + WORD bits_per_sample = 0; + unsigned int channels = 0; + unsigned int frame_size = 0; + + String device_name = "Default"; + String new_device = "Default"; + + AudioDeviceWASAPI() {} }; AudioDeviceWASAPI audio_input; AudioDeviceWASAPI audio_output; Mutex mutex; - Thread *thread; + Thread *thread = nullptr; Vector<int32_t> samples_in; - unsigned int channels; - int mix_rate; - int buffer_frames; + unsigned int channels = 0; + int mix_rate = 0; + int buffer_frames = 0; - bool thread_exited; - mutable bool exit_thread; + bool thread_exited = false; + mutable bool exit_thread = false; static _FORCE_INLINE_ void write_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i, int32_t sample); static _FORCE_INLINE_ int32_t read_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i); diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp index a8618b05d7..2c9f28717d 100644 --- a/drivers/windows/dir_access_windows.cpp +++ b/drivers/windows/dir_access_windows.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,7 +33,7 @@ #include "dir_access_windows.h" #include "core/os/memory.h" -#include "core/print_string.h" +#include "core/string/print_string.h" #include <stdio.h> #include <wchar.h> @@ -53,7 +53,6 @@ */ struct DirAccessWindowsPrivate { - HANDLE h; //handle for findfirstfile WIN32_FIND_DATA f; WIN32_FIND_DATAW fu; //unicode version @@ -62,28 +61,30 @@ struct DirAccessWindowsPrivate { // CreateFolderAsync Error DirAccessWindows::list_dir_begin() { - _cisdir = false; _cishidden = false; list_dir_end(); - p->h = FindFirstFileExW((current_dir + "\\*").c_str(), FindExInfoStandard, &p->fu, FindExSearchNameMatch, nullptr, 0); + p->h = FindFirstFileExW((LPCWSTR)(String(current_dir + "\\*").utf16().get_data()), FindExInfoStandard, &p->fu, FindExSearchNameMatch, nullptr, 0); - return (p->h == INVALID_HANDLE_VALUE) ? ERR_CANT_OPEN : OK; + if (p->h == INVALID_HANDLE_VALUE) { + return ERR_CANT_OPEN; + } + + return OK; } String DirAccessWindows::get_next() { - - if (p->h == INVALID_HANDLE_VALUE) + if (p->h == INVALID_HANDLE_VALUE) { return ""; + } _cisdir = (p->fu.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); _cishidden = (p->fu.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN); - String name = p->fu.cFileName; + String name = String::utf16((const char16_t *)(p->fu.cFileName)); if (FindNextFileW(p->h, &p->fu) == 0) { - FindClose(p->h); p->h = INVALID_HANDLE_VALUE; } @@ -92,80 +93,71 @@ String DirAccessWindows::get_next() { } bool DirAccessWindows::current_is_dir() const { - return _cisdir; } bool DirAccessWindows::current_is_hidden() const { - return _cishidden; } void DirAccessWindows::list_dir_end() { - if (p->h != INVALID_HANDLE_VALUE) { - FindClose(p->h); p->h = INVALID_HANDLE_VALUE; } } -int DirAccessWindows::get_drive_count() { +int DirAccessWindows::get_drive_count() { return drive_count; } -String DirAccessWindows::get_drive(int p_drive) { - if (p_drive < 0 || p_drive >= drive_count) +String DirAccessWindows::get_drive(int p_drive) { + if (p_drive < 0 || p_drive >= drive_count) { return ""; + } return String::chr(drives[p_drive]) + ":"; } Error DirAccessWindows::change_dir(String p_dir) { - GLOBAL_LOCK_FUNCTION p_dir = fix_path(p_dir); - wchar_t real_current_dir_name[2048]; + WCHAR real_current_dir_name[2048]; GetCurrentDirectoryW(2048, real_current_dir_name); - String prev_dir = real_current_dir_name; + String prev_dir = String::utf16((const char16_t *)real_current_dir_name); - SetCurrentDirectoryW(current_dir.c_str()); - bool worked = (SetCurrentDirectoryW(p_dir.c_str()) != 0); + SetCurrentDirectoryW((LPCWSTR)(current_dir.utf16().get_data())); + bool worked = (SetCurrentDirectoryW((LPCWSTR)(p_dir.utf16().get_data())) != 0); String base = _get_root_path(); if (base != "") { - GetCurrentDirectoryW(2048, real_current_dir_name); - String new_dir; - new_dir = String(real_current_dir_name).replace("\\", "/"); + String new_dir = String::utf16((const char16_t *)real_current_dir_name).replace("\\", "/"); if (!new_dir.begins_with(base)) { worked = false; } } if (worked) { - GetCurrentDirectoryW(2048, real_current_dir_name); - current_dir = real_current_dir_name; // TODO, utf8 parser + current_dir = String::utf16((const char16_t *)real_current_dir_name); current_dir = current_dir.replace("\\", "/"); + } - } //else { - - SetCurrentDirectoryW(prev_dir.c_str()); - //} + SetCurrentDirectoryW((LPCWSTR)(prev_dir.utf16().get_data())); return worked ? OK : ERR_INVALID_PARAMETER; } Error DirAccessWindows::make_dir(String p_dir) { - GLOBAL_LOCK_FUNCTION p_dir = fix_path(p_dir); - if (p_dir.is_rel_path()) + if (p_dir.is_rel_path()) { p_dir = current_dir.plus_file(p_dir); + } p_dir = p_dir.replace("/", "\\"); @@ -175,32 +167,29 @@ Error DirAccessWindows::make_dir(String p_dir) { p_dir = "\\\\?\\" + p_dir; //done according to // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363855(v=vs.85).aspx - success = CreateDirectoryW(p_dir.c_str(), nullptr); + success = CreateDirectoryW((LPCWSTR)(p_dir.utf16().get_data()), nullptr); err = GetLastError(); if (success) { return OK; - }; + } if (err == ERROR_ALREADY_EXISTS || err == ERROR_ACCESS_DENIED) { return ERR_ALREADY_EXISTS; - }; + } return ERR_CANT_CREATE; } String DirAccessWindows::get_current_dir(bool p_include_drive) { - String base = _get_root_path(); if (base != "") { - String bd = current_dir.replace("\\", "/").replace_first(base, ""); - if (bd.begins_with("/")) + if (bd.begins_with("/")) { return _get_root_string() + bd.substr(1, bd.length()); - else + } else { return _get_root_string() + bd; - - } else { + } } if (p_include_drive) { @@ -217,57 +206,51 @@ String DirAccessWindows::get_current_dir(bool p_include_drive) { } bool DirAccessWindows::file_exists(String p_file) { - GLOBAL_LOCK_FUNCTION - if (!p_file.is_abs_path()) + if (!p_file.is_abs_path()) { p_file = get_current_dir().plus_file(p_file); + } p_file = fix_path(p_file); - //p_file.replace("/","\\"); - - //WIN32_FILE_ATTRIBUTE_DATA fileInfo; - DWORD fileAttr; - fileAttr = GetFileAttributesW(p_file.c_str()); - if (INVALID_FILE_ATTRIBUTES == fileAttr) + fileAttr = GetFileAttributesW((LPCWSTR)(p_file.utf16().get_data())); + if (INVALID_FILE_ATTRIBUTES == fileAttr) { return false; + } return !(fileAttr & FILE_ATTRIBUTE_DIRECTORY); } bool DirAccessWindows::dir_exists(String p_dir) { - GLOBAL_LOCK_FUNCTION - if (p_dir.is_rel_path()) + if (p_dir.is_rel_path()) { p_dir = get_current_dir().plus_file(p_dir); + } p_dir = fix_path(p_dir); - //p_dir.replace("/","\\"); - - //WIN32_FILE_ATTRIBUTE_DATA fileInfo; - DWORD fileAttr; - - fileAttr = GetFileAttributesW(p_dir.c_str()); - if (INVALID_FILE_ATTRIBUTES == fileAttr) + fileAttr = GetFileAttributesW((LPCWSTR)(p_dir.utf16().get_data())); + if (INVALID_FILE_ATTRIBUTES == fileAttr) { return false; + } return (fileAttr & FILE_ATTRIBUTE_DIRECTORY); } Error DirAccessWindows::rename(String p_path, String p_new_path) { - - if (p_path.is_rel_path()) + if (p_path.is_rel_path()) { p_path = get_current_dir().plus_file(p_path); + } p_path = fix_path(p_path); - if (p_new_path.is_rel_path()) + if (p_new_path.is_rel_path()) { p_new_path = get_current_dir().plus_file(p_new_path); + } p_new_path = fix_path(p_new_path); @@ -275,16 +258,16 @@ Error DirAccessWindows::rename(String p_path, String p_new_path) { if (p_path.to_lower() == p_new_path.to_lower()) { WCHAR tmpfile[MAX_PATH]; - if (!GetTempFileNameW(fix_path(get_current_dir()).c_str(), nullptr, 0, tmpfile)) { + if (!GetTempFileNameW((LPCWSTR)(fix_path(get_current_dir()).utf16().get_data()), nullptr, 0, tmpfile)) { return FAILED; } - if (!::ReplaceFileW(tmpfile, p_path.c_str(), nullptr, 0, nullptr, nullptr)) { + if (!::ReplaceFileW(tmpfile, (LPCWSTR)(p_path.utf16().get_data()), nullptr, 0, nullptr, nullptr)) { DeleteFileW(tmpfile); return FAILED; } - return ::_wrename(tmpfile, p_new_path.c_str()) == 0 ? OK : FAILED; + return ::_wrename(tmpfile, (LPCWSTR)(p_new_path.utf16().get_data())) == 0 ? OK : FAILED; } else { if (file_exists(p_new_path)) { @@ -293,64 +276,60 @@ Error DirAccessWindows::rename(String p_path, String p_new_path) { } } - return ::_wrename(p_path.c_str(), p_new_path.c_str()) == 0 ? OK : FAILED; + return ::_wrename((LPCWSTR)(p_path.utf16().get_data()), (LPCWSTR)(p_new_path.utf16().get_data())) == 0 ? OK : FAILED; } } Error DirAccessWindows::remove(String p_path) { - - if (p_path.is_rel_path()) + if (p_path.is_rel_path()) { p_path = get_current_dir().plus_file(p_path); + } p_path = fix_path(p_path); - printf("erasing %s\n", p_path.utf8().get_data()); - //WIN32_FILE_ATTRIBUTE_DATA fileInfo; - //DWORD fileAttr = GetFileAttributesExW(p_path.c_str(), GetFileExInfoStandard, &fileInfo); - DWORD fileAttr; - fileAttr = GetFileAttributesW(p_path.c_str()); - if (INVALID_FILE_ATTRIBUTES == fileAttr) + fileAttr = GetFileAttributesW((LPCWSTR)(p_path.utf16().get_data())); + if (INVALID_FILE_ATTRIBUTES == fileAttr) { return FAILED; - if ((fileAttr & FILE_ATTRIBUTE_DIRECTORY)) - return ::_wrmdir(p_path.c_str()) == 0 ? OK : FAILED; - else - return ::_wunlink(p_path.c_str()) == 0 ? OK : FAILED; + } + if ((fileAttr & FILE_ATTRIBUTE_DIRECTORY)) { + return ::_wrmdir((LPCWSTR)(p_path.utf16().get_data())) == 0 ? OK : FAILED; + } else { + return ::_wunlink((LPCWSTR)(p_path.utf16().get_data())) == 0 ? OK : FAILED; + } } + /* FileType DirAccessWindows::get_file_type(const String& p_file) const { + WCHAR real_current_dir_name[2048]; + GetCurrentDirectoryW(2048, real_current_dir_name); + String prev_dir = Strong::utf16((const char16_t *)real_current_dir_name); - - wchar_t real_current_dir_name[2048]; - GetCurrentDirectoryW(2048,real_current_dir_name); - String prev_dir=real_current_dir_name; - - bool worked SetCurrentDirectoryW(current_dir.c_str()); + bool worked = SetCurrentDirectoryW((LPCWSTR)(current_dir.utf16().get_data())); DWORD attr; if (worked) { - - WIN32_FILE_ATTRIBUTE_DATA fileInfo; - attr = GetFileAttributesExW(p_file.c_str(), GetFileExInfoStandard, &fileInfo); - + WIN32_FILE_ATTRIBUTE_DATA fileInfo; + attr = GetFileAttributesExW((LPCWSTR)(p_file.utf16().get_data()), GetFileExInfoStandard, &fileInfo); } - SetCurrentDirectoryW(prev_dir.c_str()); + SetCurrentDirectoryW((LPCWSTR)(prev_dir.utf16().get_data())); - if (!worked) + if (!worked) { return FILE_TYPE_NONE; + } - - return (attr&FILE_ATTRIBUTE_DIRECTORY)?FILE_TYPE_ + return (attr & FILE_ATTRIBUTE_DIRECTORY) ? FILE_TYPE_ } + */ size_t DirAccessWindows::get_space_left() { - uint64_t bytes = 0; - if (!GetDiskFreeSpaceEx(nullptr, (PULARGE_INTEGER)&bytes, nullptr, nullptr)) + if (!GetDiskFreeSpaceEx(nullptr, (PULARGE_INTEGER)&bytes, nullptr, nullptr)) { return 0; + } //this is either 0 or a value in bytes. return (size_t)bytes; @@ -369,7 +348,7 @@ String DirAccessWindows::get_filesystem_type() const { DWORD dwMaxFileNameLength = 0; DWORD dwFileSystemFlags = 0; - if (::GetVolumeInformationW(unit.c_str(), + if (::GetVolumeInformationW((LPCWSTR)(unit.utf16().get_data()), szVolumeName, sizeof(szVolumeName), &dwSerialNumber, @@ -377,21 +356,17 @@ String DirAccessWindows::get_filesystem_type() const { &dwFileSystemFlags, szFileSystemName, sizeof(szFileSystemName)) == TRUE) { - - return String(szFileSystemName); + return String::utf16((const char16_t *)szFileSystemName); } ERR_FAIL_V(""); } DirAccessWindows::DirAccessWindows() { - p = memnew(DirAccessWindowsPrivate); p->h = INVALID_HANDLE_VALUE; current_dir = "."; - drive_count = 0; - #ifdef UWP_ENABLED Windows::Storage::StorageFolder ^ install_folder = Windows::ApplicationModel::Package::Current->InstalledLocation; change_dir(install_folder->Path->Data()); @@ -401,7 +376,6 @@ DirAccessWindows::DirAccessWindows() { DWORD mask = GetLogicalDrives(); for (int i = 0; i < MAX_DRIVES; i++) { - if (mask & (1 << i)) { //DRIVE EXISTS drives[drive_count] = 'A' + i; @@ -414,7 +388,6 @@ DirAccessWindows::DirAccessWindows() { } DirAccessWindows::~DirAccessWindows() { - memdelete(p); } diff --git a/drivers/windows/dir_access_windows.h b/drivers/windows/dir_access_windows.h index f59e4d7030..7f10023470 100644 --- a/drivers/windows/dir_access_windows.h +++ b/drivers/windows/dir_access_windows.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 */ @@ -42,21 +42,20 @@ struct DirAccessWindowsPrivate; class DirAccessWindows : public DirAccess { - enum { MAX_DRIVES = 26 }; - DirAccessWindowsPrivate *p; + DirAccessWindowsPrivate *p = nullptr; /* Windows stuff */ - char drives[MAX_DRIVES]; // a-z: - int drive_count; + char drives[MAX_DRIVES] = { 0 }; // a-z: + int drive_count = 0; String current_dir; - bool _cisdir; - bool _cishidden; + bool _cisdir = false; + bool _cishidden = false; public: virtual Error list_dir_begin(); ///< This starts dir listing diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index 69078b3326..35f61c0623 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,7 +33,7 @@ #include "file_access_windows.h" #include "core/os/os.h" -#include "core/print_string.h" +#include "core/string/print_string.h" #include <shlwapi.h> #include <windows.h> @@ -49,43 +49,42 @@ #endif void FileAccessWindows::check_errors() const { - ERR_FAIL_COND(!f); if (feof(f)) { - last_error = ERR_FILE_EOF; } } Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) { - path_src = p_path; path = fix_path(p_path); - if (f) + if (f) { close(); + } - const wchar_t *mode_string; + const WCHAR *mode_string; - if (p_mode_flags == READ) + if (p_mode_flags == READ) { mode_string = L"rb"; - else if (p_mode_flags == WRITE) + } else if (p_mode_flags == WRITE) { mode_string = L"wb"; - else if (p_mode_flags == READ_WRITE) + } else if (p_mode_flags == READ_WRITE) { mode_string = L"rb+"; - else if (p_mode_flags == WRITE_READ) + } else if (p_mode_flags == WRITE_READ) { mode_string = L"wb+"; - else + } else { return ERR_INVALID_PARAMETER; + } /* pretty much every implementation that uses fopen as primary backend supports utf8 encoding */ struct _stat st; - if (_wstat(path.c_str(), &st) == 0) { - - if (!S_ISREG(st.st_mode)) + if (_wstat((LPCWSTR)(path.utf16().get_data()), &st) == 0) { + if (!S_ISREG(st.st_mode)) { return ERR_FILE_CANT_OPEN; + } }; #ifdef TOOLS_ENABLED @@ -95,11 +94,10 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) { // platforms). if (p_mode_flags == READ) { WIN32_FIND_DATAW d; - HANDLE f = FindFirstFileW(path.c_str(), &d); + HANDLE f = FindFirstFileW((LPCWSTR)(path.utf16().get_data()), &d); if (f != INVALID_HANDLE_VALUE) { - String fname = d.cFileName; + String fname = String::utf16((const char16_t *)(d.cFileName)); if (fname != String()) { - String base_file = path.get_file(); if (base_file != fname && base_file.findn(fname) == 0) { WARN_PRINT("Case mismatch opening requested file '" + base_file + "', stored as '" + fname + "' in the filesystem. This file will not open when exported to other case-sensitive platforms."); @@ -115,7 +113,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) { path = path + ".tmp"; } - errno_t errcode = _wfopen_s(&f, path.c_str(), mode_string); + errno_t errcode = _wfopen_s(&f, (LPCWSTR)(path.utf16().get_data()), mode_string); if (f == nullptr) { switch (errcode) { @@ -135,15 +133,14 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) { } void FileAccessWindows::close() { - - if (!f) + if (!f) { return; + } fclose(f); f = nullptr; if (save_path != "") { - bool rename_error = true; int attempts = 4; while (rename_error && attempts) { @@ -155,16 +152,16 @@ void FileAccessWindows::close() { // UWP has no PathFileExists, so we check attributes instead DWORD fileAttr; - fileAttr = GetFileAttributesW(save_path.c_str()); + fileAttr = GetFileAttributesW((LPCWSTR)(save_path.utf16().get_data())); if (INVALID_FILE_ATTRIBUTES == fileAttr) { #else - if (!PathFileExistsW(save_path.c_str())) { + if (!PathFileExistsW((LPCWSTR)(save_path.utf16().get_data()))) { #endif //creating new file - rename_error = _wrename((save_path + ".tmp").c_str(), save_path.c_str()) != 0; + rename_error = _wrename((LPCWSTR)((save_path + ".tmp").utf16().get_data()), (LPCWSTR)(save_path.utf16().get_data())) != 0; } else { //atomic replace for existing file - rename_error = !ReplaceFileW(save_path.c_str(), (save_path + ".tmp").c_str(), nullptr, 2 | 4, nullptr, nullptr); + rename_error = !ReplaceFileW((LPCWSTR)(save_path.utf16().get_data()), (LPCWSTR)((save_path + ".tmp").utf16().get_data()), nullptr, 2 | 4, nullptr, nullptr); } if (rename_error) { attempts--; @@ -185,45 +182,44 @@ void FileAccessWindows::close() { } String FileAccessWindows::get_path() const { - return path_src; } String FileAccessWindows::get_path_absolute() const { - return path; } bool FileAccessWindows::is_open() const { - return (f != nullptr); } -void FileAccessWindows::seek(size_t p_position) { +void FileAccessWindows::seek(size_t p_position) { ERR_FAIL_COND(!f); last_error = OK; - if (fseek(f, p_position, SEEK_SET)) + if (fseek(f, p_position, SEEK_SET)) { check_errors(); + } prev_op = 0; } -void FileAccessWindows::seek_end(int64_t p_position) { +void FileAccessWindows::seek_end(int64_t p_position) { ERR_FAIL_COND(!f); - if (fseek(f, p_position, SEEK_END)) + if (fseek(f, p_position, SEEK_END)) { check_errors(); + } prev_op = 0; } -size_t FileAccessWindows::get_position() const { +size_t FileAccessWindows::get_position() const { size_t aux_position = 0; aux_position = ftell(f); if (!aux_position) { check_errors(); - }; + } return aux_position; } -size_t FileAccessWindows::get_len() const { +size_t FileAccessWindows::get_len() const { ERR_FAIL_COND_V(!f, 0); size_t pos = get_position(); @@ -235,13 +231,11 @@ size_t FileAccessWindows::get_len() const { } bool FileAccessWindows::eof_reached() const { - check_errors(); return last_error == ERR_FILE_EOF; } uint8_t FileAccessWindows::get_8() const { - ERR_FAIL_COND_V(!f, 0); if (flags == READ_WRITE || flags == WRITE_READ) { if (prev_op == WRITE) { @@ -253,13 +247,12 @@ uint8_t FileAccessWindows::get_8() const { if (fread(&b, 1, 1, f) == 0) { check_errors(); b = '\0'; - }; + } return b; } int FileAccessWindows::get_buffer(uint8_t *p_dst, int p_length) const { - ERR_FAIL_COND_V(!f, -1); if (flags == READ_WRITE || flags == WRITE_READ) { if (prev_op == WRITE) { @@ -273,20 +266,18 @@ int FileAccessWindows::get_buffer(uint8_t *p_dst, int p_length) const { }; Error FileAccessWindows::get_error() const { - return last_error; } void FileAccessWindows::flush() { - ERR_FAIL_COND(!f); fflush(f); - if (prev_op == WRITE) + if (prev_op == WRITE) { prev_op = 0; + } } void FileAccessWindows::store_8(uint8_t p_dest) { - ERR_FAIL_COND(!f); if (flags == READ_WRITE || flags == WRITE_READ) { if (prev_op == READ) { @@ -313,32 +304,27 @@ void FileAccessWindows::store_buffer(const uint8_t *p_src, int p_length) { } bool FileAccessWindows::file_exists(const String &p_name) { - FILE *g; - //printf("opening file %s\n", p_fname.c_str()); + //printf("opening file %s\n", p_fname.utf8().get_data()); String filename = fix_path(p_name); - _wfopen_s(&g, filename.c_str(), L"rb"); + _wfopen_s(&g, (LPCWSTR)(filename.utf16().get_data()), L"rb"); if (g == nullptr) { - return false; } else { - fclose(g); return true; } } uint64_t FileAccessWindows::_get_modified_time(const String &p_file) { - String file = fix_path(p_file); if (file.ends_with("/") && file != "/") file = file.substr(0, file.length() - 1); struct _stat st; - int rv = _wstat(file.c_str(), &st); + int rv = _wstat((LPCWSTR)(file.utf16().get_data()), &st); if (rv == 0) { - return st.st_mtime; } else { ERR_FAIL_V_MSG(0, "Failed to get modified time for: " + file + "."); @@ -353,15 +339,8 @@ Error FileAccessWindows::_set_unix_permissions(const String &p_file, uint32_t p_ return ERR_UNAVAILABLE; } -FileAccessWindows::FileAccessWindows() : - f(nullptr), - flags(0), - prev_op(0), - last_error(OK) { -} FileAccessWindows::~FileAccessWindows() { - close(); } -#endif +#endif // WINDOWS_ENABLED diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h index 28d4375878..507e0b2c20 100644 --- a/drivers/windows/file_access_windows.h +++ b/drivers/windows/file_access_windows.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -39,12 +39,11 @@ #include <stdio.h> class FileAccessWindows : public FileAccess { - - FILE *f; - int flags; + FILE *f = nullptr; + int flags = 0; void check_errors() const; - mutable int prev_op; - mutable Error last_error; + mutable int prev_op = 0; + mutable Error last_error = OK; String path; String path_src; String save_path; @@ -79,9 +78,10 @@ public: virtual uint32_t _get_unix_permissions(const String &p_file); virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions); - FileAccessWindows(); + FileAccessWindows() {} virtual ~FileAccessWindows(); }; -#endif -#endif +#endif // WINDOWS_ENABLED + +#endif // FILE_ACCESS_WINDOWS_H diff --git a/drivers/windows/rw_lock_windows.cpp b/drivers/windows/rw_lock_windows.cpp index 438f4bf10d..6f59e072bb 100644 --- a/drivers/windows/rw_lock_windows.cpp +++ b/drivers/windows/rw_lock_windows.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,23 +32,20 @@ #include "rw_lock_windows.h" -#include "core/error_macros.h" +#include "core/error/error_macros.h" #include "core/os/memory.h" #include <stdio.h> void RWLockWindows::read_lock() { - AcquireSRWLockShared(&lock); } void RWLockWindows::read_unlock() { - ReleaseSRWLockShared(&lock); } Error RWLockWindows::read_try_lock() { - if (TryAcquireSRWLockShared(&lock) == 0) { return ERR_BUSY; } else { @@ -57,12 +54,10 @@ Error RWLockWindows::read_try_lock() { } void RWLockWindows::write_lock() { - AcquireSRWLockExclusive(&lock); } void RWLockWindows::write_unlock() { - ReleaseSRWLockExclusive(&lock); } @@ -75,17 +70,14 @@ Error RWLockWindows::write_try_lock() { } RWLock *RWLockWindows::create_func_windows() { - return memnew(RWLockWindows); } void RWLockWindows::make_default() { - create_func = create_func_windows; } RWLockWindows::RWLockWindows() { - InitializeSRWLock(&lock); } diff --git a/drivers/windows/rw_lock_windows.h b/drivers/windows/rw_lock_windows.h index 3705c1eb38..a9d55bdef9 100644 --- a/drivers/windows/rw_lock_windows.h +++ b/drivers/windows/rw_lock_windows.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 */ @@ -38,7 +38,6 @@ #include <windows.h> class RWLockWindows : public RWLock { - SRWLOCK lock; static RWLock *create_func_windows(); diff --git a/drivers/windows/thread_windows.cpp b/drivers/windows/thread_windows.cpp index aea2db2603..ec95c9523d 100644 --- a/drivers/windows/thread_windows.cpp +++ b/drivers/windows/thread_windows.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 */ @@ -35,17 +35,14 @@ #include "core/os/memory.h" Thread::ID ThreadWindows::get_id() const { - return id; } Thread *ThreadWindows::create_thread_windows() { - return memnew(ThreadWindows); } DWORD ThreadWindows::thread_callback(LPVOID userdata) { - ThreadWindows *t = reinterpret_cast<ThreadWindows *>(userdata); ScriptServer::thread_enter(); //scripts may need to attach a stack @@ -60,7 +57,6 @@ DWORD ThreadWindows::thread_callback(LPVOID userdata) { } Thread *ThreadWindows::create_func_windows(ThreadCreateCallback p_callback, void *p_user, const Settings &) { - ThreadWindows *tr = memnew(ThreadWindows); tr->callback = p_callback; tr->user = p_user; @@ -70,12 +66,12 @@ Thread *ThreadWindows::create_func_windows(ThreadCreateCallback p_callback, void return tr; } -Thread::ID ThreadWindows::get_thread_id_func_windows() { +Thread::ID ThreadWindows::get_thread_id_func_windows() { return (ID)GetCurrentThreadId(); //must implement } -void ThreadWindows::wait_to_finish_func_windows(Thread *p_thread) { +void ThreadWindows::wait_to_finish_func_windows(Thread *p_thread) { ThreadWindows *tp = static_cast<ThreadWindows *>(p_thread); ERR_FAIL_COND(!tp); WaitForSingleObject(tp->handle, INFINITE); @@ -84,17 +80,9 @@ void ThreadWindows::wait_to_finish_func_windows(Thread *p_thread) { } void ThreadWindows::make_default() { - create_func = create_func_windows; get_thread_id_func = get_thread_id_func_windows; wait_to_finish_func = wait_to_finish_func_windows; } -ThreadWindows::ThreadWindows() : - handle(nullptr) { -} - -ThreadWindows::~ThreadWindows() { -} - #endif diff --git a/drivers/windows/thread_windows.h b/drivers/windows/thread_windows.h index 669956cd32..3801bddc2c 100644 --- a/drivers/windows/thread_windows.h +++ b/drivers/windows/thread_windows.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,17 +33,16 @@ #ifdef WINDOWS_ENABLED +#include "core/object/script_language.h" #include "core/os/thread.h" -#include "core/script_language.h" #include <windows.h> class ThreadWindows : public Thread { - ThreadCreateCallback callback; void *user; ID id; - HANDLE handle; + HANDLE handle = nullptr; static Thread *create_thread_windows(); @@ -53,14 +52,14 @@ class ThreadWindows : public Thread { static ID get_thread_id_func_windows(); static void wait_to_finish_func_windows(Thread *p_thread); - ThreadWindows(); + ThreadWindows() {} public: virtual ID get_id() const; static void make_default(); - ~ThreadWindows(); + ~ThreadWindows() {} }; #endif diff --git a/drivers/winmidi/midi_driver_winmidi.cpp b/drivers/winmidi/midi_driver_winmidi.cpp index 57fb9b0e57..730d608bbf 100644 --- a/drivers/winmidi/midi_driver_winmidi.cpp +++ b/drivers/winmidi/midi_driver_winmidi.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,17 +32,15 @@ #include "midi_driver_winmidi.h" -#include "core/print_string.h" +#include "core/string/print_string.h" void MIDIDriverWinMidi::read(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { - if (wMsg == MIM_DATA) { receive_input_packet((uint64_t)dwParam2, (uint8_t *)&dwParam1, 3); } } Error MIDIDriverWinMidi::open() { - for (UINT i = 0; i < midiInGetNumDevs(); i++) { HMIDIIN midi_in; @@ -67,7 +65,6 @@ Error MIDIDriverWinMidi::open() { } PackedStringArray MIDIDriverWinMidi::get_connected_inputs() { - PackedStringArray list; for (int i = 0; i < connected_sources.size(); i++) { @@ -87,7 +84,6 @@ PackedStringArray MIDIDriverWinMidi::get_connected_inputs() { } void MIDIDriverWinMidi::close() { - for (int i = 0; i < connected_sources.size(); i++) { HMIDIIN midi_in = connected_sources[i]; midiInStop(midi_in); @@ -100,7 +96,6 @@ MIDIDriverWinMidi::MIDIDriverWinMidi() { } MIDIDriverWinMidi::~MIDIDriverWinMidi() { - close(); } diff --git a/drivers/winmidi/midi_driver_winmidi.h b/drivers/winmidi/midi_driver_winmidi.h index c240c8c7aa..bb9a87d610 100644 --- a/drivers/winmidi/midi_driver_winmidi.h +++ b/drivers/winmidi/midi_driver_winmidi.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -34,7 +34,7 @@ #define MIDI_DRIVER_WINMIDI_H #include "core/os/midi_driver.h" -#include "core/vector.h" +#include "core/templates/vector.h" #include <stdio.h> #include <windows.h> @@ -42,7 +42,6 @@ #include <mmsystem.h> class MIDIDriverWinMidi : public MIDIDriver { - Vector<HMIDIIN> connected_sources; static void CALLBACK read(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2); diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp index 120bfa2b36..3b3c3481b6 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.cpp +++ b/drivers/xaudio2/audio_driver_xaudio2.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,27 +30,26 @@ #include "audio_driver_xaudio2.h" +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" const char *AudioDriverXAudio2::get_name() const { return "XAudio2"; } Error AudioDriverXAudio2::init() { - active = false; thread_exited = false; exit_thread = false; pcm_open = false; samples_in = nullptr; - mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); + mix_rate = GLOBAL_GET("audio/mix_rate"); // FIXME: speaker_mode seems unused in the Xaudio2 driver so far speaker_mode = SPEAKER_MODE_STEREO; channels = 2; - int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY); + int latency = GLOBAL_GET("audio/output_latency"); buffer_size = closest_power_of_2(latency * mix_rate / 1000); samples_in = memnew_arr(int32_t, buffer_size * channels); @@ -85,19 +84,15 @@ Error AudioDriverXAudio2::init() { } void AudioDriverXAudio2::thread_func(void *p_udata) { - AudioDriverXAudio2 *ad = (AudioDriverXAudio2 *)p_udata; while (!ad->exit_thread) { - if (!ad->active) { - for (int i = 0; i < AUDIO_BUFFERS; i++) { ad->xaudio_buffer[i].Flags = XAUDIO2_END_OF_STREAM; } } else { - ad->lock(); ad->audio_server_process(ad->buffer_size, ad->samples_in); @@ -105,7 +100,6 @@ void AudioDriverXAudio2::thread_func(void *p_udata) { ad->unlock(); for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) { - ad->samples_out[ad->current_buffer][i] = ad->samples_in[i] >> 16; } @@ -128,24 +122,20 @@ void AudioDriverXAudio2::thread_func(void *p_udata) { } void AudioDriverXAudio2::start() { - active = true; HRESULT hr = source_voice->Start(0); ERR_FAIL_COND_MSG(hr != S_OK, "Error starting XAudio2 driver. Error code: " + itos(hr) + "."); } int AudioDriverXAudio2::get_mix_rate() const { - return mix_rate; } AudioDriver::SpeakerMode AudioDriverXAudio2::get_speaker_mode() const { - return speaker_mode; } float AudioDriverXAudio2::get_latency() { - XAUDIO2_PERFORMANCE_DATA perf_data; xaudio->GetPerformanceData(&perf_data); if (perf_data.CurrentLatencyInSamples) { @@ -156,20 +146,18 @@ float AudioDriverXAudio2::get_latency() { } void AudioDriverXAudio2::lock() { - if (!thread) return; mutex.lock(); } -void AudioDriverXAudio2::unlock() { +void AudioDriverXAudio2::unlock() { if (!thread) return; mutex.unlock(); } void AudioDriverXAudio2::finish() { - if (!thread) return; @@ -196,15 +184,9 @@ void AudioDriverXAudio2::finish() { thread = nullptr; } -AudioDriverXAudio2::AudioDriverXAudio2() : - thread(nullptr), - current_buffer(0) { - wave_format = { 0 }; +AudioDriverXAudio2::AudioDriverXAudio2() { for (int i = 0; i < AUDIO_BUFFERS; i++) { xaudio_buffer[i] = { 0 }; samples_out[i] = 0; } } - -AudioDriverXAudio2::~AudioDriverXAudio2() { -} diff --git a/drivers/xaudio2/audio_driver_xaudio2.h b/drivers/xaudio2/audio_driver_xaudio2.h index eb4a6d6e95..e3c2d3a326 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.h +++ b/drivers/xaudio2/audio_driver_xaudio2.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,13 +41,11 @@ #include <xaudio2.h> class AudioDriverXAudio2 : public AudioDriver { - enum { AUDIO_BUFFERS = 2 }; struct XAudio2DriverVoiceCallback : public IXAudio2VoiceCallback { - HANDLE buffer_end_event; XAudio2DriverVoiceCallback() : buffer_end_event(CreateEvent(nullptr, FALSE, FALSE, nullptr)) {} @@ -64,31 +62,31 @@ class AudioDriverXAudio2 : public AudioDriver { void STDMETHODCALLTYPE OnVoiceError(void *pBufferContext, HRESULT Error) {} }; - Thread *thread; + Thread *thread = nullptr; Mutex mutex; - int32_t *samples_in; + int32_t *samples_in = nullptr; int16_t *samples_out[AUDIO_BUFFERS]; static void thread_func(void *p_udata); - int buffer_size; + int buffer_size = 0; - unsigned int mix_rate; - SpeakerMode speaker_mode; + unsigned int mix_rate = 0; + SpeakerMode speaker_mode = SpeakerMode::SPEAKER_MODE_STEREO; - int channels; + int channels = 0; - bool active; - bool thread_exited; - mutable bool exit_thread; - bool pcm_open; + bool active = false; + bool thread_exited = false; + mutable bool exit_thread = false; + bool pcm_open = false; - WAVEFORMATEX wave_format; + WAVEFORMATEX wave_format = { 0 }; Microsoft::WRL::ComPtr<IXAudio2> xaudio; - int current_buffer; - IXAudio2MasteringVoice *mastering_voice; + int current_buffer = 0; + IXAudio2MasteringVoice *mastering_voice = nullptr; XAUDIO2_BUFFER xaudio_buffer[AUDIO_BUFFERS]; - IXAudio2SourceVoice *source_voice; + IXAudio2SourceVoice *source_voice = nullptr; XAudio2DriverVoiceCallback voice_callback; public: @@ -104,7 +102,7 @@ public: virtual void finish(); AudioDriverXAudio2(); - ~AudioDriverXAudio2(); + ~AudioDriverXAudio2() {} }; #endif |