summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/alsa/audio_driver_alsa.cpp2
-rw-r--r--drivers/alsamidi/midi_driver_alsamidi.cpp2
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.cpp54
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.h18
-rw-r--r--drivers/coremidi/midi_driver_coremidi.cpp4
-rw-r--r--drivers/coremidi/midi_driver_coremidi.h9
-rw-r--r--drivers/gl_context/SCsub2
-rw-r--r--drivers/gles3/SCsub3
-rw-r--r--drivers/gles3/effects/SCsub5
-rw-r--r--drivers/gles3/effects/copy_effects.cpp165
-rw-r--r--drivers/gles3/effects/copy_effects.h74
-rw-r--r--drivers/gles3/environment/SCsub5
-rw-r--r--drivers/gles3/environment/fog.cpp (renamed from drivers/gles3/texture_loader_gles3.h)47
-rw-r--r--drivers/gles3/environment/fog.h62
-rw-r--r--drivers/gles3/environment/gi.cpp133
-rw-r--r--drivers/gles3/environment/gi.h96
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp869
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.h77
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp98
-rw-r--r--drivers/gles3/rasterizer_gles3.h51
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp2441
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h707
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp4515
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h1438
-rw-r--r--drivers/gles3/shader_gles3.cpp33
-rw-r--r--drivers/gles3/shader_gles3.h35
-rw-r--r--drivers/gles3/shaders/SCsub12
-rw-r--r--drivers/gles3/shaders/canvas.glsl135
-rw-r--r--drivers/gles3/shaders/canvas_shadow.glsl4
-rw-r--r--drivers/gles3/shaders/canvas_uniforms_inc.glsl4
-rw-r--r--drivers/gles3/shaders/copy.glsl181
-rw-r--r--drivers/gles3/shaders/cubemap_filter.glsl218
-rw-r--r--drivers/gles3/shaders/scene.glsl2414
-rw-r--r--drivers/gles3/shaders/sky.glsl168
-rw-r--r--drivers/gles3/shaders/stdlib_inc.glsl10
-rw-r--r--drivers/gles3/shaders/tonemap.glsl12
-rw-r--r--drivers/gles3/shaders/tonemap_inc.glsl127
-rw-r--r--drivers/gles3/storage/SCsub5
-rw-r--r--drivers/gles3/storage/config.cpp128
-rw-r--r--drivers/gles3/storage/config.h (renamed from drivers/gles3/texture_loader_gles3.cpp)138
-rw-r--r--drivers/gles3/storage/light_storage.cpp580
-rw-r--r--drivers/gles3/storage/light_storage.h347
-rw-r--r--drivers/gles3/storage/material_storage.cpp3577
-rw-r--r--drivers/gles3/storage/material_storage.h602
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp1558
-rw-r--r--drivers/gles3/storage/mesh_storage.h546
-rw-r--r--drivers/gles3/storage/particles_storage.cpp254
-rw-r--r--drivers/gles3/storage/particles_storage.h140
-rw-r--r--drivers/gles3/storage/texture_storage.cpp1693
-rw-r--r--drivers/gles3/storage/texture_storage.h583
-rw-r--r--drivers/gles3/storage/utilities.cpp353
-rw-r--r--drivers/gles3/storage/utilities.h159
-rw-r--r--drivers/png/image_loader_png.cpp4
-rw-r--r--drivers/png/image_loader_png.h4
-rw-r--r--drivers/png/png_driver_common.h2
-rw-r--r--drivers/png/resource_saver_png.cpp16
-rw-r--r--drivers/png/resource_saver_png.h6
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp14
-rw-r--r--drivers/register_driver_types.cpp2
-rw-r--r--drivers/register_driver_types.h2
-rw-r--r--drivers/unix/dir_access_unix.cpp41
-rw-r--r--drivers/unix/dir_access_unix.h61
-rw-r--r--drivers/unix/file_access_unix.cpp24
-rw-r--r--drivers/unix/file_access_unix.h46
-rw-r--r--drivers/unix/ip_unix.cpp45
-rw-r--r--drivers/unix/ip_unix.h3
-rw-r--r--drivers/unix/net_socket_posix.cpp18
-rw-r--r--drivers/unix/net_socket_posix.h6
-rw-r--r--drivers/unix/os_unix.cpp76
-rw-r--r--drivers/unix/os_unix.h18
-rw-r--r--drivers/unix/syslog_logger.cpp2
-rw-r--r--drivers/unix/syslog_logger.h4
-rw-r--r--drivers/unix/thread_posix.h2
-rw-r--r--drivers/vulkan/SCsub9
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp2201
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h167
-rw-r--r--drivers/vulkan/vulkan_context.cpp751
-rw-r--r--drivers/vulkan/vulkan_context.h92
-rw-r--r--drivers/vulkan/vulkan_hooks.h48
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp8
-rw-r--r--drivers/wasapi/audio_driver_wasapi.h1
-rw-r--r--drivers/windows/dir_access_windows.cpp2
-rw-r--r--drivers/windows/dir_access_windows.h38
-rw-r--r--drivers/windows/file_access_windows.cpp16
-rw-r--r--drivers/windows/file_access_windows.h41
-rw-r--r--drivers/winmidi/midi_driver_winmidi.h7
-rw-r--r--drivers/xaudio2/audio_driver_xaudio2.cpp2
-rw-r--r--drivers/xaudio2/audio_driver_xaudio2.h2
88 files changed, 18328 insertions, 10346 deletions
diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp
index 7884269103..f86c4d82ef 100644
--- a/drivers/alsa/audio_driver_alsa.cpp
+++ b/drivers/alsa/audio_driver_alsa.cpp
@@ -181,7 +181,7 @@ Error AudioDriverALSA::init() {
}
void AudioDriverALSA::thread_func(void *p_udata) {
- AudioDriverALSA *ad = (AudioDriverALSA *)p_udata;
+ AudioDriverALSA *ad = static_cast<AudioDriverALSA *>(p_udata);
while (!ad->exit_thread) {
ad->lock();
diff --git a/drivers/alsamidi/midi_driver_alsamidi.cpp b/drivers/alsamidi/midi_driver_alsamidi.cpp
index 0674c90cd6..c334146dd2 100644
--- a/drivers/alsamidi/midi_driver_alsamidi.cpp
+++ b/drivers/alsamidi/midi_driver_alsamidi.cpp
@@ -73,7 +73,7 @@ static int get_message_size(uint8_t message) {
}
void MIDIDriverALSAMidi::thread_func(void *p_udata) {
- MIDIDriverALSAMidi *md = (MIDIDriverALSAMidi *)p_udata;
+ MIDIDriverALSAMidi *md = static_cast<MIDIDriverALSAMidi *>(p_udata);
uint64_t timestamp = 0;
uint8_t buffer[256];
int expected_size = 255;
diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp
index e37a53fede..cc38c2352f 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.cpp
+++ b/drivers/coreaudio/audio_driver_coreaudio.cpp
@@ -38,11 +38,11 @@
#define kOutputBus 0
#define kInputBus 1
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
OSStatus AudioDriverCoreAudio::input_device_address_cb(AudioObjectID inObjectID,
UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses,
void *inClientData) {
- AudioDriverCoreAudio *driver = (AudioDriverCoreAudio *)inClientData;
+ AudioDriverCoreAudio *driver = static_cast<AudioDriverCoreAudio *>(inClientData);
// If our selected device is the Default call set_device to update the
// kAudioOutputUnitProperty_CurrentDevice property
@@ -56,7 +56,7 @@ OSStatus AudioDriverCoreAudio::input_device_address_cb(AudioObjectID inObjectID,
OSStatus AudioDriverCoreAudio::output_device_address_cb(AudioObjectID inObjectID,
UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses,
void *inClientData) {
- AudioDriverCoreAudio *driver = (AudioDriverCoreAudio *)inClientData;
+ AudioDriverCoreAudio *driver = static_cast<AudioDriverCoreAudio *>(inClientData);
// If our selected device is the Default call set_device to update the
// kAudioOutputUnitProperty_CurrentDevice property
@@ -72,7 +72,7 @@ Error AudioDriverCoreAudio::init() {
AudioComponentDescription desc;
memset(&desc, 0, sizeof(desc));
desc.componentType = kAudioUnitType_Output;
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
desc.componentSubType = kAudioUnitSubType_HALOutput;
#else
desc.componentSubType = kAudioUnitSubType_RemoteIO;
@@ -85,7 +85,7 @@ Error AudioDriverCoreAudio::init() {
OSStatus result = AudioComponentInstanceNew(comp, &audio_unit);
ERR_FAIL_COND_V(result != noErr, FAILED);
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
AudioObjectPropertyAddress prop;
prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
prop.mScope = kAudioObjectPropertyScopeGlobal;
@@ -135,7 +135,7 @@ Error AudioDriverCoreAudio::init() {
// 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);
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
result = AudioUnitSetProperty(audio_unit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, kOutputBus, &buffer_frames, sizeof(UInt32));
ERR_FAIL_COND_V(result != noErr, FAILED);
#endif
@@ -168,15 +168,15 @@ OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber, UInt32 inNumberFrames,
AudioBufferList *ioData) {
- AudioDriverCoreAudio *ad = (AudioDriverCoreAudio *)inRefCon;
+ AudioDriverCoreAudio *ad = static_cast<AudioDriverCoreAudio *>(inRefCon);
if (!ad->active || !ad->try_lock()) {
for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) {
AudioBuffer *abuf = &ioData->mBuffers[i];
memset(abuf->mData, 0, abuf->mDataByteSize);
- };
+ }
return 0;
- };
+ }
ad->start_counting_ticks();
@@ -195,21 +195,21 @@ OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon,
frames_left -= frames;
out += frames * ad->channels;
- };
- };
+ }
+ }
ad->stop_counting_ticks();
ad->unlock();
return 0;
-};
+}
OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber, UInt32 inNumberFrames,
AudioBufferList *ioData) {
- AudioDriverCoreAudio *ad = (AudioDriverCoreAudio *)inRefCon;
+ AudioDriverCoreAudio *ad = static_cast<AudioDriverCoreAudio *>(inRefCon);
if (!ad->active) {
return 0;
}
@@ -251,7 +251,7 @@ void AudioDriverCoreAudio::start() {
active = true;
}
}
-};
+}
void AudioDriverCoreAudio::stop() {
if (active) {
@@ -266,19 +266,19 @@ void AudioDriverCoreAudio::stop() {
int AudioDriverCoreAudio::get_mix_rate() const {
return mix_rate;
-};
+}
AudioDriver::SpeakerMode AudioDriverCoreAudio::get_speaker_mode() const {
return get_speaker_mode_by_total_channels(channels);
-};
+}
void AudioDriverCoreAudio::lock() {
mutex.lock();
-};
+}
void AudioDriverCoreAudio::unlock() {
mutex.unlock();
-};
+}
bool AudioDriverCoreAudio::try_lock() {
return mutex.try_lock() == OK;
@@ -313,7 +313,7 @@ void AudioDriverCoreAudio::finish() {
ERR_PRINT("AudioUnitUninitialize failed");
}
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
AudioObjectPropertyAddress prop;
prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
prop.mScope = kAudioObjectPropertyScopeGlobal;
@@ -339,7 +339,7 @@ Error AudioDriverCoreAudio::capture_init() {
AudioComponentDescription desc;
memset(&desc, 0, sizeof(desc));
desc.componentType = kAudioUnitType_Output;
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
desc.componentSubType = kAudioUnitSubType_HALOutput;
#else
desc.componentSubType = kAudioUnitSubType_RemoteIO;
@@ -352,7 +352,7 @@ Error AudioDriverCoreAudio::capture_init() {
OSStatus result = AudioComponentInstanceNew(comp, &input_unit);
ERR_FAIL_COND_V(result != noErr, FAILED);
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
AudioObjectPropertyAddress prop;
prop.mSelector = kAudioHardwarePropertyDefaultInputDevice;
prop.mScope = kAudioObjectPropertyScopeGlobal;
@@ -370,7 +370,7 @@ Error AudioDriverCoreAudio::capture_init() {
ERR_FAIL_COND_V(result != noErr, FAILED);
UInt32 size;
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
AudioDeviceID deviceId;
size = sizeof(AudioDeviceID);
AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
@@ -447,7 +447,7 @@ void AudioDriverCoreAudio::capture_finish() {
ERR_PRINT("AudioUnitUninitialize failed");
}
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
AudioObjectPropertyAddress prop;
prop.mSelector = kAudioHardwarePropertyDefaultInputDevice;
prop.mScope = kAudioObjectPropertyScopeGlobal;
@@ -491,7 +491,7 @@ Error AudioDriverCoreAudio::capture_stop() {
return OK;
}
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
Array AudioDriverCoreAudio::_get_device_list(bool capture) {
Array list;
@@ -521,8 +521,9 @@ Array AudioDriverCoreAudio::_get_device_list(bool capture) {
AudioObjectGetPropertyData(audioDevices[i], &prop, 0, nullptr, &size, bufferList);
UInt32 channelCount = 0;
- for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++)
+ for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++) {
channelCount += bufferList->mBuffers[j].mNumberChannels;
+ }
memfree(bufferList);
@@ -579,8 +580,9 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
AudioObjectGetPropertyData(audioDevices[i], &prop, 0, nullptr, &size, bufferList);
UInt32 channelCount = 0;
- for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++)
+ for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++) {
channelCount += bufferList->mBuffers[j].mNumberChannels;
+ }
memfree(bufferList);
diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h
index b19f133d89..7fac8a99ed 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.h
+++ b/drivers/coreaudio/audio_driver_coreaudio.h
@@ -28,16 +28,16 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef COREAUDIO_ENABLED
-
#ifndef AUDIO_DRIVER_COREAUDIO_H
#define AUDIO_DRIVER_COREAUDIO_H
+#ifdef COREAUDIO_ENABLED
+
#include "servers/audio_server.h"
-#include <AudioUnit/AudioUnit.h>
-#ifdef OSX_ENABLED
-#include <CoreAudio/AudioHardware.h>
+#import <AudioUnit/AudioUnit.h>
+#ifdef MACOS_ENABLED
+#import <CoreAudio/AudioHardware.h>
#endif
class AudioDriverCoreAudio : public AudioDriver {
@@ -58,7 +58,7 @@ class AudioDriverCoreAudio : public AudioDriver {
Vector<int32_t> samples_in;
Vector<int16_t> input_buf;
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
Array _get_device_list(bool capture = false);
void _set_device(const String &device, bool capture = false);
@@ -106,7 +106,7 @@ public:
bool try_lock();
void stop();
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
virtual Array get_device_list();
virtual String get_device();
virtual void set_device(String device);
@@ -120,6 +120,6 @@ public:
~AudioDriverCoreAudio() {}
};
-#endif
+#endif // COREAUDIO_ENABLED
-#endif
+#endif // AUDIO_DRIVER_COREAUDIO_H
diff --git a/drivers/coremidi/midi_driver_coremidi.cpp b/drivers/coremidi/midi_driver_coremidi.cpp
index ecd10f900b..dc69ab9472 100644
--- a/drivers/coremidi/midi_driver_coremidi.cpp
+++ b/drivers/coremidi/midi_driver_coremidi.cpp
@@ -34,8 +34,8 @@
#include "core/string/print_string.h"
-#include <CoreAudio/HostTime.h>
-#include <CoreServices/CoreServices.h>
+#import <CoreAudio/HostTime.h>
+#import <CoreServices/CoreServices.h>
void MIDIDriverCoreMidi::read(const MIDIPacketList *packet_list, void *read_proc_ref_con, void *src_conn_ref_con) {
MIDIPacket *packet = const_cast<MIDIPacket *>(packet_list->packet);
diff --git a/drivers/coremidi/midi_driver_coremidi.h b/drivers/coremidi/midi_driver_coremidi.h
index be0a9f610e..ac2ad99eb3 100644
--- a/drivers/coremidi/midi_driver_coremidi.h
+++ b/drivers/coremidi/midi_driver_coremidi.h
@@ -28,15 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef COREMIDI_ENABLED
-
#ifndef MIDI_DRIVER_COREMIDI_H
#define MIDI_DRIVER_COREMIDI_H
+#ifdef COREMIDI_ENABLED
+
#include "core/os/midi_driver.h"
#include "core/templates/vector.h"
-#include <CoreMIDI/CoreMIDI.h>
+#import <CoreMIDI/CoreMIDI.h>
#include <stdio.h>
class MIDIDriverCoreMidi : public MIDIDriver {
@@ -57,5 +57,6 @@ public:
virtual ~MIDIDriverCoreMidi();
};
-#endif // MIDI_DRIVER_COREMIDI_H
#endif // COREMIDI_ENABLED
+
+#endif // MIDI_DRIVER_COREMIDI_H
diff --git a/drivers/gl_context/SCsub b/drivers/gl_context/SCsub
index ddeec6f4c6..7e8bd22960 100644
--- a/drivers/gl_context/SCsub
+++ b/drivers/gl_context/SCsub
@@ -2,7 +2,7 @@
Import("env")
-if env["platform"] in ["haiku", "osx", "windows", "linuxbsd"]:
+if env["platform"] in ["haiku", "macos", "windows", "linuxbsd"]:
# Thirdparty source files
thirdparty_dir = "#thirdparty/glad/"
thirdparty_sources = [
diff --git a/drivers/gles3/SCsub b/drivers/gles3/SCsub
index 987ddcd16e..506312df80 100644
--- a/drivers/gles3/SCsub
+++ b/drivers/gles3/SCsub
@@ -5,3 +5,6 @@ Import("env")
env.add_source_files(env.drivers_sources, "*.cpp")
SConscript("shaders/SCsub")
+SConscript("storage/SCsub")
+SConscript("effects/SCsub")
+SConscript("environment/SCsub")
diff --git a/drivers/gles3/effects/SCsub b/drivers/gles3/effects/SCsub
new file mode 100644
index 0000000000..91e1140b75
--- /dev/null
+++ b/drivers/gles3/effects/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/gles3/effects/copy_effects.cpp b/drivers/gles3/effects/copy_effects.cpp
new file mode 100644
index 0000000000..de0181f887
--- /dev/null
+++ b/drivers/gles3/effects/copy_effects.cpp
@@ -0,0 +1,165 @@
+/*************************************************************************/
+/* copy_effects.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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. */
+/*************************************************************************/
+
+#ifdef GLES3_ENABLED
+
+#include "copy_effects.h"
+
+using namespace GLES3;
+
+CopyEffects *CopyEffects::singleton = nullptr;
+
+CopyEffects *CopyEffects::get_singleton() {
+ return singleton;
+}
+
+CopyEffects::CopyEffects() {
+ singleton = this;
+
+ copy.shader.initialize();
+ copy.shader_version = copy.shader.version_create();
+ copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_DEFAULT);
+
+ { // Screen Triangle.
+ glGenBuffers(1, &screen_triangle);
+ glBindBuffer(GL_ARRAY_BUFFER, screen_triangle);
+
+ const float qv[6] = {
+ -1.0f,
+ -1.0f,
+ 3.0f,
+ -1.0f,
+ -1.0f,
+ 3.0f,
+ };
+
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, qv, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+
+ glGenVertexArrays(1, &screen_triangle_array);
+ glBindVertexArray(screen_triangle_array);
+ glBindBuffer(GL_ARRAY_BUFFER, screen_triangle);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ }
+
+ { // Screen Quad
+
+ glGenBuffers(1, &quad);
+ glBindBuffer(GL_ARRAY_BUFFER, quad);
+
+ const float qv[12] = {
+ -1.0f,
+ -1.0f,
+ 1.0f,
+ -1.0f,
+ 1.0f,
+ 1.0f,
+ -1.0f,
+ -1.0f,
+ 1.0f,
+ 1.0f,
+ -1.0f,
+ 1.0f,
+ };
+
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 12, qv, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+
+ glGenVertexArrays(1, &quad_array);
+ glBindVertexArray(quad_array);
+ glBindBuffer(GL_ARRAY_BUFFER, quad);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ }
+}
+
+CopyEffects::~CopyEffects() {
+ singleton = nullptr;
+ glDeleteBuffers(1, &screen_triangle);
+ glDeleteVertexArrays(1, &screen_triangle_array);
+ glDeleteBuffers(1, &quad);
+ glDeleteVertexArrays(1, &quad_array);
+ copy.shader.version_free(copy.shader_version);
+}
+
+void CopyEffects::copy_to_rect(const Rect2i &p_rect) {
+ copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION);
+ copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION);
+ glBindVertexArray(quad_array);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ glBindVertexArray(0);
+}
+
+void CopyEffects::copy_screen() {
+ copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_DEFAULT);
+ glBindVertexArray(screen_triangle_array);
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+ glBindVertexArray(0);
+}
+
+void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region) {
+ GLuint framebuffers[2];
+ glGenFramebuffers(2, framebuffers);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]);
+ glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_source_texture, 0);
+
+ Rect2i source_region = p_region;
+ Rect2i dest_region = p_region;
+ for (int i = 1; i < p_mipmap_count; i++) {
+ dest_region.position.x >>= 1;
+ dest_region.position.y >>= 1;
+ dest_region.size.x = MAX(1, dest_region.size.x >> 1);
+ dest_region.size.y = MAX(1, dest_region.size.y >> 1);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[i % 2]);
+ glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_source_texture, i);
+ glBlitFramebuffer(source_region.position.x, source_region.position.y, source_region.size.x, source_region.size.y,
+ dest_region.position.x, dest_region.position.y, dest_region.size.x, dest_region.size.y, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[i % 2]);
+ source_region = dest_region;
+ }
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ glDeleteFramebuffers(2, framebuffers);
+}
+
+void CopyEffects::set_color(const Color &p_color, const Rect2i &p_region) {
+ copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
+ copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_region.position.x, p_region.position.y, p_region.size.x, p_region.size.y, copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
+ copy.shader.version_set_uniform(CopyShaderGLES3::COLOR_IN, p_color, copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
+ glBindVertexArray(quad_array);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ glBindVertexArray(0);
+}
+#endif // GLES3_ENABLED
diff --git a/drivers/gles3/effects/copy_effects.h b/drivers/gles3/effects/copy_effects.h
new file mode 100644
index 0000000000..b863e76579
--- /dev/null
+++ b/drivers/gles3/effects/copy_effects.h
@@ -0,0 +1,74 @@
+/*************************************************************************/
+/* copy_effects.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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 COPY_EFFECTS_GLES3_H
+#define COPY_EFFECTS_GLES3_H
+
+#ifdef GLES3_ENABLED
+
+#include "../shaders/copy.glsl.gen.h"
+
+namespace GLES3 {
+
+class CopyEffects {
+private:
+ struct Copy {
+ CopyShaderGLES3 shader;
+ RID shader_version;
+ } copy;
+
+ static CopyEffects *singleton;
+
+ // Use for full-screen effects. Slightly more efficient than screen_quad as this eliminates pixel overdraw along the diagonal.
+ GLuint screen_triangle = 0;
+ GLuint screen_triangle_array = 0;
+
+ // Use for rect-based effects.
+ GLuint quad = 0;
+ GLuint quad_array = 0;
+
+public:
+ static CopyEffects *get_singleton();
+
+ CopyEffects();
+ ~CopyEffects();
+
+ // These functions assume that a framebuffer and texture are bound already. They only manage the shader, uniforms, and vertex array.
+ void copy_to_rect(const Rect2i &p_rect);
+ void copy_screen();
+ void bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region);
+ void set_color(const Color &p_color, const Rect2i &p_region);
+};
+
+} //namespace GLES3
+
+#endif // GLES3_ENABLED
+
+#endif // COPY_EFFECTS_GLES3_H
diff --git a/drivers/gles3/environment/SCsub b/drivers/gles3/environment/SCsub
new file mode 100644
index 0000000000..91e1140b75
--- /dev/null
+++ b/drivers/gles3/environment/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/gles3/texture_loader_gles3.h b/drivers/gles3/environment/fog.cpp
index 54ddf80a96..02d88f6871 100644
--- a/drivers/gles3/texture_loader_gles3.h
+++ b/drivers/gles3/environment/fog.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* texture_loader_gles3.h */
+/* fog.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,24 +28,39 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef TEXTURE_LOADER_OPENGL_H
-#define TEXTURE_LOADER_OPENGL_H
-
#ifdef GLES3_ENABLED
-#include "core/io/resource_loader.h"
-#include "scene/resources/texture.h"
+#include "fog.h"
-class ResourceFormatGLES2Texture : public ResourceFormatLoader {
-public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
+using namespace GLES3;
- virtual ~ResourceFormatGLES2Texture() {}
-};
+/* FOG */
-#endif // GLES3_ENABLED
+RID Fog::fog_volume_allocate() {
+ return RID();
+}
+
+void Fog::fog_volume_initialize(RID p_rid) {
+}
+
+void Fog::fog_free(RID p_rid) {
+}
+
+void Fog::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) {
+}
-#endif // TEXTURE_LOADER_OPENGL_H
+void Fog::fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) {
+}
+
+void Fog::fog_volume_set_material(RID p_fog_volume, RID p_material) {
+}
+
+AABB Fog::fog_volume_get_aabb(RID p_fog_volume) const {
+ return AABB();
+}
+
+RS::FogVolumeShape Fog::fog_volume_get_shape(RID p_fog_volume) const {
+ return RS::FOG_VOLUME_SHAPE_BOX;
+}
+
+#endif // GLES3_ENABLED
diff --git a/drivers/gles3/environment/fog.h b/drivers/gles3/environment/fog.h
new file mode 100644
index 0000000000..350eb459cf
--- /dev/null
+++ b/drivers/gles3/environment/fog.h
@@ -0,0 +1,62 @@
+/*************************************************************************/
+/* fog.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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 FOG_GLES3_H
+#define FOG_GLES3_H
+
+#ifdef GLES3_ENABLED
+
+#include "core/templates/local_vector.h"
+#include "core/templates/rid_owner.h"
+#include "core/templates/self_list.h"
+#include "servers/rendering/environment/renderer_fog.h"
+
+namespace GLES3 {
+
+class Fog : public RendererFog {
+public:
+ /* FOG VOLUMES */
+
+ virtual RID fog_volume_allocate() override;
+ virtual void fog_volume_initialize(RID p_rid) override;
+ virtual void fog_free(RID p_rid) override;
+
+ virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override;
+ virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) override;
+ virtual void fog_volume_set_material(RID p_fog_volume, RID p_material) override;
+ virtual AABB fog_volume_get_aabb(RID p_fog_volume) const override;
+ virtual RS::FogVolumeShape fog_volume_get_shape(RID p_fog_volume) const override;
+};
+
+} // namespace GLES3
+
+#endif // GLES3_ENABLED
+
+#endif // FOG_GLES3_H
diff --git a/drivers/gles3/environment/gi.cpp b/drivers/gles3/environment/gi.cpp
new file mode 100644
index 0000000000..84cdb81d35
--- /dev/null
+++ b/drivers/gles3/environment/gi.cpp
@@ -0,0 +1,133 @@
+/*************************************************************************/
+/* gi.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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. */
+/*************************************************************************/
+
+#ifdef GLES3_ENABLED
+
+#include "gi.h"
+
+using namespace GLES3;
+
+/* VOXEL GI API */
+
+RID GI::voxel_gi_allocate() {
+ return RID();
+}
+
+void GI::voxel_gi_free(RID p_rid) {
+}
+
+void GI::voxel_gi_initialize(RID p_rid) {
+}
+
+void GI::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) {
+}
+
+AABB GI::voxel_gi_get_bounds(RID p_voxel_gi) const {
+ return AABB();
+}
+
+Vector3i GI::voxel_gi_get_octree_size(RID p_voxel_gi) const {
+ return Vector3i();
+}
+
+Vector<uint8_t> GI::voxel_gi_get_octree_cells(RID p_voxel_gi) const {
+ return Vector<uint8_t>();
+}
+
+Vector<uint8_t> GI::voxel_gi_get_data_cells(RID p_voxel_gi) const {
+ return Vector<uint8_t>();
+}
+
+Vector<uint8_t> GI::voxel_gi_get_distance_field(RID p_voxel_gi) const {
+ return Vector<uint8_t>();
+}
+
+Vector<int> GI::voxel_gi_get_level_counts(RID p_voxel_gi) const {
+ return Vector<int>();
+}
+
+Transform3D GI::voxel_gi_get_to_cell_xform(RID p_voxel_gi) const {
+ return Transform3D();
+}
+
+void GI::voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) {
+}
+
+float GI::voxel_gi_get_dynamic_range(RID p_voxel_gi) const {
+ return 0;
+}
+
+void GI::voxel_gi_set_propagation(RID p_voxel_gi, float p_range) {
+}
+
+float GI::voxel_gi_get_propagation(RID p_voxel_gi) const {
+ return 0;
+}
+
+void GI::voxel_gi_set_energy(RID p_voxel_gi, float p_range) {
+}
+
+float GI::voxel_gi_get_energy(RID p_voxel_gi) const {
+ return 0.0;
+}
+
+void GI::voxel_gi_set_bias(RID p_voxel_gi, float p_range) {
+}
+
+float GI::voxel_gi_get_bias(RID p_voxel_gi) const {
+ return 0.0;
+}
+
+void GI::voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) {
+}
+
+float GI::voxel_gi_get_normal_bias(RID p_voxel_gi) const {
+ return 0.0;
+}
+
+void GI::voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) {
+}
+
+bool GI::voxel_gi_is_interior(RID p_voxel_gi) const {
+ return false;
+}
+
+void GI::voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) {
+}
+
+bool GI::voxel_gi_is_using_two_bounces(RID p_voxel_gi) const {
+ return false;
+}
+
+uint32_t GI::voxel_gi_get_version(RID p_voxel_gi) const {
+ return 0;
+}
+
+#endif // GLES3_ENABLED
diff --git a/drivers/gles3/environment/gi.h b/drivers/gles3/environment/gi.h
new file mode 100644
index 0000000000..7a0634f22b
--- /dev/null
+++ b/drivers/gles3/environment/gi.h
@@ -0,0 +1,96 @@
+/*************************************************************************/
+/* gi.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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 GI_GLES3_H
+#define GI_GLES3_H
+
+#ifdef GLES3_ENABLED
+
+#include "core/templates/local_vector.h"
+#include "core/templates/rid_owner.h"
+#include "core/templates/self_list.h"
+#include "servers/rendering/environment/renderer_gi.h"
+
+#include "platform_config.h"
+#ifndef OPENGL_INCLUDE_H
+#include <GLES3/gl3.h>
+#else
+#include OPENGL_INCLUDE_H
+#endif
+
+namespace GLES3 {
+
+class GI : public RendererGI {
+public:
+ /* VOXEL GI API */
+
+ virtual RID voxel_gi_allocate() override;
+ virtual void voxel_gi_free(RID p_rid) override;
+ virtual void voxel_gi_initialize(RID p_rid) override;
+ virtual void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &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 voxel_gi_get_bounds(RID p_voxel_gi) const override;
+ virtual Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const override;
+ virtual Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const override;
+ virtual Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const override;
+ virtual Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) const override;
+
+ virtual Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const override;
+ virtual Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) const override;
+
+ virtual void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) override;
+ virtual float voxel_gi_get_dynamic_range(RID p_voxel_gi) const override;
+
+ virtual void voxel_gi_set_propagation(RID p_voxel_gi, float p_range) override;
+ virtual float voxel_gi_get_propagation(RID p_voxel_gi) const override;
+
+ virtual void voxel_gi_set_energy(RID p_voxel_gi, float p_range) override;
+ virtual float voxel_gi_get_energy(RID p_voxel_gi) const override;
+
+ virtual void voxel_gi_set_bias(RID p_voxel_gi, float p_range) override;
+ virtual float voxel_gi_get_bias(RID p_voxel_gi) const override;
+
+ virtual void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) override;
+ virtual float voxel_gi_get_normal_bias(RID p_voxel_gi) const override;
+
+ virtual void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) override;
+ virtual bool voxel_gi_is_interior(RID p_voxel_gi) const override;
+
+ virtual void voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) override;
+ virtual bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const override;
+
+ virtual uint32_t voxel_gi_get_version(RID p_voxel_gi) const override;
+};
+
+}; // namespace GLES3
+
+#endif // GLES3_ENABLED
+
+#endif // GI_GLES3_H
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 451960d772..83154acd51 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -34,10 +34,13 @@
#include "core/os/os.h"
#include "rasterizer_scene_gles3.h"
-#include "rasterizer_storage_gles3.h"
#include "core/config/project_settings.h"
#include "servers/rendering/rendering_server_default.h"
+#include "storage/config.h"
+#include "storage/material_storage.h"
+#include "storage/mesh_storage.h"
+#include "storage/texture_storage.h"
#ifndef GLES_OVER_GL
#define glClearDepth glClearDepthf
@@ -54,57 +57,57 @@
//};
void RasterizerCanvasGLES3::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) {
- p_mat4[0] = p_transform.elements[0][0];
- p_mat4[1] = p_transform.elements[0][1];
+ p_mat4[0] = p_transform.columns[0][0];
+ p_mat4[1] = p_transform.columns[0][1];
p_mat4[2] = 0;
p_mat4[3] = 0;
- p_mat4[4] = p_transform.elements[1][0];
- p_mat4[5] = p_transform.elements[1][1];
+ p_mat4[4] = p_transform.columns[1][0];
+ p_mat4[5] = p_transform.columns[1][1];
p_mat4[6] = 0;
p_mat4[7] = 0;
p_mat4[8] = 0;
p_mat4[9] = 0;
p_mat4[10] = 1;
p_mat4[11] = 0;
- p_mat4[12] = p_transform.elements[2][0];
- p_mat4[13] = p_transform.elements[2][1];
+ p_mat4[12] = p_transform.columns[2][0];
+ p_mat4[13] = p_transform.columns[2][1];
p_mat4[14] = 0;
p_mat4[15] = 1;
}
void RasterizerCanvasGLES3::_update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4) {
- p_mat2x4[0] = p_transform.elements[0][0];
- p_mat2x4[1] = p_transform.elements[1][0];
+ p_mat2x4[0] = p_transform.columns[0][0];
+ p_mat2x4[1] = p_transform.columns[1][0];
p_mat2x4[2] = 0;
- p_mat2x4[3] = p_transform.elements[2][0];
+ p_mat2x4[3] = p_transform.columns[2][0];
- p_mat2x4[4] = p_transform.elements[0][1];
- p_mat2x4[5] = p_transform.elements[1][1];
+ p_mat2x4[4] = p_transform.columns[0][1];
+ p_mat2x4[5] = p_transform.columns[1][1];
p_mat2x4[6] = 0;
- p_mat2x4[7] = p_transform.elements[2][1];
+ p_mat2x4[7] = p_transform.columns[2][1];
}
void RasterizerCanvasGLES3::_update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3) {
- p_mat2x3[0] = p_transform.elements[0][0];
- p_mat2x3[1] = p_transform.elements[0][1];
- p_mat2x3[2] = p_transform.elements[1][0];
- p_mat2x3[3] = p_transform.elements[1][1];
- p_mat2x3[4] = p_transform.elements[2][0];
- p_mat2x3[5] = p_transform.elements[2][1];
+ p_mat2x3[0] = p_transform.columns[0][0];
+ p_mat2x3[1] = p_transform.columns[0][1];
+ p_mat2x3[2] = p_transform.columns[1][0];
+ p_mat2x3[3] = p_transform.columns[1][1];
+ p_mat2x3[4] = p_transform.columns[2][0];
+ p_mat2x3[5] = p_transform.columns[2][1];
}
void RasterizerCanvasGLES3::_update_transform_to_mat4(const Transform3D &p_transform, float *p_mat4) {
- p_mat4[0] = p_transform.basis.elements[0][0];
- p_mat4[1] = p_transform.basis.elements[1][0];
- p_mat4[2] = p_transform.basis.elements[2][0];
+ p_mat4[0] = p_transform.basis.rows[0][0];
+ p_mat4[1] = p_transform.basis.rows[1][0];
+ p_mat4[2] = p_transform.basis.rows[2][0];
p_mat4[3] = 0;
- p_mat4[4] = p_transform.basis.elements[0][1];
- p_mat4[5] = p_transform.basis.elements[1][1];
- p_mat4[6] = p_transform.basis.elements[2][1];
+ p_mat4[4] = p_transform.basis.rows[0][1];
+ p_mat4[5] = p_transform.basis.rows[1][1];
+ p_mat4[6] = p_transform.basis.rows[2][1];
p_mat4[7] = 0;
- p_mat4[8] = p_transform.basis.elements[0][2];
- p_mat4[9] = p_transform.basis.elements[1][2];
- p_mat4[10] = p_transform.basis.elements[2][2];
+ p_mat4[8] = p_transform.basis.rows[0][2];
+ p_mat4[9] = p_transform.basis.rows[1][2];
+ p_mat4[10] = p_transform.basis.rows[2][2];
p_mat4[11] = 0;
p_mat4[12] = p_transform.origin.x;
p_mat4[13] = p_transform.origin.y;
@@ -113,12 +116,14 @@ void RasterizerCanvasGLES3::_update_transform_to_mat4(const Transform3D &p_trans
}
void RasterizerCanvasGLES3::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) {
- storage->frame.current_rt = nullptr;
-
- storage->_set_current_render_target(p_to_render_target);
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
Transform2D canvas_transform_inverse = p_canvas_transform.affine_inverse();
+ // Clear out any state that may have been left from the 3D pass.
+ reset_canvas();
+
// TODO: Setup Directional Lights
// TODO: Setup lights
@@ -127,18 +132,18 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
//update canvas state uniform buffer
StateBuffer state_buffer;
- Size2i ssize = storage->render_target_get_size(p_to_render_target);
+ Size2i ssize = texture_storage->render_target_get_size(p_to_render_target);
Transform3D screen_transform;
- screen_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f);
+ screen_transform.translate_local(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f);
screen_transform.scale(Vector3(2.0f / ssize.width, 2.0f / ssize.height, 1.0f));
_update_transform_to_mat4(screen_transform, state_buffer.screen_transform);
_update_transform_2d_to_mat4(p_canvas_transform, state_buffer.canvas_transform);
Transform2D normal_transform = p_canvas_transform;
- normal_transform.elements[0].normalize();
- normal_transform.elements[1].normalize();
- normal_transform.elements[2] = Vector2();
+ normal_transform.columns[0].normalize();
+ normal_transform.columns[1].normalize();
+ normal_transform.columns[2] = Vector2();
_update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform);
state_buffer.canvas_modulate[0] = p_modulate.r;
@@ -146,11 +151,14 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
state_buffer.canvas_modulate[2] = p_modulate.b;
state_buffer.canvas_modulate[3] = p_modulate.a;
- Size2 render_target_size = storage->render_target_get_size(p_to_render_target);
+ Size2 render_target_size = texture_storage->render_target_get_size(p_to_render_target);
state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x;
state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y;
- state_buffer.time = storage->frame.time;
+ // TODO: temporary, this should be set at the top of this function
+ glViewport(0, 0, render_target_size.x, render_target_size.y);
+
+ state_buffer.time = state.time;
state_buffer.use_pixel_snap = p_snap_2d_vertices_to_pixel;
state_buffer.directional_light_count = 0; //directional_light_count;
@@ -163,7 +171,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
state_buffer.screen_to_sdf[0] = 1.0 / state_buffer.sdf_to_screen[0];
state_buffer.screen_to_sdf[1] = 1.0 / state_buffer.sdf_to_screen[1];
- Rect2 sdf_rect = storage->render_target_get_sdf_rect(p_to_render_target);
+ Rect2 sdf_rect = texture_storage->render_target_get_sdf_rect(p_to_render_target);
Rect2 sdf_tex_rect(sdf_rect.position / canvas_scale, sdf_rect.size / canvas_scale);
state_buffer.sdf_to_tex[0] = 1.0 / sdf_tex_rect.size.width;
@@ -171,10 +179,13 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
state_buffer.sdf_to_tex[2] = -sdf_tex_rect.position.x / sdf_tex_rect.size.width;
state_buffer.sdf_to_tex[3] = -sdf_tex_rect.position.y / sdf_tex_rect.size.height;
- //print_line("w: " + itos(ssize.width) + " s: " + rtos(canvas_scale));
state_buffer.tex_to_sdf = 1.0 / ((canvas_scale.x + canvas_scale.y) * 0.5);
- glBindBufferBase(GL_UNIFORM_BUFFER, 0, state.canvas_state_buffer);
+ glBindBufferBase(GL_UNIFORM_BUFFER, BASE_UNIFORM_LOCATION, state.canvas_state_buffer);
glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), &state_buffer, GL_STREAM_DRAW);
+
+ GLuint global_buffer = material_storage->global_shader_uniforms_get_uniform_buffer();
+
+ glBindBufferBase(GL_UNIFORM_BUFFER, GLOBAL_UNIFORM_LOCATION, global_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
@@ -183,19 +194,100 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
state.default_repeat = p_default_repeat;
}
- state.current_tex = RID();
- state.current_tex_ptr = nullptr;
- state.current_normal = RID();
- state.current_specular = RID();
- state.canvas_texscreen_used = false;
-
r_sdf_used = false;
int item_count = 0;
+ bool backbuffer_cleared = false;
+ bool time_used = false;
+ bool material_screen_texture_found = false;
+ Rect2 back_buffer_rect;
+ bool backbuffer_copy = false;
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex);
Item *ci = p_item_list;
+ Item *canvas_group_owner = nullptr;
+
while (ci) {
+ if (ci->copy_back_buffer && canvas_group_owner == nullptr) {
+ backbuffer_copy = true;
+
+ if (ci->copy_back_buffer->full) {
+ back_buffer_rect = Rect2();
+ } else {
+ back_buffer_rect = ci->copy_back_buffer->rect;
+ }
+ }
+
+ // Check material for something that may change flow of rendering, but do not bind for now.
+ RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material;
+ if (material.is_valid()) {
+ GLES3::CanvasMaterialData *md = static_cast<GLES3::CanvasMaterialData *>(material_storage->material_get_data(material, RS::SHADER_CANVAS_ITEM));
+ if (md && md->shader_data->valid) {
+ if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) {
+ if (!material_screen_texture_found) {
+ backbuffer_copy = true;
+ back_buffer_rect = Rect2();
+ }
+ }
+
+ if (md->shader_data->uses_sdf) {
+ r_sdf_used = true;
+ }
+ if (md->shader_data->uses_time) {
+ time_used = true;
+ }
+ }
+ }
+
+ if (ci->canvas_group_owner != nullptr) {
+ if (canvas_group_owner == nullptr) {
+ // Canvas group begins here, render until before this item
+
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
+ item_count = 0;
+
+ Rect2i group_rect = ci->canvas_group_owner->global_rect_cache;
+
+ if (ci->canvas_group_owner->canvas_group->mode == RS::CANVAS_GROUP_MODE_OPAQUE) {
+ texture_storage->render_target_copy_to_back_buffer(p_to_render_target, group_rect, false);
+ } else if (!backbuffer_cleared) {
+ texture_storage->render_target_clear_back_buffer(p_to_render_target, Rect2i(), Color(0, 0, 0, 0));
+ backbuffer_cleared = true;
+ }
+
+ backbuffer_copy = false;
+ canvas_group_owner = ci->canvas_group_owner; //continue until owner found
+ }
+
+ ci->canvas_group_owner = nullptr; //must be cleared
+ }
+
+ if (!backbuffer_cleared && canvas_group_owner == nullptr && ci->canvas_group != nullptr && !backbuffer_copy) {
+ texture_storage->render_target_clear_back_buffer(p_to_render_target, Rect2i(), Color(0, 0, 0, 0));
+ backbuffer_cleared = true;
+ }
+
+ if (ci == canvas_group_owner) {
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, true);
+ item_count = 0;
+
+ if (ci->canvas_group->blur_mipmaps) {
+ texture_storage->render_target_gen_back_buffer_mipmaps(p_to_render_target, ci->global_rect_cache);
+ }
+
+ canvas_group_owner = nullptr;
+ }
+
+ if (backbuffer_copy) {
+ //render anything pending, including clearing if no items
+
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
+ item_count = 0;
+
+ texture_storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, true);
+
+ backbuffer_copy = false;
+ material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies
+ }
+
// just add all items for now
items[item_count++] = ci;
@@ -207,118 +299,155 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
ci = ci->next;
}
+
+ if (time_used) {
+ RenderingServerDefault::redraw_request();
+ }
+
+ // Clear out state used in 2D pass
+ reset_canvas();
}
void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
Item *current_clip = nullptr;
Transform2D canvas_transform_inverse = p_canvas_transform_inverse;
- RID framebuffer;
- Vector<Color> clear_colors;
-
- canvas_begin();
+ canvas_begin(p_to_render_target, p_to_backbuffer);
RID prev_material;
uint32_t index = 0;
+ GLES3::CanvasShaderData::BlendMode last_blend_mode = GLES3::CanvasShaderData::BLEND_MODE_MIX;
+ GLES3::CanvasShaderData *shader_data_cache = nullptr;
+
+ state.current_tex = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE);
+ state.current_tex_ptr = nullptr;
+ state.current_normal = RID();
+ state.current_specular = RID();
+ state.canvas_texscreen_used = false;
+ state.current_shader_version = state.canvas_shader_default_version;
for (int i = 0; i < p_item_count; i++) {
Item *ci = items[i];
+ if (current_clip != ci->final_clip_owner) {
+ _render_batch(index);
+
+ current_clip = ci->final_clip_owner;
+ //setup clip
+ if (current_clip) {
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(current_clip->final_clip_rect.position.x, current_clip->final_clip_rect.position.y, current_clip->final_clip_rect.size.x, current_clip->final_clip_rect.size.y);
+ } else {
+ glDisable(GL_SCISSOR_TEST);
+ }
+ }
+
RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material;
- RasterizerStorageGLES3::Material *material_ptr = storage->material_owner.get_or_null(material);
if (material.is_null() && ci->canvas_group != nullptr) {
material = default_canvas_group_material;
}
if (material != prev_material) {
- RasterizerStorageGLES3::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.
- }
+ _render_batch(index);
+ GLES3::CanvasMaterialData *material_data = nullptr;
+ if (material.is_valid()) {
+ material_data = static_cast<GLES3::CanvasMaterialData *>(material_storage->material_get_data(material, RS::SHADER_CANVAS_ITEM));
}
-
- if (shader_ptr) {
- if (true) { //check that shader has changed
- if (shader_ptr->canvas_item.uses_time) {
- RenderingServerDefault::redraw_request();
- }
- //state.canvas_shader.version_bind_shader(shader_ptr->version, CanvasShaderGLES3::MODE_QUAD);
- state.current_shader_version = shader_ptr->version;
+ if (material_data) {
+ if (material_data->shader_data->version.is_valid() && material_data->shader_data->valid) {
+ // Bind uniform buffer and textures
+ material_data->bind_uniforms();
+ state.current_shader_version = material_data->shader_data->version;
+ shader_data_cache = material_data->shader_data;
+ } else {
+ state.current_shader_version = state.canvas_shader_default_version;
+ shader_data_cache = nullptr;
}
+ } else {
+ state.current_shader_version = state.canvas_shader_default_version;
+ shader_data_cache = nullptr;
+ }
+ prev_material = material;
+ }
- int tc = material_ptr->textures.size();
- Pair<StringName, RID> *textures = material_ptr->textures.ptrw();
-
- ShaderCompiler::GeneratedCode::Texture *texture_uniforms = shader_ptr->texture_uniforms.ptrw();
-
- for (int ti = 0; ti < tc; i++) {
- glActiveTexture(GL_TEXTURE0 + ti);
-
- RasterizerStorageGLES3::Texture *t = storage->texture_owner.get_or_null(textures[ti].second);
-
- if (!t) {
- switch (texture_uniforms[i].hint) {
- 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_ANISOTROPY: {
- 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;
- }
+ GLES3::CanvasShaderData::BlendMode blend_mode = shader_data_cache ? shader_data_cache->blend_mode : GLES3::CanvasShaderData::BLEND_MODE_MIX;
- continue;
- }
+ if (last_blend_mode != blend_mode) {
+ if (last_blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) {
+ // re-enable it
+ glEnable(GL_BLEND);
+ } else if (blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) {
+ // disable it
+ glDisable(GL_BLEND);
+ }
- //Set texture filter and repeat texture_uniforms[i].filter texture_uniforms[i].repeat
+ switch (blend_mode) {
+ case GLES3::CanvasShaderData::BLEND_MODE_DISABLED: {
+ // Nothing to do here.
- if (t->redraw_if_visible) {
- RenderingServerDefault::redraw_request();
+ } break;
+ case GLES3::CanvasShaderData::BLEND_MODE_MIX: {
+ glBlendEquation(GL_FUNC_ADD);
+ if (state.transparent_render_target) {
+ 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);
}
- t = t->get_ptr();
+ } break;
+ case GLES3::CanvasShaderData::BLEND_MODE_ADD: {
+ glBlendEquation(GL_FUNC_ADD);
+ if (state.transparent_render_target) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE);
+ } else {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
+ }
-#ifdef TOOLS_ENABLED
- if (t->detect_normal && texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL) {
- t->detect_normal(t->detect_normal_ud);
+ } break;
+ case GLES3::CanvasShaderData::BLEND_MODE_SUB: {
+ glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
+ if (state.transparent_render_target) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE);
+ } else {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
}
-#endif
- if (t->render_target) {
- t->render_target->used_in_frame = true;
+ } break;
+ case GLES3::CanvasShaderData::BLEND_MODE_MUL: {
+ glBlendEquation(GL_FUNC_ADD);
+ if (state.transparent_render_target) {
+ glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO);
+ } else {
+ glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE);
}
- glBindTexture(t->target, t->tex_id);
- }
+ } break;
+ case GLES3::CanvasShaderData::BLEND_MODE_PMALPHA: {
+ glBlendEquation(GL_FUNC_ADD);
+ if (state.transparent_render_target) {
+ 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);
+ }
- } else {
- //state.canvas_shader.version_bind_shader(state.canvas_shader_default_version, CanvasShaderGLES3::MODE_QUAD);
- state.current_shader_version = state.canvas_shader_default_version;
+ } break;
}
- prev_material = material;
+ last_blend_mode = blend_mode;
}
_render_item(p_to_render_target, ci, canvas_transform_inverse, current_clip, p_lights, index);
}
// Render last command
- state.end_batch = true;
_render_batch(index);
-
- canvas_end();
}
void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, uint32_t &r_index) {
+ // Used by Polygon and Mesh.
+ static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP };
+
RS::CanvasItemTextureFilter current_filter = state.default_filter;
RS::CanvasItemTextureRepeat current_repeat = state.default_repeat;
@@ -337,8 +466,7 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
uint32_t base_flags = 0;
- RID last_texture;
- Size2 texpixel_size;
+ bool reclip = false;
bool skipping = false;
@@ -349,7 +477,10 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
continue;
}
- _update_transform_2d_to_mat2x3(base_transform * draw_transform, state.instance_data_array[r_index].world);
+ if (c->type != Item::Command::TYPE_MESH) {
+ // For Meshes, this gets updated below.
+ _update_transform_2d_to_mat2x3(base_transform * draw_transform, state.instance_data_array[r_index].world);
+ }
for (int i = 0; i < 4; i++) {
state.instance_data_array[r_index].modulation[i] = 0.0;
@@ -358,7 +489,6 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
state.instance_data_array[r_index].dst_rect[i] = 0.0;
state.instance_data_array[r_index].lights[i] = uint32_t(0);
}
- state.instance_data_array[r_index].flags = base_flags;
state.instance_data_array[r_index].color_texture_pixel_size[0] = 0.0;
state.instance_data_array[r_index].color_texture_pixel_size[1] = 0.0;
@@ -375,21 +505,20 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
current_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED;
}
- if (rect->texture != last_texture || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_RECT) {
- state.end_batch = true;
+ if (rect->texture != state.current_tex || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_RECT) {
_render_batch(r_index);
state.current_primitive_points = 0;
state.current_command = Item::Command::TYPE_RECT;
}
- _bind_canvas_texture(rect->texture, current_filter, current_repeat, r_index, last_texture, texpixel_size);
- state.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_QUAD);
+ _bind_canvas_texture(rect->texture, current_filter, current_repeat, r_index);
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_QUAD);
Rect2 src_rect;
Rect2 dst_rect;
if (rect->texture != RID()) {
- src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * texpixel_size, rect->source.size * texpixel_size) : Rect2(0, 0, 1, 1);
+ src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * state.current_pixel_size, rect->source.size * state.current_pixel_size) : Rect2(0, 0, 1, 1);
dst_rect = Rect2(rect->rect.position, rect->rect.size);
if (dst_rect.size.width < 0) {
@@ -454,39 +583,37 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
state.instance_data_array[r_index].dst_rect[1] = dst_rect.position.y;
state.instance_data_array[r_index].dst_rect[2] = dst_rect.size.width;
state.instance_data_array[r_index].dst_rect[3] = dst_rect.size.height;
- //_render_batch(r_index);
+
r_index++;
if (r_index >= state.max_instances_per_batch - 1) {
- //r_index--;
- state.end_batch = true;
_render_batch(r_index);
}
} break;
case Item::Command::TYPE_NINEPATCH: {
- /*
const Item::CommandNinePatch *np = static_cast<const Item::CommandNinePatch *>(c);
- //bind pipeline
- {
- RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_NINEPATCH].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
- RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
+ if (np->texture != state.current_tex || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_NINEPATCH) {
+ _render_batch(r_index);
+
+ state.current_primitive_points = 0;
+ state.current_command = Item::Command::TYPE_NINEPATCH;
}
//bind textures
-
- _bind_canvas_texture(p_draw_list, np->texture, current_filter, current_repeat, index, last_texture, texpixel_size);
+ _bind_canvas_texture(np->texture, current_filter, current_repeat, r_index);
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_NINEPATCH);
Rect2 src_rect;
Rect2 dst_rect(np->rect.position.x, np->rect.position.y, np->rect.size.x, np->rect.size.y);
if (np->texture == RID()) {
- texpixel_size = Size2(1, 1);
+ state.current_pixel_size = Size2(1, 1);
src_rect = Rect2(0, 0, 1, 1);
} else {
if (np->source != Rect2()) {
- src_rect = Rect2(np->source.position.x * texpixel_size.width, np->source.position.y * texpixel_size.height, np->source.size.x * texpixel_size.width, np->source.size.y * texpixel_size.height);
+ src_rect = Rect2(np->source.position.x * state.current_pixel_size.width, np->source.position.y * state.current_pixel_size.height, np->source.size.x * state.current_pixel_size.width, np->source.size.y * state.current_pixel_size.height);
state.instance_data_array[r_index].color_texture_pixel_size[0] = 1.0 / np->source.size.width;
state.instance_data_array[r_index].color_texture_pixel_size[1] = 1.0 / np->source.size.height;
@@ -522,14 +649,14 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
state.instance_data_array[r_index].ninepatch_margins[2] = np->margin[SIDE_RIGHT];
state.instance_data_array[r_index].ninepatch_margins[3] = np->margin[SIDE_BOTTOM];
- RD::get_singleton()->draw_list_set_state.instance_data_array[r_index](p_draw_list, &state.instance_data_array[r_index], sizeof(PushConstant));
- RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);
- RD::get_singleton()->draw_list_draw(p_draw_list, true);
+ r_index++;
+ if (r_index >= state.max_instances_per_batch - 1) {
+ _render_batch(r_index);
+ }
// Restore if overridden.
- state.instance_data_array[r_index].color_texture_pixel_size[0] = texpixel_size.x;
- state.instance_data_array[r_index].color_texture_pixel_size[1] = texpixel_size.y;
-*/
+ state.instance_data_array[r_index].color_texture_pixel_size[0] = state.current_pixel_size.x;
+ state.instance_data_array[r_index].color_texture_pixel_size[1] = state.current_pixel_size.y;
} break;
case Item::Command::TYPE_POLYGON: {
@@ -538,15 +665,14 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
PolygonBuffers *pb = polygon_buffers.polygons.getptr(polygon->polygon.polygon_id);
ERR_CONTINUE(!pb);
- if (polygon->texture != last_texture || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_POLYGON) {
- state.end_batch = true;
+ if (polygon->texture != state.current_tex || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_POLYGON) {
_render_batch(r_index);
state.current_primitive_points = 0;
state.current_command = Item::Command::TYPE_POLYGON;
}
- _bind_canvas_texture(polygon->texture, current_filter, current_repeat, r_index, last_texture, texpixel_size);
- state.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_ATTRIBUTES);
+ _bind_canvas_texture(polygon->texture, current_filter, current_repeat, r_index);
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_ATTRIBUTES);
state.current_primitive = polygon->primitive;
state.instance_data_array[r_index].modulation[0] = base_color.r;
@@ -560,27 +686,12 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
state.instance_data_array[r_index].ninepatch_margins[j] = 0;
}
- // If the previous operation is not done yet, allocated a new buffer
- GLint syncStatus;
- glGetSynciv(state.fences[state.current_buffer], GL_SYNC_STATUS, sizeof(GLint), nullptr, &syncStatus);
- if (syncStatus == GL_UNSIGNALED) {
- _allocate_instance_data_buffer();
- } else {
- glDeleteSync(state.fences[state.current_buffer]);
- }
-
- glBindBufferBase(GL_UNIFORM_BUFFER, 3, state.canvas_instance_data_buffers[state.current_buffer]);
-#ifdef JAVASCRIPT_ENABLED
- //WebGL 2.0 does not support mapping buffers, so use slow glBufferData instead
- glBufferData(GL_UNIFORM_BUFFER, sizeof(InstanceData), &state.instance_data_array[0], GL_DYNAMIC_DRAW);
-#else
- void *ubo = glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(InstanceData), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
- memcpy(ubo, &state.instance_data_array[0], sizeof(InstanceData));
- glUnmapBuffer(GL_UNIFORM_BUFFER);
-#endif
+ _bind_instance_data_buffer(1);
glBindVertexArray(pb->vertex_array);
- static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP };
+ if (pb->color_disabled) {
+ glVertexAttrib4f(RS::ARRAY_COLOR, pb->color.r, pb->color.g, pb->color.b, pb->color.a);
+ }
if (pb->index_buffer != 0) {
glDrawElements(prim[polygon->primitive], pb->count, GL_UNSIGNED_INT, nullptr);
@@ -591,21 +702,25 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
state.fences[state.current_buffer] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
state.current_buffer = (state.current_buffer + 1) % state.canvas_instance_data_buffers.size();
+
+ if (pb->color_disabled) {
+ // Reset so this doesn't pollute other draw calls.
+ glVertexAttrib4f(RS::ARRAY_COLOR, 1.0, 1.0, 1.0, 1.0);
+ }
} break;
case Item::Command::TYPE_PRIMITIVE: {
const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c);
- if (last_texture != default_canvas_texture || state.current_primitive_points != primitive->point_count || state.current_command != Item::Command::TYPE_PRIMITIVE) {
- state.end_batch = true;
+ if (state.current_primitive_points != primitive->point_count || state.current_command != Item::Command::TYPE_PRIMITIVE) {
_render_batch(r_index);
state.current_primitive_points = primitive->point_count;
state.current_command = Item::Command::TYPE_PRIMITIVE;
}
- _bind_canvas_texture(RID(), current_filter, current_repeat, r_index, last_texture, texpixel_size);
- state.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_PRIMITIVE);
+ _bind_canvas_texture(RID(), current_filter, current_repeat, r_index);
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_PRIMITIVE);
- for (uint32_t j = 0; j < MIN(3, primitive->point_count); j++) {
+ for (uint32_t j = 0; j < MIN(3u, primitive->point_count); j++) {
state.instance_data_array[r_index].points[j * 2 + 0] = primitive->points[j].x;
state.instance_data_array[r_index].points[j * 2 + 1] = primitive->points[j].y;
state.instance_data_array[r_index].uvs[j * 2 + 0] = primitive->uvs[j].x;
@@ -636,8 +751,6 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
r_index++;
}
if (r_index >= state.max_instances_per_batch - 1) {
- //r_index--;
- state.end_batch = true;
_render_batch(r_index);
}
} break;
@@ -645,12 +758,17 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
case Item::Command::TYPE_MESH:
case Item::Command::TYPE_MULTIMESH:
case Item::Command::TYPE_PARTICLES: {
- /*
+ GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
RID mesh;
RID mesh_instance;
RID texture;
Color modulate(1, 1, 1, 1);
- int instance_count = 1;
+ uint32_t instance_count = 1;
+ GLuint multimesh_buffer = 0;
+ uint32_t multimesh_stride = 0;
+ uint32_t multimesh_color_offset = 0;
+ bool multimesh_uses_color = false;
+ bool multimesh_uses_custom_data = false;
if (c->type == Item::Command::TYPE_MESH) {
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
@@ -662,26 +780,24 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
} else if (c->type == Item::Command::TYPE_MULTIMESH) {
const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c);
RID multimesh = mm->multimesh;
- mesh = storage->multimesh_get_mesh(multimesh);
+ mesh = mesh_storage->multimesh_get_mesh(multimesh);
texture = mm->texture;
- if (storage->multimesh_get_transform_format(multimesh) != RS::MULTIMESH_TRANSFORM_2D) {
+ if (mesh_storage->multimesh_get_transform_format(multimesh) != RS::MULTIMESH_TRANSFORM_2D) {
break;
}
- instance_count = storage->multimesh_get_instances_to_draw(multimesh);
+ instance_count = mesh_storage->multimesh_get_instances_to_draw(multimesh);
if (instance_count == 0) {
break;
}
- state.instance_data_array[r_index].flags |= 1; //multimesh, trails disabled
- if (storage->multimesh_uses_colors(multimesh)) {
- state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_COLORS;
- }
- if (storage->multimesh_uses_custom_data(multimesh)) {
- state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
- }
+ multimesh_buffer = mesh_storage->multimesh_get_gl_buffer(multimesh);
+ multimesh_stride = mesh_storage->multimesh_get_stride(multimesh);
+ multimesh_color_offset = mesh_storage->multimesh_get_color_offset(multimesh);
+ multimesh_uses_color = mesh_storage->multimesh_uses_colors(multimesh);
+ multimesh_uses_custom_data = mesh_storage->multimesh_uses_custom_data(multimesh);
}
// TODO: implement particles here
@@ -690,16 +806,20 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
break;
}
- if (texture != last_texture || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_PRIMITIVE) {
- state.end_batch = true;
+ if (texture != state.current_tex || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_PRIMITIVE) {
_render_batch(r_index);
state.current_primitive_points = 0;
state.current_command = c->type;
}
- _bind_canvas_texture(texture, current_filter, current_repeat, r_index, last_texture, texpixel_size);
+ _bind_canvas_texture(texture, current_filter, current_repeat, r_index);
+ if (instance_count == 1) {
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_ATTRIBUTES);
+ } else {
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_INSTANCED);
+ }
- uint32_t surf_count = storage->mesh_get_surface_count(mesh);
+ uint32_t surf_count = mesh_storage->mesh_get_surface_count(mesh);
state.instance_data_array[r_index].modulation[0] = base_color.r * modulate.r;
state.instance_data_array[r_index].modulation[1] = base_color.g * modulate.g;
@@ -711,19 +831,74 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
state.instance_data_array[r_index].dst_rect[j] = 0;
state.instance_data_array[r_index].ninepatch_margins[j] = 0;
}
-
+ _bind_instance_data_buffer(1);
for (uint32_t j = 0; j < surf_count; j++) {
- RS::SurfaceData *surface = storage->mesh_get_surface(mesh, j);
+ void *surface = mesh_storage->mesh_get_surface(mesh, j);
- RS::PrimitiveType primitive = storage->mesh_surface_get_primitive(surface);
+ RS::PrimitiveType primitive = mesh_storage->mesh_surface_get_primitive(surface);
ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX);
- glBindVertexArray(surface->vertex_array);
- static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP };
+ GLuint vertex_array_gl = 0;
+ GLuint index_array_gl = 0;
+
+ uint32_t input_mask = 0; // 2D meshes always use the same vertex format
+ if (mesh_instance.is_valid()) {
+ mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, vertex_array_gl);
+ } else {
+ mesh_storage->mesh_surface_get_vertex_arrays_and_format(surface, input_mask, vertex_array_gl);
+ }
- // Draw directly, no need to batch
+ index_array_gl = mesh_storage->mesh_surface_get_index_buffer(surface, 0);
+ bool use_index_buffer = false;
+ glBindVertexArray(vertex_array_gl);
+ if (index_array_gl != 0) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_gl);
+ use_index_buffer = true;
+ }
+
+ if (instance_count > 1) {
+ // Bind instance buffers.
+ glBindBuffer(GL_ARRAY_BUFFER, multimesh_buffer);
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0));
+ glVertexAttribDivisor(1, 1);
+ glEnableVertexAttribArray(2);
+ glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 4));
+ glVertexAttribDivisor(2, 1);
+
+ if (multimesh_uses_color || multimesh_uses_custom_data) {
+ glEnableVertexAttribArray(5);
+ glVertexAttribIPointer(5, 4, GL_UNSIGNED_INT, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(multimesh_color_offset * sizeof(float)));
+ glVertexAttribDivisor(5, 1);
+ }
+ }
+
+ GLenum primitive_gl = prim[int(primitive)];
+ if (instance_count == 1) {
+ if (use_index_buffer) {
+ glDrawElements(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), mesh_storage->mesh_surface_get_index_type(surface), 0);
+ } else {
+ glDrawArrays(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(surface));
+ }
+ } else {
+ if (use_index_buffer) {
+ glDrawElementsInstanced(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), mesh_storage->mesh_surface_get_index_type(surface), 0, instance_count);
+ } else {
+ glDrawArraysInstanced(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), instance_count);
+ }
+ }
+
+ state.fences[state.current_buffer] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+
+ state.current_buffer = (state.current_buffer + 1) % state.canvas_instance_data_buffers.size();
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ if (instance_count > 1) {
+ glDisableVertexAttribArray(5);
+ glDisableVertexAttribArray(6);
+ glDisableVertexAttribArray(7);
+ glDisableVertexAttribArray(8);
+ }
}
- */
} break;
case Item::Command::TYPE_TRANSFORM: {
const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c);
@@ -731,20 +906,19 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
} break;
case Item::Command::TYPE_CLIP_IGNORE: {
- /*
const Item::CommandClipIgnore *ci = static_cast<const Item::CommandClipIgnore *>(c);
if (current_clip) {
if (ci->ignore != reclip) {
if (ci->ignore) {
- RD::get_singleton()->draw_list_disable_scissor(p_draw_list);
+ glDisable(GL_SCISSOR_TEST);
reclip = true;
} else {
- RD::get_singleton()->draw_list_enable_scissor(p_draw_list, current_clip->final_clip_rect);
+ // Scissor area is already set
+ glEnable(GL_SCISSOR_TEST);
reclip = false;
}
}
}
- */
} break;
case Item::Command::TYPE_ANIMATION_SLICE: {
/*
@@ -760,28 +934,16 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
c = c->next;
}
+
+ if (current_clip && reclip) {
+ //will make it re-enable clipping if needed afterwards
+ current_clip = nullptr;
+ }
}
void RasterizerCanvasGLES3::_render_batch(uint32_t &r_index) {
- if (state.end_batch && r_index > 0) {
- // If the previous operation is not done yet, allocate a new buffer
- GLint syncStatus;
- glGetSynciv(state.fences[state.current_buffer], GL_SYNC_STATUS, sizeof(GLint), nullptr, &syncStatus);
- if (syncStatus == GL_UNSIGNALED) {
- _allocate_instance_data_buffer();
- } else {
- glDeleteSync(state.fences[state.current_buffer]);
- }
-
- glBindBufferBase(GL_UNIFORM_BUFFER, 3, state.canvas_instance_data_buffers[state.current_buffer]);
-#ifdef JAVASCRIPT_ENABLED
- //WebGL 2.0 does not support mapping buffers, so use slow glBufferData instead
- glBufferData(GL_UNIFORM_BUFFER, sizeof(InstanceData) * r_index, state.instance_data_array, GL_DYNAMIC_DRAW);
-#else
- void *ubo = glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(InstanceData) * r_index, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
- memcpy(ubo, state.instance_data_array, sizeof(InstanceData) * r_index);
- glUnmapBuffer(GL_UNIFORM_BUFFER);
-#endif
+ if (r_index > 0) {
+ _bind_instance_data_buffer(r_index);
glBindVertexArray(data.canvas_quad_array);
if (state.current_primitive_points == 0) {
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, r_index);
@@ -793,7 +955,6 @@ void RasterizerCanvasGLES3::_render_batch(uint32_t &r_index) {
state.fences[state.current_buffer] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
state.current_buffer = (state.current_buffer + 1) % state.canvas_instance_data_buffers.size();
- state.end_batch = false;
//copy the new data into the base of the batch
for (int i = 0; i < 4; i++) {
state.instance_data_array[0].modulation[i] = state.instance_data_array[r_index].modulation[i];
@@ -816,25 +977,30 @@ void RasterizerCanvasGLES3::_render_batch(uint32_t &r_index) {
}
}
-// TODO maybe dont use
-void RasterizerCanvasGLES3::_end_batch(uint32_t &r_index) {
- for (int i = 0; i < 4; i++) {
- state.instance_data_array[r_index].modulation[i] = 0.0;
- state.instance_data_array[r_index].ninepatch_margins[i] = 0.0;
- state.instance_data_array[r_index].src_rect[i] = 0.0;
- state.instance_data_array[r_index].dst_rect[i] = 0.0;
+void RasterizerCanvasGLES3::_bind_instance_data_buffer(uint32_t p_max_index) {
+ if (p_max_index == 0) {
+ return;
+ }
+ // If the previous operation is not done yet, allocate a new buffer
+ if (state.fences[state.current_buffer] != GLsync()) {
+ GLint syncStatus;
+ glGetSynciv(state.fences[state.current_buffer], GL_SYNC_STATUS, sizeof(GLint), nullptr, &syncStatus);
+ if (syncStatus == GL_UNSIGNALED) {
+ _allocate_instance_data_buffer();
+ } else {
+ glDeleteSync(state.fences[state.current_buffer]);
+ }
}
- state.instance_data_array[r_index].flags = uint32_t(0);
- state.instance_data_array[r_index].color_texture_pixel_size[0] = 0.0;
- state.instance_data_array[r_index].color_texture_pixel_size[1] = 0.0;
-
- state.instance_data_array[r_index].pad[0] = 0.0;
- state.instance_data_array[r_index].pad[1] = 0.0;
- state.instance_data_array[r_index].lights[0] = uint32_t(0);
- state.instance_data_array[r_index].lights[1] = uint32_t(0);
- state.instance_data_array[r_index].lights[2] = uint32_t(0);
- state.instance_data_array[r_index].lights[3] = uint32_t(0);
+ glBindBufferBase(GL_UNIFORM_BUFFER, INSTANCE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer]);
+#ifdef JAVASCRIPT_ENABLED
+ //WebGL 2.0 does not support mapping buffers, so use slow glBufferData instead
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(InstanceData) * p_max_index, state.instance_data_array, GL_DYNAMIC_DRAW);
+#else
+ void *ubo = glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(InstanceData) * p_max_index, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
+ memcpy(ubo, state.instance_data_array, sizeof(InstanceData) * p_max_index);
+ glUnmapBuffer(GL_UNIFORM_BUFFER);
+#endif
}
RID RasterizerCanvasGLES3::light_create() {
@@ -876,64 +1042,76 @@ bool RasterizerCanvasGLES3::free(RID p_rid) {
void RasterizerCanvasGLES3::update() {
}
-void RasterizerCanvasGLES3::canvas_begin() {
- state.using_transparent_rt = false;
+void RasterizerCanvasGLES3::canvas_begin(RID p_to_render_target, bool p_to_backbuffer) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
+ GLES3::RenderTarget *render_target = texture_storage->get_render_target(p_to_render_target);
+
+ if (p_to_backbuffer) {
+ glBindFramebuffer(GL_FRAMEBUFFER, render_target->backbuffer_fbo);
+ glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 4);
+ GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE));
+ glBindTexture(GL_TEXTURE_2D, tex->tex_id);
+ } else {
+ glBindFramebuffer(GL_FRAMEBUFFER, render_target->fbo);
+ glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 4);
+ glBindTexture(GL_TEXTURE_2D, render_target->backbuffer);
+ }
- if (storage->frame.current_rt) {
- storage->bind_framebuffer(storage->frame.current_rt->fbo);
- state.using_transparent_rt = storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT];
+ if (render_target->is_transparent) {
+ state.transparent_render_target = true;
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ } else {
+ state.transparent_render_target = false;
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
- if (storage->frame.current_rt && storage->frame.current_rt->clear_requested) {
- const Color &col = storage->frame.current_rt->clear_color;
+ if (render_target && render_target->clear_requested) {
+ const Color &col = render_target->clear_color;
glClearColor(col.r, col.g, col.b, col.a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
- storage->frame.current_rt->clear_requested = false;
+ render_target->clear_requested = false;
}
- reset_canvas();
-
glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex);
+ GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE));
+ glBindTexture(GL_TEXTURE_2D, tex->tex_id);
}
-void RasterizerCanvasGLES3::canvas_end() {
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_UNIFORM_BUFFER, 0);
-}
+void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ GLES3::Config *config = GLES3::Config::get_singleton();
-void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index, RID &r_last_texture, Size2 &r_texpixel_size) {
if (p_texture == RID()) {
- p_texture = default_canvas_texture;
+ p_texture = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE);
}
- if (r_last_texture == p_texture) {
+ if (state.current_tex == p_texture) {
return; //nothing to do, its the same
}
+ state.current_tex = p_texture;
- state.end_batch = true;
- _render_batch(r_index);
-
- RasterizerStorageGLES3::CanvasTexture *ct = nullptr;
+ GLES3::CanvasTexture *ct = nullptr;
- RasterizerStorageGLES3::Texture *t = storage->texture_owner.get_or_null(p_texture);
+ GLES3::Texture *t = texture_storage->get_texture(p_texture);
if (t) {
//regular texture
if (!t->canvas_texture) {
- t->canvas_texture = memnew(RasterizerStorageGLES3::CanvasTexture);
+ t->canvas_texture = memnew(GLES3::CanvasTexture);
t->canvas_texture->diffuse = p_texture;
}
ct = t->canvas_texture;
} else {
- ct = storage->canvas_texture_owner.get_or_null(p_texture);
+ ct = texture_storage->get_canvas_texture(p_texture);
}
if (!ct) {
// Invalid Texture RID.
- _bind_canvas_texture(default_canvas_texture, p_base_filter, p_base_repeat, r_index, r_last_texture, r_texpixel_size);
+ _bind_canvas_texture(default_canvas_texture, p_base_filter, p_base_repeat, r_index);
return;
}
@@ -943,66 +1121,60 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe
RS::CanvasItemTextureRepeat repeat = ct->texture_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? ct->texture_repeat : p_base_repeat;
ERR_FAIL_COND(repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
- RasterizerStorageGLES3::Texture *texture = storage->texture_owner.get_or_null(ct->diffuse);
+ GLES3::Texture *texture = texture_storage->get_texture(ct->diffuse);
if (!texture) {
- state.current_tex = RID();
- state.current_tex_ptr = nullptr;
- ct->size_cache = Size2i(1, 1);
-
+ state.current_tex = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE);
+ GLES3::Texture *tex = texture_storage->get_texture(state.current_tex);
+ state.current_tex_ptr = tex;
+ ct->size_cache = Size2i(tex->width, tex->height);
glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex);
-
+ glBindTexture(GL_TEXTURE_2D, tex->tex_id);
} else {
- texture = texture->get_ptr();
-
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture->tex_id);
- state.current_tex = ct->diffuse;
+ state.current_tex = p_texture;
state.current_tex_ptr = texture;
ct->size_cache = Size2i(texture->width, texture->height);
- texture->GLSetFilter(GL_TEXTURE_2D, filter);
- texture->GLSetRepeat(GL_TEXTURE_2D, repeat);
+ texture->gl_set_filter(filter);
+ texture->gl_set_repeat(repeat);
}
- RasterizerStorageGLES3::Texture *normal_map = storage->texture_owner.get_or_null(ct->normal_map);
+ GLES3::Texture *normal_map = texture_storage->get_texture(ct->normal_map);
if (!normal_map) {
state.current_normal = RID();
ct->use_normal_cache = false;
- glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 6);
- glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex);
+ glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 6);
+ GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_NORMAL));
+ glBindTexture(GL_TEXTURE_2D, tex->tex_id);
} else {
- normal_map = normal_map->get_ptr();
-
- glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 6);
+ glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 6);
glBindTexture(GL_TEXTURE_2D, normal_map->tex_id);
state.current_normal = ct->normal_map;
ct->use_normal_cache = true;
- texture->GLSetFilter(GL_TEXTURE_2D, filter);
- texture->GLSetRepeat(GL_TEXTURE_2D, repeat);
+ texture->gl_set_filter(filter);
+ texture->gl_set_repeat(repeat);
}
- RasterizerStorageGLES3::Texture *specular_map = storage->texture_owner.get_or_null(ct->specular);
+ GLES3::Texture *specular_map = texture_storage->get_texture(ct->specular);
if (!specular_map) {
state.current_specular = RID();
ct->use_specular_cache = false;
- glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 7);
- glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex);
-
+ glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 7);
+ GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE));
+ glBindTexture(GL_TEXTURE_2D, tex->tex_id);
} else {
- specular_map = specular_map->get_ptr();
-
- glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 7);
+ glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 7);
glBindTexture(GL_TEXTURE_2D, specular_map->tex_id);
state.current_specular = ct->specular;
ct->use_specular_cache = true;
- texture->GLSetFilter(GL_TEXTURE_2D, filter);
- texture->GLSetRepeat(GL_TEXTURE_2D, repeat);
+ texture->gl_set_filter(filter);
+ texture->gl_set_repeat(repeat);
}
if (ct->use_specular_cache) {
@@ -1022,32 +1194,19 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe
state.instance_data_array[r_index].specular_shininess |= uint32_t(CLAMP(ct->specular_color.g * 255.0, 0, 255)) << 8;
state.instance_data_array[r_index].specular_shininess |= uint32_t(CLAMP(ct->specular_color.r * 255.0, 0, 255));
- r_texpixel_size.x = 1.0 / float(ct->size_cache.x);
- r_texpixel_size.y = 1.0 / float(ct->size_cache.y);
+ state.current_pixel_size.x = 1.0 / float(ct->size_cache.x);
+ state.current_pixel_size.y = 1.0 / float(ct->size_cache.y);
- state.instance_data_array[r_index].color_texture_pixel_size[0] = r_texpixel_size.x;
- state.instance_data_array[r_index].color_texture_pixel_size[1] = r_texpixel_size.y;
-
- r_last_texture = p_texture;
-}
-
-void RasterizerCanvasGLES3::_set_uniforms() {
+ state.instance_data_array[r_index].color_texture_pixel_size[0] = state.current_pixel_size.x;
+ state.instance_data_array[r_index].color_texture_pixel_size[1] = state.current_pixel_size.y;
}
void RasterizerCanvasGLES3::reset_canvas() {
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
- glDisable(GL_DITHER);
glEnable(GL_BLEND);
-
- // Default to Mix.
- glBlendEquation(GL_FUNC_ADD);
- if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::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);
- }
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@@ -1056,7 +1215,7 @@ void RasterizerCanvasGLES3::reset_canvas() {
void RasterizerCanvasGLES3::canvas_debug_viewport_shadows(Light *p_lights_with_shadow) {
}
-void RasterizerCanvasGLES3::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) {
+void RasterizerCanvasGLES3::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, Projection *p_xform_cache) {
}
void RasterizerCanvasGLES3::draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {
@@ -1090,8 +1249,8 @@ RendererCanvasRender::PolygonID RasterizerCanvasGLES3::request_polygon(const Vec
{
glBindBuffer(GL_ARRAY_BUFFER, pb.vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, stride * vertex_count * sizeof(float), nullptr, GL_STATIC_DRAW); // TODO may not be necessary
- const uint8_t *r = polygon_buffer.ptr();
- float *fptr = (float *)r;
+ uint8_t *r = polygon_buffer.ptrw();
+ float *fptr = reinterpret_cast<float *>(r);
uint32_t *uptr = (uint32_t *)r;
uint32_t base_offset = 0;
{
@@ -1109,11 +1268,7 @@ RendererCanvasRender::PolygonID RasterizerCanvasGLES3::request_polygon(const Vec
}
// Next add colors
- if (p_colors.size() == 1) {
- glDisableVertexAttribArray(RS::ARRAY_COLOR);
- Color m = p_colors[0];
- glVertexAttrib4f(RS::ARRAY_COLOR, m.r, m.g, m.b, m.a);
- } else if ((uint32_t)p_colors.size() == vertex_count) {
+ if ((uint32_t)p_colors.size() == vertex_count) {
glEnableVertexAttribArray(RS::ARRAY_COLOR);
glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(base_offset * sizeof(float)));
@@ -1128,7 +1283,8 @@ RendererCanvasRender::PolygonID RasterizerCanvasGLES3::request_polygon(const Vec
base_offset += 4;
} else {
glDisableVertexAttribArray(RS::ARRAY_COLOR);
- glVertexAttrib4f(RS::ARRAY_COLOR, 1.0, 1.0, 1.0, 1.0);
+ pb.color_disabled = true;
+ pb.color = p_colors.size() == 1 ? p_colors[0] : Color(1.0, 1.0, 1.0, 1.0);
}
if ((uint32_t)p_uvs.size() == vertex_count) {
@@ -1248,7 +1404,21 @@ void RasterizerCanvasGLES3::_allocate_instance_data_buffer() {
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
-void RasterizerCanvasGLES3::initialize() {
+void RasterizerCanvasGLES3::set_time(double p_time) {
+ state.time = p_time;
+}
+
+RasterizerCanvasGLES3 *RasterizerCanvasGLES3::singleton = nullptr;
+
+RasterizerCanvasGLES3 *RasterizerCanvasGLES3::get_singleton() {
+ return singleton;
+}
+
+RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
+ singleton = this;
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
// quad buffer
{
glGenBuffers(1, &data.canvas_quad_vertices);
@@ -1370,10 +1540,7 @@ void RasterizerCanvasGLES3::initialize() {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
- //state.canvas_shadow_shader.init();
-
- int uniform_max_size;
- glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &uniform_max_size);
+ int uniform_max_size = config->max_uniform_buffer_size;
if (uniform_max_size < 65536) {
state.max_lights_per_render = 64;
state.max_instances_per_batch = 128;
@@ -1387,6 +1554,7 @@ void RasterizerCanvasGLES3::initialize() {
state.fences.resize(64);
glGenBuffers(64, state.canvas_instance_data_buffers.ptr());
for (int i = 0; i < 64; i++) {
+ state.fences[i] = GLsync();
glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_instance_data_buffers[i]);
glBufferData(GL_UNIFORM_BUFFER, sizeof(InstanceData) * state.max_instances_per_batch, nullptr, GL_DYNAMIC_DRAW);
}
@@ -1400,27 +1568,19 @@ void RasterizerCanvasGLES3::initialize() {
glBindBuffer(GL_UNIFORM_BUFFER, 0);
String global_defines;
- global_defines += "#define MAX_GLOBAL_VARIABLES 256\n"; // TODO: this is arbitrary for now
+ global_defines += "#define MAX_GLOBAL_SHADER_UNIFORMS 256\n"; // TODO: this is arbitrary for now
global_defines += "#define MAX_LIGHTS " + itos(state.max_instances_per_batch) + "\n";
global_defines += "#define MAX_DRAW_DATA_INSTANCES " + itos(state.max_instances_per_batch) + "\n";
- state.canvas_shader.initialize(global_defines);
- state.canvas_shader_default_version = state.canvas_shader.version_create();
- state.canvas_shader.version_bind_shader(state.canvas_shader_default_version, CanvasShaderGLES3::MODE_QUAD);
-
- //state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows);
-
- //state.canvas_shader.bind();
-
- //state.lens_shader.init();
-
- //state.canvas_shader.set_conditional(CanvasOldShaderGLES3::USE_PIXEL_SNAP, GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false));
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.initialize(global_defines);
+ state.canvas_shader_default_version = GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_create();
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.canvas_shader_default_version, CanvasShaderGLES3::MODE_QUAD);
{
- default_canvas_group_shader = storage->shader_allocate();
- storage->shader_initialize(default_canvas_group_shader);
+ default_canvas_group_shader = material_storage->shader_allocate();
+ material_storage->shader_initialize(default_canvas_group_shader);
- storage->shader_set_code(default_canvas_group_shader, R"(
+ material_storage->shader_set_code(default_canvas_group_shader, R"(
// Default CanvasGroup shader.
shader_type canvas_item;
@@ -1435,31 +1595,26 @@ void fragment() {
COLOR *= c;
}
)");
- default_canvas_group_material = storage->material_allocate();
- storage->material_initialize(default_canvas_group_material);
+ default_canvas_group_material = material_storage->material_allocate();
+ material_storage->material_initialize(default_canvas_group_material);
- storage->material_set_shader(default_canvas_group_material, default_canvas_group_shader);
+ material_storage->material_set_shader(default_canvas_group_material, default_canvas_group_shader);
}
- default_canvas_texture = storage->canvas_texture_allocate();
- storage->canvas_texture_initialize(default_canvas_texture);
-
- state.using_light = nullptr;
- state.using_transparent_rt = false;
- state.using_skeleton = false;
state.current_shader_version = state.canvas_shader_default_version;
+ state.time = 0.0;
}
-RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
-}
RasterizerCanvasGLES3::~RasterizerCanvasGLES3() {
- state.canvas_shader.version_free(state.canvas_shader_default_version);
- storage->free(default_canvas_group_material);
- storage->free(default_canvas_group_shader);
- storage->free(default_canvas_texture);
-}
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+
+ memdelete_arr(state.instance_data_array);
+
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_free(state.canvas_shader_default_version);
+ material_storage->material_free(default_canvas_group_material);
+ material_storage->shader_free(default_canvas_group_shader);
+ singleton = nullptr;
-void RasterizerCanvasGLES3::finalize() {
glDeleteBuffers(1, &data.canvas_quad_vertices);
glDeleteVertexArrays(1, &data.canvas_quad_array);
diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h
index 908d79f9f8..f920e37130 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.h
+++ b/drivers/gles3/rasterizer_canvas_gles3.h
@@ -28,21 +28,24 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef RASTERIZER_CANVAS_OPENGL_H
-#define RASTERIZER_CANVAS_OPENGL_H
+#ifndef RASTERIZER_CANVAS_GLES3_H
+#define RASTERIZER_CANVAS_GLES3_H
#ifdef GLES3_ENABLED
#include "rasterizer_scene_gles3.h"
-#include "rasterizer_storage_gles3.h"
#include "servers/rendering/renderer_canvas_render.h"
#include "servers/rendering/renderer_compositor.h"
+#include "storage/material_storage.h"
+#include "storage/texture_storage.h"
#include "shaders/canvas.glsl.gen.h"
class RasterizerSceneGLES3;
class RasterizerCanvasGLES3 : public RendererCanvasRender {
+ static RasterizerCanvasGLES3 *singleton;
+
_FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4);
_FORCE_INLINE_ void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3);
@@ -50,13 +53,6 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender {
_FORCE_INLINE_ void _update_transform_to_mat4(const Transform3D &p_transform, float *p_mat4);
enum {
- BASE_UNIFORM_BUFFER_OBJECT = 0,
- MATERIAL_UNIFORM_BUFFER_OBJECT = 1,
- TRANSFORMS_UNIFORM_BUFFER_OBJECT = 2,
- CANVAS_TEXTURE_UNIFORM_BUFFER_OBJECT = 3,
- };
-
- enum {
FLAGS_INSTANCING_MASK = 0x7F,
FLAGS_INSTANCING_HAS_COLORS = (1 << 7),
@@ -100,6 +96,14 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender {
};
public:
+ enum {
+ BASE_UNIFORM_LOCATION = 0,
+ GLOBAL_UNIFORM_LOCATION = 1,
+ LIGHT_UNIFORM_LOCATION = 2,
+ INSTANCE_UNIFORM_LOCATION = 3,
+ MATERIAL_UNIFORM_LOCATION = 4,
+ };
+
struct StateBuffer {
float canvas_transform[16];
float screen_transform[16];
@@ -164,40 +168,24 @@ public:
LocalVector<GLsync> fences;
uint32_t current_buffer = 0;
- InstanceData *instance_data_array;
+ InstanceData *instance_data_array = nullptr;
bool canvas_texscreen_used;
- CanvasShaderGLES3 canvas_shader;
RID canvas_shader_current_version;
RID canvas_shader_default_version;
- //CanvasShadowShaderGLES3 canvas_shadow_shader;
- //LensDistortedShaderGLES3 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();
+ Size2 current_pixel_size = Size2();
RID current_normal = RID();
RID current_specular = RID();
- RasterizerStorageGLES3::Texture *current_tex_ptr;
+ GLES3::Texture *current_tex_ptr;
RID current_shader_version = RID();
RS::PrimitiveType current_primitive = RS::PRIMITIVE_MAX;
uint32_t current_primitive_points = 0;
Item::Command::Type current_command = Item::Command::TYPE_RECT;
- bool end_batch = false;
+ bool transparent_render_target = false;
- Transform3D vp;
- Light *using_light;
- bool using_shadow;
- bool using_transparent_rt;
-
- // FROM RD Renderer
+ double time = 0.0;
uint32_t max_lights_per_render;
uint32_t max_lights_per_item;
@@ -215,20 +203,13 @@ public:
typedef void Texture;
- RasterizerSceneGLES3 *scene_render;
-
- RasterizerStorageGLES3 *storage;
-
- void _set_uniforms();
-
- void canvas_begin();
- void canvas_end();
+ void canvas_begin(RID p_to_render_target, bool p_to_backbuffer);
//virtual void draw_window_margins(int *black_margin, RID *black_image) override;
void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
- virtual void reset_canvas();
- 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);
+ void reset_canvas();
+ 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, Projection *p_xform_cache);
virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) override;
@@ -247,13 +228,15 @@ public:
bool free(RID p_rid) override;
void update() override;
- void _bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index, RID &r_last_texture, Size2 &r_texpixel_size);
+ void _bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index);
struct PolygonBuffers {
GLuint vertex_buffer;
GLuint vertex_array;
GLuint index_buffer;
int count;
+ bool color_disabled = false;
+ Color color;
};
struct {
@@ -268,14 +251,16 @@ public:
void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer = false);
void _render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, uint32_t &r_index);
void _render_batch(uint32_t &p_max_index);
- void _end_batch(uint32_t &p_max_index);
+ void _bind_instance_data_buffer(uint32_t p_max_index);
void _allocate_instance_data_buffer();
- void initialize();
- void finalize();
+ void set_time(double p_time);
+
+ static RasterizerCanvasGLES3 *get_singleton();
RasterizerCanvasGLES3();
~RasterizerCanvasGLES3();
};
#endif // GLES3_ENABLED
-#endif // RASTERIZER_CANVAS_OPENGL_H
+
+#endif // RASTERIZER_CANVAS_GLES3_H
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 087bf36473..33303b1e38 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -29,11 +29,13 @@
/*************************************************************************/
#include "rasterizer_gles3.h"
+#include "storage/utilities.h"
#ifdef GLES3_ENABLED
#include "core/config/project_settings.h"
#include "core/os/os.h"
+#include "storage/texture_storage.h"
#define _EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242
#define _EXT_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243
@@ -67,7 +69,7 @@
#endif
#endif
-#if !defined(IPHONE_ENABLED) && !defined(JAVASCRIPT_ENABLED)
+#if !defined(IOS_ENABLED) && !defined(JAVASCRIPT_ENABLED)
// We include EGL below to get debug callback on GLES2 platforms,
// but EGL is not available on iOS.
#define CAN_DEBUG
@@ -95,14 +97,12 @@ void RasterizerGLES3::begin_frame(double frame_step) {
double time_roll_over = GLOBAL_GET("rendering/limits/time/time_rollover_secs");
time_total = Math::fmod(time_total, time_roll_over);
- storage.frame.time = time_total;
- storage.frame.count++;
- storage.frame.delta = frame_step;
+ canvas->set_time(time_total);
+ scene->set_time(time_total, frame_step);
- storage.update_dirty_resources();
-
- storage.info.render_final = storage.info.render;
- storage.info.render.reset();
+ GLES3::Utilities *utilities = GLES3::Utilities::get_singleton();
+ utilities->info.render_final = utilities->info.render;
+ utilities->info.render.reset();
//scene->iteration();
}
@@ -193,13 +193,31 @@ typedef void (*DEBUGPROCARB)(GLenum source,
typedef void (*DebugMessageCallbackARB)(DEBUGPROCARB callback, const void *userParam);
void RasterizerGLES3::initialize() {
- print_verbose("Using OpenGL video driver");
+ print_line("OpenGL Renderer: " + RS::get_singleton()->get_video_adapter_name());
+}
- storage._main_thread_id = Thread::get_caller_id();
+void RasterizerGLES3::finalize() {
+ memdelete(scene);
+ memdelete(canvas);
+ memdelete(gi);
+ memdelete(fog);
+ memdelete(copy_effects);
+ memdelete(light_storage);
+ memdelete(particles_storage);
+ memdelete(mesh_storage);
+ memdelete(material_storage);
+ memdelete(texture_storage);
+ memdelete(utilities);
+ memdelete(config);
+}
+RasterizerGLES3::RasterizerGLES3() {
#ifdef GLAD_ENABLED
if (!gladLoadGL()) {
ERR_PRINT("Error initializing GLAD");
+ // FIXME this is an early return from a constructor. Any other code using this instance will crash or the finalizer will crash, because none of
+ // the members of this instance are initialized, so this just makes debugging harder. It should either crash here intentionally,
+ // or we need to actually test for this situation before constructing this.
return;
}
#endif
@@ -248,50 +266,53 @@ void RasterizerGLES3::initialize() {
#endif // GLES_OVER_GL
#endif // CAN_DEBUG
- print_line("OpenGL Renderer: " + RS::get_singleton()->get_video_adapter_name());
- storage.initialize();
- canvas.initialize();
- // scene.initialize();
-
- // make sure the OS knows to only access the renderer from the main thread
- OS::get_singleton()->set_render_main_thread_mode(OS::RENDER_MAIN_THREAD_ONLY);
+ // OpenGL needs to be initialized before initializing the Rasterizers
+ config = memnew(GLES3::Config);
+ utilities = memnew(GLES3::Utilities);
+ texture_storage = memnew(GLES3::TextureStorage);
+ material_storage = memnew(GLES3::MaterialStorage);
+ mesh_storage = memnew(GLES3::MeshStorage);
+ particles_storage = memnew(GLES3::ParticlesStorage);
+ light_storage = memnew(GLES3::LightStorage);
+ copy_effects = memnew(GLES3::CopyEffects);
+ gi = memnew(GLES3::GI);
+ fog = memnew(GLES3::Fog);
+ canvas = memnew(RasterizerCanvasGLES3());
+ scene = memnew(RasterizerSceneGLES3());
}
-RasterizerGLES3::RasterizerGLES3() {
- canvas.storage = &storage;
- canvas.scene_render = &scene;
- storage.canvas = &canvas;
- //scene.storage = &storage;
- storage.scene = &scene;
+RasterizerGLES3::~RasterizerGLES3() {
}
void RasterizerGLES3::prepare_for_blitting_render_targets() {
}
void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect) {
- ERR_FAIL_COND(storage.frame.current_rt);
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
- RasterizerStorageGLES3::RenderTarget *rt = storage.render_target_owner.get_or_null(p_render_target);
+ GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
ERR_FAIL_COND(!rt);
// TODO: do we need a keep 3d linear option?
+ // Make sure we are drawing to the right context.
+ DisplayServer::get_singleton()->gl_window_make_current(p_screen);
+
if (rt->external.fbo != 0) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->external.fbo);
} else {
glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo);
}
glReadBuffer(GL_COLOR_ATTACHMENT0);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
- glBlitFramebuffer(0, 0, rt->width, rt->height, 0, p_screen_rect.size.y, p_screen_rect.size.x, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
+ // Flip content upside down to correct for coordinates.
+ glBlitFramebuffer(0, 0, rt->size.x, rt->size.y, 0, p_screen_rect.size.y, p_screen_rect.size.x, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
// is this p_screen useless in a multi window environment?
void RasterizerGLES3::blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) {
- // do this once off for all blits
- storage.bind_framebuffer_system();
-
- storage.frame.current_rt = nullptr;
+ // All blits are going to the system framebuffer, so just bind once.
+ glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
for (int i = 0; i < p_amount; i++) {
const BlitToScreen &blit = p_render_targets[i];
@@ -322,12 +343,8 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
}
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(), VS::TEXTURE_TYPE_2D, p_use_filter ? VS::TEXTURE_FLAG_FILTER : 0);
- storage._texture_allocate_internal(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), RenderingDevice::TEXTURE_TYPE_2D);
- storage.texture_set_data(texture, p_image);
+ RID texture = texture_storage->texture_allocate();
+ texture_storage->texture_2d_initialize(texture, p_image);
Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height());
Rect2 screenrect;
@@ -349,13 +366,12 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
screenrect.position += ((Size2(win_size.width, win_size.height) - screenrect.size) / 2.0).floor();
}
- RasterizerStorageGLES3::Texture *t = storage.texture_owner.get_or_null(texture);
- glActiveTexture(GL_TEXTURE0 + storage.config.max_texture_image_units - 1);
+ GLES3::Texture *t = texture_storage->get_texture(texture);
+ glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 1);
glBindTexture(GL_TEXTURE_2D, t->tex_id);
glBindTexture(GL_TEXTURE_2D, 0);
- canvas.canvas_end();
- storage.free(texture);
+ texture_storage->texture_free(texture);
end_frame(true);
}
diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h
index a641e189c5..97543af0d5 100644
--- a/drivers/gles3/rasterizer_gles3.h
+++ b/drivers/gles3/rasterizer_gles3.h
@@ -28,15 +28,24 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef RASTERIZER_OPENGL_H
-#define RASTERIZER_OPENGL_H
+#ifndef RASTERIZER_GLES3_H
+#define RASTERIZER_GLES3_H
#ifdef GLES3_ENABLED
+#include "effects/copy_effects.h"
+#include "environment/fog.h"
+#include "environment/gi.h"
#include "rasterizer_canvas_gles3.h"
#include "rasterizer_scene_gles3.h"
-#include "rasterizer_storage_gles3.h"
#include "servers/rendering/renderer_compositor.h"
+#include "storage/config.h"
+#include "storage/light_storage.h"
+#include "storage/material_storage.h"
+#include "storage/mesh_storage.h"
+#include "storage/particles_storage.h"
+#include "storage/texture_storage.h"
+#include "storage/utilities.h"
class RasterizerGLES3 : public RendererCompositor {
private:
@@ -46,16 +55,32 @@ private:
double time_total = 0.0;
protected:
- RasterizerStorageGLES3 storage;
- RasterizerCanvasGLES3 canvas;
- RasterizerSceneGLES3 scene;
+ GLES3::Config *config = nullptr;
+ GLES3::Utilities *utilities = nullptr;
+ GLES3::TextureStorage *texture_storage = nullptr;
+ GLES3::MaterialStorage *material_storage = nullptr;
+ GLES3::MeshStorage *mesh_storage = nullptr;
+ GLES3::ParticlesStorage *particles_storage = nullptr;
+ GLES3::LightStorage *light_storage = nullptr;
+ GLES3::GI *gi = nullptr;
+ GLES3::Fog *fog = nullptr;
+ GLES3::CopyEffects *copy_effects = nullptr;
+ RasterizerCanvasGLES3 *canvas = nullptr;
+ RasterizerSceneGLES3 *scene = nullptr;
void _blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect);
public:
- RendererStorage *get_storage() { return &storage; }
- RendererCanvasRender *get_canvas() { return &canvas; }
- RendererSceneRender *get_scene() { return &scene; }
+ RendererUtilities *get_utilities() { return utilities; }
+ RendererLightStorage *get_light_storage() { return light_storage; }
+ RendererMaterialStorage *get_material_storage() { return material_storage; }
+ RendererMeshStorage *get_mesh_storage() { return mesh_storage; }
+ RendererParticlesStorage *get_particles_storage() { return particles_storage; }
+ RendererTextureStorage *get_texture_storage() { return texture_storage; }
+ RendererGI *get_gi() { return gi; }
+ RendererFog *get_fog() { return fog; }
+ RendererCanvasRender *get_canvas() { return canvas; }
+ RendererSceneRender *get_scene() { return scene; }
void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true);
@@ -67,7 +92,7 @@ public:
void end_frame(bool p_swap_buffers);
- void finalize() {}
+ void finalize();
static RendererCompositor *_create_current() {
return memnew(RasterizerGLES3);
@@ -75,16 +100,16 @@ public:
static void make_current() {
_create_func = _create_current;
+ low_end = true;
}
- virtual bool is_low_end() const { return true; }
uint64_t get_frame_number() const { return frame; }
double get_frame_delta_time() const { return delta; }
RasterizerGLES3();
- ~RasterizerGLES3() {}
+ ~RasterizerGLES3();
};
#endif // GLES3_ENABLED
-#endif
+#endif // RASTERIZER_GLES3_H
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 121dc86fb2..3e416bc615 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -29,85 +29,374 @@
/*************************************************************************/
#include "rasterizer_scene_gles3.h"
+#include "core/config/project_settings.h"
+#include "core/templates/sort_array.h"
+#include "servers/rendering/rendering_server_default.h"
+#include "servers/rendering/rendering_server_globals.h"
+#include "storage/config.h"
+#include "storage/light_storage.h"
+#include "storage/mesh_storage.h"
+#include "storage/texture_storage.h"
+
#ifdef GLES3_ENABLED
-// TODO: 3D support not implemented yet.
+RasterizerSceneGLES3 *RasterizerSceneGLES3::singleton = nullptr;
-RasterizerSceneGLES3::GeometryInstance *RasterizerSceneGLES3::geometry_instance_create(RID p_base) {
- return nullptr;
-}
+RenderGeometryInstance *RasterizerSceneGLES3::geometry_instance_create(RID p_base) {
+ RS::InstanceType type = RSG::utilities->get_base_type(p_base);
+ ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr);
-void RasterizerSceneGLES3::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) {
-}
+ GeometryInstanceGLES3 *ginstance = geometry_instance_alloc.alloc();
+ ginstance->data = memnew(GeometryInstanceGLES3::Data);
-void RasterizerSceneGLES3::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) {
-}
+ ginstance->data->base = p_base;
+ ginstance->data->base_type = type;
-void RasterizerSceneGLES3::geometry_instance_set_material_overlay(GeometryInstance *p_geometry_instance, RID p_overlay) {
-}
+ ginstance->_mark_dirty();
-void RasterizerSceneGLES3::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_material) {
+ return ginstance;
}
-void RasterizerSceneGLES3::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) {
-}
+uint32_t RasterizerSceneGLES3::geometry_instance_get_pair_mask() {
+ return (1 << RS::INSTANCE_LIGHT);
+}
+
+void RasterizerSceneGLES3::GeometryInstanceGLES3::pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) {
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
+ omni_light_count = 0;
+ spot_light_count = 0;
+ omni_lights.clear();
+ spot_lights.clear();
-void RasterizerSceneGLES3::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) {
+ for (uint32_t i = 0; i < p_light_instance_count; i++) {
+ RS::LightType type = RasterizerSceneGLES3::get_singleton()->light_instance_get_type(p_light_instances[i]);
+ switch (type) {
+ case RS::LIGHT_OMNI: {
+ if (omni_light_count < (uint32_t)config->max_lights_per_object) {
+ omni_lights.push_back(p_light_instances[i]);
+ omni_light_count++;
+ }
+ } break;
+ case RS::LIGHT_SPOT: {
+ if (spot_light_count < (uint32_t)config->max_lights_per_object) {
+ spot_lights.push_back(p_light_instances[i]);
+ spot_light_count++;
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+}
+
+void RasterizerSceneGLES3::geometry_instance_free(RenderGeometryInstance *p_geometry_instance) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ GeometryInstanceSurface *surf = ginstance->surface_caches;
+ while (surf) {
+ GeometryInstanceSurface *next = surf->next;
+ geometry_instance_surface_alloc.free(surf);
+ surf = next;
+ }
+ memdelete(ginstance->data);
+ geometry_instance_alloc.free(ginstance);
+}
+
+void RasterizerSceneGLES3::GeometryInstanceGLES3::_mark_dirty() {
+ if (dirty_list_element.in_list()) {
+ return;
+ }
+
+ //clear surface caches
+ GeometryInstanceSurface *surf = surface_caches;
+
+ while (surf) {
+ GeometryInstanceSurface *next = surf->next;
+ RasterizerSceneGLES3::get_singleton()->geometry_instance_surface_alloc.free(surf);
+ surf = next;
+ }
+
+ surface_caches = nullptr;
+
+ RasterizerSceneGLES3::get_singleton()->geometry_instance_dirty_list.add(&dirty_list_element);
+}
+
+void RasterizerSceneGLES3::GeometryInstanceGLES3::set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) {
+}
+
+void RasterizerSceneGLES3::GeometryInstanceGLES3::set_lightmap_capture(const Color *p_sh9) {
+}
+
+void RasterizerSceneGLES3::_update_dirty_geometry_instances() {
+ while (geometry_instance_dirty_list.first()) {
+ _geometry_instance_update(geometry_instance_dirty_list.first()->self());
+ }
+}
+
+void RasterizerSceneGLES3::_geometry_instance_dependency_changed(Dependency::DependencyChangedNotification p_notification, DependencyTracker *p_tracker) {
+ switch (p_notification) {
+ case Dependency::DEPENDENCY_CHANGED_MATERIAL:
+ case Dependency::DEPENDENCY_CHANGED_MESH:
+ case Dependency::DEPENDENCY_CHANGED_PARTICLES:
+ case Dependency::DEPENDENCY_CHANGED_MULTIMESH:
+ case Dependency::DEPENDENCY_CHANGED_SKELETON_DATA: {
+ static_cast<RenderGeometryInstance *>(p_tracker->userdata)->_mark_dirty();
+ } break;
+ case Dependency::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_tracker->userdata);
+ if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
+ ginstance->instance_count = GLES3::MeshStorage::get_singleton()->multimesh_get_instances_to_draw(ginstance->data->base);
+ }
+ } break;
+ default: {
+ //rest of notifications of no interest
+ } break;
+ }
+}
+
+void RasterizerSceneGLES3::_geometry_instance_dependency_deleted(const RID &p_dependency, DependencyTracker *p_tracker) {
+ static_cast<RenderGeometryInstance *>(p_tracker->userdata)->_mark_dirty();
}
-void RasterizerSceneGLES3::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) {
-}
+void RasterizerSceneGLES3::_geometry_instance_add_surface_with_material(GeometryInstanceGLES3 *ginstance, uint32_t p_surface, GLES3::SceneMaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) {
+ GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
+
+ bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture;
+ bool has_base_alpha = ((p_material->shader_data->uses_alpha && !p_material->shader_data->uses_alpha_clip) || has_read_screen_alpha);
+ bool has_blend_alpha = p_material->shader_data->uses_blend_alpha;
+ bool has_alpha = has_base_alpha || has_blend_alpha;
+
+ uint32_t flags = 0;
+
+ if (p_material->shader_data->uses_screen_texture) {
+ flags |= GeometryInstanceSurface::FLAG_USES_SCREEN_TEXTURE;
+ }
+
+ if (p_material->shader_data->uses_depth_texture) {
+ flags |= GeometryInstanceSurface::FLAG_USES_DEPTH_TEXTURE;
+ }
-void RasterizerSceneGLES3::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) {
-}
+ if (p_material->shader_data->uses_normal_texture) {
+ flags |= GeometryInstanceSurface::FLAG_USES_NORMAL_TEXTURE;
+ }
-void RasterizerSceneGLES3::geometry_instance_set_transparency(GeometryInstance *p_geometry_instance, float p_transparency) {
-}
+ if (ginstance->data->cast_double_sided_shadows) {
+ flags |= GeometryInstanceSurface::FLAG_USES_DOUBLE_SIDED_SHADOWS;
+ }
-void RasterizerSceneGLES3::geometry_instance_set_fade_range(GeometryInstance *p_geometry_instance, bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) {
-}
+ if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == GLES3::SceneShaderData::DEPTH_TEST_DISABLED) {
+ //material is only meant for alpha pass
+ flags |= GeometryInstanceSurface::FLAG_PASS_ALPHA;
+ if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == GLES3::SceneShaderData::DEPTH_TEST_DISABLED)) {
+ flags |= GeometryInstanceSurface::FLAG_PASS_DEPTH;
+ flags |= GeometryInstanceSurface::FLAG_PASS_SHADOW;
+ }
+ } else {
+ flags |= GeometryInstanceSurface::FLAG_PASS_OPAQUE;
+ flags |= GeometryInstanceSurface::FLAG_PASS_DEPTH;
+ flags |= GeometryInstanceSurface::FLAG_PASS_SHADOW;
+ }
-void RasterizerSceneGLES3::geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) {
-}
+ GLES3::SceneMaterialData *material_shadow = nullptr;
+ void *surface_shadow = nullptr;
+ if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass && !p_material->shader_data->uses_alpha_clip) {
+ flags |= GeometryInstanceSurface::FLAG_USES_SHARED_SHADOW_MATERIAL;
+ material_shadow = static_cast<GLES3::SceneMaterialData *>(GLES3::MaterialStorage::get_singleton()->material_get_data(scene_globals.default_material, RS::SHADER_SPATIAL));
-void RasterizerSceneGLES3::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) {
-}
+ RID shadow_mesh = mesh_storage->mesh_get_shadow_mesh(p_mesh);
-void RasterizerSceneGLES3::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) {
-}
+ if (shadow_mesh.is_valid()) {
+ surface_shadow = mesh_storage->mesh_get_surface(shadow_mesh, p_surface);
+ }
-void RasterizerSceneGLES3::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) {
-}
+ } else {
+ material_shadow = p_material;
+ }
-void RasterizerSceneGLES3::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) {
-}
+ GeometryInstanceSurface *sdcache = geometry_instance_surface_alloc.alloc();
-void RasterizerSceneGLES3::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) {
-}
+ sdcache->flags = flags;
-void RasterizerSceneGLES3::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) {
-}
+ sdcache->shader = p_material->shader_data;
+ sdcache->material = p_material;
+ sdcache->surface = mesh_storage->mesh_get_surface(p_mesh, p_surface);
+ sdcache->primitive = mesh_storage->mesh_surface_get_primitive(sdcache->surface);
+ sdcache->surface_index = p_surface;
-uint32_t RasterizerSceneGLES3::geometry_instance_get_pair_mask() {
- return 0;
-}
+ if (ginstance->data->dirty_dependencies) {
+ RSG::utilities->base_update_dependency(p_mesh, &ginstance->data->dependency_tracker);
+ }
+
+ //shadow
+ sdcache->shader_shadow = material_shadow->shader_data;
+ sdcache->material_shadow = material_shadow;
+
+ sdcache->surface_shadow = surface_shadow ? surface_shadow : sdcache->surface;
+
+ sdcache->owner = ginstance;
+
+ sdcache->next = ginstance->surface_caches;
+ ginstance->surface_caches = sdcache;
+
+ //sortkey
+
+ sdcache->sort.sort_key1 = 0;
+ sdcache->sort.sort_key2 = 0;
-void RasterizerSceneGLES3::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) {
+ sdcache->sort.surface_index = p_surface;
+ sdcache->sort.material_id_low = p_material_id & 0x0000FFFF;
+ sdcache->sort.material_id_hi = p_material_id >> 16;
+ sdcache->sort.shader_id = p_shader_id;
+ sdcache->sort.geometry_id = p_mesh.get_local_index();
+ sdcache->sort.priority = p_material->priority;
}
-void RasterizerSceneGLES3::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) {
-}
+void RasterizerSceneGLES3::_geometry_instance_add_surface_with_material_chain(GeometryInstanceGLES3 *ginstance, uint32_t p_surface, GLES3::SceneMaterialData *p_material_data, RID p_mat_src, RID p_mesh) {
+ GLES3::SceneMaterialData *material_data = p_material_data;
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+
+ _geometry_instance_add_surface_with_material(ginstance, p_surface, material_data, p_mat_src.get_local_index(), material_storage->material_get_shader_id(p_mat_src), p_mesh);
-void RasterizerSceneGLES3::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) {
-}
+ while (material_data->next_pass.is_valid()) {
+ RID next_pass = material_data->next_pass;
+ material_data = static_cast<GLES3::SceneMaterialData *>(material_storage->material_get_data(next_pass, RS::SHADER_SPATIAL));
+ if (!material_data || !material_data->shader_data->valid) {
+ break;
+ }
+ if (ginstance->data->dirty_dependencies) {
+ material_storage->material_update_dependency(next_pass, &ginstance->data->dependency_tracker);
+ }
+ _geometry_instance_add_surface_with_material(ginstance, p_surface, material_data, next_pass.get_local_index(), material_storage->material_get_shader_id(next_pass), p_mesh);
+ }
+}
+
+void RasterizerSceneGLES3::_geometry_instance_add_surface(GeometryInstanceGLES3 *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) {
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ RID m_src;
+
+ m_src = ginstance->data->material_override.is_valid() ? ginstance->data->material_override : p_material;
+
+ GLES3::SceneMaterialData *material_data = nullptr;
+
+ if (m_src.is_valid()) {
+ material_data = static_cast<GLES3::SceneMaterialData *>(material_storage->material_get_data(m_src, RS::SHADER_SPATIAL));
+ if (!material_data || !material_data->shader_data->valid) {
+ material_data = nullptr;
+ }
+ }
+
+ if (material_data) {
+ if (ginstance->data->dirty_dependencies) {
+ material_storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker);
+ }
+ } else {
+ material_data = static_cast<GLES3::SceneMaterialData *>(material_storage->material_get_data(scene_globals.default_material, RS::SHADER_SPATIAL));
+ m_src = scene_globals.default_material;
+ }
+
+ ERR_FAIL_COND(!material_data);
-void RasterizerSceneGLES3::geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) {
-}
+ _geometry_instance_add_surface_with_material_chain(ginstance, p_surface, material_data, m_src, p_mesh);
-void RasterizerSceneGLES3::geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) {
+ if (ginstance->data->material_overlay.is_valid()) {
+ m_src = ginstance->data->material_overlay;
+
+ material_data = static_cast<GLES3::SceneMaterialData *>(material_storage->material_get_data(m_src, RS::SHADER_SPATIAL));
+ if (material_data && material_data->shader_data->valid) {
+ if (ginstance->data->dirty_dependencies) {
+ material_storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker);
+ }
+
+ _geometry_instance_add_surface_with_material_chain(ginstance, p_surface, material_data, m_src, p_mesh);
+ }
+ }
}
-void RasterizerSceneGLES3::geometry_instance_free(GeometryInstance *p_geometry_instance) {
+void RasterizerSceneGLES3::_geometry_instance_update(RenderGeometryInstance *p_geometry_instance) {
+ GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+
+ if (ginstance->data->dirty_dependencies) {
+ ginstance->data->dependency_tracker.update_begin();
+ }
+
+ //add geometry for drawing
+ switch (ginstance->data->base_type) {
+ case RS::INSTANCE_MESH: {
+ const RID *materials = nullptr;
+ uint32_t surface_count;
+ RID mesh = ginstance->data->base;
+
+ materials = mesh_storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+ if (materials) {
+ //if no materials, no surfaces.
+ const RID *inst_materials = ginstance->data->surface_materials.ptr();
+ uint32_t surf_mat_count = ginstance->data->surface_materials.size();
+
+ for (uint32_t j = 0; j < surface_count; j++) {
+ RID material = (j < surf_mat_count && inst_materials[j].is_valid()) ? inst_materials[j] : materials[j];
+ _geometry_instance_add_surface(ginstance, j, material, mesh);
+ }
+ }
+
+ ginstance->instance_count = -1;
+
+ } break;
+
+ case RS::INSTANCE_MULTIMESH: {
+ RID mesh = mesh_storage->multimesh_get_mesh(ginstance->data->base);
+ if (mesh.is_valid()) {
+ const RID *materials = nullptr;
+ uint32_t surface_count;
+
+ materials = mesh_storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+ if (materials) {
+ for (uint32_t j = 0; j < surface_count; j++) {
+ _geometry_instance_add_surface(ginstance, j, materials[j], mesh);
+ }
+ }
+
+ ginstance->instance_count = mesh_storage->multimesh_get_instances_to_draw(ginstance->data->base);
+ }
+
+ } break;
+ case RS::INSTANCE_PARTICLES: {
+ } break;
+
+ default: {
+ }
+ }
+
+ bool store_transform = true;
+ ginstance->base_flags = 0;
+
+ if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
+ if (mesh_storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
+ }
+ if (mesh_storage->multimesh_uses_colors(ginstance->data->base)) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
+ }
+ if (mesh_storage->multimesh_uses_custom_data(ginstance->data->base)) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
+ }
+
+ //ginstance->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_globals.default_shader_rd, TRANSFORMS_UNIFORM_SET);
+
+ } else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) {
+ } else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
+ }
+
+ ginstance->store_transform_cache = store_transform;
+
+ if (ginstance->data->dirty_dependencies) {
+ ginstance->data->dependency_tracker.update_end();
+ ginstance->data->dirty_dependencies = false;
+ }
+
+ ginstance->dirty_list_element.remove_from_list();
}
/* SHADOW ATLAS API */
@@ -136,107 +425,624 @@ int RasterizerSceneGLES3::get_directional_light_shadow_size(RID p_light_intance)
void RasterizerSceneGLES3::set_directional_shadow_count(int p_count) {
}
-/* SDFGI UPDATE */
+/* SKY API */
-void RasterizerSceneGLES3::sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) {
+void RasterizerSceneGLES3::_free_sky_data(Sky *p_sky) {
+ if (p_sky->radiance != 0) {
+ glDeleteTextures(1, &p_sky->radiance);
+ p_sky->radiance = 0;
+ glDeleteFramebuffers(1, &p_sky->radiance_framebuffer);
+ p_sky->radiance_framebuffer = 0;
+ }
}
-int RasterizerSceneGLES3::sdfgi_get_pending_region_count(RID p_render_buffers) const {
- return 0;
+RID RasterizerSceneGLES3::sky_allocate() {
+ return sky_owner.allocate_rid();
}
-AABB RasterizerSceneGLES3::sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const {
- return AABB();
+void RasterizerSceneGLES3::sky_initialize(RID p_rid) {
+ sky_owner.initialize_rid(p_rid);
}
-uint32_t RasterizerSceneGLES3::sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const {
- return 0;
-}
+void RasterizerSceneGLES3::sky_set_radiance_size(RID p_sky, int p_radiance_size) {
+ Sky *sky = sky_owner.get_or_null(p_sky);
+ ERR_FAIL_COND(!sky);
+ ERR_FAIL_COND_MSG(p_radiance_size < 32 || p_radiance_size > 2048, "Sky radiance size must be between 32 and 2048");
-/* SKY API */
+ if (sky->radiance_size == p_radiance_size) {
+ return; // No need to update
+ }
-RID RasterizerSceneGLES3::sky_allocate() {
- return RID();
-}
+ sky->radiance_size = p_radiance_size;
-void RasterizerSceneGLES3::sky_initialize(RID p_rid) {
+ _free_sky_data(sky);
+ _invalidate_sky(sky);
}
-void RasterizerSceneGLES3::sky_set_radiance_size(RID p_sky, int p_radiance_size) {
-}
+void RasterizerSceneGLES3::sky_set_mode(RID p_sky, RS::SkyMode p_mode) {
+ Sky *sky = sky_owner.get_or_null(p_sky);
+ ERR_FAIL_COND(!sky);
-void RasterizerSceneGLES3::sky_set_mode(RID p_sky, RS::SkyMode p_samples) {
+ if (sky->mode == p_mode) {
+ return;
+ }
+
+ sky->mode = p_mode;
+ _invalidate_sky(sky);
}
void RasterizerSceneGLES3::sky_set_material(RID p_sky, RID p_material) {
-}
+ Sky *sky = sky_owner.get_or_null(p_sky);
+ ERR_FAIL_COND(!sky);
+
+ if (sky->material == p_material) {
+ return;
+ }
+
+ sky->material = p_material;
+ _invalidate_sky(sky);
+}
+
+void RasterizerSceneGLES3::_invalidate_sky(Sky *p_sky) {
+ if (!p_sky->dirty) {
+ p_sky->dirty = true;
+ p_sky->dirty_list = dirty_sky_list;
+ dirty_sky_list = p_sky;
+ }
+}
+
+void RasterizerSceneGLES3::_update_dirty_skys() {
+ Sky *sky = dirty_sky_list;
-Ref<Image> RasterizerSceneGLES3::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) {
- return Ref<Image>();
-}
+ while (sky) {
+ if (sky->radiance == 0) {
+ sky->mipmap_count = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBA8) - 1;
+ // Left uninitialized, will attach a texture at render time
+ glGenFramebuffers(1, &sky->radiance_framebuffer);
+
+ GLenum internal_format = GL_RGB10_A2;
+
+ glGenTextures(1, &sky->radiance);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance);
+
+#ifdef GLES_OVER_GL
+ GLenum format = GL_RGBA;
+ GLenum type = GL_UNSIGNED_INT_2_10_10_10_REV;
+ //TODO, on low-end compare this to allocating each face of each mip individually
+ // see: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexStorage2D.xhtml
+ for (int i = 0; i < 6; i++) {
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, sky->radiance_size, sky->radiance_size, 0, format, type, nullptr);
+ }
+
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+#else
+ glTexStorage2D(GL_TEXTURE_CUBE_MAP, sky->mipmap_count, internal_format, sky->radiance_size, sky->radiance_size);
+#endif
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ 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);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count - 1);
+
+ glGenTextures(1, &sky->raw_radiance);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, sky->raw_radiance);
+
+#ifdef GLES_OVER_GL
+ //TODO, on low-end compare this to allocating each face of each mip individually
+ // see: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexStorage2D.xhtml
+ for (int i = 0; i < 6; i++) {
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, sky->radiance_size, sky->radiance_size, 0, format, type, nullptr);
+ }
+
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+#else
+ glTexStorage2D(GL_TEXTURE_CUBE_MAP, sky->mipmap_count, internal_format, sky->radiance_size, sky->radiance_size);
+#endif
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ 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);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count - 1);
+
+ glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+ }
+
+ sky->reflection_dirty = true;
+ sky->processing_layer = 0;
+
+ Sky *next = sky->dirty_list;
+ sky->dirty_list = nullptr;
+ sky->dirty = false;
+ sky = next;
+ }
+
+ dirty_sky_list = nullptr;
+}
+
+void RasterizerSceneGLES3::_setup_sky(RID p_env, RID p_render_buffers, const PagedArray<RID> &p_lights, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size) {
+ GLES3::LightStorage *light_storage = GLES3::LightStorage::get_singleton();
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ ERR_FAIL_COND(p_env.is_null());
+
+ GLES3::SkyMaterialData *material = nullptr;
+ Sky *sky = sky_owner.get_or_null(environment_get_sky(p_env));
+
+ RID sky_material;
+
+ GLES3::SkyShaderData *shader_data = nullptr;
+
+ if (sky) {
+ sky_material = sky->material;
+
+ if (sky_material.is_valid()) {
+ material = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (!material) {
+ sky_material = sky_globals.default_material;
+ material = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ }
+
+ ERR_FAIL_COND(!material);
+
+ shader_data = material->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+
+ if (shader_data->uses_time && time - sky->prev_time > 0.00001) {
+ sky->prev_time = time;
+ sky->reflection_dirty = true;
+ RenderingServerDefault::redraw_request();
+ }
+
+ if (material != sky->prev_material) {
+ sky->prev_material = material;
+ sky->reflection_dirty = true;
+ }
+
+ if (material->uniform_set_updated) {
+ material->uniform_set_updated = false;
+ sky->reflection_dirty = true;
+ }
+
+ if (!p_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
+ sky->prev_position = p_transform.origin;
+ sky->reflection_dirty = true;
+ }
+
+ if (shader_data->uses_light) {
+ sky_globals.directional_light_count = 0;
+ for (int i = 0; i < (int)p_lights.size(); i++) {
+ LightInstance *li = light_instance_owner.get_or_null(p_lights[i]);
+ if (!li) {
+ continue;
+ }
+ RID base = li->light;
+
+ ERR_CONTINUE(base.is_null());
+
+ RS::LightType type = light_storage->light_get_type(base);
+ if (type == RS::LIGHT_DIRECTIONAL && light_storage->light_directional_get_sky_mode(base) != RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_ONLY) {
+ DirectionalLightData &sky_light_data = sky_globals.directional_lights[sky_globals.directional_light_count];
+ Transform3D light_transform = li->transform;
+ Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
+
+ sky_light_data.direction[0] = world_direction.x;
+ sky_light_data.direction[1] = world_direction.y;
+ sky_light_data.direction[2] = world_direction.z;
+
+ float sign = light_storage->light_is_negative(base) ? -1 : 1;
+ sky_light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY);
+
+ Color linear_col = light_storage->light_get_color(base);
+ sky_light_data.color[0] = linear_col.r;
+ sky_light_data.color[1] = linear_col.g;
+ sky_light_data.color[2] = linear_col.b;
+
+ sky_light_data.enabled = true;
+
+ float angular_diameter = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+ if (angular_diameter > 0.0) {
+ angular_diameter = Math::tan(Math::deg2rad(angular_diameter));
+ } else {
+ angular_diameter = 0.0;
+ }
+ sky_light_data.size = angular_diameter;
+ sky_globals.directional_light_count++;
+ if (sky_globals.directional_light_count >= sky_globals.max_directional_lights) {
+ break;
+ }
+ }
+ }
+ // Check whether the directional_light_buffer changes
+ bool light_data_dirty = false;
+
+ // Light buffer is dirty if we have fewer or more lights
+ // If we have fewer lights, make sure that old lights are disabled
+ if (sky_globals.directional_light_count != sky_globals.last_frame_directional_light_count) {
+ light_data_dirty = true;
+ for (uint32_t i = sky_globals.directional_light_count; i < sky_globals.max_directional_lights; i++) {
+ sky_globals.directional_lights[i].enabled = false;
+ }
+ }
+
+ if (!light_data_dirty) {
+ for (uint32_t i = 0; i < sky_globals.directional_light_count; i++) {
+ if (sky_globals.directional_lights[i].direction[0] != sky_globals.last_frame_directional_lights[i].direction[0] ||
+ sky_globals.directional_lights[i].direction[1] != sky_globals.last_frame_directional_lights[i].direction[1] ||
+ sky_globals.directional_lights[i].direction[2] != sky_globals.last_frame_directional_lights[i].direction[2] ||
+ sky_globals.directional_lights[i].energy != sky_globals.last_frame_directional_lights[i].energy ||
+ sky_globals.directional_lights[i].color[0] != sky_globals.last_frame_directional_lights[i].color[0] ||
+ sky_globals.directional_lights[i].color[1] != sky_globals.last_frame_directional_lights[i].color[1] ||
+ sky_globals.directional_lights[i].color[2] != sky_globals.last_frame_directional_lights[i].color[2] ||
+ sky_globals.directional_lights[i].enabled != sky_globals.last_frame_directional_lights[i].enabled ||
+ sky_globals.directional_lights[i].size != sky_globals.last_frame_directional_lights[i].size) {
+ light_data_dirty = true;
+ break;
+ }
+ }
+ }
+
+ if (light_data_dirty) {
+ glBindBufferBase(GL_UNIFORM_BUFFER, SKY_DIRECTIONAL_LIGHT_UNIFORM_LOCATION, sky_globals.directional_light_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(DirectionalLightData) * sky_globals.max_directional_lights, sky_globals.directional_lights, GL_STREAM_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+ DirectionalLightData *temp = sky_globals.last_frame_directional_lights;
+ sky_globals.last_frame_directional_lights = sky_globals.directional_lights;
+ sky_globals.directional_lights = temp;
+ sky_globals.last_frame_directional_light_count = sky_globals.directional_light_count;
+ sky->reflection_dirty = true;
+ }
+ }
+
+ if (!sky->radiance) {
+ _invalidate_sky(sky);
+ _update_dirty_skys();
+ }
+ }
+}
+
+void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection, const Transform3D &p_transform) {
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ ERR_FAIL_COND(p_env.is_null());
+
+ Sky *sky = sky_owner.get_or_null(environment_get_sky(p_env));
+ ERR_FAIL_COND(!sky);
+
+ GLES3::SkyMaterialData *material_data = nullptr;
+ RID sky_material;
+
+ RS::EnvironmentBG background = environment_get_background(p_env);
+
+ if (sky) {
+ ERR_FAIL_COND(!sky);
+ sky_material = sky->material;
+
+ if (sky_material.is_valid()) {
+ material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ if (!material_data || !material_data->shader_data->valid) {
+ material_data = nullptr;
+ }
+ }
+
+ if (!material_data) {
+ sky_material = sky_globals.default_material;
+ material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ }
+ } else if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
+ sky_material = sky_globals.fog_material;
+ material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ }
+
+ ERR_FAIL_COND(!material_data);
+ material_data->bind_uniforms();
+
+ GLES3::SkyShaderData *shader_data = material_data->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+
+ // Camera
+ Projection camera;
+
+ if (environment_get_sky_custom_fov(p_env)) {
+ 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(environment_get_sky_custom_fov(p_env), aspect, near_plane, far_plane);
+ } else {
+ camera = p_projection;
+ }
+ Basis sky_transform = environment_get_sky_orientation(p_env);
+ sky_transform.invert();
+ sky_transform = p_transform.basis * sky_transform;
+
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_bind_shader(shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::ORIENTATION, sky_transform, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, camera.matrix[2][0], camera.matrix[0][0], camera.matrix[2][1], camera.matrix[1][1], shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+
+ glBindVertexArray(sky_globals.screen_triangle_array);
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+}
+
+void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_projection, const Transform3D &p_transform) {
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ ERR_FAIL_COND(p_env.is_null());
+
+ Sky *sky = sky_owner.get_or_null(environment_get_sky(p_env));
+ ERR_FAIL_COND(!sky);
+
+ GLES3::SkyMaterialData *material_data = nullptr;
+ RID sky_material;
+
+ RS::EnvironmentBG background = environment_get_background(p_env);
+
+ if (sky) {
+ ERR_FAIL_COND(!sky);
+ sky_material = sky->material;
+
+ if (sky_material.is_valid()) {
+ material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ if (!material_data || !material_data->shader_data->valid) {
+ material_data = nullptr;
+ }
+ }
+
+ if (!material_data) {
+ sky_material = sky_globals.default_material;
+ material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ }
+ } else if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
+ sky_material = sky_globals.fog_material;
+ material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ }
+
+ ERR_FAIL_COND(!material_data);
+ material_data->bind_uniforms();
+
+ GLES3::SkyShaderData *shader_data = material_data->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+
+ bool update_single_frame = sky->mode == RS::SKY_MODE_REALTIME || sky->mode == RS::SKY_MODE_QUALITY;
+ RS::SkyMode sky_mode = sky->mode;
+
+ if (sky_mode == RS::SKY_MODE_AUTOMATIC) {
+ if (shader_data->uses_time || shader_data->uses_position) {
+ update_single_frame = true;
+ sky_mode = RS::SKY_MODE_REALTIME;
+ } else if (shader_data->uses_light || shader_data->ubo_size > 0) {
+ update_single_frame = false;
+ sky_mode = RS::SKY_MODE_INCREMENTAL;
+ } else {
+ update_single_frame = true;
+ sky_mode = RS::SKY_MODE_QUALITY;
+ }
+ }
+
+ if (sky->processing_layer == 0 && sky_mode == RS::SKY_MODE_INCREMENTAL) {
+ // On the first frame after creating sky, rebuild in single frame
+ update_single_frame = true;
+ sky_mode = RS::SKY_MODE_QUALITY;
+ }
+
+ int max_processing_layer = sky->mipmap_count;
+
+ // Update radiance cubemap
+ if (sky->reflection_dirty && (sky->processing_layer > max_processing_layer || update_single_frame)) {
+ static const Vector3 view_normals[6] = {
+ Vector3(+1, 0, 0),
+ Vector3(-1, 0, 0),
+ Vector3(0, +1, 0),
+ Vector3(0, -1, 0),
+ Vector3(0, 0, +1),
+ Vector3(0, 0, -1)
+ };
+ static const Vector3 view_up[6] = {
+ Vector3(0, -1, 0),
+ Vector3(0, -1, 0),
+ Vector3(0, 0, +1),
+ Vector3(0, 0, -1),
+ Vector3(0, -1, 0),
+ Vector3(0, -1, 0)
+ };
+
+ Projection cm;
+ cm.set_perspective(90, 1, 0.01, 10.0);
+ Projection correction;
+ correction.set_depth_correction(true);
+ cm = correction * cm;
+
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_bind_shader(shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, cm.matrix[2][0], cm.matrix[0][0], cm.matrix[2][1], cm.matrix[1][1], shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+
+ // Bind a vertex array or else OpenGL complains. We won't actually use it
+ glBindVertexArray(sky_globals.screen_triangle_array);
+
+ glViewport(0, 0, sky->radiance_size, sky->radiance_size);
+ glBindFramebuffer(GL_FRAMEBUFFER, sky->radiance_framebuffer);
+
+ for (int i = 0; i < 6; i++) {
+ Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::ORIENTATION, local_view, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, sky->raw_radiance, 0);
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+ }
+
+ if (update_single_frame) {
+ for (int i = 0; i < max_processing_layer; i++) {
+ _filter_sky_radiance(sky, i);
+ }
+ } else {
+ _filter_sky_radiance(sky, 0); //Just copy over the first mipmap
+ }
+ sky->processing_layer = 1;
+
+ sky->reflection_dirty = false;
+ } else {
+ if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) {
+ _filter_sky_radiance(sky, sky->processing_layer);
+ sky->processing_layer++;
+ }
+ }
+}
+
+// Helper functions for IBL filtering
+
+Vector3 importance_sample_GGX(Vector2 xi, float roughness4) {
+ // Compute distribution direction
+ float phi = 2.0 * Math_PI * xi.x;
+ float cos_theta = sqrt((1.0 - xi.y) / (1.0 + (roughness4 - 1.0) * xi.y));
+ float sin_theta = sqrt(1.0 - cos_theta * cos_theta);
+
+ // Convert to spherical direction
+ Vector3 half_vector;
+ half_vector.x = sin_theta * cos(phi);
+ half_vector.y = sin_theta * sin(phi);
+ half_vector.z = cos_theta;
+
+ return half_vector;
+}
+
+float distribution_GGX(float NdotH, float roughness4) {
+ float NdotH2 = NdotH * NdotH;
+ float denom = (NdotH2 * (roughness4 - 1.0) + 1.0);
+ denom = Math_PI * denom * denom;
+
+ return roughness4 / denom;
+}
+
+float radical_inverse_vdC(uint32_t bits) {
+ 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);
+
+ return float(bits) * 2.3283064365386963e-10;
+}
+
+Vector2 hammersley(uint32_t i, uint32_t N) {
+ return Vector2(float(i) / float(N), radical_inverse_vdC(i));
+}
+
+void RasterizerSceneGLES3::_filter_sky_radiance(Sky *p_sky, int p_base_layer) {
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, p_sky->raw_radiance);
+ glBindFramebuffer(GL_FRAMEBUFFER, p_sky->radiance_framebuffer);
-/* ENVIRONMENT API */
+ CubemapFilterShaderGLES3::ShaderVariant mode = CubemapFilterShaderGLES3::MODE_DEFAULT;
-RID RasterizerSceneGLES3::environment_allocate() {
- return RID();
-}
+ if (p_base_layer == 0) {
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+ // Copy over base layer without filtering.
+ mode = CubemapFilterShaderGLES3::MODE_COPY;
+ }
-void RasterizerSceneGLES3::environment_initialize(RID p_rid) {
-}
+ int size = p_sky->radiance_size >> p_base_layer;
+ glViewport(0, 0, size, size);
+ glBindVertexArray(sky_globals.screen_triangle_array);
-void RasterizerSceneGLES3::environment_set_background(RID p_env, RS::EnvironmentBG p_bg) {
-}
+ material_storage->shaders.cubemap_filter_shader.version_bind_shader(scene_globals.cubemap_filter_shader_version, mode);
-void RasterizerSceneGLES3::environment_set_sky(RID p_env, RID p_sky) {
-}
+ if (p_base_layer > 0) {
+ const uint32_t sample_counts[4] = { 1, sky_globals.ggx_samples / 4, sky_globals.ggx_samples / 2, sky_globals.ggx_samples };
+ uint32_t sample_count = sample_counts[MIN(3, p_base_layer)];
-void RasterizerSceneGLES3::environment_set_sky_custom_fov(RID p_env, float p_scale) {
-}
+ float roughness = float(p_base_layer) / (p_sky->mipmap_count);
+ float roughness4 = roughness * roughness;
+ roughness4 *= roughness4;
-void RasterizerSceneGLES3::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) {
-}
+ float solid_angle_texel = 4.0 * Math_PI / float(6 * size * size);
-void RasterizerSceneGLES3::environment_set_bg_color(RID p_env, const Color &p_color) {
-}
+ LocalVector<float> sample_directions;
+ sample_directions.resize(4 * sample_count);
-void RasterizerSceneGLES3::environment_set_bg_energy(RID p_env, float p_energy) {
-}
+ uint32_t index = 0;
+ float weight = 0.0;
+ for (uint32_t i = 0; i < sample_count; i++) {
+ Vector2 xi = hammersley(i, sample_count);
+ Vector3 dir = importance_sample_GGX(xi, roughness4);
+ Vector3 light_vec = (2.0 * dir.z * dir - Vector3(0.0, 0.0, 1.0));
-void RasterizerSceneGLES3::environment_set_canvas_max_layer(RID p_env, int p_max_layer) {
-}
+ if (light_vec.z < 0.0) {
+ continue;
+ }
+
+ sample_directions[index * 4] = light_vec.x;
+ sample_directions[index * 4 + 1] = light_vec.y;
+ sample_directions[index * 4 + 2] = light_vec.z;
+
+ float D = distribution_GGX(dir.z, roughness4);
+ float pdf = D * dir.z / (4.0 * dir.z) + 0.0001;
+
+ float solid_angle_sample = 1.0 / (float(sample_count) * pdf + 0.0001);
+
+ float mip_level = MAX(0.5 * log2(solid_angle_sample / solid_angle_texel) + float(MAX(1, p_base_layer - 3)), 1.0);
-void RasterizerSceneGLES3::environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source) {
+ sample_directions[index * 4 + 3] = mip_level;
+ weight += light_vec.z;
+ index++;
+ }
+
+ glUniform4fv(material_storage->shaders.cubemap_filter_shader.version_get_uniform(CubemapFilterShaderGLES3::SAMPLE_DIRECTIONS_MIP, scene_globals.cubemap_filter_shader_version, mode), sample_count, sample_directions.ptr());
+ material_storage->shaders.cubemap_filter_shader.version_set_uniform(CubemapFilterShaderGLES3::WEIGHT, weight, scene_globals.cubemap_filter_shader_version, mode);
+ material_storage->shaders.cubemap_filter_shader.version_set_uniform(CubemapFilterShaderGLES3::SAMPLE_COUNT, index, scene_globals.cubemap_filter_shader_version, mode);
+ }
+
+ for (int i = 0; i < 6; i++) {
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, p_sky->radiance, p_base_layer);
+#ifdef DEBUG_ENABLED
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ WARN_PRINT("Could not bind sky radiance face: " + itos(i) + ", status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
+ }
+#endif
+ material_storage->shaders.cubemap_filter_shader.version_set_uniform(CubemapFilterShaderGLES3::FACE_ID, i, scene_globals.cubemap_filter_shader_version, mode);
+
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+ }
+ glBindVertexArray(0);
+ glViewport(0, 0, p_sky->screen_size.x, p_sky->screen_size.y);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
-void RasterizerSceneGLES3::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, float p_glow_map_strength, RID p_glow_map) {
+Ref<Image> RasterizerSceneGLES3::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) {
+ return Ref<Image>();
}
+/* ENVIRONMENT API */
+
void RasterizerSceneGLES3::environment_glow_set_use_bicubic_upscale(bool p_enable) {
+ glow_bicubic_upscale = p_enable;
}
void RasterizerSceneGLES3::environment_glow_set_use_high_quality(bool p_enable) {
-}
-
-void RasterizerSceneGLES3::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) {
+ glow_high_quality = p_enable;
}
void RasterizerSceneGLES3::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) {
}
-void RasterizerSceneGLES3::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) {
-}
-
void RasterizerSceneGLES3::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) {
}
-void RasterizerSceneGLES3::environment_set_ssil(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_sharpness, float p_normal_rejection) {
-}
void RasterizerSceneGLES3::environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) {
}
-void RasterizerSceneGLES3::environment_set_sdfgi(RID p_env, bool p_enable, int p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) {
-}
-
void RasterizerSceneGLES3::environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) {
}
@@ -246,18 +1052,6 @@ void RasterizerSceneGLES3::environment_set_sdfgi_frames_to_converge(RS::Environm
void RasterizerSceneGLES3::environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) {
}
-void RasterizerSceneGLES3::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 RasterizerSceneGLES3::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) {
-}
-
-void RasterizerSceneGLES3::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) {
-}
-
-void RasterizerSceneGLES3::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) {
-}
-
void RasterizerSceneGLES3::environment_set_volumetric_fog_volume_size(int p_size, int p_depth) {
}
@@ -268,18 +1062,6 @@ Ref<Image> RasterizerSceneGLES3::environment_bake_panorama(RID p_env, bool p_bak
return Ref<Image>();
}
-bool RasterizerSceneGLES3::is_environment(RID p_env) const {
- return false;
-}
-
-RS::EnvironmentBG RasterizerSceneGLES3::environment_get_background(RID p_env) const {
- return RS::ENV_BG_KEEP;
-}
-
-int RasterizerSceneGLES3::environment_get_canvas_max_layer(RID p_env) const {
- return 0;
-}
-
RID RasterizerSceneGLES3::camera_effects_allocate() {
return RID();
}
@@ -299,23 +1081,39 @@ void RasterizerSceneGLES3::camera_effects_set_dof_blur(RID p_camera_effects, boo
void RasterizerSceneGLES3::camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) {
}
-void RasterizerSceneGLES3::shadows_quality_set(RS::ShadowQuality p_quality) {
+void RasterizerSceneGLES3::positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) {
}
-void RasterizerSceneGLES3::directional_shadow_quality_set(RS::ShadowQuality p_quality) {
+void RasterizerSceneGLES3::directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) {
}
RID RasterizerSceneGLES3::light_instance_create(RID p_light) {
- return RID();
+ RID li = light_instance_owner.make_rid(LightInstance());
+
+ LightInstance *light_instance = light_instance_owner.get_or_null(li);
+
+ light_instance->self = li;
+ light_instance->light = p_light;
+ light_instance->light_type = RSG::light_storage->light_get_type(p_light);
+
+ return li;
}
void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ light_instance->transform = p_transform;
}
void RasterizerSceneGLES3::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ light_instance->aabb = p_aabb;
}
-void RasterizerSceneGLES3::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) {
+void RasterizerSceneGLES3::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) {
}
void RasterizerSceneGLES3::light_instance_mark_visible(RID p_light_instance) {
@@ -401,35 +1199,1172 @@ bool RasterizerSceneGLES3::voxel_gi_needs_update(RID p_probe) const {
return false;
}
-void RasterizerSceneGLES3::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects) {
+void RasterizerSceneGLES3::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects) {
}
void RasterizerSceneGLES3::voxel_gi_set_quality(RS::VoxelGIQuality) {
}
-void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) {
-}
+void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append) {
+ GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
+
+ if (p_render_list == RENDER_LIST_OPAQUE) {
+ scene_state.used_screen_texture = false;
+ scene_state.used_normal_texture = false;
+ scene_state.used_depth_texture = false;
+ }
+
+ Plane near_plane;
+ if (p_render_data->cam_orthogonal) {
+ near_plane = Plane(-p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->cam_transform.origin);
+ near_plane.d += p_render_data->cam_projection.get_z_near();
+ }
+ float z_max = p_render_data->cam_projection.get_z_far() - p_render_data->cam_projection.get_z_near();
+
+ RenderList *rl = &render_list[p_render_list];
+
+ // Parse any updates on our geometry, updates surface caches and such
+ _update_dirty_geometry_instances();
+
+ if (!p_append) {
+ rl->clear();
+ if (p_render_list == RENDER_LIST_OPAQUE) {
+ render_list[RENDER_LIST_ALPHA].clear(); //opaque fills alpha too
+ }
+ }
+
+ //fill list
+
+ for (int i = 0; i < (int)p_render_data->instances->size(); i++) {
+ GeometryInstanceGLES3 *inst = static_cast<GeometryInstanceGLES3 *>((*p_render_data->instances)[i]);
+
+ if (p_render_data->cam_orthogonal) {
+ Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal);
+ inst->depth = near_plane.distance_to(support_min);
+ } else {
+ Vector3 aabb_center = inst->transformed_aabb.position + (inst->transformed_aabb.size * 0.5);
+ inst->depth = p_render_data->cam_transform.origin.distance_to(aabb_center);
+ }
+ uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15);
+
+ uint32_t flags = inst->base_flags; //fill flags if appropriate
+
+ if (inst->non_uniform_scale) {
+ flags |= INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE;
+ }
+
+ // Sets the index values for lookup in the shader
+ // This has to be done after _setup_lights was called this frame
+ // TODO, check shadow status of lights here, if using shadows, skip here and add below
+ if (p_pass_mode == PASS_MODE_COLOR) {
+ if (inst->omni_light_count) {
+ inst->omni_light_gl_cache.resize(inst->omni_light_count);
+ for (uint32_t j = 0; j < inst->omni_light_count; j++) {
+ inst->omni_light_gl_cache[j] = light_instance_get_gl_id(inst->omni_lights[j]);
+ }
+ }
+ if (inst->spot_light_count) {
+ inst->spot_light_gl_cache.resize(inst->spot_light_count);
+ for (uint32_t j = 0; j < inst->spot_light_count; j++) {
+ inst->spot_light_gl_cache[j] = light_instance_get_gl_id(inst->spot_lights[j]);
+ }
+ }
+ }
+
+ inst->flags_cache = flags;
+
+ GeometryInstanceSurface *surf = inst->surface_caches;
+
+ while (surf) {
+ // LOD
+
+ if (p_render_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
+ //lod
+ Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->lod_camera_plane.normal);
+ Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->lod_camera_plane.normal);
+
+ float distance_min = p_render_data->lod_camera_plane.distance_to(lod_support_min);
+ float distance_max = p_render_data->lod_camera_plane.distance_to(lod_support_max);
+
+ float distance = 0.0;
+
+ if (distance_min * distance_max < 0.0) {
+ //crossing plane
+ distance = 0.0;
+ } else if (distance_min >= 0.0) {
+ distance = distance_min;
+ } else if (distance_max <= 0.0) {
+ distance = -distance_max;
+ }
+
+ if (p_render_data->cam_orthogonal) {
+ distance = 1.0;
+ }
+
+ uint32_t indices;
+ surf->lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, &indices);
+ /*
+ if (p_render_data->render_info) {
+ indices = _indices_to_primitives(surf->primitive, indices);
+ if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += indices;
+ } else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += indices;
+ }
+ }
+ */
+ } else {
+ surf->lod_index = 0;
+ /*
+ if (p_render_data->render_info) {
+ uint32_t to_draw = mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ to_draw = _indices_to_primitives(surf->primitive, to_draw);
+ to_draw *= inst->instance_count;
+ if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ } else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ }
+ }
+ */
+ }
+
+ // ADD Element
+ if (p_pass_mode == PASS_MODE_COLOR) {
+#ifdef DEBUG_ENABLED
+ bool force_alpha = unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW);
+#else
+ bool force_alpha = false;
+#endif
+ if (!force_alpha && (surf->flags & GeometryInstanceSurface::FLAG_PASS_OPAQUE)) {
+ rl->add_element(surf);
+ }
+ if (force_alpha || (surf->flags & GeometryInstanceSurface::FLAG_PASS_ALPHA)) {
+ render_list[RENDER_LIST_ALPHA].add_element(surf);
+ }
+
+ if (surf->flags & GeometryInstanceSurface::FLAG_USES_SCREEN_TEXTURE) {
+ scene_state.used_screen_texture = true;
+ }
+ if (surf->flags & GeometryInstanceSurface::FLAG_USES_NORMAL_TEXTURE) {
+ scene_state.used_normal_texture = true;
+ }
+ if (surf->flags & GeometryInstanceSurface::FLAG_USES_DEPTH_TEXTURE) {
+ scene_state.used_depth_texture = true;
+ }
+
+ /*
+ Add elements here if there are shadows
+ */
+
+ } else if (p_pass_mode == PASS_MODE_SHADOW) {
+ if (surf->flags & GeometryInstanceSurface::FLAG_PASS_SHADOW) {
+ rl->add_element(surf);
+ }
+ } else {
+ if (surf->flags & (GeometryInstanceSurface::FLAG_PASS_DEPTH | GeometryInstanceSurface::FLAG_PASS_OPAQUE)) {
+ rl->add_element(surf);
+ }
+ }
+
+ surf->sort.depth_layer = depth_layer;
+
+ surf = surf->next;
+ }
+ }
+}
+
+// Needs to be called after _setup_lights so that directional_light_count is accurate.
+void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_pancake_shadows) {
+ Projection correction;
+ correction.set_depth_correction(p_flip_y);
+ Projection projection = correction * p_render_data->cam_projection;
+ //store camera into ubo
+ GLES3::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix);
+ GLES3::MaterialStorage::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix);
+ GLES3::MaterialStorage::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix);
+ GLES3::MaterialStorage::store_transform(p_render_data->inv_cam_transform, scene_state.ubo.view_matrix);
+
+ scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
+
+ scene_state.ubo.z_far = p_render_data->z_far;
+ scene_state.ubo.z_near = p_render_data->z_near;
+
+ scene_state.ubo.viewport_size[0] = p_screen_size.x;
+ scene_state.ubo.viewport_size[1] = p_screen_size.y;
+
+ Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size);
+ scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x;
+ scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y;
+
+ //time global variables
+ scene_state.ubo.time = time;
+
+ if (is_environment(p_render_data->environment)) {
+ RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment);
+ RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment);
+
+ float bg_energy = environment_get_bg_energy(p_render_data->environment);
+ scene_state.ubo.ambient_light_color_energy[3] = bg_energy;
+
+ scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_render_data->environment);
+
+ //ambient
+ if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) {
+ Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment);
+ color = color.srgb_to_linear();
+
+ scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy;
+ scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy;
+ scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy;
+ scene_state.ubo.use_ambient_light = true;
+ scene_state.ubo.use_ambient_cubemap = false;
+ } else {
+ float energy = environment_get_ambient_light_energy(p_render_data->environment);
+ Color color = environment_get_ambient_light(p_render_data->environment);
+ color = color.srgb_to_linear();
+ scene_state.ubo.ambient_light_color_energy[0] = color.r * energy;
+ scene_state.ubo.ambient_light_color_energy[1] = color.g * energy;
+ scene_state.ubo.ambient_light_color_energy[2] = color.b * energy;
+
+ Basis sky_transform = environment_get_sky_orientation(p_render_data->environment);
+ sky_transform = sky_transform.inverse() * p_render_data->cam_transform.basis;
+ GLES3::MaterialStorage::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform);
+ scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY;
+ scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR;
+ }
+
+ //specular
+ RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_render_data->environment);
+ if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) {
+ scene_state.ubo.use_reflection_cubemap = true;
+ } else {
+ scene_state.ubo.use_reflection_cubemap = false;
+ }
+
+ scene_state.ubo.fog_enabled = environment_get_fog_enabled(p_render_data->environment);
+ scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment);
+ scene_state.ubo.fog_height = environment_get_fog_height(p_render_data->environment);
+ scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment);
+ scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment);
+
+ Color fog_color = environment_get_fog_light_color(p_render_data->environment).srgb_to_linear();
+ float fog_energy = environment_get_fog_light_energy(p_render_data->environment);
+
+ scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
+ scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
+ scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
+
+ scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_render_data->environment);
+
+ } else {
+ }
+
+ if (scene_state.ubo_buffer == 0) {
+ glGenBuffers(1, &scene_state.ubo_buffer);
+ }
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::UBO), &scene_state.ubo, GL_STREAM_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+}
+
+// Puts lights into Uniform Buffers. Needs to be called before _fill_list as this caches the index of each light in the Uniform Buffer
+void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_omni_light_count, uint32_t &r_spot_light_count) {
+ GLES3::LightStorage *light_storage = GLES3::LightStorage::get_singleton();
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
+ const Transform3D inverse_transform = p_render_data->inv_cam_transform;
+
+ const PagedArray<RID> &lights = *p_render_data->lights;
+
+ r_directional_light_count = 0;
+ r_omni_light_count = 0;
+ r_spot_light_count = 0;
+
+ int num_lights = lights.size();
+
+ for (int i = 0; i < num_lights; i++) {
+ LightInstance *li = light_instance_owner.get_or_null(lights[i]);
+ if (!li) {
+ continue;
+ }
+ RID base = li->light;
+
+ ERR_CONTINUE(base.is_null());
+
+ RS::LightType type = light_storage->light_get_type(base);
+ switch (type) {
+ case RS::LIGHT_DIRECTIONAL: {
+ if (r_directional_light_count >= RendererSceneRender::MAX_DIRECTIONAL_LIGHTS || light_storage->light_directional_get_sky_mode(base) == RS::LIGHT_DIRECTIONAL_SKY_MODE_SKY_ONLY) {
+ continue;
+ }
+
+ DirectionalLightData &light_data = scene_state.directional_lights[r_directional_light_count];
+
+ Transform3D light_transform = li->transform;
+
+ Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized();
+
+ light_data.direction[0] = direction.x;
+ light_data.direction[1] = direction.y;
+ light_data.direction[2] = direction.z;
+
+ float sign = light_storage->light_is_negative(base) ? -1 : 1;
+
+ light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI;
+
+ Color linear_col = light_storage->light_get_color(base).srgb_to_linear();
+ light_data.color[0] = linear_col.r;
+ light_data.color[1] = linear_col.g;
+ light_data.color[2] = linear_col.b;
+
+ float size = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+ light_data.size = 1.0 - Math::cos(Math::deg2rad(size)); //angle to cosine offset
+
+ light_data.specular = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR);
-void RasterizerSceneGLES3::render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
-}
+ r_directional_light_count++;
+ } break;
+ case RS::LIGHT_OMNI: {
+ if (r_omni_light_count >= (uint32_t)config->max_renderable_lights) {
+ continue;
+ }
-void RasterizerSceneGLES3::render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) {
-}
+ const real_t distance = p_render_data->cam_transform.origin.distance_to(li->transform.origin);
+
+ if (light_storage->light_is_distance_fade_enabled(li->light)) {
+ const float fade_begin = light_storage->light_get_distance_fade_begin(li->light);
+ const float fade_length = light_storage->light_get_distance_fade_length(li->light);
+
+ if (distance > fade_begin) {
+ if (distance > fade_begin + fade_length) {
+ // Out of range, don't draw this light to improve performance.
+ continue;
+ }
+ }
+ }
+
+ li->gl_id = r_omni_light_count;
-void RasterizerSceneGLES3::set_scene_pass(uint64_t p_pass) {
+ scene_state.omni_light_sort[r_omni_light_count].instance = li;
+ scene_state.omni_light_sort[r_omni_light_count].depth = distance;
+ r_omni_light_count++;
+ } break;
+ case RS::LIGHT_SPOT: {
+ if (r_spot_light_count >= (uint32_t)config->max_renderable_lights) {
+ continue;
+ }
+
+ const real_t distance = p_render_data->cam_transform.origin.distance_to(li->transform.origin);
+
+ if (light_storage->light_is_distance_fade_enabled(li->light)) {
+ const float fade_begin = light_storage->light_get_distance_fade_begin(li->light);
+ const float fade_length = light_storage->light_get_distance_fade_length(li->light);
+
+ if (distance > fade_begin) {
+ if (distance > fade_begin + fade_length) {
+ // Out of range, don't draw this light to improve performance.
+ continue;
+ }
+ }
+ }
+
+ li->gl_id = r_spot_light_count;
+
+ scene_state.spot_light_sort[r_spot_light_count].instance = li;
+ scene_state.spot_light_sort[r_spot_light_count].depth = distance;
+ r_spot_light_count++;
+ } break;
+ }
+ }
+
+ if (r_omni_light_count) {
+ SortArray<InstanceSort<LightInstance>> sorter;
+ sorter.sort(scene_state.omni_light_sort, r_omni_light_count);
+ }
+
+ if (r_spot_light_count) {
+ SortArray<InstanceSort<LightInstance>> sorter;
+ sorter.sort(scene_state.spot_light_sort, r_spot_light_count);
+ }
+
+ for (uint32_t i = 0; i < (r_omni_light_count + r_spot_light_count); i++) {
+ uint32_t index = (i < r_omni_light_count) ? i : i - (r_omni_light_count);
+ LightData &light_data = (i < r_omni_light_count) ? scene_state.omni_lights[index] : scene_state.spot_lights[index];
+ //RS::LightType type = (i < omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT;
+ LightInstance *li = (i < r_omni_light_count) ? scene_state.omni_light_sort[index].instance : scene_state.spot_light_sort[index].instance;
+ RID base = li->light;
+
+ Transform3D light_transform = li->transform;
+ Vector3 pos = inverse_transform.xform(light_transform.origin);
+
+ light_data.position[0] = pos.x;
+ light_data.position[1] = pos.y;
+ light_data.position[2] = pos.z;
+
+ float radius = MAX(0.001, light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE));
+ light_data.inv_radius = 1.0 / radius;
+
+ Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, -1))).normalized();
+
+ light_data.direction[0] = direction.x;
+ light_data.direction[1] = direction.y;
+ light_data.direction[2] = direction.z;
+
+ float size = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+
+ light_data.size = size;
+
+ float sign = light_storage->light_is_negative(base) ? -1 : 1;
+ Color linear_col = light_storage->light_get_color(base).srgb_to_linear();
+
+ // Reuse fade begin, fade length and distance for shadow LOD determination later.
+ float fade_begin = 0.0;
+ float fade_length = 0.0;
+ real_t distance = 0.0;
+
+ float fade = 1.0;
+ if (light_storage->light_is_distance_fade_enabled(li->light)) {
+ fade_begin = light_storage->light_get_distance_fade_begin(li->light);
+ fade_length = light_storage->light_get_distance_fade_length(li->light);
+ distance = p_render_data->cam_transform.origin.distance_to(li->transform.origin);
+
+ if (distance > fade_begin) {
+ // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player.
+ fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_begin) / fade_length);
+ }
+ }
+
+ float energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI * fade;
+
+ light_data.color[0] = linear_col.r * energy;
+ light_data.color[1] = linear_col.g * energy;
+ light_data.color[2] = linear_col.b * energy;
+
+ light_data.attenuation = light_storage->light_get_param(base, RS::LIGHT_PARAM_ATTENUATION);
+
+ light_data.inv_spot_attenuation = 1.0f / light_storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+
+ float spot_angle = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE);
+ light_data.cos_spot_angle = Math::cos(Math::deg2rad(spot_angle));
+
+ light_data.specular_amount = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 2.0;
+
+ light_data.shadow_opacity = 0.0;
+ }
+
+ // TODO, to avoid stalls, should rotate between 3 buffers based on frame index.
+ // TODO, consider mapping the buffer as in 2D
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_OMNILIGHT_UNIFORM_LOCATION, scene_state.omni_light_buffer);
+ if (r_omni_light_count) {
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(LightData) * r_omni_light_count, scene_state.omni_lights);
+ }
+
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_SPOTLIGHT_UNIFORM_LOCATION, scene_state.spot_light_buffer);
+ if (r_spot_light_count) {
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(LightData) * r_spot_light_count, scene_state.spot_lights);
+ }
+
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION, scene_state.directional_light_buffer);
+ if (r_directional_light_count) {
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(DirectionalLightData) * r_directional_light_count, scene_state.directional_lights);
+ }
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+}
+
+void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ GLES3::Config *config = GLES3::Config::get_singleton();
+ RENDER_TIMESTAMP("Setup 3D Scene");
+
+ RenderBuffers *rb = nullptr;
+ if (p_render_buffers.is_valid()) {
+ rb = render_buffers_owner.get_or_null(p_render_buffers);
+ ERR_FAIL_COND(!rb);
+ }
+
+ // Assign render data
+ // Use the format from rendererRD
+ RenderDataGLES3 render_data;
+ {
+ render_data.render_buffers = p_render_buffers;
+ render_data.transparent_bg = rb->is_transparent;
+ // Our first camera is used by default
+ render_data.cam_transform = p_camera_data->main_transform;
+ render_data.inv_cam_transform = render_data.cam_transform.affine_inverse();
+ render_data.cam_projection = p_camera_data->main_projection;
+ render_data.cam_orthogonal = p_camera_data->is_orthogonal;
+
+ render_data.view_count = p_camera_data->view_count;
+ for (uint32_t v = 0; v < p_camera_data->view_count; v++) {
+ render_data.view_eye_offset[v] = p_camera_data->view_offset[v].origin;
+ render_data.view_projection[v] = p_camera_data->view_projection[v];
+ }
+
+ render_data.z_near = p_camera_data->main_projection.get_z_near();
+ render_data.z_far = p_camera_data->main_projection.get_z_far();
+
+ render_data.instances = &p_instances;
+ render_data.lights = &p_lights;
+ render_data.reflection_probes = &p_reflection_probes;
+ render_data.environment = p_environment;
+ render_data.camera_effects = p_camera_effects;
+ render_data.reflection_probe = p_reflection_probe;
+ render_data.reflection_probe_pass = p_reflection_probe_pass;
+
+ // this should be the same for all cameras..
+ render_data.lod_distance_multiplier = p_camera_data->main_projection.get_lod_multiplier();
+ render_data.lod_camera_plane = Plane(-p_camera_data->main_transform.basis.get_column(Vector3::AXIS_Z), p_camera_data->main_transform.get_origin());
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
+ render_data.screen_mesh_lod_threshold = 0.0;
+ } else {
+ render_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
+ }
+ render_data.render_info = r_render_info;
+ }
+
+ PagedArray<RID> empty;
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
+ render_data.lights = &empty;
+ render_data.reflection_probes = &empty;
+ }
+
+ bool reverse_cull = false;
+
+ ///////////
+ // Fill Light lists here
+ //////////
+
+ GLuint global_buffer = GLES3::MaterialStorage::get_singleton()->global_shader_uniforms_get_uniform_buffer();
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_GLOBALS_UNIFORM_LOCATION, global_buffer);
+
+ Color clear_color;
+ if (p_render_buffers.is_valid()) {
+ clear_color = texture_storage->render_target_get_clear_request_color(rb->render_target);
+ } else {
+ clear_color = texture_storage->get_default_clear_color();
+ }
+
+ bool fb_cleared = false;
+
+ Size2i screen_size;
+ screen_size.x = rb->width;
+ screen_size.y = rb->height;
+
+ bool use_wireframe = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME;
+
+ SceneState::TonemapUBO tonemap_ubo;
+ if (render_data.environment.is_valid()) {
+ tonemap_ubo.exposure = environment_get_exposure(render_data.environment);
+ tonemap_ubo.white = environment_get_white(render_data.environment);
+ tonemap_ubo.tonemapper = int32_t(environment_get_tone_mapper(render_data.environment));
+ }
+
+ if (scene_state.tonemap_buffer == 0) {
+ // Only create if using 3D
+ glGenBuffers(1, &scene_state.tonemap_buffer);
+ }
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_TONEMAP_UNIFORM_LOCATION, scene_state.tonemap_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::TonemapUBO), &tonemap_ubo, GL_STREAM_DRAW);
+
+ _setup_lights(&render_data, false, render_data.directional_light_count, render_data.omni_light_count, render_data.spot_light_count);
+ _setup_environment(&render_data, render_data.reflection_probe.is_valid(), screen_size, !render_data.reflection_probe.is_valid(), clear_color, false);
+
+ _fill_render_list(RENDER_LIST_OPAQUE, &render_data, PASS_MODE_COLOR);
+ render_list[RENDER_LIST_OPAQUE].sort_by_key();
+ render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority();
+
+ bool draw_sky = false;
+ bool draw_sky_fog_only = false;
+ bool keep_color = false;
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
+ clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black
+ } else if (render_data.environment.is_valid()) {
+ RS::EnvironmentBG bg_mode = environment_get_background(render_data.environment);
+ float bg_energy = environment_get_bg_energy(render_data.environment);
+ switch (bg_mode) {
+ case RS::ENV_BG_CLEAR_COLOR: {
+ clear_color.r *= bg_energy;
+ clear_color.g *= bg_energy;
+ clear_color.b *= bg_energy;
+ if (environment_get_fog_enabled(render_data.environment)) {
+ draw_sky_fog_only = true;
+ GLES3::MaterialStorage::get_singleton()->material_set_param(sky_globals.fog_material, "clear_color", Variant(clear_color));
+ }
+ } break;
+ case RS::ENV_BG_COLOR: {
+ clear_color = environment_get_bg_color(render_data.environment);
+ clear_color.r *= bg_energy;
+ clear_color.g *= bg_energy;
+ clear_color.b *= bg_energy;
+ if (environment_get_fog_enabled(render_data.environment)) {
+ draw_sky_fog_only = true;
+ GLES3::MaterialStorage::get_singleton()->material_set_param(sky_globals.fog_material, "clear_color", Variant(clear_color));
+ }
+ } break;
+ case RS::ENV_BG_SKY: {
+ draw_sky = true;
+ } break;
+ case RS::ENV_BG_CANVAS: {
+ keep_color = true;
+ } break;
+ case RS::ENV_BG_KEEP: {
+ keep_color = true;
+ } break;
+ case RS::ENV_BG_CAMERA_FEED: {
+ } break;
+ default: {
+ }
+ }
+ // setup sky if used for ambient, reflections, or background
+ if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(render_data.environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(render_data.environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
+ RENDER_TIMESTAMP("Setup Sky");
+ Projection projection = render_data.cam_projection;
+ if (render_data.reflection_probe.is_valid()) {
+ Projection correction;
+ correction.set_depth_correction(true);
+ projection = correction * render_data.cam_projection;
+ }
+
+ _setup_sky(render_data.environment, p_render_buffers, *render_data.lights, projection, render_data.cam_transform, screen_size);
+
+ if (environment_get_sky(render_data.environment).is_valid()) {
+ if (environment_get_reflection_source(render_data.environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(render_data.environment) == RS::ENV_AMBIENT_SOURCE_SKY || (environment_get_reflection_source(render_data.environment) == RS::ENV_REFLECTION_SOURCE_BG && environment_get_background(render_data.environment) == RS::ENV_BG_SKY)) {
+ _update_sky_radiance(render_data.environment, projection, render_data.cam_transform);
+ }
+ } else {
+ // do not try to draw sky if invalid
+ draw_sky = false;
+ }
+ }
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, rb->framebuffer);
+ glViewport(0, 0, rb->width, rb->height);
+
+ // Do depth prepass if it's explicitly enabled
+ bool use_depth_prepass = config->use_depth_prepass;
+
+ // Don't do depth prepass we are rendering overdraw
+ use_depth_prepass = use_depth_prepass && get_debug_draw_mode() != RS::VIEWPORT_DEBUG_DRAW_OVERDRAW;
+
+ if (use_depth_prepass) {
+ RENDER_TIMESTAMP("Depth Prepass");
+ //pre z pass
+
+ glDisable(GL_BLEND);
+ glDepthMask(GL_TRUE);
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LEQUAL);
+ glDisable(GL_SCISSOR_TEST);
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+ scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
+
+ glColorMask(0, 0, 0, 0);
+ glClearDepth(1.0f);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, 0, use_wireframe);
+ _render_list_template<PASS_MODE_DEPTH>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_OPAQUE].elements.size());
+
+ glColorMask(1, 1, 1, 1);
+
+ fb_cleared = true;
+ scene_state.used_depth_prepass = true;
+ } else {
+ scene_state.used_depth_prepass = false;
+ }
+
+ glBlendEquation(GL_FUNC_ADD);
+
+ if (render_data.transparent_bg) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ } else {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
+ glDisable(GL_BLEND);
+ }
+ scene_state.current_blend_mode = GLES3::SceneShaderData::BLEND_MODE_MIX;
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LEQUAL);
+ glDepthMask(GL_TRUE);
+ scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
+ scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_OPAQUE;
+
+ if (!fb_cleared) {
+ glClearDepth(1.0f);
+ glClear(GL_DEPTH_BUFFER_BIT);
+ }
+
+ if (!keep_color) {
+ glClearBufferfv(GL_COLOR, 0, clear_color.components);
+ }
+ RENDER_TIMESTAMP("Render Opaque Pass");
+ uint32_t spec_constant_base_flags = 0;
+
+ {
+ // Specialization Constants that apply for entire rendering pass.
+ if (render_data.directional_light_count == 0) {
+ spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS;
+ }
+
+ if (render_data.environment.is_null() || (render_data.environment.is_valid() && !environment_get_fog_enabled(render_data.environment))) {
+ spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_FOG;
+ }
+ }
+ // Render Opaque Objects.
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, spec_constant_base_flags, use_wireframe);
+
+ _render_list_template<PASS_MODE_COLOR>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_OPAQUE].elements.size());
+
+ if (draw_sky) {
+ RENDER_TIMESTAMP("Render Sky");
+ if (scene_state.current_depth_test != GLES3::SceneShaderData::DEPTH_TEST_ENABLED) {
+ glEnable(GL_DEPTH_TEST);
+ scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
+ }
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_BLEND);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
+ scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_DISABLED;
+ scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
+
+ _draw_sky(render_data.environment, render_data.cam_projection, render_data.cam_transform);
+ }
+
+ RENDER_TIMESTAMP("Render 3D Transparent Pass");
+ glEnable(GL_BLEND);
+
+ //Render transparent pass
+ RenderListParameters render_list_params_alpha(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, spec_constant_base_flags, use_wireframe);
+
+ _render_list_template<PASS_MODE_COLOR_TRANSPARENT>(&render_list_params_alpha, &render_data, 0, render_list[RENDER_LIST_ALPHA].elements.size(), true);
+
+ if (p_render_buffers.is_valid()) {
+ _render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex);
+ }
+ glDisable(GL_BLEND);
+ texture_storage->render_target_disable_clear_request(rb->render_target);
+}
+
+template <PassMode p_pass_mode>
+void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, const RenderDataGLES3 *p_render_data, uint32_t p_from_element, uint32_t p_to_element, bool p_alpha_pass) {
+ GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
+ GLuint prev_vertex_array_gl = 0;
+ GLuint prev_index_array_gl = 0;
+
+ GLES3::SceneMaterialData *prev_material_data = nullptr;
+ GLES3::SceneShaderData *prev_shader = nullptr;
+ GeometryInstanceGLES3 *prev_inst = nullptr;
+ SceneShaderGLES3::ShaderVariant prev_variant = SceneShaderGLES3::ShaderVariant::MODE_COLOR;
+
+ SceneShaderGLES3::ShaderVariant shader_variant = SceneShaderGLES3::MODE_COLOR; // Assigned to silence wrong -Wmaybe-initialized.
+
+ switch (p_pass_mode) {
+ case PASS_MODE_COLOR:
+ case PASS_MODE_COLOR_TRANSPARENT: {
+ } break;
+ case PASS_MODE_COLOR_ADDITIVE: {
+ shader_variant = SceneShaderGLES3::MODE_ADDITIVE;
+ } break;
+ case PASS_MODE_SHADOW:
+ case PASS_MODE_DEPTH: {
+ shader_variant = SceneShaderGLES3::MODE_DEPTH;
+ } break;
+ }
+
+ if (p_pass_mode == PASS_MODE_COLOR || p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) {
+ glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 2);
+ GLuint texture_to_bind = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_CUBEMAP_BLACK))->tex_id;
+ if (p_render_data->environment.is_valid()) {
+ Sky *sky = sky_owner.get_or_null(environment_get_sky(p_render_data->environment));
+ if (sky && sky->radiance != 0) {
+ texture_to_bind = sky->radiance;
+ // base_spec_constant |= USE_RADIANCE_MAP;
+ }
+ glBindTexture(GL_TEXTURE_CUBE_MAP, texture_to_bind);
+ }
+ }
+
+ for (uint32_t i = p_from_element; i < p_to_element; i++) {
+ const GeometryInstanceSurface *surf = p_params->elements[i];
+ GeometryInstanceGLES3 *inst = surf->owner;
+
+ if (p_pass_mode == PASS_MODE_COLOR && !(surf->flags & GeometryInstanceSurface::FLAG_PASS_OPAQUE)) {
+ continue; // Objects with "Depth-prepass" transparency are included in both render lists, but should only be rendered in the transparent pass
+ }
+
+ if (inst->instance_count == 0) {
+ continue;
+ }
+
+ //uint32_t base_spec_constants = p_params->spec_constant_base_flags;
+
+ GLES3::SceneShaderData *shader;
+ GLES3::SceneMaterialData *material_data;
+ void *mesh_surface;
+
+ if (p_pass_mode == PASS_MODE_SHADOW) {
+ shader = surf->shader_shadow;
+ material_data = surf->material_shadow;
+ mesh_surface = surf->surface_shadow;
+ } else {
+ shader = surf->shader;
+ material_data = surf->material;
+ mesh_surface = surf->surface;
+ }
+
+ if (!mesh_surface) {
+ continue;
+ }
+
+ if (p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) {
+ if (scene_state.current_depth_test != shader->depth_test) {
+ if (shader->depth_test == GLES3::SceneShaderData::DEPTH_TEST_DISABLED) {
+ glDisable(GL_DEPTH_TEST);
+ } else {
+ glEnable(GL_DEPTH_TEST);
+ }
+ scene_state.current_depth_test = shader->depth_test;
+ }
+ }
+
+ if (scene_state.current_depth_draw != shader->depth_draw) {
+ switch (shader->depth_draw) {
+ case GLES3::SceneShaderData::DEPTH_DRAW_OPAQUE: {
+ glDepthMask(p_pass_mode == PASS_MODE_COLOR);
+ } break;
+ case GLES3::SceneShaderData::DEPTH_DRAW_ALWAYS: {
+ glDepthMask(GL_TRUE);
+ } break;
+ case GLES3::SceneShaderData::DEPTH_DRAW_DISABLED: {
+ glDepthMask(GL_FALSE);
+ } break;
+ }
+
+ scene_state.current_depth_draw = shader->depth_draw;
+ }
+
+ if (p_pass_mode == PASS_MODE_COLOR_TRANSPARENT || p_pass_mode == PASS_MODE_COLOR_ADDITIVE) {
+ GLES3::SceneShaderData::BlendMode desired_blend_mode;
+ if (p_pass_mode == PASS_MODE_COLOR_ADDITIVE) {
+ desired_blend_mode = GLES3::SceneShaderData::BLEND_MODE_ADD;
+ } else {
+ desired_blend_mode = shader->blend_mode;
+ }
+
+ if (desired_blend_mode != scene_state.current_blend_mode) {
+ switch (desired_blend_mode) {
+ case GLES3::SceneShaderData::BLEND_MODE_MIX: {
+ glBlendEquation(GL_FUNC_ADD);
+ if (p_render_data->transparent_bg) {
+ 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 GLES3::SceneShaderData::BLEND_MODE_ADD: {
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(p_pass_mode == PASS_MODE_COLOR_TRANSPARENT ? GL_SRC_ALPHA : GL_ONE, GL_ONE);
+
+ } break;
+ case GLES3::SceneShaderData::BLEND_MODE_SUB: {
+ glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+
+ } break;
+ case GLES3::SceneShaderData::BLEND_MODE_MUL: {
+ glBlendEquation(GL_FUNC_ADD);
+ if (p_render_data->transparent_bg) {
+ glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO);
+ } else {
+ glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE);
+ }
+
+ } break;
+ case GLES3::SceneShaderData::BLEND_MODE_ALPHA_TO_COVERAGE: {
+ // Do nothing for now.
+ } break;
+ }
+ scene_state.current_blend_mode = desired_blend_mode;
+ }
+ }
+
+ //find cull variant
+ GLES3::SceneShaderData::Cull cull_mode = shader->cull_mode;
+
+ if ((surf->flags & GeometryInstanceSurface::FLAG_USES_DOUBLE_SIDED_SHADOWS)) {
+ cull_mode = GLES3::SceneShaderData::CULL_DISABLED;
+ } else {
+ bool mirror = inst->mirror;
+ if (p_params->reverse_cull) {
+ mirror = !mirror;
+ }
+ if (cull_mode == GLES3::SceneShaderData::CULL_FRONT && mirror) {
+ cull_mode = GLES3::SceneShaderData::CULL_BACK;
+ } else if (cull_mode == GLES3::SceneShaderData::CULL_BACK && mirror) {
+ cull_mode = GLES3::SceneShaderData::CULL_FRONT;
+ }
+ }
+
+ if (scene_state.cull_mode != cull_mode) {
+ if (cull_mode == GLES3::SceneShaderData::CULL_DISABLED) {
+ glDisable(GL_CULL_FACE);
+ } else {
+ if (scene_state.cull_mode == GLES3::SceneShaderData::CULL_DISABLED) {
+ // Last time was disabled, so enable and set proper face.
+ glEnable(GL_CULL_FACE);
+ }
+ glCullFace(cull_mode == GLES3::SceneShaderData::CULL_FRONT ? GL_FRONT : GL_BACK);
+ }
+ scene_state.cull_mode = cull_mode;
+ }
+
+ RS::PrimitiveType primitive = surf->primitive;
+ static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP };
+ GLenum primitive_gl = prim[int(primitive)];
+
+ GLuint vertex_array_gl = 0;
+ GLuint index_array_gl = 0;
+
+ //skeleton and blend shape
+ if (surf->owner->mesh_instance.is_valid()) {
+ mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, shader->vertex_input_mask, vertex_array_gl);
+ } else {
+ mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, shader->vertex_input_mask, vertex_array_gl);
+ }
+
+ index_array_gl = mesh_storage->mesh_surface_get_index_buffer(mesh_surface, surf->lod_index);
+
+ if (prev_vertex_array_gl != vertex_array_gl) {
+ glBindVertexArray(vertex_array_gl);
+ prev_vertex_array_gl = vertex_array_gl;
+ }
+
+ bool use_index_buffer = index_array_gl != 0;
+ if (prev_index_array_gl != index_array_gl) {
+ if (index_array_gl != 0) {
+ // Bind index each time so we can use LODs
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_gl);
+ }
+ prev_index_array_gl = index_array_gl;
+ }
+
+ Transform3D world_transform;
+ if (inst->store_transform_cache) {
+ world_transform = inst->transform;
+ }
+
+ if (prev_material_data != material_data) {
+ material_data->bind_uniforms();
+ prev_material_data = material_data;
+ }
+
+ SceneShaderGLES3::ShaderVariant instance_variant = shader_variant;
+ if (inst->instance_count > 0) {
+ instance_variant = SceneShaderGLES3::ShaderVariant(1 + int(shader_variant));
+ }
+
+ if (prev_shader != shader || prev_variant != instance_variant) {
+ material_storage->shaders.scene_shader.version_bind_shader(shader->version, instance_variant);
+ float opaque_prepass_threshold = 0.0;
+ if (p_pass_mode == PASS_MODE_DEPTH) {
+ opaque_prepass_threshold = 0.99;
+ } else if (p_pass_mode == PASS_MODE_SHADOW) {
+ opaque_prepass_threshold = 0.1;
+ }
+
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OPAQUE_PREPASS_THRESHOLD, opaque_prepass_threshold, shader->version, instance_variant);
+
+ prev_shader = shader;
+ prev_variant = instance_variant;
+ }
+
+ if (prev_inst != inst || prev_shader != shader || prev_variant != instance_variant) {
+ // Rebind the light indices.
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT, inst->omni_light_count, shader->version, instance_variant);
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT, inst->spot_light_count, shader->version, instance_variant);
+
+ if (inst->omni_light_count) {
+ glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::OMNI_LIGHT_INDICES, shader->version, instance_variant), inst->omni_light_count, inst->omni_light_gl_cache.ptr());
+ }
+
+ if (inst->spot_light_count) {
+ glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES, shader->version, instance_variant), inst->spot_light_count, inst->spot_light_gl_cache.ptr());
+ }
+
+ prev_inst = inst;
+ }
+
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant);
+ if (inst->instance_count > 0) {
+ // Using MultiMesh.
+ // Bind instance buffers.
+
+ GLuint multimesh_buffer = mesh_storage->multimesh_get_gl_buffer(inst->data->base);
+ glBindBuffer(GL_ARRAY_BUFFER, multimesh_buffer);
+ uint32_t multimesh_stride = mesh_storage->multimesh_get_stride(inst->data->base);
+ glEnableVertexAttribArray(12);
+ glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0));
+ glVertexAttribDivisor(12, 1);
+ glEnableVertexAttribArray(13);
+ glVertexAttribPointer(13, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 4));
+ glVertexAttribDivisor(13, 1);
+ glEnableVertexAttribArray(14);
+ glVertexAttribPointer(14, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 8));
+ glVertexAttribDivisor(14, 1);
+
+ if (mesh_storage->multimesh_uses_colors(inst->data->base) || mesh_storage->multimesh_uses_custom_data(inst->data->base)) {
+ glEnableVertexAttribArray(15);
+ glVertexAttribIPointer(15, 4, GL_UNSIGNED_INT, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(mesh_storage->multimesh_get_color_offset(inst->data->base) * sizeof(float)));
+ glVertexAttribDivisor(15, 1);
+ }
+ if (use_index_buffer) {
+ glDrawElementsInstanced(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface), mesh_storage->mesh_surface_get_index_type(mesh_surface), 0, inst->instance_count);
+ } else {
+ glDrawArraysInstanced(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface), inst->instance_count);
+ }
+ } else {
+ // Using regular Mesh.
+ if (use_index_buffer) {
+ glDrawElements(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface), mesh_storage->mesh_surface_get_index_type(mesh_surface), 0);
+ } else {
+ glDrawArrays(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface));
+ }
+ }
+ if (inst->instance_count > 0) {
+ glDisableVertexAttribArray(12);
+ glDisableVertexAttribArray(13);
+ glDisableVertexAttribArray(14);
+ glDisableVertexAttribArray(15);
+ }
+ }
+}
+
+void RasterizerSceneGLES3::render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+}
+
+void RasterizerSceneGLES3::render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<RenderGeometryInstance *> &p_instances) {
}
void RasterizerSceneGLES3::set_time(double p_time, double p_step) {
+ time = p_time;
+ time_step = p_step;
}
void RasterizerSceneGLES3::set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) {
+ debug_draw = p_debug_draw;
}
RID RasterizerSceneGLES3::render_buffers_create() {
- return RID();
+ RenderBuffers rb;
+ return render_buffers_owner.make_rid(rb);
}
-void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) {
+void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
+ ERR_FAIL_COND(!rb);
+
+ //rb->internal_width = p_internal_width; // ignore for now
+ //rb->internal_height = p_internal_height;
+ rb->width = p_width;
+ rb->height = p_height;
+ //rb->fsr_sharpness = p_fsr_sharpness;
+ rb->render_target = p_render_target;
+ //rb->msaa = p_msaa;
+ //rb->screen_space_aa = p_screen_space_aa;
+ //rb->use_debanding = p_use_debanding;
+ //rb->view_count = p_view_count;
+
+ _free_render_buffer_data(rb);
+
+ GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
+
+ rb->is_transparent = rt->is_transparent;
+
+ // framebuffer
+ glGenFramebuffers(1, &rb->framebuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, rb->framebuffer);
+
+ glBindTexture(GL_TEXTURE_2D, rt->color);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
+
+ glGenTextures(1, &rb->depth_texture);
+ glBindTexture(GL_TEXTURE_2D, rb->depth_texture);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 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, rb->depth_texture, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, texture_storage->system_fbo);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ _free_render_buffer_data(rb);
+ WARN_PRINT("Could not create 3D renderbuffer, status: " + texture_storage->get_framebuffer_error(status));
+ return;
+ }
+}
+
+void RasterizerSceneGLES3::_free_render_buffer_data(RenderBuffers *rb) {
+ if (rb->depth_texture) {
+ glDeleteTextures(1, &rb->depth_texture);
+ rb->depth_texture = 0;
+ }
+ if (rb->framebuffer) {
+ glDeleteFramebuffers(1, &rb->framebuffer);
+ rb->framebuffer = 0;
+ }
+}
+
+//clear render buffers
+/*
+
+
+ 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;
+ }
+
+ if (rt->multisample_active) {
+ glDeleteFramebuffers(1, &rt->multisample_fbo);
+ rt->multisample_fbo = 0;
+
+ glDeleteRenderbuffers(1, &rt->multisample_depth);
+ rt->multisample_depth = 0;
+
+ glDeleteRenderbuffers(1, &rt->multisample_color);
+
+ rt->multisample_color = 0;
+ }
+*/
+
+void RasterizerSceneGLES3::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) {
}
void RasterizerSceneGLES3::gi_set_use_half_resolution(bool p_enable) {
@@ -453,10 +2388,31 @@ TypedArray<Image> RasterizerSceneGLES3::bake_render_uv2(RID p_base, const Vector
}
bool RasterizerSceneGLES3::free(RID p_rid) {
- return false;
+ if (is_environment(p_rid)) {
+ environment_free(p_rid);
+ } else if (sky_owner.owns(p_rid)) {
+ Sky *sky = sky_owner.get_or_null(p_rid);
+ ERR_FAIL_COND_V(!sky, false);
+ _free_sky_data(sky);
+ sky_owner.free(p_rid);
+ } else if (render_buffers_owner.owns(p_rid)) {
+ RenderBuffers *rb = render_buffers_owner.get_or_null(p_rid);
+ ERR_FAIL_COND_V(!rb, false);
+ _free_render_buffer_data(rb);
+ render_buffers_owner.free(p_rid);
+
+ } else if (light_instance_owner.owns(p_rid)) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_rid);
+ ERR_FAIL_COND_V(!light_instance, false);
+ light_instance_owner.free(p_rid);
+ } else {
+ return false;
+ }
+ return true;
}
void RasterizerSceneGLES3::update() {
+ _update_dirty_skys();
}
void RasterizerSceneGLES3::sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) {
@@ -469,6 +2425,209 @@ void RasterizerSceneGLES3::light_projectors_set_filter(RS::LightProjectorFilter
}
RasterizerSceneGLES3::RasterizerSceneGLES3() {
+ singleton = this;
+
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
+ {
+ // Setup Lights
+
+ config->max_renderable_lights = MIN(config->max_renderable_lights, config->max_uniform_buffer_size / (int)sizeof(RasterizerSceneGLES3::LightData));
+ config->max_lights_per_object = MIN(config->max_lights_per_object, config->max_renderable_lights);
+
+ uint32_t light_buffer_size = config->max_renderable_lights * sizeof(LightData);
+ scene_state.omni_lights = memnew_arr(LightData, config->max_renderable_lights);
+ scene_state.omni_light_sort = memnew_arr(InstanceSort<LightInstance>, config->max_renderable_lights);
+ glGenBuffers(1, &scene_state.omni_light_buffer);
+ glBindBuffer(GL_UNIFORM_BUFFER, scene_state.omni_light_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, light_buffer_size, nullptr, GL_STREAM_DRAW);
+
+ scene_state.spot_lights = memnew_arr(LightData, config->max_renderable_lights);
+ scene_state.spot_light_sort = memnew_arr(InstanceSort<LightInstance>, config->max_renderable_lights);
+ glGenBuffers(1, &scene_state.spot_light_buffer);
+ glBindBuffer(GL_UNIFORM_BUFFER, scene_state.spot_light_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, light_buffer_size, nullptr, GL_STREAM_DRAW);
+
+ uint32_t directional_light_buffer_size = MAX_DIRECTIONAL_LIGHTS * sizeof(DirectionalLightData);
+ scene_state.directional_lights = memnew_arr(DirectionalLightData, MAX_DIRECTIONAL_LIGHTS);
+ glGenBuffers(1, &scene_state.directional_light_buffer);
+ glBindBuffer(GL_UNIFORM_BUFFER, scene_state.directional_light_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, directional_light_buffer_size, nullptr, GL_STREAM_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ }
+
+ {
+ sky_globals.max_directional_lights = 4;
+ uint32_t directional_light_buffer_size = sky_globals.max_directional_lights * sizeof(DirectionalLightData);
+ sky_globals.directional_lights = memnew_arr(DirectionalLightData, sky_globals.max_directional_lights);
+ sky_globals.last_frame_directional_lights = memnew_arr(DirectionalLightData, sky_globals.max_directional_lights);
+ sky_globals.last_frame_directional_light_count = sky_globals.max_directional_lights + 1;
+ glGenBuffers(1, &sky_globals.directional_light_buffer);
+ glBindBuffer(GL_UNIFORM_BUFFER, sky_globals.directional_light_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, directional_light_buffer_size, nullptr, GL_STREAM_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ }
+
+ {
+ String global_defines;
+ global_defines += "#define MAX_GLOBAL_SHADER_UNIFORMS 256\n"; // TODO: this is arbitrary for now
+ global_defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(config->max_renderable_lights) + "\n";
+ global_defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n";
+ global_defines += "\n#define MAX_FORWARD_LIGHTS " + itos(config->max_lights_per_object) + "\n";
+ material_storage->shaders.scene_shader.initialize(global_defines);
+ scene_globals.shader_default_version = material_storage->shaders.scene_shader.version_create();
+ material_storage->shaders.scene_shader.version_bind_shader(scene_globals.shader_default_version, SceneShaderGLES3::MODE_COLOR);
+ }
+
+ {
+ //default material and shader
+ scene_globals.default_shader = material_storage->shader_allocate();
+ material_storage->shader_initialize(scene_globals.default_shader);
+ material_storage->shader_set_code(scene_globals.default_shader, R"(
+// Default 3D material shader (clustered).
+
+shader_type spatial;
+
+void vertex() {
+ ROUGHNESS = 0.8;
+}
+
+void fragment() {
+ ALBEDO = vec3(0.6);
+ ROUGHNESS = 0.8;
+ METALLIC = 0.2;
+}
+)");
+ scene_globals.default_material = material_storage->material_allocate();
+ material_storage->material_initialize(scene_globals.default_material);
+ material_storage->material_set_shader(scene_globals.default_material, scene_globals.default_shader);
+ }
+
+ {
+ // Initialize Sky stuff
+ sky_globals.roughness_layers = GLOBAL_GET("rendering/reflections/sky_reflections/roughness_layers");
+ sky_globals.ggx_samples = GLOBAL_GET("rendering/reflections/sky_reflections/ggx_samples");
+
+ String global_defines;
+ global_defines += "#define MAX_GLOBAL_SHADER_UNIFORMS 256\n"; // TODO: this is arbitrary for now
+ global_defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(sky_globals.max_directional_lights) + "\n";
+ material_storage->shaders.sky_shader.initialize(global_defines);
+ sky_globals.shader_default_version = material_storage->shaders.sky_shader.version_create();
+ material_storage->shaders.sky_shader.version_bind_shader(sky_globals.shader_default_version, SkyShaderGLES3::MODE_BACKGROUND);
+ }
+
+ {
+ String global_defines;
+ global_defines += "\n#define MAX_SAMPLE_COUNT " + itos(sky_globals.ggx_samples) + "\n";
+ material_storage->shaders.cubemap_filter_shader.initialize(global_defines);
+ scene_globals.cubemap_filter_shader_version = material_storage->shaders.cubemap_filter_shader.version_create();
+ material_storage->shaders.cubemap_filter_shader.version_bind_shader(scene_globals.cubemap_filter_shader_version, CubemapFilterShaderGLES3::MODE_DEFAULT);
+ }
+
+ {
+ sky_globals.default_shader = material_storage->shader_allocate();
+
+ material_storage->shader_initialize(sky_globals.default_shader);
+
+ material_storage->shader_set_code(sky_globals.default_shader, R"(
+// Default sky shader.
+
+shader_type sky;
+
+void sky() {
+ COLOR = vec3(0.0);
+}
+)");
+ sky_globals.default_material = material_storage->material_allocate();
+ material_storage->material_initialize(sky_globals.default_material);
+
+ material_storage->material_set_shader(sky_globals.default_material, sky_globals.default_shader);
+ }
+ {
+ sky_globals.fog_shader = material_storage->shader_allocate();
+ material_storage->shader_initialize(sky_globals.fog_shader);
+
+ material_storage->shader_set_code(sky_globals.fog_shader, R"(
+// Default clear color sky shader.
+
+shader_type sky;
+
+uniform vec4 clear_color;
+
+void sky() {
+ COLOR = clear_color.rgb;
+}
+)");
+ sky_globals.fog_material = material_storage->material_allocate();
+ material_storage->material_initialize(sky_globals.fog_material);
+
+ material_storage->material_set_shader(sky_globals.fog_material, sky_globals.fog_shader);
+ }
+
+ {
+ glGenBuffers(1, &sky_globals.screen_triangle);
+ glBindBuffer(GL_ARRAY_BUFFER, sky_globals.screen_triangle);
+
+ const float qv[6] = {
+ -1.0f,
+ -1.0f,
+ 3.0f,
+ -1.0f,
+ -1.0f,
+ 3.0f,
+ };
+
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, qv, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+
+ glGenVertexArrays(1, &sky_globals.screen_triangle_array);
+ glBindVertexArray(sky_globals.screen_triangle_array);
+ glBindBuffer(GL_ARRAY_BUFFER, sky_globals.screen_triangle);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ }
+
+#ifdef GLES_OVER_GL
+ glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS);
+#endif
+
+ // MultiMesh may read from color when color is disabled, so make sure that the color defaults to white instead of black;
+ glVertexAttrib4f(RS::ARRAY_COLOR, 1.0, 1.0, 1.0, 1.0);
+}
+
+RasterizerSceneGLES3::~RasterizerSceneGLES3() {
+ glDeleteBuffers(1, &scene_state.directional_light_buffer);
+ glDeleteBuffers(1, &scene_state.omni_light_buffer);
+ glDeleteBuffers(1, &scene_state.spot_light_buffer);
+ memdelete_arr(scene_state.directional_lights);
+ memdelete_arr(scene_state.omni_lights);
+ memdelete_arr(scene_state.spot_lights);
+ memdelete_arr(scene_state.omni_light_sort);
+ memdelete_arr(scene_state.spot_light_sort);
+
+ // Scene Shader
+ GLES3::MaterialStorage::get_singleton()->shaders.scene_shader.version_free(scene_globals.shader_default_version);
+ GLES3::MaterialStorage::get_singleton()->shaders.cubemap_filter_shader.version_free(scene_globals.cubemap_filter_shader_version);
+ RSG::material_storage->material_free(scene_globals.default_material);
+ RSG::material_storage->shader_free(scene_globals.default_shader);
+
+ // Sky Shader
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_free(sky_globals.shader_default_version);
+ RSG::material_storage->material_free(sky_globals.default_material);
+ RSG::material_storage->shader_free(sky_globals.default_shader);
+ RSG::material_storage->material_free(sky_globals.fog_material);
+ RSG::material_storage->shader_free(sky_globals.fog_shader);
+ glDeleteBuffers(1, &sky_globals.screen_triangle);
+ glDeleteVertexArrays(1, &sky_globals.screen_triangle_array);
+ glDeleteTextures(1, &sky_globals.radical_inverse_vdc_cache_tex);
+ glDeleteBuffers(1, &sky_globals.directional_light_buffer);
+ memdelete_arr(sky_globals.directional_lights);
+ memdelete_arr(sky_globals.last_frame_directional_lights);
+
+ singleton = nullptr;
}
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index 12bb21a5a0..a54d87a3a3 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -28,52 +28,610 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef RASTERIZER_SCENE_OPENGL_H
-#define RASTERIZER_SCENE_OPENGL_H
+#ifndef RASTERIZER_SCENE_GLES3_H
+#define RASTERIZER_SCENE_GLES3_H
#ifdef GLES3_ENABLED
-#include "core/math/camera_matrix.h"
+#include "core/math/projection.h"
+#include "core/templates/paged_allocator.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
#include "scene/resources/mesh.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
+#include "shader_gles3.h"
+#include "shaders/cubemap_filter.glsl.gen.h"
+#include "shaders/sky.glsl.gen.h"
+#include "storage/material_storage.h"
+#include "storage/utilities.h"
+
+enum RenderListType {
+ RENDER_LIST_OPAQUE, //used for opaque objects
+ RENDER_LIST_ALPHA, //used for transparent objects
+ RENDER_LIST_SECONDARY, //used for shadows and other objects
+ RENDER_LIST_MAX
+};
+
+enum PassMode {
+ PASS_MODE_COLOR,
+ PASS_MODE_COLOR_TRANSPARENT,
+ PASS_MODE_COLOR_ADDITIVE,
+ PASS_MODE_SHADOW,
+ PASS_MODE_DEPTH,
+};
+
+// These should share as much as possible with SkyUniform Location
+enum SceneUniformLocation {
+ SCENE_TONEMAP_UNIFORM_LOCATION,
+ SCENE_GLOBALS_UNIFORM_LOCATION,
+ SCENE_DATA_UNIFORM_LOCATION,
+ SCENE_MATERIAL_UNIFORM_LOCATION,
+ SCENE_EMPTY, // Unused, put here to avoid conflicts with SKY_DIRECTIONAL_LIGHT_UNIFORM_LOCATION.
+ SCENE_OMNILIGHT_UNIFORM_LOCATION,
+ SCENE_SPOTLIGHT_UNIFORM_LOCATION,
+ SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
+};
+
+enum SkyUniformLocation {
+ SKY_TONEMAP_UNIFORM_LOCATION,
+ SKY_GLOBALS_UNIFORM_LOCATION,
+ SKY_EMPTY, // Unused, put here to avoid conflicts with SCENE_DATA_UNIFORM_LOCATION.
+ SKY_MATERIAL_UNIFORM_LOCATION,
+ SKY_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
+};
+
+enum {
+ SPEC_CONSTANT_DISABLE_LIGHTMAP = 0,
+ SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS = 1,
+ SPEC_CONSTANT_DISABLE_OMNI_LIGHTS = 2,
+ SPEC_CONSTANT_DISABLE_SPOT_LIGHTS = 3,
+ SPEC_CONSTANT_DISABLE_FOG = 4,
+};
+
+struct RenderDataGLES3 {
+ RID render_buffers = RID();
+ bool transparent_bg = false;
+
+ Transform3D cam_transform = Transform3D();
+ Transform3D inv_cam_transform = Transform3D();
+ Projection cam_projection = Projection();
+ bool cam_orthogonal = false;
+
+ // For stereo rendering
+ uint32_t view_count = 1;
+ Vector3 view_eye_offset[RendererSceneRender::MAX_RENDER_VIEWS];
+ Projection view_projection[RendererSceneRender::MAX_RENDER_VIEWS];
+
+ float z_near = 0.0;
+ float z_far = 0.0;
+
+ const PagedArray<RenderGeometryInstance *> *instances = nullptr;
+ const PagedArray<RID> *lights = nullptr;
+ const PagedArray<RID> *reflection_probes = nullptr;
+ RID environment = RID();
+ RID camera_effects = RID();
+ RID reflection_probe = RID();
+ int reflection_probe_pass = 0;
+
+ float lod_distance_multiplier = 0.0;
+ Plane lod_camera_plane = Plane();
+ float screen_mesh_lod_threshold = 0.0;
+
+ uint32_t directional_light_count = 0;
+ uint32_t spot_light_count = 0;
+ uint32_t omni_light_count = 0;
+
+ RendererScene::RenderInfo *render_info = nullptr;
+};
+
+class RasterizerCanvasGLES3;
class RasterizerSceneGLES3 : public RendererSceneRender {
+private:
+ static RasterizerSceneGLES3 *singleton;
+ RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
+ uint64_t scene_pass = 0;
+
+ template <class T>
+ struct InstanceSort {
+ float depth;
+ T *instance = nullptr;
+ bool operator<(const InstanceSort &p_sort) const {
+ return depth < p_sort.depth;
+ }
+ };
+
+ struct SceneGlobals {
+ RID shader_default_version;
+ RID default_material;
+ RID default_shader;
+ RID cubemap_filter_shader_version;
+ } scene_globals;
+
+ /* LIGHT INSTANCE */
+
+ struct LightData {
+ float position[3];
+ float inv_radius;
+
+ float direction[3]; // Only used by SpotLight
+ float size;
+
+ float color[3];
+ float attenuation;
+
+ float inv_spot_attenuation;
+ float cos_spot_angle;
+ float specular_amount;
+ float shadow_opacity;
+ };
+ static_assert(sizeof(LightData) % 16 == 0, "LightData size must be a multiple of 16 bytes");
+
+ struct DirectionalLightData {
+ float direction[3];
+ float energy;
+
+ float color[3];
+ float size;
+
+ uint32_t enabled; // For use by SkyShaders
+ float pad[2];
+ float specular;
+ };
+ static_assert(sizeof(DirectionalLightData) % 16 == 0, "DirectionalLightData size must be a multiple of 16 bytes");
+
+ struct LightInstance {
+ RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
+
+ AABB aabb;
+ RID self;
+ RID light;
+ Transform3D transform;
+
+ Vector3 light_vector;
+ Vector3 spot_vector;
+ float linear_att = 0.0;
+
+ uint64_t shadow_pass = 0;
+ uint64_t last_scene_pass = 0;
+ uint64_t last_scene_shadow_pass = 0;
+ uint64_t last_pass = 0;
+ uint32_t cull_mask = 0;
+ uint32_t light_directional_index = 0;
+
+ Rect2 directional_rect;
+
+ uint32_t gl_id = -1;
+
+ LightInstance() {}
+ };
+
+ mutable RID_Owner<LightInstance> light_instance_owner;
+
+ class GeometryInstanceGLES3;
+
+ // Cached data for drawing surfaces
+ struct GeometryInstanceSurface {
+ enum {
+ FLAG_PASS_DEPTH = 1,
+ FLAG_PASS_OPAQUE = 2,
+ FLAG_PASS_ALPHA = 4,
+ FLAG_PASS_SHADOW = 8,
+ FLAG_USES_SHARED_SHADOW_MATERIAL = 128,
+ FLAG_USES_SCREEN_TEXTURE = 2048,
+ FLAG_USES_DEPTH_TEXTURE = 4096,
+ FLAG_USES_NORMAL_TEXTURE = 8192,
+ FLAG_USES_DOUBLE_SIDED_SHADOWS = 16384,
+ };
+
+ union {
+ struct {
+ uint64_t lod_index : 8;
+ uint64_t surface_index : 8;
+ uint64_t geometry_id : 32;
+ uint64_t material_id_low : 16;
+
+ uint64_t material_id_hi : 16;
+ uint64_t shader_id : 32;
+ uint64_t uses_softshadow : 1;
+ uint64_t uses_projector : 1;
+ uint64_t uses_forward_gi : 1;
+ uint64_t uses_lightmap : 1;
+ uint64_t depth_layer : 4;
+ uint64_t priority : 8;
+ };
+ struct {
+ uint64_t sort_key1;
+ uint64_t sort_key2;
+ };
+ } sort;
+
+ RS::PrimitiveType primitive = RS::PRIMITIVE_MAX;
+ uint32_t flags = 0;
+ uint32_t surface_index = 0;
+ uint32_t lod_index = 0;
+
+ void *surface = nullptr;
+ GLES3::SceneShaderData *shader = nullptr;
+ GLES3::SceneMaterialData *material = nullptr;
+
+ void *surface_shadow = nullptr;
+ GLES3::SceneShaderData *shader_shadow = nullptr;
+ GLES3::SceneMaterialData *material_shadow = nullptr;
+
+ GeometryInstanceSurface *next = nullptr;
+ GeometryInstanceGLES3 *owner = nullptr;
+ };
+
+ class GeometryInstanceGLES3 : public RenderGeometryInstanceBase {
+ public:
+ //used during rendering
+ bool store_transform_cache = true;
+
+ int32_t instance_count = 0;
+
+ bool can_sdfgi = false;
+ bool using_projectors = false;
+ bool using_softshadows = false;
+
+ uint32_t omni_light_count = 0;
+ LocalVector<RID> omni_lights;
+ uint32_t spot_light_count = 0;
+ LocalVector<RID> spot_lights;
+ LocalVector<uint32_t> omni_light_gl_cache;
+ LocalVector<uint32_t> spot_light_gl_cache;
+
+ //used during setup
+ GeometryInstanceSurface *surface_caches = nullptr;
+ SelfList<GeometryInstanceGLES3> dirty_list_element;
+
+ GeometryInstanceGLES3() :
+ dirty_list_element(this) {}
+
+ virtual void _mark_dirty() override;
+ virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override;
+ virtual void set_lightmap_capture(const Color *p_sh9) override;
+
+ virtual void pair_light_instances(const RID *p_light_instances, uint32_t p_light_instance_count) override;
+ virtual void pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {}
+ virtual void pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) override {}
+ virtual void pair_voxel_gi_instances(const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override {}
+
+ virtual void set_softshadow_projector_pairing(bool p_softshadow, bool p_projector) override {}
+ };
+
+ enum {
+ INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 5,
+ INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9,
+ INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10,
+ INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11,
+ INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
+ INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
+ INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14,
+ INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15,
+ };
+
+ static void _geometry_instance_dependency_changed(Dependency::DependencyChangedNotification p_notification, DependencyTracker *p_tracker);
+ static void _geometry_instance_dependency_deleted(const RID &p_dependency, DependencyTracker *p_tracker);
+
+ SelfList<GeometryInstanceGLES3>::List geometry_instance_dirty_list;
+
+ // Use PagedAllocator instead of RID to maximize performance
+ PagedAllocator<GeometryInstanceGLES3> geometry_instance_alloc;
+ PagedAllocator<GeometryInstanceSurface> geometry_instance_surface_alloc;
+
+ void _geometry_instance_add_surface_with_material(GeometryInstanceGLES3 *ginstance, uint32_t p_surface, GLES3::SceneMaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh);
+ void _geometry_instance_add_surface_with_material_chain(GeometryInstanceGLES3 *ginstance, uint32_t p_surface, GLES3::SceneMaterialData *p_material, RID p_mat_src, RID p_mesh);
+ void _geometry_instance_add_surface(GeometryInstanceGLES3 *ginstance, uint32_t p_surface, RID p_material, RID p_mesh);
+ void _geometry_instance_update(RenderGeometryInstance *p_geometry_instance);
+ void _update_dirty_geometry_instances();
+
+ struct SceneState {
+ struct UBO {
+ float projection_matrix[16];
+ float inv_projection_matrix[16];
+ float inv_view_matrix[16];
+ float view_matrix[16];
+
+ float viewport_size[2];
+ float screen_pixel_size[2];
+
+ float ambient_light_color_energy[4];
+
+ float ambient_color_sky_mix;
+ uint32_t material_uv2_mode;
+ float pad2;
+ uint32_t use_ambient_light = 0;
+
+ uint32_t use_ambient_cubemap = 0;
+ uint32_t use_reflection_cubemap = 0;
+ float fog_aerial_perspective;
+ float time;
+
+ float radiance_inverse_xform[12];
+
+ uint32_t directional_light_count;
+ float z_far;
+ float z_near;
+ float pad1;
+
+ uint32_t fog_enabled;
+ float fog_density;
+ float fog_height;
+ float fog_height_density;
+
+ float fog_light_color[3];
+ float fog_sun_scatter;
+ };
+ static_assert(sizeof(UBO) % 16 == 0, "Scene UBO size must be a multiple of 16 bytes");
+
+ struct TonemapUBO {
+ float exposure = 1.0;
+ float white = 1.0;
+ int32_t tonemapper = 0;
+ int32_t pad = 0;
+ };
+ static_assert(sizeof(TonemapUBO) % 16 == 0, "Tonemap UBO size must be a multiple of 16 bytes");
+
+ UBO ubo;
+ GLuint ubo_buffer = 0;
+ GLuint tonemap_buffer = 0;
+
+ bool used_depth_prepass = false;
+
+ GLES3::SceneShaderData::BlendMode current_blend_mode = GLES3::SceneShaderData::BLEND_MODE_MIX;
+ GLES3::SceneShaderData::DepthDraw current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_OPAQUE;
+ GLES3::SceneShaderData::DepthTest current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_DISABLED;
+ GLES3::SceneShaderData::Cull cull_mode = GLES3::SceneShaderData::CULL_BACK;
+
+ bool texscreen_copied = false;
+ bool used_screen_texture = false;
+ bool used_normal_texture = false;
+ bool used_depth_texture = false;
+
+ LightData *omni_lights = nullptr;
+ LightData *spot_lights = nullptr;
+
+ InstanceSort<LightInstance> *omni_light_sort;
+ InstanceSort<LightInstance> *spot_light_sort;
+ GLuint omni_light_buffer = 0;
+ GLuint spot_light_buffer = 0;
+ uint32_t omni_light_count = 0;
+ uint32_t spot_light_count = 0;
+
+ DirectionalLightData *directional_lights = nullptr;
+ GLuint directional_light_buffer = 0;
+ } scene_state;
+
+ struct RenderListParameters {
+ GeometryInstanceSurface **elements = nullptr;
+ int element_count = 0;
+ bool reverse_cull = false;
+ uint32_t spec_constant_base_flags = 0;
+ bool force_wireframe = false;
+
+ RenderListParameters(GeometryInstanceSurface **p_elements, int p_element_count, bool p_reverse_cull, uint32_t p_spec_constant_base_flags, bool p_force_wireframe = false) {
+ elements = p_elements;
+ element_count = p_element_count;
+ reverse_cull = p_reverse_cull;
+ spec_constant_base_flags = p_spec_constant_base_flags;
+ force_wireframe = p_force_wireframe;
+ }
+ };
+
+ struct RenderList {
+ LocalVector<GeometryInstanceSurface *> elements;
+
+ void clear() {
+ elements.clear();
+ }
+
+ //should eventually be replaced by radix
+
+ struct SortByKey {
+ _FORCE_INLINE_ bool operator()(const GeometryInstanceSurface *A, const GeometryInstanceSurface *B) const {
+ return (A->sort.sort_key2 == B->sort.sort_key2) ? (A->sort.sort_key1 < B->sort.sort_key1) : (A->sort.sort_key2 < B->sort.sort_key2);
+ }
+ };
+
+ void sort_by_key() {
+ SortArray<GeometryInstanceSurface *, SortByKey> sorter;
+ sorter.sort(elements.ptr(), elements.size());
+ }
+
+ void sort_by_key_range(uint32_t p_from, uint32_t p_size) {
+ SortArray<GeometryInstanceSurface *, SortByKey> sorter;
+ sorter.sort(elements.ptr() + p_from, p_size);
+ }
+
+ struct SortByDepth {
+ _FORCE_INLINE_ bool operator()(const GeometryInstanceSurface *A, const GeometryInstanceSurface *B) const {
+ return (A->owner->depth < B->owner->depth);
+ }
+ };
+
+ void sort_by_depth() { //used for shadows
+
+ SortArray<GeometryInstanceSurface *, SortByDepth> sorter;
+ sorter.sort(elements.ptr(), elements.size());
+ }
+
+ struct SortByReverseDepthAndPriority {
+ _FORCE_INLINE_ bool operator()(const GeometryInstanceSurface *A, const GeometryInstanceSurface *B) const {
+ return (A->sort.priority == B->sort.priority) ? (A->owner->depth > B->owner->depth) : (A->sort.priority < B->sort.priority);
+ }
+ };
+
+ void sort_by_reverse_depth_and_priority() { //used for alpha
+
+ SortArray<GeometryInstanceSurface *, SortByReverseDepthAndPriority> sorter;
+ sorter.sort(elements.ptr(), elements.size());
+ }
+
+ _FORCE_INLINE_ void add_element(GeometryInstanceSurface *p_element) {
+ elements.push_back(p_element);
+ }
+ };
+
+ RenderList render_list[RENDER_LIST_MAX];
+
+ void _setup_lights(const RenderDataGLES3 *p_render_data, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_omni_light_count, uint32_t &r_spot_light_count);
+ void _setup_environment(const RenderDataGLES3 *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_pancake_shadows);
+ void _fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append = false);
+
+ template <PassMode p_pass_mode>
+ _FORCE_INLINE_ void _render_list_template(RenderListParameters *p_params, const RenderDataGLES3 *p_render_data, uint32_t p_from_element, uint32_t p_to_element, bool p_alpha_pass = false);
+
+protected:
+ double time;
+ double time_step = 0;
+
+ struct RenderBuffers {
+ int internal_width = 0;
+ int internal_height = 0;
+ int width = 0;
+ int height = 0;
+ //float fsr_sharpness = 0.2f;
+ RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
+ //RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
+ //bool use_debanding = false;
+ //uint32_t view_count = 1;
+
+ bool is_transparent = false;
+
+ RID render_target;
+ GLuint internal_texture = 0; // Used for rendering when post effects are enabled
+ GLuint depth_texture = 0; // Main depth texture
+ GLuint framebuffer = 0; // Main framebuffer, contains internal_texture and depth_texture or render_target->color and depth_texture
+
+ //built-in textures used for ping pong image processing and blurring
+ struct Blur {
+ RID texture;
+
+ struct Mipmap {
+ RID texture;
+ int width;
+ int height;
+ GLuint fbo;
+ };
+
+ Vector<Mipmap> mipmaps;
+ };
+
+ Blur blur[2]; //the second one starts from the first mipmap
+ };
+
+ bool screen_space_roughness_limiter = false;
+ float screen_space_roughness_limiter_amount = 0.25;
+ float screen_space_roughness_limiter_limit = 0.18;
+
+ mutable RID_Owner<RenderBuffers, true> render_buffers_owner;
+
+ void _free_render_buffer_data(RenderBuffers *rb);
+ void _allocate_blur_textures(RenderBuffers *rb);
+ void _allocate_depth_backbuffer_textures(RenderBuffers *rb);
+
+ void _render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
+
+ /* Environment */
+
+ RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;
+ bool ssao_half_size = false;
+ float ssao_adaptive_target = 0.5;
+ int ssao_blur_passes = 2;
+ float ssao_fadeout_from = 50.0;
+ float ssao_fadeout_to = 300.0;
+
+ bool glow_bicubic_upscale = false;
+ bool glow_high_quality = false;
+ RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGHNESS_QUALITY_LOW;
+
+ /* Sky */
+
+ struct SkyGlobals {
+ float fog_aerial_perspective = 0.0;
+ Color fog_light_color;
+ float fog_sun_scatter = 0.0;
+ bool fog_enabled = false;
+ float fog_density = 0.0;
+ float z_far = 0.0;
+ uint32_t directional_light_count = 0;
+
+ DirectionalLightData *directional_lights = nullptr;
+ DirectionalLightData *last_frame_directional_lights = nullptr;
+ uint32_t last_frame_directional_light_count = 0;
+ GLuint directional_light_buffer = 0;
+
+ RID shader_default_version;
+ RID default_material;
+ RID default_shader;
+ RID fog_material;
+ RID fog_shader;
+ GLuint screen_triangle = 0;
+ GLuint screen_triangle_array = 0;
+ GLuint radical_inverse_vdc_cache_tex = 0;
+ uint32_t max_directional_lights = 4;
+ uint32_t roughness_layers = 8;
+ uint32_t ggx_samples = 128;
+ } sky_globals;
+
+ struct Sky {
+ // Screen Buffers
+ GLuint half_res_pass = 0;
+ GLuint half_res_framebuffer = 0;
+ GLuint quarter_res_pass = 0;
+ GLuint quarter_res_framebuffer = 0;
+ Size2i screen_size = Size2i(0, 0);
+
+ // Radiance Cubemap
+ GLuint radiance = 0;
+ GLuint radiance_framebuffer = 0;
+ GLuint raw_radiance = 0;
+
+ RID material;
+ GLuint uniform_buffer;
+
+ int radiance_size = 256;
+ int mipmap_count = 1;
+
+ RS::SkyMode mode = RS::SKY_MODE_AUTOMATIC;
+
+ //ReflectionData reflection;
+ bool reflection_dirty = false;
+ bool dirty = false;
+ int processing_layer = 0;
+ Sky *dirty_list = nullptr;
+
+ //State to track when radiance cubemap needs updating
+ GLES3::SkyMaterialData *prev_material;
+ Vector3 prev_position = Vector3(0.0, 0.0, 0.0);
+ float prev_time = 0.0f;
+ };
+
+ Sky *dirty_sky_list = nullptr;
+ mutable RID_Owner<Sky, true> sky_owner;
+
+ void _setup_sky(RID p_env, RID p_render_buffers, const PagedArray<RID> &p_lights, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size);
+ void _invalidate_sky(Sky *p_sky);
+ void _update_dirty_skys();
+ void _update_sky_radiance(RID p_env, const Projection &p_projection, const Transform3D &p_transform);
+ void _filter_sky_radiance(Sky *p_sky, int p_base_layer);
+ void _draw_sky(RID p_env, const Projection &p_projection, const Transform3D &p_transform);
+ void _free_sky_data(Sky *p_sky);
+
public:
- struct State {
- //SceneShaderGLES3 scene_shader;
- } state;
-
- GeometryInstance *geometry_instance_create(RID p_base) override;
- 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_material_overlay(GeometryInstance *p_geometry_instance, RID p_overlay) 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 Transform3D &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_transparency(GeometryInstance *p_geometry_instance, float p_transparency) override;
- void geometry_instance_set_fade_range(GeometryInstance *p_geometry_instance, bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) override;
- void geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) 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;
+ static RasterizerSceneGLES3 *get_singleton() { return singleton; }
- uint32_t geometry_instance_get_pair_mask() override;
- 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_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override;
- void geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) override;
+ RasterizerCanvasGLES3 *canvas;
+
+ RenderGeometryInstance *geometry_instance_create(RID p_base) override;
+ void geometry_instance_free(RenderGeometryInstance *p_geometry_instance) override;
- void geometry_instance_free(GeometryInstance *p_geometry_instance) override;
+ uint32_t geometry_instance_get_pair_mask() override;
/* SHADOW ATLAS API */
@@ -88,65 +646,46 @@ public:
/* 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;
- AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const override;
- uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const override;
+ 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;
+ }
/* SKY API */
RID sky_allocate() override;
void sky_initialize(RID p_rid) override;
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_mode(RID p_sky, RS::SkyMode p_mode) 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;
/* ENVIRONMENT API */
- RID environment_allocate() override;
- void environment_initialize(RID p_rid) override;
- 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) 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, float p_glow_map_strength, RID p_glow_map) 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_ssil(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_sharpness, float p_normal_rejection) override;
- void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override;
- void environment_set_sdfgi(RID p_env, bool p_enable, int p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) override;
+ void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) 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_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) 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_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) 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;
Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) override;
- bool is_environment(RID p_env) const override;
- RS::EnvironmentBG environment_get_background(RID p_env) const override;
- int environment_get_canvas_max_layer(RID p_env) const override;
-
RID camera_effects_allocate() override;
void camera_effects_initialize(RID p_rid) override;
void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) override;
@@ -155,15 +694,24 @@ public:
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 shadows_quality_set(RS::ShadowQuality p_quality) override;
- void directional_shadow_quality_set(RS::ShadowQuality p_quality) override;
+ void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
+ void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
RID light_instance_create(RID p_light) override;
void light_instance_set_transform(RID p_light_instance, const Transform3D &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 Transform3D &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_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &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;
+ _FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->light_type;
+ }
+ _FORCE_INLINE_ uint32_t light_instance_get_gl_id(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->gl_id;
+ }
+
RID fog_volume_instance_create(RID p_fog_volume) override;
void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override;
void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) override;
@@ -191,20 +739,30 @@ public:
RID voxel_gi_instance_create(RID p_voxel_gi) override;
void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) override;
bool voxel_gi_needs_update(RID p_probe) const override;
- void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects) override;
+ void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects) override;
void voxel_gi_set_quality(RS::VoxelGIQuality) override;
- void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override;
- void render_material(const Transform3D &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_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) override;
+ void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override;
+ void render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
+ void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<RenderGeometryInstance *> &p_instances) override;
+
+ void set_scene_pass(uint64_t p_pass) override {
+ scene_pass = p_pass;
+ }
+
+ _FORCE_INLINE_ uint64_t get_scene_pass() {
+ return scene_pass;
+ }
- 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;
+ _FORCE_INLINE_ RS::ViewportDebugDraw get_debug_draw_mode() const {
+ return debug_draw;
+ }
RID render_buffers_create() override;
- void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override;
+ void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
void gi_set_use_half_resolution(bool p_enable) override;
void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override;
@@ -223,8 +781,9 @@ public:
void light_projectors_set_filter(RS::LightProjectorFilter p_filter) override;
RasterizerSceneGLES3();
+ ~RasterizerSceneGLES3();
};
#endif // GLES3_ENABLED
-#endif // RASTERIZER_SCENE_OPENGL_H
+#endif // RASTERIZER_SCENE_GLES3_H
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
deleted file mode 100644
index fda208b812..0000000000
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ /dev/null
@@ -1,4515 +0,0 @@
-/*************************************************************************/
-/* rasterizer_storage_gles3.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (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_gles3.h"
-#ifdef GLES3_ENABLED
-
-#include "core/config/project_settings.h"
-#include "core/math/transform_3d.h"
-#include "rasterizer_canvas_gles3.h"
-#include "rasterizer_scene_gles3.h"
-#include "servers/rendering/shader_language.h"
-
-GLuint RasterizerStorageGLES3::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_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
-
-#define _GL_TEXTURE_EXTERNAL_OES 0x8D65
-
-#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
-#endif //!GLES_OVER_GL
-
-void RasterizerStorageGLES3::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);
-}
-
-bool RasterizerStorageGLES3::can_create_resources_async() const {
- return false;
-}
-
-Ref<Image> RasterizerStorageGLES3::_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: {
-#ifdef GLES_OVER_GL
- r_gl_internal_format = GL_R8;
- r_gl_format = GL_RED;
- r_gl_type = GL_UNSIGNED_BYTE;
-#else
- r_gl_internal_format = GL_LUMINANCE;
- r_gl_format = GL_LUMINANCE;
- r_gl_type = GL_UNSIGNED_BYTE;
-#endif
- } break;
- case Image::FORMAT_LA8: {
-#ifdef GLES_OVER_GL
- r_gl_internal_format = GL_RG8;
- r_gl_format = GL_RG;
- r_gl_type = GL_UNSIGNED_BYTE;
-#else
- r_gl_internal_format = GL_LUMINANCE_ALPHA;
- r_gl_format = GL_LUMINANCE_ALPHA;
- r_gl_type = GL_UNSIGNED_BYTE;
-#endif
- } break;
- case Image::FORMAT_R8: {
- r_gl_internal_format = GL_R8;
- r_gl_format = GL_RED;
- r_gl_type = GL_UNSIGNED_BYTE;
-
- } break;
- case Image::FORMAT_RG8: {
- r_gl_internal_format = GL_RG8;
- r_gl_format = GL_RG;
- r_gl_type = GL_UNSIGNED_BYTE;
-
- } break;
- case Image::FORMAT_RGB8: {
- r_gl_internal_format = GL_RGB8;
- r_gl_format = GL_RGB;
- r_gl_type = GL_UNSIGNED_BYTE;
- //r_srgb = true;
-
- } break;
- case Image::FORMAT_RGBA8: {
- r_gl_format = GL_RGBA;
- r_gl_internal_format = GL_RGBA8;
- r_gl_type = GL_UNSIGNED_BYTE;
- //r_srgb = true;
-
- } break;
- case Image::FORMAT_RGBA4444: {
- r_gl_internal_format = GL_RGBA4;
- r_gl_format = GL_RGBA;
- r_gl_type = GL_UNSIGNED_SHORT_4_4_4_4;
-
- } break;
- //case Image::FORMAT_RGBA5551: {
- // 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: {
- r_gl_internal_format = GL_R32F;
- r_gl_format = GL_RED;
- r_gl_type = GL_FLOAT;
-
- } break;
- case Image::FORMAT_RGF: {
- r_gl_internal_format = GL_RG32F;
- r_gl_format = GL_RG;
- r_gl_type = GL_FLOAT;
-
- } break;
- case Image::FORMAT_RGBF: {
- r_gl_internal_format = GL_RGB32F;
- r_gl_format = GL_RGB;
- r_gl_type = GL_FLOAT;
-
- } break;
- case Image::FORMAT_RGBAF: {
- r_gl_internal_format = GL_RGBA32F;
- r_gl_format = GL_RGBA;
- r_gl_type = GL_FLOAT;
-
- } break;
- case Image::FORMAT_RH: {
- r_gl_internal_format = GL_R16F;
- r_gl_format = GL_RED;
- r_gl_type = GL_HALF_FLOAT;
- } break;
- case Image::FORMAT_RGH: {
- r_gl_internal_format = GL_RG16F;
- r_gl_format = GL_RG;
- r_gl_type = GL_HALF_FLOAT;
-
- } break;
- case Image::FORMAT_RGBH: {
- r_gl_internal_format = GL_RGB16F;
- r_gl_format = GL_RGB;
- r_gl_type = GL_HALF_FLOAT;
-
- } break;
- case Image::FORMAT_RGBAH: {
- r_gl_internal_format = GL_RGBA16F;
- r_gl_format = GL_RGBA;
- r_gl_type = GL_HALF_FLOAT;
-
- } break;
- case Image::FORMAT_RGBE9995: {
- r_gl_internal_format = GL_RGB9_E5;
- r_gl_format = GL_RGB;
- r_gl_type = GL_UNSIGNED_INT_5_9_9_9_REV;
-
- } 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;
- //r_srgb = 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;
- //r_srgb = 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;
- //r_srgb = 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;
- //r_srgb = 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_ETC: {
- if (config.etc_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: {
- if (config.etc2_supported) {
- r_gl_internal_format = _EXT_COMPRESSED_R11_EAC;
- r_gl_format = GL_RED;
- r_gl_type = GL_UNSIGNED_BYTE;
- r_compressed = true;
-
- } else {
- need_decompress = true;
- }
- } break;
- case Image::FORMAT_ETC2_R11S: {
- if (config.etc2_supported) {
- r_gl_internal_format = _EXT_COMPRESSED_SIGNED_R11_EAC;
- r_gl_format = GL_RED;
- r_gl_type = GL_UNSIGNED_BYTE;
- r_compressed = true;
-
- } else {
- need_decompress = true;
- }
- } break;
- case Image::FORMAT_ETC2_RG11: {
- if (config.etc2_supported) {
- r_gl_internal_format = _EXT_COMPRESSED_RG11_EAC;
- r_gl_format = GL_RG;
- r_gl_type = GL_UNSIGNED_BYTE;
- r_compressed = true;
-
- } else {
- need_decompress = true;
- }
- } break;
- case Image::FORMAT_ETC2_RG11S: {
- if (config.etc2_supported) {
- r_gl_internal_format = _EXT_COMPRESSED_SIGNED_RG11_EAC;
- r_gl_format = GL_RG;
- r_gl_type = GL_UNSIGNED_BYTE;
- r_compressed = true;
-
- } else {
- need_decompress = true;
- }
- } break;
- case Image::FORMAT_ETC2_RGB8: {
- if (config.etc2_supported) {
- r_gl_internal_format = _EXT_COMPRESSED_RGB8_ETC2;
- r_gl_format = GL_RGB;
- r_gl_type = GL_UNSIGNED_BYTE;
- r_compressed = true;
- //r_srgb = true;
-
- } else {
- need_decompress = true;
- }
- } break;
- case Image::FORMAT_ETC2_RGBA8: {
- if (config.etc2_supported) {
- r_gl_internal_format = _EXT_COMPRESSED_RGBA8_ETC2_EAC;
- r_gl_format = GL_RGBA;
- r_gl_type = GL_UNSIGNED_BYTE;
- r_compressed = true;
- //r_srgb = true;
-
- } else {
- need_decompress = true;
- }
- } break;
- case Image::FORMAT_ETC2_RGB8A1: {
- if (config.etc2_supported) {
- r_gl_internal_format = _EXT_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
- r_gl_format = GL_RGBA;
- r_gl_type = GL_UNSIGNED_BYTE;
- r_compressed = true;
- //r_srgb = true;
-
- } else {
- 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 RasterizerStorageGLES3::texture_allocate() {
- RID id = texture_create();
- ERR_FAIL_COND_V(id == RID(), id);
- return id;
-}
-
-void RasterizerStorageGLES3::texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) {
- Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!tex);
-
- int w = p_image->get_width();
- int h = p_image->get_height();
-
- _texture_allocate_internal(p_texture, w, h, 1, p_image->get_format(), RenderingDevice::TEXTURE_TYPE_2D, 0);
- texture_set_data(p_texture, p_image);
-}
-
-void RasterizerStorageGLES3::texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) {
-}
-
-void RasterizerStorageGLES3::texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) {
-}
-
-void RasterizerStorageGLES3::texture_proxy_initialize(RID p_texture, RID p_base) {
- texture_set_proxy(p_texture, p_base);
-}
-
-//RID RasterizerStorageGLES3::texture_2d_create(const Ref<Image> &p_image) {
-// RID id = texture_create();
-// ERR_FAIL_COND_V(id == RID(), id);
-
-// int w = p_image->get_width();
-// int h = p_image->get_height();
-
-// texture_allocate(id, w, h, 1, p_image->get_format(), RenderingDevice::TEXTURE_TYPE_2D, 0);
-
-// texture_set_data(id, p_image);
-
-// return id;
-//}
-
-//RID RasterizerStorageGLES3::texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) {
-// return RID();
-//}
-
-//void RasterizerStorageGLES3::texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer) {
-// // only 1 layer so far
-// texture_set_data(p_texture, p_image);
-//}
-void RasterizerStorageGLES3::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) {
- // only 1 layer so far
- texture_set_data(p_texture, p_image);
-}
-
-void RasterizerStorageGLES3::texture_2d_placeholder_initialize(RID p_texture) {
-}
-
-void RasterizerStorageGLES3::texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) {
-}
-
-void RasterizerStorageGLES3::texture_3d_placeholder_initialize(RID p_texture) {
-}
-
-Ref<Image> RasterizerStorageGLES3::texture_2d_get(RID p_texture) const {
- Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!tex, Ref<Image>());
-
- /*
-#ifdef TOOLS_ENABLED
- if (tex->image_cache_2d.is_valid()) {
- return tex->image_cache_2d;
- }
-#endif
- Vector<uint8_t> data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0);
- ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
- Ref<Image> image;
- image.instance();
- image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data);
- ERR_FAIL_COND_V(image->empty(), Ref<Image>());
- if (tex->format != tex->validated_format) {
- image->convert(tex->format);
- }
-
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
- tex->image_cache_2d = image;
- }
-#endif
-*/
- ERR_FAIL_COND_V(!tex->images.size(), Ref<Image>());
-
- return tex->images[0];
-
- // return image;
-
- // return Ref<Image>();
-}
-
-void RasterizerStorageGLES3::texture_replace(RID p_texture, RID p_by_texture) {
- Texture *tex_to = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!tex_to);
- Texture *tex_from = texture_owner.get_or_null(p_by_texture);
- ERR_FAIL_COND(!tex_from);
-
- tex_to->destroy();
- tex_to->copy_from(*tex_from);
-
- // copy image data and upload to GL
- tex_to->images.resize(tex_from->images.size());
-
- for (int n = 0; n < tex_from->images.size(); n++) {
- texture_set_data(p_texture, tex_from->images[n], n);
- }
-
- free(p_by_texture);
-}
-
-bool RasterizerStorageGLES3::_is_main_thread() {
- //#if defined DEBUG_ENABLED && defined TOOLS_ENABLED
- // must be called from main thread in OpenGL
- bool is_main_thread = _main_thread_id == Thread::get_caller_id();
- //#endif
- return is_main_thread;
-}
-
-RID RasterizerStorageGLES3::texture_create() {
- ERR_FAIL_COND_V(!_is_main_thread(), RID());
-
- 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 RasterizerStorageGLES3::_texture_allocate_internal(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, RenderingDevice::TextureType p_type, uint32_t p_flags) {
- // GLenum format;
- // GLenum internal_format;
- // GLenum type;
-
- // bool compressed = false;
-
- if (p_flags & TEXTURE_FLAG_USED_FOR_STREAMING) {
- p_flags &= ~TEXTURE_FLAG_MIPMAPS; // no mipies for video
- }
-
- Texture *texture = texture_owner.get_or_null(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 RenderingDevice::TEXTURE_TYPE_2D: {
- texture->target = GL_TEXTURE_2D;
- texture->images.resize(1);
- } break;
- // case RenderingDevice::TEXTURE_TYPE_EXTERNAL: {
- //#ifdef ANDROID_ENABLED
- // texture->target = _GL_TEXTURE_EXTERNAL_OES;
- //#else
- // texture->target = GL_TEXTURE_2D;
- //#endif
- // texture->images.resize(0);
- // } break;
- case RenderingDevice::TEXTURE_TYPE_CUBE: {
- texture->target = GL_TEXTURE_CUBE_MAP;
- texture->images.resize(6);
- } break;
- case RenderingDevice::TEXTURE_TYPE_2D_ARRAY:
- case RenderingDevice::TEXTURE_TYPE_3D: {
- texture->target = GL_TEXTURE_3D;
- ERR_PRINT("3D textures and Texture Arrays are not supported in OpenGL. Please switch to the Vulkan backend.");
- return;
- } break;
- default: {
- ERR_PRINT("Unknown texture type!");
- return;
- }
- }
-
-#if 0
- // if (p_type != RS::TEXTURE_TYPE_EXTERNAL) {
- if (p_type == RenderingDevice::TEXTURE_TYPE_2D) {
- 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 & TEXTURE_FLAG_REPEAT || p_flags & TEXTURE_FLAG_MIPMAPS)) {
- if (p_flags & 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 &= ~(TEXTURE_FLAG_REPEAT | TEXTURE_FLAG_MIPMAPS);
- } else {
- texture->alloc_height = po2_height;
- texture->alloc_width = po2_width;
- texture->resize_to_po2 = true;
- }
- }
- }
-
- GLenum format;
- GLenum internal_format;
- GLenum type;
- bool compressed = false;
-
- 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;
- }
-#endif
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(texture->target, texture->tex_id);
-
- // if (p_type == RS::TEXTURE_TYPE_EXTERNAL) {
- // glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- // glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- // glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- // glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- // } else if (p_flags & TEXTURE_FLAG_USED_FOR_STREAMING) {
- // //prealloc if video
- // glTexImage2D(texture->target, 0, internal_format, texture->alloc_width, texture->alloc_height, 0, format, type, NULL);
- // }
-
- texture->active = true;
-}
-
-void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer) {
- Texture *texture = texture_owner.get_or_null(p_texture);
-
- ERR_FAIL_COND(!_is_main_thread());
-
- ERR_FAIL_COND(!texture);
- if (texture->target == GL_TEXTURE_3D) {
- // Target is set to a 3D texture or array texture, exit early to avoid spamming errors
- return;
- }
- ERR_FAIL_COND(!texture->active);
- ERR_FAIL_COND(texture->render_target);
- ERR_FAIL_COND(p_image.is_null());
- ERR_FAIL_COND(texture->format != p_image->get_format());
-
- ERR_FAIL_COND(!p_image->get_width());
- ERR_FAIL_COND(!p_image->get_height());
-
- // ERR_FAIL_COND(texture->type == RS::TEXTURE_TYPE_EXTERNAL);
-
- GLenum type;
- GLenum format;
- GLenum internal_format;
- bool compressed = false;
-
- if (config.keep_original_textures && !(texture->flags & TEXTURE_FLAG_USED_FOR_STREAMING)) {
- texture->images.write[p_layer] = p_image;
- }
-
- // print_line("texture_set_data width " + itos (p_image->get_width()) + " height " + itos(p_image->get_height()));
-
- 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 & 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 = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : GL_TEXTURE_2D;
-
- texture->data_size = img->get_data().size();
- Vector<uint8_t> read = img->get_data();
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(texture->target, texture->tex_id);
-
- texture->ignore_mipmaps = compressed && !img->has_mipmaps();
-
- // set filtering and repeat state
- _texture_set_state_from_flags(texture);
-
- //set swizle for older format compatibility
-#ifdef GLES_OVER_GL
- switch (texture->format) {
- case Image::FORMAT_L8: {
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED);
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_RED);
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_RED);
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_ONE);
-
- } break;
- case Image::FORMAT_LA8: {
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED);
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_RED);
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_RED);
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_GREEN);
- } break;
- default: {
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED);
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_BLUE);
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_ALPHA);
-
- } break;
- }
-#endif
-
- int mipmaps = ((texture->flags & 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 (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 & 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]);
- }
- }
-
- 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 & TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != RenderingDevice::TEXTURE_TYPE_CUBE || 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 RasterizerStorageGLES3::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> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) const {
- Texture *texture = texture_owner.get_or_null(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);
-
- PoolVector<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
- PoolVector<uint8_t>::Write wb = data.write();
-
- 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);
-
- PoolVector<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
- PoolVector<uint8_t>::Write wb = data.write();
-
- 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, NULL);
-
- 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 RasterizerStorageGLES3::_texture_set_state_from_flags(Texture *p_tex) {
- if ((p_tex->flags & TEXTURE_FLAG_MIPMAPS) && !p_tex->ignore_mipmaps) {
- if (p_tex->flags & TEXTURE_FLAG_FILTER) {
- // these do not exactly correspond ...
- p_tex->GLSetFilter(p_tex->target, RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS);
- //texture->glTexParam_MinFilter(texture->target, config.use_fast_texture_filter ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR);
- } else {
- p_tex->GLSetFilter(p_tex->target, RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS);
- //texture->glTexParam_MinFilter(texture->target, config.use_fast_texture_filter ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_LINEAR);
- }
- } else {
- if (p_tex->flags & TEXTURE_FLAG_FILTER) {
- p_tex->GLSetFilter(p_tex->target, RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR);
- //texture->glTexParam_MinFilter(texture->target, GL_LINEAR);
- } else {
- p_tex->GLSetFilter(p_tex->target, RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
- // texture->glTexParam_MinFilter(texture->target, GL_NEAREST);
- }
- }
-
- if (((p_tex->flags & TEXTURE_FLAG_REPEAT) || (p_tex->flags & TEXTURE_FLAG_MIRRORED_REPEAT)) && p_tex->target != GL_TEXTURE_CUBE_MAP) {
- if (p_tex->flags & TEXTURE_FLAG_MIRRORED_REPEAT) {
- p_tex->GLSetRepeat(p_tex->target, RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
- } else {
- p_tex->GLSetRepeat(p_tex->target, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- }
- } else {
- p_tex->GLSetRepeat(p_tex->target, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- }
-}
-
-void RasterizerStorageGLES3::texture_set_flags(RID p_texture, uint32_t p_flags) {
- Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!texture);
-
- bool had_mipmaps = texture->flags & TEXTURE_FLAG_MIPMAPS;
-
- texture->flags = p_flags;
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(texture->target, texture->tex_id);
-
- // set filtering and repeat state
- _texture_set_state_from_flags(texture);
-
- if ((texture->flags & TEXTURE_FLAG_MIPMAPS) && !texture->ignore_mipmaps) {
- if (!had_mipmaps && texture->mipmaps == 1) {
- glGenerateMipmap(texture->target);
- }
- }
-}
-
-uint32_t RasterizerStorageGLES3::texture_get_flags(RID p_texture) const {
- Texture *texture = texture_owner.get_or_null(p_texture);
-
- ERR_FAIL_COND_V(!texture, 0);
-
- return texture->flags;
-}
-
-Image::Format RasterizerStorageGLES3::texture_get_format(RID p_texture) const {
- Texture *texture = texture_owner.get_or_null(p_texture);
-
- ERR_FAIL_COND_V(!texture, Image::FORMAT_L8);
-
- return texture->format;
-}
-
-RenderingDevice::TextureType RasterizerStorageGLES3::texture_get_type(RID p_texture) const {
- Texture *texture = texture_owner.get_or_null(p_texture);
-
- ERR_FAIL_COND_V(!texture, RenderingDevice::TEXTURE_TYPE_2D);
-
- return texture->type;
-}
-
-uint32_t RasterizerStorageGLES3::texture_get_texid(RID p_texture) const {
- Texture *texture = texture_owner.get_or_null(p_texture);
-
- ERR_FAIL_COND_V(!texture, 0);
-
- return texture->tex_id;
-}
-
-void RasterizerStorageGLES3::texture_bind(RID p_texture, uint32_t p_texture_no) {
- Texture *texture = texture_owner.get_or_null(p_texture);
-
- ERR_FAIL_COND(!texture);
-
- glActiveTexture(GL_TEXTURE0 + p_texture_no);
- glBindTexture(texture->target, texture->tex_id);
-}
-
-uint32_t RasterizerStorageGLES3::texture_get_width(RID p_texture) const {
- Texture *texture = texture_owner.get_or_null(p_texture);
-
- ERR_FAIL_COND_V(!texture, 0);
-
- return texture->width;
-}
-
-uint32_t RasterizerStorageGLES3::texture_get_height(RID p_texture) const {
- Texture *texture = texture_owner.get_or_null(p_texture);
-
- ERR_FAIL_COND_V(!texture, 0);
-
- return texture->height;
-}
-
-uint32_t RasterizerStorageGLES3::texture_get_depth(RID p_texture) const {
- Texture *texture = texture_owner.get_or_null(p_texture);
-
- ERR_FAIL_COND_V(!texture, 0);
-
- return texture->depth;
-}
-
-void RasterizerStorageGLES3::texture_set_size_override(RID p_texture, int p_width, int p_height) {
- Texture *texture = texture_owner.get_or_null(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 RasterizerStorageGLES3::texture_set_path(RID p_texture, const String &p_path) {
- Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!texture);
-
- texture->path = p_path;
-}
-
-String RasterizerStorageGLES3::texture_get_path(RID p_texture) const {
- Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!texture, "");
-
- return texture->path;
-}
-
-void RasterizerStorageGLES3::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.get_or_null(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 RasterizerStorageGLES3::texture_set_shrink_all_x2_on_set_data(bool p_enable) {
- config.shrink_textures_x2 = p_enable;
-}
-
-void RasterizerStorageGLES3::textures_keep_original(bool p_enable) {
- config.keep_original_textures = p_enable;
-}
-
-Size2 RasterizerStorageGLES3::texture_size_with_proxy(RID p_texture) {
- const Texture *texture = texture_owner.get_or_null(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);
- }
-}
-
-// example use in 3.2
-// VS::get_singleton()->texture_set_proxy(default_texture->proxy, texture_rid);
-
-// p_proxy is the source (pre-existing) texture?
-// and p_texture is the one that is being made into a proxy?
-//This naming is confusing. Comments!!!
-
-// The naming of the parameters seemed to be reversed?
-// The p_proxy is the source texture
-// and p_texture is actually the proxy????
-
-void RasterizerStorageGLES3::texture_set_proxy(RID p_texture, RID p_proxy) {
- Texture *texture = texture_owner.get_or_null(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.get_or_null(p_proxy);
- ERR_FAIL_COND(!proxy);
- ERR_FAIL_COND(proxy == texture);
- proxy->proxy_owners.insert(texture);
- texture->proxy = proxy;
- }
-}
-
-void RasterizerStorageGLES3::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) {
- Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!texture);
-
- texture->redraw_if_visible = p_enable;
-}
-
-void RasterizerStorageGLES3::texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
- Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!texture);
-
- texture->detect_3d = p_callback;
- texture->detect_3d_ud = p_userdata;
-}
-
-void RasterizerStorageGLES3::texture_set_detect_srgb_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
- Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!texture);
-
- texture->detect_srgb = p_callback;
- texture->detect_srgb_ud = p_userdata;
-}
-
-void RasterizerStorageGLES3::texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
- Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!texture);
-
- texture->detect_normal = p_callback;
- texture->detect_normal_ud = p_userdata;
-}
-
-RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source, int p_resolution) const {
- return RID();
-}
-
-RID RasterizerStorageGLES3::canvas_texture_allocate() {
- return canvas_texture_owner.allocate_rid();
-}
-
-void RasterizerStorageGLES3::canvas_texture_initialize(RID p_rid) {
- canvas_texture_owner.initialize_rid(p_rid);
-}
-
-void RasterizerStorageGLES3::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) {
- CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture);
- switch (p_channel) {
- case RS::CANVAS_TEXTURE_CHANNEL_DIFFUSE: {
- ct->diffuse = p_texture;
- } break;
- case RS::CANVAS_TEXTURE_CHANNEL_NORMAL: {
- ct->normal_map = p_texture;
- } break;
- case RS::CANVAS_TEXTURE_CHANNEL_SPECULAR: {
- ct->specular = p_texture;
- } break;
- }
-}
-
-void RasterizerStorageGLES3::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess) {
- CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture);
- ct->specular_color.r = p_specular_color.r;
- ct->specular_color.g = p_specular_color.g;
- ct->specular_color.b = p_specular_color.b;
- ct->specular_color.a = p_shininess;
-}
-
-void RasterizerStorageGLES3::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) {
- CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture);
- ct->texture_filter = p_filter;
-}
-void RasterizerStorageGLES3::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) {
- CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture);
- ct->texture_repeat = p_repeat;
-}
-
-RID RasterizerStorageGLES3::sky_create() {
- Sky *sky = memnew(Sky);
- sky->radiance = 0;
- return sky_owner.make_rid(sky);
-}
-
-void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size) {
-}
-
-/* SHADER API */
-
-RID RasterizerStorageGLES3::shader_allocate() {
- Shader *shader = memnew(Shader);
- shader->mode = RS::SHADER_CANVAS_ITEM;
- //shader->shader = &scene->state.scene_shader;
- RID rid = shader_owner.make_rid(shader);
- _shader_make_dirty(shader);
- shader->self = rid;
-
- return rid;
-}
-
-void RasterizerStorageGLES3::shader_initialize(RID p_rid) {
- // noop
-}
-
-//RID RasterizerStorageGLES3::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 RasterizerStorageGLES3::_shader_make_dirty(Shader *p_shader) {
- if (p_shader->dirty_list.in_list()) {
- return;
- }
-
- _shader_dirty_list.add(&p_shader->dirty_list);
-}
-
-void RasterizerStorageGLES3::shader_set_code(RID p_shader, const String &p_code) {
- Shader *shader = shader_owner.get_or_null(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 if (mode_string == "spatial") {
- mode = RS::SHADER_SPATIAL;
- } else {
- mode = RS::SHADER_MAX;
- ERR_PRINT("shader type " + mode_string + " not supported in OpenGL renderer");
- }
-
- if (shader->version.is_valid() && mode != shader->mode) {
- shader->shader->version_free(shader->version);
- shader->version = RID();
- }
-
- 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 if (mode == RS::SHADER_PARTICLES) {
- } else if (mode == RS::SHADER_SKY) {
- } else {
- return;
- }
-
- if (shader->version.is_null() && shader->shader) {
- shader->version = shader->shader->version_create();
- }
-
- _shader_make_dirty(shader);
-}
-
-String RasterizerStorageGLES3::shader_get_code(RID p_shader) const {
- const Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND_V(!shader, "");
-
- return shader->code;
-}
-
-void RasterizerStorageGLES3::_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.is_empty()) {
- return; //just invalid, but no error
- }
-
- ShaderCompiler::GeneratedCode gen_code;
- ShaderCompiler::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;
- p_shader->canvas_item.uses_modulate = false;
- p_shader->canvas_item.uses_color = false;
- p_shader->canvas_item.uses_vertex = false;
-
- p_shader->canvas_item.uses_world_matrix = false;
- p_shader->canvas_item.uses_extra_matrix = false;
- p_shader->canvas_item.uses_projection_matrix = false;
- p_shader->canvas_item.uses_instance_custom = 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;
- shaders.actions_canvas.usage_flag_pointers["MODULATE"] = &p_shader->canvas_item.uses_modulate;
- shaders.actions_canvas.usage_flag_pointers["COLOR"] = &p_shader->canvas_item.uses_color;
-
- shaders.actions_canvas.usage_flag_pointers["VERTEX"] = &p_shader->canvas_item.uses_vertex;
-
- shaders.actions_canvas.usage_flag_pointers["WORLD_MATRIX"] = &p_shader->canvas_item.uses_world_matrix;
- shaders.actions_canvas.usage_flag_pointers["EXTRA_MATRIX"] = &p_shader->canvas_item.uses_extra_matrix;
- shaders.actions_canvas.usage_flag_pointers["PROJECTION_MATRIX"] = &p_shader->canvas_item.uses_projection_matrix;
- shaders.actions_canvas.usage_flag_pointers["INSTANCE_CUSTOM"] = &p_shader->canvas_item.uses_instance_custom;
-
- actions = &shaders.actions_canvas;
- actions->uniforms = &p_shader->uniforms;
- } break;
-
- case RS::SHADER_SPATIAL: {
- // TODO remove once 3D is added back
- return;
- 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.uses_tangent = false;
- p_shader->spatial.uses_ensure_correct_normals = 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.render_mode_flags["ensure_correct_normals"] = &p_shader->spatial.uses_ensure_correct_normals;
-
- 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;
-
- // Use of any of these BUILTINS indicate the need for transformed tangents.
- // This is needed to know when to transform tangents in software skinning.
- shaders.actions_scene.usage_flag_pointers["TANGENT"] = &p_shader->spatial.uses_tangent;
- shaders.actions_scene.usage_flag_pointers["NORMALMAP"] = &p_shader->spatial.uses_tangent;
-
- 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;
- } 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;
- }
-
- Vector<StringName> texture_uniform_names;
- for (int i = 0; i < gen_code.texture_uniforms.size(); i++) {
- texture_uniform_names.push_back(gen_code.texture_uniforms[i].name);
- }
-
- p_shader->shader->version_set_code(p_shader->version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_names);
-
- p_shader->texture_uniforms = gen_code.texture_uniforms;
-
- p_shader->uses_vertex_time = gen_code.uses_vertex_time;
- p_shader->uses_fragment_time = gen_code.uses_fragment_time;
-
- for (SelfList<Material> *E = p_shader->materials.first(); E; E = E->next()) {
- _material_make_dirty(E->self());
- }
-
- p_shader->valid = true;
-}
-
-void RasterizerStorageGLES3::update_dirty_shaders() {
- while (_shader_dirty_list.first()) {
- _update_shader(_shader_dirty_list.first()->self());
- }
-}
-
-void RasterizerStorageGLES3::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
- Shader *shader = shader_owner.get_or_null(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_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: {
- // not sure what this should be in godot 4
- // pi.type = Variant::POOL_INT_ARRAY;
- 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::TRANSFORM3D;
- } break;
-
- case ShaderLanguage::TYPE_SAMPLER2D:
- // case ShaderLanguage::TYPE_SAMPLEREXT:
- case ShaderLanguage::TYPE_ISAMPLER2D:
- case ShaderLanguage::TYPE_USAMPLER2D: {
- pi.type = Variant::OBJECT;
- pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
- pi.hint_string = "Texture";
- } 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:
- case ShaderLanguage::TYPE_SAMPLER3D:
- case ShaderLanguage::TYPE_ISAMPLER3D:
- case ShaderLanguage::TYPE_USAMPLER3D: {
- // Not implemented in OpenGL
- } break;
- // new for godot 4
- case ShaderLanguage::TYPE_SAMPLERCUBEARRAY:
- case ShaderLanguage::TYPE_STRUCT:
- case ShaderLanguage::TYPE_MAX: {
- } break;
- }
-
- p_param_list->push_back(pi);
- }
-}
-
-void RasterizerStorageGLES3::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index) {
- Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND(!shader);
- ERR_FAIL_COND(p_texture.is_valid() && !texture_owner.owns(p_texture));
-
- if (!p_texture.is_valid()) {
- if (shader->default_textures.has(p_name) && shader->default_textures[p_name].has(p_index)) {
- shader->default_textures[p_name].erase(p_index);
-
- if (shader->default_textures[p_name].is_empty()) {
- shader->default_textures.erase(p_name);
- }
- }
- } else {
- if (!shader->default_textures.has(p_name)) {
- shader->default_textures[p_name] = Map<int, RID>();
- }
- shader->default_textures[p_name][p_index] = p_texture;
- }
-
- _shader_make_dirty(shader);
-}
-
-RID RasterizerStorageGLES3::shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const {
- const Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND_V(!shader, RID());
-
- if (shader->default_textures.has(p_name) && shader->default_textures[p_name].has(p_index)) {
- return shader->default_textures[p_name][p_index];
- }
-
- return RID();
-}
-
-/* COMMON MATERIAL API */
-
-void RasterizerStorageGLES3::_material_make_dirty(Material *p_material) const {
- if (p_material->dirty_list.in_list()) {
- return;
- }
-
- _material_dirty_list.add(&p_material->dirty_list);
-}
-
-RID RasterizerStorageGLES3::material_allocate() {
- Material *material = memnew(Material);
- return material_owner.make_rid(material);
-}
-
-void RasterizerStorageGLES3::material_initialize(RID p_rid) {
-}
-
-//RID RasterizerStorageGLES3::material_create() {
-// Material *material = memnew(Material);
-
-// return material_owner.make_rid(material);
-//}
-
-void RasterizerStorageGLES3::material_set_shader(RID p_material, RID p_shader) {
- Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
-
- Shader *shader = shader_owner.get_or_null(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 RasterizerStorageGLES3::material_get_shader(RID p_material) const {
- const Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND_V(!material, RID());
-
- if (material->shader) {
- return material->shader->self;
- }
-
- return RID();
-}
-
-void RasterizerStorageGLES3::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) {
- Material *material = material_owner.get_or_null(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 RasterizerStorageGLES3::material_get_param(RID p_material, const StringName &p_param) const {
- const Material *material = material_owner.get_or_null(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 RasterizerStorageGLES3::material_get_param_default(RID p_material, const StringName &p_param) const {
- const Material *material = material_owner.get_or_null(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 RasterizerStorageGLES3::material_set_line_width(RID p_material, float p_width) {
- Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
-
- material->line_width = p_width;
-}
-
-void RasterizerStorageGLES3::material_set_next_pass(RID p_material, RID p_next_material) {
- Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
-
- material->next_pass = p_next_material;
-}
-
-bool RasterizerStorageGLES3::material_is_animated(RID p_material) {
- Material *material = material_owner.get_or_null(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 RasterizerStorageGLES3::material_casts_shadows(RID p_material) {
- Material *material = material_owner.get_or_null(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;
-}
-
-bool RasterizerStorageGLES3::material_uses_tangents(RID p_material) {
- Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND_V(!material, false);
-
- if (!material->shader) {
- return false;
- }
-
- if (material->shader->dirty_list.in_list()) {
- _update_shader(material->shader);
- }
-
- return material->shader->spatial.uses_tangent;
-}
-
-bool RasterizerStorageGLES3::material_uses_ensure_correct_normals(RID p_material) {
- Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND_V(!material, false);
-
- if (!material->shader) {
- return false;
- }
-
- if (material->shader->dirty_list.in_list()) {
- _update_shader(material->shader);
- }
-
- return material->shader->spatial.uses_ensure_correct_normals;
-}
-
-void RasterizerStorageGLES3::material_add_instance_owner(RID p_material, DependencyTracker *p_instance) {
- /*
- Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
-
- Map<InstanceBaseDependency *, int>::Element *E = material->instance_owners.find(p_instance);
- if (E) {
- E->get()++;
- } else {
- material->instance_owners[p_instance] = 1;
- }
-*/
-}
-
-void RasterizerStorageGLES3::material_remove_instance_owner(RID p_material, DependencyTracker *p_instance) {
- /*
- Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
-
- Map<InstanceBaseDependency *, 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 RasterizerStorageGLES3::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.get_or_null(p_material);
- ERR_FAIL_COND(!material);
-
- material->render_priority = priority;
-}
-
-void RasterizerStorageGLES3::_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<InstanceBaseDependency *, 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 ShaderGLES3
-
- if (p_material->shader && p_material->shader->texture_uniforms.size() > 0) {
- p_material->textures.resize(p_material->shader->texture_uniforms.size());
-
- 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, Map<int, RID>>::Element *W = p_material->shader->default_textures.find(E->key());
-
- // TODO: make texture uniform array properly works with GLES3
- if (W && W->get().has(0)) {
- texture = W->get()[0];
- }
- }
-
- p_material->textures.write[E->get().texture_order] = Pair<StringName, RID>(E->key(), texture);
- }
- } else {
- p_material->textures.clear();
- }
-}
-/*
-void RasterizerStorageGLES3::_material_add_geometry(RID p_material, Geometry *p_geometry) {
- Material *material = material_owner.get_or_null(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 RasterizerStorageGLES3::_material_remove_geometry(RID p_material, Geometry *p_geometry) {
- Material *material = material_owner.get_or_null(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 RasterizerStorageGLES3::update_dirty_materials() {
- while (_material_dirty_list.first()) {
- Material *material = _material_dirty_list.first()->self();
- _update_material(material);
- }
-}
-
-/* MESH API */
-
-RID RasterizerStorageGLES3::mesh_allocate() {
- return RID();
-}
-
-void RasterizerStorageGLES3::mesh_initialize(RID p_rid) {
-}
-
-void RasterizerStorageGLES3::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) {
-}
-
-bool RasterizerStorageGLES3::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {
- return false;
-}
-
-RID RasterizerStorageGLES3::mesh_instance_create(RID p_base) {
- return RID();
-}
-
-void RasterizerStorageGLES3::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) {
-}
-
-void RasterizerStorageGLES3::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) {
-}
-
-void RasterizerStorageGLES3::mesh_instance_check_for_update(RID p_mesh_instance) {
-}
-
-void RasterizerStorageGLES3::update_mesh_instances() {
-}
-
-void RasterizerStorageGLES3::reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) {
-}
-
-float RasterizerStorageGLES3::reflection_probe_get_mesh_lod_threshold(RID p_probe) const {
- return 0.0;
-}
-
-void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) {
-}
-
-int RasterizerStorageGLES3::mesh_get_blend_shape_count(RID p_mesh) const {
- return 0;
-}
-
-void RasterizerStorageGLES3::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) {
-}
-
-RS::BlendShapeMode RasterizerStorageGLES3::mesh_get_blend_shape_mode(RID p_mesh) const {
- return RS::BLEND_SHAPE_MODE_NORMALIZED;
-}
-
-void RasterizerStorageGLES3::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
-}
-
-void RasterizerStorageGLES3::mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
-}
-
-void RasterizerStorageGLES3::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
-}
-
-void RasterizerStorageGLES3::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) {
-}
-
-RID RasterizerStorageGLES3::mesh_surface_get_material(RID p_mesh, int p_surface) const {
- return RID();
-}
-
-RS::SurfaceData RasterizerStorageGLES3::mesh_get_surface(RID p_mesh, int p_surface) const {
- return RS::SurfaceData();
-}
-
-int RasterizerStorageGLES3::mesh_get_surface_count(RID p_mesh) const {
- return 1;
-}
-
-void RasterizerStorageGLES3::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) {
-}
-
-AABB RasterizerStorageGLES3::mesh_get_custom_aabb(RID p_mesh) const {
- return AABB();
-}
-
-AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
- return AABB();
-}
-
-void RasterizerStorageGLES3::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
-}
-
-void RasterizerStorageGLES3::mesh_clear(RID p_mesh) {
-}
-
-/* MULTIMESH API */
-
-RID RasterizerStorageGLES3::multimesh_allocate() {
- return RID();
-}
-
-void RasterizerStorageGLES3::multimesh_initialize(RID p_rid) {
-}
-
-void RasterizerStorageGLES3::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) {
-}
-
-int RasterizerStorageGLES3::multimesh_get_instance_count(RID p_multimesh) const {
- return 0;
-}
-
-void RasterizerStorageGLES3::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
-}
-
-void RasterizerStorageGLES3::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) {
-}
-
-void RasterizerStorageGLES3::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) {
-}
-
-void RasterizerStorageGLES3::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) {
-}
-
-void RasterizerStorageGLES3::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) {
-}
-
-RID RasterizerStorageGLES3::multimesh_get_mesh(RID p_multimesh) const {
- return RID();
-}
-
-AABB RasterizerStorageGLES3::multimesh_get_aabb(RID p_multimesh) const {
- return AABB();
-}
-
-Transform3D RasterizerStorageGLES3::multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
- return Transform3D();
-}
-
-Transform2D RasterizerStorageGLES3::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const {
- return Transform2D();
-}
-
-Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh, int p_index) const {
- return Color();
-}
-
-Color RasterizerStorageGLES3::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const {
- return Color();
-}
-
-void RasterizerStorageGLES3::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
-}
-
-Vector<float> RasterizerStorageGLES3::multimesh_get_buffer(RID p_multimesh) const {
- return Vector<float>();
-}
-
-void RasterizerStorageGLES3::multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
-}
-
-int RasterizerStorageGLES3::multimesh_get_visible_instances(RID p_multimesh) const {
- return 0;
-}
-
-/* SKELETON API */
-
-RID RasterizerStorageGLES3::skeleton_allocate() {
- return RID();
-}
-
-void RasterizerStorageGLES3::skeleton_initialize(RID p_rid) {
-}
-
-void RasterizerStorageGLES3::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton) {
-}
-
-void RasterizerStorageGLES3::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) {
-}
-
-int RasterizerStorageGLES3::skeleton_get_bone_count(RID p_skeleton) const {
- return 0;
-}
-
-void RasterizerStorageGLES3::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) {
-}
-
-Transform3D RasterizerStorageGLES3::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const {
- return Transform3D();
-}
-
-void RasterizerStorageGLES3::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) {
-}
-
-Transform2D RasterizerStorageGLES3::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const {
- return Transform2D();
-}
-
-/* Light API */
-
-RID RasterizerStorageGLES3::directional_light_allocate() {
- return RID();
-}
-
-void RasterizerStorageGLES3::directional_light_initialize(RID p_rid) {
-}
-
-RID RasterizerStorageGLES3::omni_light_allocate() {
- return RID();
-}
-
-void RasterizerStorageGLES3::omni_light_initialize(RID p_rid) {
-}
-
-RID RasterizerStorageGLES3::spot_light_allocate() {
- return RID();
-}
-
-void RasterizerStorageGLES3::spot_light_initialize(RID p_rid) {
-}
-
-RID RasterizerStorageGLES3::reflection_probe_allocate() {
- return RID();
-}
-
-void RasterizerStorageGLES3::reflection_probe_initialize(RID p_rid) {
-}
-
-void RasterizerStorageGLES3::light_set_color(RID p_light, const Color &p_color) {
-}
-
-void RasterizerStorageGLES3::light_set_param(RID p_light, RS::LightParam p_param, float p_value) {
-}
-
-void RasterizerStorageGLES3::light_set_shadow(RID p_light, bool p_enabled) {
-}
-
-void RasterizerStorageGLES3::light_set_shadow_color(RID p_light, const Color &p_color) {
-}
-
-void RasterizerStorageGLES3::light_set_projector(RID p_light, RID p_texture) {
-}
-
-void RasterizerStorageGLES3::light_set_negative(RID p_light, bool p_enable) {
-}
-
-void RasterizerStorageGLES3::light_set_cull_mask(RID p_light, uint32_t p_mask) {
-}
-
-void RasterizerStorageGLES3::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) {
-}
-
-void RasterizerStorageGLES3::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) {
-}
-
-void RasterizerStorageGLES3::light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) {
-}
-
-void RasterizerStorageGLES3::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) {
-}
-
-void RasterizerStorageGLES3::light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) {
-}
-
-void RasterizerStorageGLES3::light_directional_set_blend_splits(RID p_light, bool p_enable) {
-}
-
-bool RasterizerStorageGLES3::light_directional_get_blend_splits(RID p_light) const {
- return false;
-}
-
-void RasterizerStorageGLES3::light_directional_set_sky_only(RID p_light, bool p_sky_only) {
-}
-
-bool RasterizerStorageGLES3::light_directional_is_sky_only(RID p_light) const {
- return false;
-}
-
-RS::LightDirectionalShadowMode RasterizerStorageGLES3::light_directional_get_shadow_mode(RID p_light) {
- return RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
-}
-
-RS::LightOmniShadowMode RasterizerStorageGLES3::light_omni_get_shadow_mode(RID p_light) {
- return RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
-}
-
-bool RasterizerStorageGLES3::light_has_shadow(RID p_light) const {
- return false;
-}
-
-bool RasterizerStorageGLES3::light_has_projector(RID p_light) const {
- return false;
-}
-
-RS::LightType RasterizerStorageGLES3::light_get_type(RID p_light) const {
- return RS::LIGHT_OMNI;
-}
-
-AABB RasterizerStorageGLES3::light_get_aabb(RID p_light) const {
- return AABB();
-}
-
-float RasterizerStorageGLES3::light_get_param(RID p_light, RS::LightParam p_param) {
- return 0.0;
-}
-
-Color RasterizerStorageGLES3::light_get_color(RID p_light) {
- return Color();
-}
-
-RS::LightBakeMode RasterizerStorageGLES3::light_get_bake_mode(RID p_light) {
- return RS::LIGHT_BAKE_DISABLED;
-}
-
-uint32_t RasterizerStorageGLES3::light_get_max_sdfgi_cascade(RID p_light) {
- return 0;
-}
-
-uint64_t RasterizerStorageGLES3::light_get_version(RID p_light) const {
- return 0;
-}
-
-/* PROBE API */
-
-void RasterizerStorageGLES3::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) {
-}
-
-void RasterizerStorageGLES3::reflection_probe_set_intensity(RID p_probe, float p_intensity) {
-}
-
-void RasterizerStorageGLES3::reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) {
-}
-
-void RasterizerStorageGLES3::reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) {
-}
-
-void RasterizerStorageGLES3::reflection_probe_set_ambient_energy(RID p_probe, float p_energy) {
-}
-
-void RasterizerStorageGLES3::reflection_probe_set_max_distance(RID p_probe, float p_distance) {
-}
-
-void RasterizerStorageGLES3::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) {
-}
-
-void RasterizerStorageGLES3::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) {
-}
-
-void RasterizerStorageGLES3::reflection_probe_set_as_interior(RID p_probe, bool p_enable) {
-}
-
-void RasterizerStorageGLES3::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {
-}
-
-void RasterizerStorageGLES3::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) {
-}
-
-void RasterizerStorageGLES3::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) {
-}
-
-void RasterizerStorageGLES3::reflection_probe_set_resolution(RID p_probe, int p_resolution) {
-}
-
-AABB RasterizerStorageGLES3::reflection_probe_get_aabb(RID p_probe) const {
- return AABB();
-}
-
-RS::ReflectionProbeUpdateMode RasterizerStorageGLES3::reflection_probe_get_update_mode(RID p_probe) const {
- return RenderingServer::REFLECTION_PROBE_UPDATE_ONCE;
-}
-
-uint32_t RasterizerStorageGLES3::reflection_probe_get_cull_mask(RID p_probe) const {
- return 0;
-}
-
-Vector3 RasterizerStorageGLES3::reflection_probe_get_extents(RID p_probe) const {
- return Vector3();
-}
-
-Vector3 RasterizerStorageGLES3::reflection_probe_get_origin_offset(RID p_probe) const {
- return Vector3();
-}
-
-float RasterizerStorageGLES3::reflection_probe_get_origin_max_distance(RID p_probe) const {
- return 0.0;
-}
-
-bool RasterizerStorageGLES3::reflection_probe_renders_shadows(RID p_probe) const {
- return false;
-}
-
-void RasterizerStorageGLES3::base_update_dependency(RID p_base, DependencyTracker *p_instance) {
-}
-
-void RasterizerStorageGLES3::skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) {
-}
-
-/* DECAL API */
-
-RID RasterizerStorageGLES3::decal_allocate() {
- return RID();
-}
-
-void RasterizerStorageGLES3::decal_initialize(RID p_rid) {
-}
-
-void RasterizerStorageGLES3::decal_set_extents(RID p_decal, const Vector3 &p_extents) {
-}
-
-void RasterizerStorageGLES3::decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) {
-}
-
-void RasterizerStorageGLES3::decal_set_emission_energy(RID p_decal, float p_energy) {
-}
-
-void RasterizerStorageGLES3::decal_set_albedo_mix(RID p_decal, float p_mix) {
-}
-
-void RasterizerStorageGLES3::decal_set_modulate(RID p_decal, const Color &p_modulate) {
-}
-
-void RasterizerStorageGLES3::decal_set_cull_mask(RID p_decal, uint32_t p_layers) {
-}
-
-void RasterizerStorageGLES3::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) {
-}
-
-void RasterizerStorageGLES3::decal_set_fade(RID p_decal, float p_above, float p_below) {
-}
-
-void RasterizerStorageGLES3::decal_set_normal_fade(RID p_decal, float p_fade) {
-}
-
-AABB RasterizerStorageGLES3::decal_get_aabb(RID p_decal) const {
- return AABB();
-}
-
-/* VOXEL GI API */
-
-RID RasterizerStorageGLES3::voxel_gi_allocate() {
- return RID();
-}
-
-void RasterizerStorageGLES3::voxel_gi_initialize(RID p_rid) {
-}
-
-void RasterizerStorageGLES3::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) {
-}
-
-AABB RasterizerStorageGLES3::voxel_gi_get_bounds(RID p_voxel_gi) const {
- return AABB();
-}
-
-Vector3i RasterizerStorageGLES3::voxel_gi_get_octree_size(RID p_voxel_gi) const {
- return Vector3i();
-}
-
-Vector<uint8_t> RasterizerStorageGLES3::voxel_gi_get_octree_cells(RID p_voxel_gi) const {
- return Vector<uint8_t>();
-}
-
-Vector<uint8_t> RasterizerStorageGLES3::voxel_gi_get_data_cells(RID p_voxel_gi) const {
- return Vector<uint8_t>();
-}
-
-Vector<uint8_t> RasterizerStorageGLES3::voxel_gi_get_distance_field(RID p_voxel_gi) const {
- return Vector<uint8_t>();
-}
-
-Vector<int> RasterizerStorageGLES3::voxel_gi_get_level_counts(RID p_voxel_gi) const {
- return Vector<int>();
-}
-
-Transform3D RasterizerStorageGLES3::voxel_gi_get_to_cell_xform(RID p_voxel_gi) const {
- return Transform3D();
-}
-
-void RasterizerStorageGLES3::voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) {
-}
-
-float RasterizerStorageGLES3::voxel_gi_get_dynamic_range(RID p_voxel_gi) const {
- return 0;
-}
-
-void RasterizerStorageGLES3::voxel_gi_set_propagation(RID p_voxel_gi, float p_range) {
-}
-
-float RasterizerStorageGLES3::voxel_gi_get_propagation(RID p_voxel_gi) const {
- return 0;
-}
-
-void RasterizerStorageGLES3::voxel_gi_set_energy(RID p_voxel_gi, float p_range) {
-}
-
-float RasterizerStorageGLES3::voxel_gi_get_energy(RID p_voxel_gi) const {
- return 0.0;
-}
-
-void RasterizerStorageGLES3::voxel_gi_set_bias(RID p_voxel_gi, float p_range) {
-}
-
-float RasterizerStorageGLES3::voxel_gi_get_bias(RID p_voxel_gi) const {
- return 0.0;
-}
-
-void RasterizerStorageGLES3::voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) {
-}
-
-float RasterizerStorageGLES3::voxel_gi_get_normal_bias(RID p_voxel_gi) const {
- return 0.0;
-}
-
-void RasterizerStorageGLES3::voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) {
-}
-
-bool RasterizerStorageGLES3::voxel_gi_is_interior(RID p_voxel_gi) const {
- return false;
-}
-
-void RasterizerStorageGLES3::voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) {
-}
-
-bool RasterizerStorageGLES3::voxel_gi_is_using_two_bounces(RID p_voxel_gi) const {
- return false;
-}
-
-void RasterizerStorageGLES3::voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) {
-}
-
-float RasterizerStorageGLES3::voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const {
- return 0;
-}
-
-uint32_t RasterizerStorageGLES3::voxel_gi_get_version(RID p_voxel_gi) {
- return 0;
-}
-
-/* LIGHTMAP CAPTURE */
-RID RasterizerStorageGLES3::lightmap_allocate() {
- return RID();
-}
-
-void RasterizerStorageGLES3::lightmap_initialize(RID p_rid) {
-}
-
-void RasterizerStorageGLES3::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) {
-}
-
-void RasterizerStorageGLES3::lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) {
-}
-
-void RasterizerStorageGLES3::lightmap_set_probe_interior(RID p_lightmap, bool p_interior) {
-}
-
-void RasterizerStorageGLES3::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) {
-}
-
-PackedVector3Array RasterizerStorageGLES3::lightmap_get_probe_capture_points(RID p_lightmap) const {
- return PackedVector3Array();
-}
-
-PackedColorArray RasterizerStorageGLES3::lightmap_get_probe_capture_sh(RID p_lightmap) const {
- return PackedColorArray();
-}
-
-PackedInt32Array RasterizerStorageGLES3::lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const {
- return PackedInt32Array();
-}
-
-PackedInt32Array RasterizerStorageGLES3::lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const {
- return PackedInt32Array();
-}
-
-AABB RasterizerStorageGLES3::lightmap_get_aabb(RID p_lightmap) const {
- return AABB();
-}
-
-void RasterizerStorageGLES3::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) {
-}
-
-bool RasterizerStorageGLES3::lightmap_is_interior(RID p_lightmap) const {
- return false;
-}
-
-void RasterizerStorageGLES3::lightmap_set_probe_capture_update_speed(float p_speed) {
-}
-
-float RasterizerStorageGLES3::lightmap_get_probe_capture_update_speed() const {
- return 0;
-}
-
-/* OCCLUDER */
-
-void RasterizerStorageGLES3::occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) {
-}
-
-/* PARTICLES */
-
-RID RasterizerStorageGLES3::particles_allocate() {
- return RID();
-}
-
-void RasterizerStorageGLES3::particles_initialize(RID p_rid) {
-}
-
-void RasterizerStorageGLES3::particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) {
-}
-
-void RasterizerStorageGLES3::particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
-}
-
-void RasterizerStorageGLES3::particles_set_emitting(RID p_particles, bool p_emitting) {
-}
-
-void RasterizerStorageGLES3::particles_set_amount(RID p_particles, int p_amount) {
-}
-
-void RasterizerStorageGLES3::particles_set_lifetime(RID p_particles, double p_lifetime) {
-}
-
-void RasterizerStorageGLES3::particles_set_one_shot(RID p_particles, bool p_one_shot) {
-}
-
-void RasterizerStorageGLES3::particles_set_pre_process_time(RID p_particles, double p_time) {
-}
-
-void RasterizerStorageGLES3::particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) {
-}
-
-void RasterizerStorageGLES3::particles_set_randomness_ratio(RID p_particles, real_t p_ratio) {
-}
-
-void RasterizerStorageGLES3::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) {
-}
-
-void RasterizerStorageGLES3::particles_set_speed_scale(RID p_particles, double p_scale) {
-}
-
-void RasterizerStorageGLES3::particles_set_use_local_coordinates(RID p_particles, bool p_enable) {
-}
-
-void RasterizerStorageGLES3::particles_set_process_material(RID p_particles, RID p_material) {
-}
-
-void RasterizerStorageGLES3::particles_set_fixed_fps(RID p_particles, int p_fps) {
-}
-
-void RasterizerStorageGLES3::particles_set_interpolate(RID p_particles, bool p_enable) {
-}
-
-void RasterizerStorageGLES3::particles_set_fractional_delta(RID p_particles, bool p_enable) {
-}
-
-void RasterizerStorageGLES3::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) {
-}
-
-void RasterizerStorageGLES3::particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) {
-}
-
-void RasterizerStorageGLES3::particles_set_collision_base_size(RID p_particles, real_t p_size) {
-}
-
-void RasterizerStorageGLES3::particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) {
-}
-
-void RasterizerStorageGLES3::particles_set_trails(RID p_particles, bool p_enable, double p_length) {
-}
-
-void RasterizerStorageGLES3::particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) {
-}
-
-void RasterizerStorageGLES3::particles_restart(RID p_particles) {
-}
-
-void RasterizerStorageGLES3::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) {
-}
-
-void RasterizerStorageGLES3::particles_set_draw_passes(RID p_particles, int p_count) {
-}
-
-void RasterizerStorageGLES3::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {
-}
-
-void RasterizerStorageGLES3::particles_request_process(RID p_particles) {
-}
-
-AABB RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) {
- return AABB();
-}
-
-AABB RasterizerStorageGLES3::particles_get_aabb(RID p_particles) const {
- return AABB();
-}
-
-void RasterizerStorageGLES3::particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) {
-}
-
-bool RasterizerStorageGLES3::particles_get_emitting(RID p_particles) {
- return false;
-}
-
-int RasterizerStorageGLES3::particles_get_draw_passes(RID p_particles) const {
- return 0;
-}
-
-RID RasterizerStorageGLES3::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const {
- return RID();
-}
-
-void RasterizerStorageGLES3::particles_add_collision(RID p_particles, RID p_instance) {
-}
-
-void RasterizerStorageGLES3::particles_remove_collision(RID p_particles, RID p_instance) {
-}
-
-void RasterizerStorageGLES3::particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) {
-}
-
-void RasterizerStorageGLES3::update_particles() {
-}
-
-/* PARTICLES COLLISION */
-
-RID RasterizerStorageGLES3::particles_collision_allocate() {
- return RID();
-}
-
-void RasterizerStorageGLES3::particles_collision_initialize(RID p_rid) {
-}
-
-void RasterizerStorageGLES3::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) {
-}
-
-void RasterizerStorageGLES3::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) {
-}
-
-void RasterizerStorageGLES3::particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) {
-}
-
-void RasterizerStorageGLES3::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) {
-}
-
-void RasterizerStorageGLES3::particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) {
-}
-
-void RasterizerStorageGLES3::particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) {
-}
-
-void RasterizerStorageGLES3::particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) {
-}
-
-void RasterizerStorageGLES3::particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) {
-}
-
-void RasterizerStorageGLES3::particles_collision_height_field_update(RID p_particles_collision) {
-}
-
-void RasterizerStorageGLES3::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) {
-}
-
-AABB RasterizerStorageGLES3::particles_collision_get_aabb(RID p_particles_collision) const {
- return AABB();
-}
-
-bool RasterizerStorageGLES3::particles_collision_is_heightfield(RID p_particles_collision) const {
- return false;
-}
-
-RID RasterizerStorageGLES3::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const {
- return RID();
-}
-
-RID RasterizerStorageGLES3::particles_collision_instance_create(RID p_collision) {
- return RID();
-}
-
-void RasterizerStorageGLES3::particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) {
-}
-
-void RasterizerStorageGLES3::particles_collision_instance_set_active(RID p_collision_instance, bool p_active) {
-}
-
-RID RasterizerStorageGLES3::fog_volume_allocate() {
- return RID();
-}
-
-void RasterizerStorageGLES3::fog_volume_initialize(RID p_rid) {
-}
-
-void RasterizerStorageGLES3::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) {
-}
-
-void RasterizerStorageGLES3::fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) {
-}
-
-void RasterizerStorageGLES3::fog_volume_set_material(RID p_fog_volume, RID p_material) {
-}
-
-AABB RasterizerStorageGLES3::fog_volume_get_aabb(RID p_fog_volume) const {
- return AABB();
-}
-
-RS::FogVolumeShape RasterizerStorageGLES3::fog_volume_get_shape(RID p_fog_volume) const {
- return RS::FOG_VOLUME_SHAPE_BOX;
-}
-
-/* VISIBILITY NOTIFIER */
-RID RasterizerStorageGLES3::visibility_notifier_allocate() {
- return RID();
-}
-
-void RasterizerStorageGLES3::visibility_notifier_initialize(RID p_notifier) {
-}
-
-void RasterizerStorageGLES3::visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) {
-}
-
-void RasterizerStorageGLES3::visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) {
-}
-
-AABB RasterizerStorageGLES3::visibility_notifier_get_aabb(RID p_notifier) const {
- return AABB();
-}
-
-void RasterizerStorageGLES3::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) {
-}
-
-/* GLOBAL VARIABLES */
-
-void RasterizerStorageGLES3::global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) {
-}
-
-void RasterizerStorageGLES3::global_variable_remove(const StringName &p_name) {
-}
-
-Vector<StringName> RasterizerStorageGLES3::global_variable_get_list() const {
- return Vector<StringName>();
-}
-
-void RasterizerStorageGLES3::global_variable_set(const StringName &p_name, const Variant &p_value) {
-}
-
-void RasterizerStorageGLES3::global_variable_set_override(const StringName &p_name, const Variant &p_value) {
-}
-
-Variant RasterizerStorageGLES3::global_variable_get(const StringName &p_name) const {
- return Variant();
-}
-
-RS::GlobalVariableType RasterizerStorageGLES3::global_variable_get_type(const StringName &p_name) const {
- return RS::GLOBAL_VAR_TYPE_MAX;
-}
-
-void RasterizerStorageGLES3::global_variables_load_settings(bool p_load_textures) {
-}
-
-void RasterizerStorageGLES3::global_variables_clear() {
-}
-
-int32_t RasterizerStorageGLES3::global_variables_instance_allocate(RID p_instance) {
- return 0;
-}
-
-void RasterizerStorageGLES3::global_variables_instance_free(RID p_instance) {
-}
-
-void RasterizerStorageGLES3::global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) {
-}
-
-bool RasterizerStorageGLES3::particles_is_inactive(RID p_particles) const {
- return false;
-}
-
-/* RENDER TARGET */
-
-void RasterizerStorageGLES3::_set_current_render_target(RID p_render_target) {
- RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
-
- if (rt) {
- if (rt->allocate_is_dirty) {
- rt->allocate_is_dirty = false;
- _render_target_allocate(rt);
- }
-
- frame.current_rt = rt;
- ERR_FAIL_COND(!rt);
- frame.clear_request = false;
-
- glViewport(0, 0, rt->width, rt->height);
-
- _dims.rt_width = rt->width;
- _dims.rt_height = rt->height;
- _dims.win_width = rt->width;
- _dims.win_height = rt->height;
-
- } else {
- frame.current_rt = nullptr;
- frame.clear_request = false;
- bind_framebuffer_system();
- }
-}
-
-void RasterizerStorageGLES3::_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 = RasterizerStorageGLES3::system_fbo;
- return;
- }
-
- GLuint color_internal_format;
- GLuint color_format;
- GLuint color_type = GL_UNSIGNED_BYTE;
- Image::Format image_format;
-
- if (rt->flags[RendererStorage::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.get_or_null(rt->texture);
- ERR_FAIL_COND(!texture);
-
- // framebuffer
- glGenFramebuffers(1, &rt->fbo);
- bind_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 & 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);
- }
-
- 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_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_8X) {
- 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);
- bind_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);
-
- 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);
-
- 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);
- rt->multisample_active = false;
-
- glDeleteFramebuffers(1, &rt->multisample_fbo);
- rt->multisample_fbo = 0;
-
- glDeleteRenderbuffers(1, &rt->multisample_depth);
- rt->multisample_depth = 0;
-
- glDeleteRenderbuffers(1, &rt->multisample_color);
- rt->multisample_color = 0;
- }
-
- glBindRenderbuffer(GL_RENDERBUFFER, 0);
- bind_framebuffer(0);
-
- } 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[RendererStorage::RENDER_TARGET_NO_SAMPLING])) {
- if (true) {
- glGenTextures(1, &rt->copy_screen_effect.color);
- glBindTexture(GL_TEXTURE_2D, rt->copy_screen_effect.color);
-
- if (rt->flags[RendererStorage::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);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- glGenFramebuffers(1, &rt->copy_screen_effect.fbo);
- bind_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[RendererStorage::RENDER_TARGET_NO_3D] && rt->width >= 2 && rt->height >= 2) {
- if (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);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(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);
- bind_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");
- bind_framebuffer_system();
- 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);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- }
- }
- rt->mip_maps_allocated = true;
- }
-
- bind_framebuffer_system();
-}
-
-void RasterizerStorageGLES3::_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.get_or_null(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.get_or_null(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;
-
- glDeleteRenderbuffers(1, &rt->multisample_color);
-
- rt->multisample_color = 0;
- }
-}
-
-RID RasterizerStorageGLES3::render_target_create() {
- RenderTarget *rt = memnew(RenderTarget);
- Texture *t = memnew(Texture);
-
- t->type = RenderingDevice::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 RasterizerStorageGLES3::render_target_set_position(RID p_render_target, int p_x, int p_y) {
- RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
-
- rt->x = p_x;
- rt->y = p_y;
-}
-
-void RasterizerStorageGLES3::render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) {
- RenderTarget *rt = render_target_owner.get_or_null(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;
-
- // print_line("render_target_set_size " + itos(p_render_target.get_id()) + ", w " + itos(p_width) + " h " + itos(p_height));
-
- rt->allocate_is_dirty = true;
- //_render_target_allocate(rt);
-}
-
-// TODO: convert to Size2i internally
-Size2i RasterizerStorageGLES3::render_target_get_size(RID p_render_target) {
- RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, Size2());
-
- return Size2i(rt->width, rt->height);
-}
-
-RID RasterizerStorageGLES3::render_target_get_texture(RID p_render_target) {
- RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
-
- if (rt->external.fbo == 0) {
- return rt->texture;
- } else {
- return rt->external.texture;
- }
-}
-
-void RasterizerStorageGLES3::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {
- RenderTarget *rt = render_target_owner.get_or_null(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.get_or_null(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);
- bind_framebuffer(rt->external.fbo);
-
- // allocate a texture
- t = memnew(Texture);
-
- t->type = RenderingDevice::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
- bind_framebuffer(rt->external.fbo);
-
- // find our texture
- t = texture_owner.get_or_null(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
- {
- // 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);
- bind_framebuffer_system();
-
- if (status != GL_FRAMEBUFFER_COMPLETE) {
- printf("framebuffer fail, status: %x\n", status);
- }
-
- ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
- }
-}
-
-void RasterizerStorageGLES3::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {
- RenderTarget *rt = render_target_owner.get_or_null(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 RasterizerStorageGLES3::render_target_was_used(RID p_render_target) {
- RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, false);
-
- return rt->used_in_frame;
-}
-
-void RasterizerStorageGLES3::render_target_clear_used(RID p_render_target) {
- RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
-
- rt->used_in_frame = false;
-}
-
-void RasterizerStorageGLES3::render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) {
- RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
-
- if (rt->msaa == p_msaa) {
- return;
- }
-
- _render_target_clear(rt);
- rt->msaa = p_msaa;
- _render_target_allocate(rt);
-}
-
-//RasterizerStorageGLES3::RenderTarget * RasterizerStorageGLES3::render_target_get(RID p_render_target)
-//{
-// return render_target_owner.get_or_null(p_render_target);
-//}
-
-void RasterizerStorageGLES3::render_target_set_use_fxaa(RID p_render_target, bool p_fxaa) {
- RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
-
- rt->use_fxaa = p_fxaa;
-}
-
-void RasterizerStorageGLES3::render_target_set_use_debanding(RID p_render_target, bool p_debanding) {
- RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
-
- if (p_debanding) {
- WARN_PRINT_ONCE("Debanding is not supported in the OpenGL backend. Switch to the Vulkan backend and make sure HDR is enabled.");
- }
-
- rt->use_debanding = p_debanding;
-}
-
-void RasterizerStorageGLES3::render_target_request_clear(RID p_render_target, const Color &p_clear_color) {
- RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
- rt->clear_requested = true;
- rt->clear_color = p_clear_color;
-
- // ERR_FAIL_COND(!frame.current_rt);
- // frame.clear_request = true;
- // frame.clear_request_color = p_color;
-}
-
-bool RasterizerStorageGLES3::render_target_is_clear_requested(RID p_render_target) {
- RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, false);
- return rt->clear_requested;
-}
-Color RasterizerStorageGLES3::render_target_get_clear_request_color(RID p_render_target) {
- RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, Color());
- return rt->clear_color;
-}
-
-void RasterizerStorageGLES3::render_target_disable_clear_request(RID p_render_target) {
- RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
- rt->clear_requested = false;
-}
-
-void RasterizerStorageGLES3::render_target_do_clear_request(RID p_render_target) {
-}
-
-void RasterizerStorageGLES3::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) {
-}
-
-Rect2i RasterizerStorageGLES3::render_target_get_sdf_rect(RID p_render_target) const {
- return Rect2i();
-}
-
-void RasterizerStorageGLES3::render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) {
-}
-
-/* CANVAS SHADOW */
-
-RID RasterizerStorageGLES3::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);
- bind_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, NULL);
-#endif
- }
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cls->distance, 0);
-
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- //printf("errnum: %x\n",status);
- bind_framebuffer_system();
-
- 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 RasterizerStorageGLES3::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 RasterizerStorageGLES3::canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines) {
- CanvasOccluder *co = canvas_occluder_owner.get(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()) {
- PoolVector<float> geometry;
- PoolVector<uint16_t> indices;
- int lc = p_lines.size();
-
- geometry.resize(lc * 6);
- indices.resize(lc * 3);
-
- PoolVector<float>::Write vw = geometry.write();
- PoolVector<uint16_t>::Write iw = indices.write();
-
- PoolVector<Vector2>::Read lr = p_lines.read();
-
- 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 RasterizerStorageGLES3::get_base_type(RID p_rid) const {
- return RS::INSTANCE_NONE;
-
- /*
- 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 RasterizerStorageGLES3::free(RID p_rid) {
- if (render_target_owner.owns(p_rid)) {
- RenderTarget *rt = render_target_owner.get_or_null(p_rid);
- _render_target_clear(rt);
-
- Texture *t = texture_owner.get_or_null(rt->texture);
- if (t) {
- 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.get_or_null(p_rid);
- // can't free a render target texture
- ERR_FAIL_COND_V(t->render_target, true);
- if (t->canvas_texture) {
- memdelete(t->canvas_texture);
- }
-
- info.texture_mem -= t->total_data_size;
- texture_owner.free(p_rid);
- memdelete(t);
-
- return true;
- } else if (canvas_texture_owner.owns(p_rid)) {
- canvas_texture_owner.free(p_rid);
- return true;
- } else if (sky_owner.owns(p_rid)) {
- Sky *sky = sky_owner.get_or_null(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.get_or_null(p_rid);
-
- if (shader->shader && shader->version.is_valid()) {
- shader->shader->version_free(shader->version);
- }
-
- 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.get_or_null(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<InstanceBaseDependency *, int>::Element *E = m->instance_owners.front(); E; E = E->next()) {
- InstanceBaseDependency *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 {
- return false;
- }
- /*
- } else if (skeleton_owner.owns(p_rid)) {
- Skeleton *s = skeleton_owner.get_or_null(p_rid);
-
- if (s->update_list.in_list()) {
- skeleton_update_list.remove(&s->update_list);
- }
-
- for (Set<InstanceBaseDependency *>::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.get_or_null(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.get_or_null(p_rid);
- multimesh->instance_remove_deps();
-
- if (multimesh->mesh.is_valid()) {
- Mesh *mesh = mesh_owner.get_or_null(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.get_or_null(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.get_or_null(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.get_or_null(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.get_or_null(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.get_or_null(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.get_or_null(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;
- */
-}
-
-bool RasterizerStorageGLES3::has_os_feature(const String &p_feature) const {
- if (p_feature == "s3tc") {
- return config.s3tc_supported;
- }
-
- if (p_feature == "etc") {
- return config.etc_supported;
- }
-
- if (p_feature == "skinning_fallback") {
- return config.use_skeleton_software;
- }
-
- return false;
-}
-
-////////////////////////////////////////////
-
-void RasterizerStorageGLES3::set_debug_generate_wireframes(bool p_generate) {
-}
-
-//void RasterizerStorageGLES3::render_info_begin_capture() {
-// info.snap = info.render;
-//}
-
-//void RasterizerStorageGLES3::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;
-// info.snap._2d_item_count = info.render._2d_item_count - info.snap._2d_item_count;
-// info.snap._2d_draw_call_count = info.render._2d_draw_call_count - info.snap._2d_draw_call_count;
-//}
-
-//int RasterizerStorageGLES3::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;
-// /*
-// case RS::INFO_2D_ITEMS_IN_FRAME: {
-// return info.snap._2d_item_count;
-// } break;
-// case RS::INFO_2D_DRAW_CALLS_IN_FRAME: {
-// return info.snap._2d_draw_call_count;
-// } break;
-// */
-// default: {
-// return get_render_info(p_info);
-// }
-// }
-//}
-
-//int RasterizerStorageGLES3::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_2D_ITEMS_IN_FRAME:
-// return info.render_final._2d_item_count;
-// case RS::INFO_2D_DRAW_CALLS_IN_FRAME:
-// return info.render_final._2d_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 RasterizerStorageGLES3::get_video_adapter_name() const {
- return (const char *)glGetString(GL_RENDERER);
-}
-
-String RasterizerStorageGLES3::get_video_adapter_vendor() const {
- return (const char *)glGetString(GL_VENDOR);
-}
-
-RenderingDevice::DeviceType RasterizerStorageGLES3::get_video_adapter_type() const {
- return RenderingDevice::DeviceType::DEVICE_TYPE_OTHER;
-}
-
-void RasterizerStorageGLES3::initialize() {
- RasterizerStorageGLES3::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 = true; // false
- config.shrink_textures_x2 = false;
- config.depth_internalformat = GL_DEPTH_COMPONENT;
- config.depth_type = GL_UNSIGNED_INT;
-
-#ifdef GLES_OVER_GL
- config.float_texture_supported = true;
- config.s3tc_supported = true;
- config.etc_supported = false;
- config.support_npot_repeat_mipmap = true;
- config.depth_buffer_internalformat = GL_DEPTH_COMPONENT24;
-#else
- 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.etc_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture") || config.extensions.has("WEBGL_compressed_texture_etc1");
- 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
-
-#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
-
- config.support_half_float_vertices = true;
-//every platform should support this except web, iOS has issues with their support, so add option to disable
-#ifdef JAVASCRIPT_ENABLED
- config.support_half_float_vertices = false;
-#endif
- bool disable_half_float = false; //GLOBAL_GET("rendering/opengl/compatibility/disable_half_float");
- if (disable_half_float) {
- config.support_half_float_vertices = false;
- }
-
- config.etc_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture");
- config.latc_supported = config.extensions.has("GL_EXT_texture_compression_latc");
- config.bptc_supported = config.extensions.has("GL_ARB_texture_compression_bptc");
- 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");
- config.srgb_decode_supported = config.extensions.has("GL_EXT_texture_sRGB_decode");
- //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);
- bind_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);
-
- bind_framebuffer_system();
- 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);
- bind_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;
- }
-
- bind_framebuffer_system();
- 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.initialize();
- shaders.copy_version = shaders.copy.version_create(); //TODO
- shaders.copy.version_bind_shader(shaders.copy_version, CopyShaderGLES3::MODE_COPY_SECTION);
- //shaders.cubemap_filter.init();
- //bool ggx_hq = GLOBAL_GET("rendering/quality/reflections/high_quality_ggx");
- //shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::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);
- }
-
- // 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);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(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 = false; //GLOBAL_GET("rendering/quality/shading/force_vertex_shading");
- config.use_fast_texture_filter = false; //GLOBAL_GET("rendering/quality/filters/use_nearest_mipmap_filter");
- //config.should_orphan = GLOBAL_GET("rendering/options/api_usage_legacy/orphan_buffers");
-}
-
-void RasterizerStorageGLES3::finalize() {
-}
-
-void RasterizerStorageGLES3::_copy_screen() {
- bind_quad_array();
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-}
-
-void RasterizerStorageGLES3::update_memory_info() {
-}
-
-uint64_t RasterizerStorageGLES3::get_rendering_info(RS::RenderingInfo p_info) {
- return 0;
-}
-
-void RasterizerStorageGLES3::update_dirty_resources() {
- update_dirty_shaders();
- update_dirty_materials();
- // update_dirty_skeletons();
- // update_dirty_multimeshes();
-}
-
-RasterizerStorageGLES3::RasterizerStorageGLES3() {
- RasterizerStorageGLES3::system_fbo = 0;
- config.should_orphan = true;
-}
-
-RasterizerStorageGLES3::~RasterizerStorageGLES3() {
- shaders.copy.version_free(shaders.copy_version);
-}
-
-#endif // GLES3_ENABLED
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
deleted file mode 100644
index 0dfc909777..0000000000
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ /dev/null
@@ -1,1438 +0,0 @@
-/*************************************************************************/
-/* rasterizer_storage_gles3.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef RASTERIZER_STORAGE_OPENGL_H
-#define RASTERIZER_STORAGE_OPENGL_H
-
-#ifdef GLES3_ENABLED
-
-#include "core/templates/local_vector.h"
-#include "core/templates/rid_owner.h"
-#include "core/templates/self_list.h"
-#include "servers/rendering/renderer_compositor.h"
-#include "servers/rendering/renderer_storage.h"
-#include "servers/rendering/shader_compiler.h"
-#include "servers/rendering/shader_language.h"
-
-#include "shaders/copy.glsl.gen.h"
-
-class RasterizerCanvasGLES3;
-class RasterizerSceneGLES3;
-
-class RasterizerStorageGLES3 : public RendererStorage {
- friend class RasterizerGLES3;
-
- Thread::ID _main_thread_id = 0;
- bool _is_main_thread();
-
-public:
- RasterizerCanvasGLES3 *canvas;
- RasterizerSceneGLES3 *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 OpenGL
- // bool generate_wireframes;
-
- Set<String> extensions;
-
- bool float_texture_supported;
- bool s3tc_supported;
- bool latc_supported;
- bool rgtc_supported;
- bool bptc_supported;
- bool etc_supported;
- bool etc2_supported;
- bool srgb_decode_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 render_to_mipmap_supported;
-
- GLuint depth_internalformat;
- GLuint depth_type;
- GLuint depth_buffer_internalformat;
-
- // in some cases the legacy render didn't orphan. We will mark these
- // so the user can switch orphaning off for them.
- bool should_orphan;
- } config;
-
- struct Resources {
- GLuint white_tex;
- GLuint black_tex;
- GLuint normal_tex;
- GLuint aniso_tex;
-
- 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;
- LocalVector<float> skeleton_transform_cpu_buffer;
-
- } resources;
-
- mutable struct Shaders {
- ShaderCompiler compiler;
-
- CopyShaderGLES3 copy;
- RID copy_version;
- //CubemapFilterShaderGLES3 cubemap_filter;
-
- ShaderCompiler::IdentifierActions actions_canvas;
- ShaderCompiler::IdentifierActions actions_scene;
- ShaderCompiler::IdentifierActions actions_particles;
-
- } shaders;
-
- struct Info {
- uint64_t texture_mem = 0;
- uint64_t vertex_mem = 0;
-
- 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;
- uint32_t _2d_item_count;
- uint32_t _2d_draw_call_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;
- _2d_item_count = 0;
- _2d_draw_call_count = 0;
- }
- } render, render_final, snap;
-
- Info() {
- render.reset();
- render_final.reset();
- }
-
- } info;
-
- void bind_quad_array() const;
-
- /////////////////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////API////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////
-
- bool can_create_resources_async() const override;
-
- // TEXTURE API
-
- enum OpenGLTextureFlags {
- TEXTURE_FLAG_MIPMAPS = 1, /// Enable automatic mipmap generation - when available
- TEXTURE_FLAG_REPEAT = 2, /// Repeat texture (Tiling), otherwise Clamping
- TEXTURE_FLAG_FILTER = 4, /// Create texture with linear (or available) filter
- TEXTURE_FLAG_ANISOTROPIC_FILTER = 8,
- TEXTURE_FLAG_CONVERT_TO_LINEAR = 16,
- TEXTURE_FLAG_MIRRORED_REPEAT = 32, /// Repeat texture, with alternate sections mirrored
- TEXTURE_FLAG_USED_FOR_STREAMING = 2048,
- TEXTURE_FLAGS_DEFAULT = TEXTURE_FLAG_REPEAT | TEXTURE_FLAG_MIPMAPS | TEXTURE_FLAG_FILTER
- };
-
- /* CANVAS TEXTURE API (2D) */
-
- struct CanvasTexture {
- RID diffuse;
- RID normal_map;
- RID specular;
- Color specular_color = Color(1, 1, 1, 1);
- float shininess = 1.0;
-
- RS::CanvasItemTextureFilter texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
- RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
-
- Size2i size_cache = Size2i(1, 1);
- bool use_normal_cache = false;
- bool use_specular_cache = false;
- bool cleared_cache = true;
- };
-
- RID_Owner<CanvasTexture, true> canvas_texture_owner;
-
- struct RenderTarget;
-
- struct Texture {
- RID self;
-
- Texture *proxy;
- Set<Texture *> proxy_owners;
-
- String path;
- uint32_t flags;
- int width, height, depth;
- int alloc_width, alloc_height;
- Image::Format format;
- RenderingDevice::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;
-
- RS::TextureDetectCallback detect_3d;
- void *detect_3d_ud;
-
- RS::TextureDetectCallback detect_srgb;
- void *detect_srgb_ud;
-
- RS::TextureDetectCallback detect_normal;
- void *detect_normal_ud;
-
- CanvasTexture *canvas_texture = nullptr;
-
- // some silly opengl shenanigans where
- // texture coords start from bottom left, means we need to draw render target textures upside down
- // to be compatible with vulkan etc.
- bool is_upside_down() const {
- if (proxy) {
- return proxy->is_upside_down();
- }
-
- return render_target != nullptr;
- }
-
- Texture() {
- create();
- }
-
- _ALWAYS_INLINE_ Texture *get_ptr() {
- if (proxy) {
- return proxy; //->get_ptr(); only one level of indirection, else not inlining possible.
- } else {
- return this;
- }
- }
-
- ~Texture() {
- destroy();
-
- if (tex_id != 0) {
- glDeleteTextures(1, &tex_id);
- }
- }
-
- void copy_from(const Texture &o) {
- proxy = o.proxy;
- flags = o.flags;
- width = o.width;
- height = o.height;
- alloc_width = o.alloc_width;
- alloc_height = o.alloc_height;
- format = o.format;
- type = o.type;
- target = o.target;
- data_size = o.data_size;
- total_data_size = o.total_data_size;
- ignore_mipmaps = o.ignore_mipmaps;
- compressed = o.compressed;
- mipmaps = o.mipmaps;
- resize_to_po2 = o.resize_to_po2;
- active = o.active;
- tex_id = o.tex_id;
- stored_cube_sides = o.stored_cube_sides;
- render_target = o.render_target;
- redraw_if_visible = o.redraw_if_visible;
- detect_3d = o.detect_3d;
- detect_3d_ud = o.detect_3d_ud;
- detect_srgb = o.detect_srgb;
- detect_srgb_ud = o.detect_srgb_ud;
- detect_normal = o.detect_normal;
- detect_normal_ud = o.detect_normal_ud;
-
- images.clear();
- }
-
- void create() {
- proxy = nullptr;
- flags = 0;
- width = 0;
- height = 0;
- alloc_width = 0;
- alloc_height = 0;
- format = Image::FORMAT_L8;
- type = RenderingDevice::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;
- }
- void destroy() {
- images.clear();
-
- for (Set<Texture *>::Element *E = proxy_owners.front(); E; E = E->next()) {
- E->get()->proxy = nullptr;
- }
-
- if (proxy) {
- proxy->proxy_owners.erase(this);
- }
- }
-
- // texture state
- void GLSetFilter(GLenum p_target, RS::CanvasItemTextureFilter p_filter) {
- if (p_filter == state_filter) {
- return;
- }
- state_filter = p_filter;
- GLint pmin = GL_LINEAR; // param min
- GLint pmag = GL_LINEAR; // param mag
- switch (state_filter) {
- default: {
- } break;
- case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
- pmin = GL_LINEAR_MIPMAP_LINEAR;
- pmag = GL_LINEAR;
- } break;
- case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: {
- pmin = GL_NEAREST;
- pmag = GL_NEAREST;
- } break;
- case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: {
- pmin = GL_NEAREST_MIPMAP_NEAREST;
- pmag = GL_NEAREST;
- } break;
- }
- glTexParameteri(p_target, GL_TEXTURE_MIN_FILTER, pmin);
- glTexParameteri(p_target, GL_TEXTURE_MAG_FILTER, pmag);
- }
- void GLSetRepeat(GLenum p_target, RS::CanvasItemTextureRepeat p_repeat) {
- if (p_repeat == state_repeat) {
- return;
- }
- state_repeat = p_repeat;
- GLint prep = GL_CLAMP_TO_EDGE; // parameter repeat
- switch (state_repeat) {
- default: {
- } break;
- case RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {
- prep = GL_REPEAT;
- } break;
- case RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: {
- prep = GL_MIRRORED_REPEAT;
- } break;
- }
- glTexParameteri(p_target, GL_TEXTURE_WRAP_S, prep);
- glTexParameteri(p_target, GL_TEXTURE_WRAP_T, prep);
- }
-
- private:
- RS::CanvasItemTextureFilter state_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
- RS::CanvasItemTextureRepeat state_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
- };
-
- mutable RID_PtrOwner<Texture> 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;
-
- void _texture_set_state_from_flags(Texture *p_tex);
-
- // new
- RID texture_allocate() override;
- void texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) override;
- void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) override;
- void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) override;
- void texture_proxy_initialize(RID p_texture, RID p_base) override; //all slices, then all the mipmaps, must be coherent
-
- 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 {}
-
- void texture_2d_placeholder_initialize(RID p_texture) override;
- void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) override;
- void texture_3d_placeholder_initialize(RID p_texture) override;
-
- Ref<Image> texture_2d_get(RID p_texture) const override;
- 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>>(); }
-
- 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 {}
-
- 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 {}
-
- // old
- uint32_t texture_get_width(RID p_texture) const;
- uint32_t texture_get_height(RID p_texture) const;
-
-private:
- RID texture_create();
-
- //void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, RenderingDevice::TextureType p_type, uint32_t p_flags = TEXTURE_FLAGS_DEFAULT);
- void _texture_allocate_internal(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, RenderingDevice::TextureType p_type, uint32_t p_flags = TEXTURE_FLAGS_DEFAULT);
-
- void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0);
- 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);
- //Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const;
- void texture_set_flags(RID p_texture, uint32_t p_flags);
- uint32_t texture_get_flags(RID p_texture) const;
- Image::Format texture_get_format(RID p_texture) const;
- RenderingDevice::TextureType texture_get_type(RID p_texture) const;
- uint32_t texture_get_texid(RID p_texture) const;
- uint32_t texture_get_depth(RID p_texture) const;
- void texture_set_size_override(RID p_texture, int p_width, int p_height) override;
-
- void texture_bind(RID p_texture, uint32_t p_texture_no);
-
- void texture_set_path(RID p_texture, const String &p_path) override;
- String texture_get_path(RID p_texture) const override;
-
- void texture_set_shrink_all_x2_on_set_data(bool p_enable);
-
- void texture_debug_usage(List<RS::TextureInfo> *r_info) override;
-
- RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const;
-
- void textures_keep_original(bool p_enable);
-
- void texture_set_proxy(RID p_texture, RID p_proxy);
- Size2 texture_size_with_proxy(RID p_texture) override;
-
- void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override;
- void texture_set_detect_srgb_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata);
- 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 {}
-
- void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) override;
-
-public:
- RID canvas_texture_allocate() override;
- void canvas_texture_initialize(RID p_rid) override;
-
- 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_specular_color, float p_shininess) override;
-
- void canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) override;
- void canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) override;
-
- /* SKY API */
- // not sure if used in godot 4?
- struct Sky {
- RID self;
- RID panorama;
- GLuint radiance;
- int radiance_size;
- };
-
- mutable RID_PtrOwner<Sky> sky_owner;
-
- RID sky_create();
- 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;
- ShaderGLES3 *shader;
- String code;
- SelfList<Material>::List materials;
-
- Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
-
- RID version;
-
- SelfList<Shader> dirty_list;
-
- Map<StringName, Map<int, RID>> default_textures;
-
- Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
-
- 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;
- bool uses_modulate;
- bool uses_color;
- bool uses_vertex;
-
- // all these should disable item joining if used in a custom shader
- bool uses_world_matrix;
- bool uses_extra_matrix;
- bool uses_projection_matrix;
- bool uses_instance_custom;
-
- } 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 uses_tangent;
- bool uses_ensure_correct_normals;
- 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;
- version = RID();
- last_pass = 0;
- }
- };
-
- mutable RID_PtrOwner<Shader> shader_owner;
- mutable SelfList<Shader>::List _shader_dirty_list;
-
- void _shader_make_dirty(Shader *p_shader);
-
- RID shader_allocate() override;
- void shader_initialize(RID p_rid) override;
-
- //RID shader_create() override;
-
- void shader_set_code(RID p_shader, const String &p_code) override;
- String shader_get_code(RID p_shader) const override;
- void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const override;
-
- void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override;
- RID shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const override;
-
- RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override { return RS::ShaderNativeSourceCode(); };
-
- void _update_shader(Shader *p_shader) const;
- void update_dirty_shaders();
-
- // new
- Variant shader_get_param_default(RID p_material, const StringName &p_param) const override { return Variant(); }
-
- // COMMON MATERIAL API
-
- struct Material {
- RID self;
- 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<InstanceBaseDependency *, 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;
-
- // new
- 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 {}
-
- // old
- RID material_allocate() override;
- void material_initialize(RID p_rid) override;
-
- //RID material_create() override;
-
- void material_set_shader(RID p_material, RID p_shader) override;
- RID material_get_shader(RID p_material) const;
-
- 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;
- Variant material_get_param_default(RID p_material, const StringName &p_param) const;
-
- void material_set_line_width(RID p_material, float p_width);
- void material_set_next_pass(RID p_material, RID p_next_material) override;
-
- bool material_is_animated(RID p_material) override;
- bool material_casts_shadows(RID p_material) override;
- bool material_uses_tangents(RID p_material);
- bool material_uses_ensure_correct_normals(RID p_material);
-
- void material_add_instance_owner(RID p_material, DependencyTracker *p_instance);
- void material_remove_instance_owner(RID p_material, DependencyTracker *p_instance);
-
- void material_set_render_priority(RID p_material, int priority) override;
-
- void update_dirty_materials();
-
- /* MESH API */
-
- RID mesh_allocate() override;
- void mesh_initialize(RID p_rid) override;
- 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;
- RID mesh_instance_create(RID p_base) override;
- 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_mesh_lod_threshold(RID p_probe, float p_ratio) override;
- float reflection_probe_get_mesh_lod_threshold(RID p_probe) const override;
-
- void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override;
-
- int mesh_get_blend_shape_count(RID p_mesh) const override;
-
- void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override;
- RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override;
-
- void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
- void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
- void mesh_surface_update_skin_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) override;
- RID mesh_surface_get_material(RID p_mesh, int p_surface) const override;
-
- RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override;
- int mesh_get_surface_count(RID p_mesh) const override;
-
- void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override;
- AABB mesh_get_custom_aabb(RID p_mesh) const override;
-
- AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override;
- void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override;
- void mesh_clear(RID p_mesh) override;
-
- /* MULTIMESH API */
-
- struct MultiMesh {
- RID mesh;
- int instances = 0;
- RS::MultimeshTransformFormat xform_format = RS::MULTIMESH_TRANSFORM_3D;
- bool uses_colors = false;
- bool uses_custom_data = false;
- int visible_instances = -1;
- AABB aabb;
- bool aabb_dirty = false;
- bool buffer_set = false;
- uint32_t stride_cache = 0;
- uint32_t color_offset_cache = 0;
- uint32_t custom_data_offset_cache = 0;
-
- Vector<float> data_cache; //used if individual setting is used
- bool *data_cache_dirty_regions = nullptr;
- uint32_t data_cache_used_dirty_regions = 0;
-
- RID buffer; //storage buffer
- RID uniform_set_3d;
- RID uniform_set_2d;
-
- bool dirty = false;
- MultiMesh *dirty_list = nullptr;
-
- Dependency dependency;
- };
-
- mutable RID_Owner<MultiMesh, true> multimesh_owner;
-
- MultiMesh *multimesh_dirty_list = nullptr;
-
- _FORCE_INLINE_ void _multimesh_make_local(MultiMesh *multimesh) const;
- _FORCE_INLINE_ void _multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb);
- _FORCE_INLINE_ void _multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb);
- _FORCE_INLINE_ void _multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances);
- void _update_dirty_multimeshes();
-
- RID multimesh_allocate() override;
- void multimesh_initialize(RID p_rid) override;
- void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override;
- int multimesh_get_instance_count(RID p_multimesh) const override;
-
- void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override;
- void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &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 override;
- AABB multimesh_get_aabb(RID p_multimesh) const override;
-
- Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override;
- Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override;
- Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override;
- Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override;
- void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
- Vector<float> multimesh_get_buffer(RID p_multimesh) const override;
-
- void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override;
- int multimesh_get_visible_instances(RID p_multimesh) const override;
-
- _FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- return multimesh->xform_format;
- }
-
- _FORCE_INLINE_ bool multimesh_uses_colors(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- return multimesh->uses_colors;
- }
-
- _FORCE_INLINE_ bool multimesh_uses_custom_data(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- return multimesh->uses_custom_data;
- }
-
- _FORCE_INLINE_ uint32_t multimesh_get_instances_to_draw(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- if (multimesh->visible_instances >= 0) {
- return multimesh->visible_instances;
- }
- return multimesh->instances;
- }
-
- /* SKELETON API */
-
- RID skeleton_allocate() override;
- void skeleton_initialize(RID p_rid) override;
- void skeleton_allocate_data(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;
- void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) override;
- Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override;
- 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;
-
- /* Light API */
-
- RID directional_light_allocate() override;
- void directional_light_initialize(RID p_rid) override;
- RID omni_light_allocate() override;
- void omni_light_initialize(RID p_rid) override;
- RID spot_light_allocate() override;
- void spot_light_initialize(RID p_rid) override;
- RID reflection_probe_allocate() override;
- void reflection_probe_initialize(RID p_rid) override;
-
- 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;
- 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;
-
- RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) override;
- RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) override;
-
- bool light_has_shadow(RID p_light) const override;
- bool light_has_projector(RID p_light) const override;
-
- RS::LightType light_get_type(RID p_light) const override;
- AABB light_get_aabb(RID p_light) const override;
- float light_get_param(RID p_light, RS::LightParam p_param) override;
- Color light_get_color(RID p_light) override;
- RS::LightBakeMode light_get_bake_mode(RID p_light) override;
- uint32_t light_get_max_sdfgi_cascade(RID p_light) override;
- uint64_t light_get_version(RID p_light) const override;
-
- /* PROBE API */
-
- 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;
- RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const override;
- uint32_t reflection_probe_get_cull_mask(RID p_probe) const override;
- Vector3 reflection_probe_get_extents(RID p_probe) const override;
- Vector3 reflection_probe_get_origin_offset(RID p_probe) const override;
- float reflection_probe_get_origin_max_distance(RID p_probe) const override;
- bool reflection_probe_renders_shadows(RID p_probe) const override;
-
- 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_allocate() override;
- void decal_initialize(RID p_rid) override;
- 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;
-
- /* VOXEL GI API */
-
- RID voxel_gi_allocate() override;
- void voxel_gi_initialize(RID p_rid) override;
- void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &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;
-
- AABB voxel_gi_get_bounds(RID p_voxel_gi) const override;
- Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const override;
- Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const override;
- Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const override;
- Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) const override;
-
- Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const override;
- Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) const override;
-
- void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) override;
- float voxel_gi_get_dynamic_range(RID p_voxel_gi) const override;
-
- void voxel_gi_set_propagation(RID p_voxel_gi, float p_range) override;
- float voxel_gi_get_propagation(RID p_voxel_gi) const override;
-
- void voxel_gi_set_energy(RID p_voxel_gi, float p_range) override;
- float voxel_gi_get_energy(RID p_voxel_gi) const override;
-
- void voxel_gi_set_bias(RID p_voxel_gi, float p_range) override;
- float voxel_gi_get_bias(RID p_voxel_gi) const override;
-
- void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) override;
- float voxel_gi_get_normal_bias(RID p_voxel_gi) const override;
-
- void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) override;
- bool voxel_gi_is_interior(RID p_voxel_gi) const override;
-
- void voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) override;
- bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const override;
-
- void voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) override;
- float voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const override;
-
- uint32_t voxel_gi_get_version(RID p_voxel_gi) override;
-
- /* LIGHTMAP CAPTURE */
- RID lightmap_allocate() override;
- void lightmap_initialize(RID p_rid) override;
- 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;
- PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const override;
- PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const override;
- PackedInt32Array lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const override;
- AABB lightmap_get_aabb(RID p_lightmap) const override;
- 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;
- void lightmap_set_probe_capture_update_speed(float p_speed) override;
- float lightmap_get_probe_capture_update_speed() const override;
-
- /* OCCLUDER */
-
- void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices);
-
- /* PARTICLES */
-
- RID particles_allocate() override;
- void particles_initialize(RID p_rid) override;
- void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) override;
- void particles_emit(RID p_particles, const Transform3D &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, double 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, double p_time) override;
- void particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) override;
- void particles_set_randomness_ratio(RID p_particles, real_t p_ratio) override;
- void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) override;
- void particles_set_speed_scale(RID p_particles, double 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_interpolate(RID p_particles, bool p_enable) 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, const Vector3 &p_up_axis) override;
- void particles_set_collision_base_size(RID p_particles, real_t p_size) override;
-
- void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) override;
-
- void particles_set_trails(RID p_particles, bool p_enable, double p_length) override;
- void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) 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;
- AABB particles_get_aabb(RID p_particles) const override;
-
- void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override;
-
- bool particles_get_emitting(RID p_particles) override;
- int particles_get_draw_passes(RID p_particles) const override;
- RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const override;
-
- void particles_add_collision(RID p_particles, RID p_instance) override;
- void particles_remove_collision(RID p_particles, RID p_instance) override;
-
- void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) override;
-
- void update_particles() override;
-
- /* PARTICLES COLLISION */
-
- RID particles_collision_allocate() override;
- void particles_collision_initialize(RID p_rid) override;
- 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, real_t 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, real_t p_strength) override;
- void particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) override;
- void particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t 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;
- bool particles_collision_is_heightfield(RID p_particles_collision) const override;
- RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const override;
-
- RID particles_collision_instance_create(RID p_collision) override;
- void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) override;
- void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override;
-
- /* FOG VOLUMES */
-
- RID fog_volume_allocate() override;
- void fog_volume_initialize(RID p_rid) override;
-
- void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override;
- void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) override;
- void fog_volume_set_material(RID p_fog_volume, RID p_material) override;
- AABB fog_volume_get_aabb(RID p_fog_volume) const override;
- RS::FogVolumeShape fog_volume_get_shape(RID p_fog_volume) const override;
-
- /* VISIBILITY NOTIFIER */
- RID visibility_notifier_allocate() override;
- void visibility_notifier_initialize(RID p_notifier) override;
- void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) override;
- void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) override;
-
- AABB visibility_notifier_get_aabb(RID p_notifier) const override;
- void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) 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;
-
- 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;
- RS::GlobalVariableType global_variable_get_type(const StringName &p_name) const override;
-
- 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;
- 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;
-
- // RENDER TARGET
-
- struct RenderTarget {
- RID self;
- GLuint fbo = 0;
- GLuint color = 0;
- GLuint depth = 0;
-
- GLuint multisample_fbo = 0;
- GLuint multisample_color = 0;
- GLuint multisample_depth = 0;
- bool multisample_active = false;
-
- struct Effect {
- GLuint fbo = 0;
- int width = 0;
- int height = 0;
-
- GLuint color = 0;
-
- Effect() {
- }
- };
-
- Effect copy_screen_effect;
-
- struct MipMaps {
- struct Size {
- GLuint fbo;
- GLuint color;
- int width;
- int height;
- };
-
- Vector<Size> sizes;
- GLuint color = 0;
- int levels = 0;
-
- MipMaps() {
- }
- };
-
- MipMaps mip_maps[2];
-
- struct External {
- GLuint fbo = 0;
- GLuint color = 0;
- GLuint depth = 0;
- RID texture;
-
- External() {
- }
- } external;
-
- int x = 0, y = 0, width = 0, height = 0;
-
- bool flags[RENDER_TARGET_FLAG_MAX];
-
- // instead of allocating sized render targets immediately,
- // defer this for faster startup
- bool allocate_is_dirty = false;
- bool used_in_frame = false;
- RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
-
- bool use_fxaa = false;
- bool use_debanding = false;
-
- RID texture;
-
- bool used_dof_blur_near = false;
- bool mip_maps_allocated = false;
-
- Color clear_color = Color(1, 1, 1, 1);
- bool clear_requested = false;
-
- RenderTarget() {
- 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);
- void _set_current_render_target(RID p_render_target);
-
- RID render_target_create() override;
- 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, uint32_t p_view_count) override;
- Size2i render_target_get_size(RID p_render_target);
- RID render_target_get_texture(RID p_render_target) override;
- 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;
- void render_target_clear_used(RID p_render_target);
- void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa);
- void render_target_set_use_fxaa(RID p_render_target, bool p_fxaa);
- void render_target_set_use_debanding(RID p_render_target, bool p_debanding);
-
- // new
- void render_target_set_as_unused(RID p_render_target) override {
- render_target_clear_used(p_render_target);
- }
-
- 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;
- Color render_target_get_clear_request_color(RID p_render_target) override;
- 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;
- void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override;
-
- // access from canvas
- // RenderTarget * render_target_get(RID p_render_target);
-
- /* CANVAS SHADOW */
-
- struct CanvasLightShadow {
- RID self;
- int size;
- int height;
- GLuint fbo;
- GLuint depth;
- GLuint distance; //for older devices
- };
-
- RID_PtrOwner<CanvasLightShadow> canvas_light_shadow_owner;
-
- RID canvas_light_shadow_buffer_create(int p_width);
-
- /* LIGHT SHADOW MAPPING */
- /*
- struct CanvasOccluder {
- RID self;
-
- GLuint vertex_id; // 0 means, unconfigured
- GLuint index_id; // 0 means, unconfigured
- LocalVector<Vector2> lines;
- int len;
- };
-
- RID_Owner<CanvasOccluder> canvas_occluder_owner;
-
- RID canvas_light_occluder_create();
- void canvas_light_occluder_set_polylines(RID p_occluder, const LocalVector<Vector2> &p_lines);
-*/
-
- RS::InstanceType get_base_type(RID p_rid) const override;
-
- bool free(RID p_rid) override;
-
- struct Frame {
- RenderTarget *current_rt;
-
- // these 2 may have been superseded by the equivalents in the render target.
- // these may be able to be removed.
- bool clear_request;
- Color clear_request_color;
-
- float time;
- float delta;
- uint64_t count;
-
- Frame() {
- // current_rt = nullptr;
- // clear_request = false;
- }
- } frame;
-
- void initialize();
- void finalize();
-
- void _copy_screen();
-
- void update_memory_info() override;
- uint64_t get_rendering_info(RS::RenderingInfo p_info) override;
-
- bool has_os_feature(const String &p_feature) const override;
-
- void update_dirty_resources() override;
-
- void set_debug_generate_wireframes(bool p_generate) override;
-
- // void render_info_begin_capture() override;
- // void render_info_end_capture() override;
- // int get_captured_render_info(RS::RenderInfo p_info) override;
-
- // int get_render_info(RS::RenderInfo p_info) override;
- String get_video_adapter_name() const override;
- String get_video_adapter_vendor() const override;
- RenderingDevice::DeviceType get_video_adapter_type() const override;
-
- 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();
- }
-
- // make access easier to these
- struct Dimensions {
- // render target
- int rt_width;
- int rt_height;
-
- // window
- int win_width;
- int win_height;
- Dimensions() {
- rt_width = 0;
- rt_height = 0;
- win_width = 0;
- win_height = 0;
- }
- } _dims;
-
- void buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target = GL_ARRAY_BUFFER, GLenum p_usage = GL_DYNAMIC_DRAW, bool p_optional_orphan = false) const;
- bool safe_buffer_sub_data(unsigned int p_total_buffer_size, GLenum p_target, unsigned int p_offset, unsigned int p_data_size, const void *p_data, unsigned int &r_offset_after) const;
-
- void bind_framebuffer(GLuint framebuffer) {
- glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
- }
-
- void bind_framebuffer_system() {
- glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
- }
-
- RasterizerStorageGLES3();
- ~RasterizerStorageGLES3();
-};
-
-inline bool RasterizerStorageGLES3::safe_buffer_sub_data(unsigned int p_total_buffer_size, GLenum p_target, unsigned int p_offset, unsigned int p_data_size, const void *p_data, unsigned int &r_offset_after) const {
- r_offset_after = p_offset + p_data_size;
-#ifdef DEBUG_ENABLED
- // we are trying to write across the edge of the buffer
- if (r_offset_after > p_total_buffer_size) {
- return false;
- }
-#endif
- glBufferSubData(p_target, p_offset, p_data_size, p_data);
- return true;
-}
-
-// standardize the orphan / upload in one place so it can be changed per platform as necessary, and avoid future
-// bugs causing pipeline stalls
-inline void RasterizerStorageGLES3::buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target, GLenum p_usage, bool p_optional_orphan) const {
- // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData
- // Was previously #ifndef GLES_OVER_GL however this causes stalls on desktop mac also (and possibly other)
- if (!p_optional_orphan || (config.should_orphan)) {
- glBufferData(p_target, p_buffer_size, nullptr, p_usage);
-#ifdef RASTERIZER_EXTRA_CHECKS
- // fill with garbage off the end of the array
- if (p_buffer_size) {
- unsigned int start = p_offset + p_data_size;
- unsigned int end = start + 1024;
- if (end < p_buffer_size) {
- uint8_t *garbage = (uint8_t *)alloca(1024);
- for (int n = 0; n < 1024; n++) {
- garbage[n] = Math::random(0, 255);
- }
- glBufferSubData(p_target, start, 1024, garbage);
- }
- }
-#endif
- }
- glBufferSubData(p_target, p_offset, p_data_size, p_data);
-}
-
-#endif // GLES3_ENABLED
-
-#endif // RASTERIZER_STORAGE_OPENGL_H
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index 7ae8b4e3bf..21ccef3518 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/drivers/gles3/shader_gles3.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "shader_gles3.h"
+
#ifdef GLES3_ENABLED
#include "core/io/compression.h"
@@ -164,11 +165,21 @@ void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant
builder.append("\n"); //make sure defines begin at newline
builder.append(general_defines.get_data());
builder.append(variant_defines[p_variant]);
+ builder.append("\n");
for (int j = 0; j < p_version->custom_defines.size(); j++) {
builder.append(p_version->custom_defines[j].get_data());
}
builder.append("\n"); //make sure defines begin at newline
+ // Default to highp precision unless specified otherwise.
+ builder.append("precision highp float;\n");
+ builder.append("precision highp int;\n");
+#ifndef GLES_OVER_GL
+ builder.append("precision highp sampler2D;\n");
+ builder.append("precision highp samplerCube;\n");
+ builder.append("precision highp sampler2DArray;\n");
+#endif
+
for (uint32_t i = 0; i < p_template.chunks.size(); i++) {
const StageTemplate::Chunk &chunk = p_template.chunks[i];
switch (chunk.type) {
@@ -326,7 +337,7 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_
glDeleteProgram(spec.id);
spec.id = 0;
- ERR_PRINT("No OpenGL program link log. What the frick?");
+ ERR_PRINT("No OpenGL program link log. Something is wrong.");
ERR_FAIL();
}
@@ -463,8 +474,8 @@ bool ShaderGLES3::_load_from_cache(Version *p_version) {
String sha1 = _version_get_sha1(p_version);
String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
- FileAccessRef f = FileAccess::open(path, FileAccess::READ);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(path, FileAccess::READ);
+ if (f.is_null()) {
return false;
}
@@ -529,8 +540,8 @@ void ShaderGLES3::_save_to_cache(Version *p_version) {
String sha1 = _version_get_sha1(p_version);
String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
- FileAccessRef f = FileAccess::open(path, FileAccess::WRITE);
- ERR_FAIL_COND(!f);
+ Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE);
+ ERR_FAIL_COND(f.is_null());
f->store_buffer((const uint8_t *)shader_file_header, 4);
f->store_32(cache_file_version); //file version
uint32_t variant_count = variant_count;
@@ -540,8 +551,6 @@ void ShaderGLES3::_save_to_cache(Version *p_version) {
f->store_32(p_version->variant_data[i].size()); //stage count
f->store_buffer(p_version->variant_data[i].ptr(), p_version->variant_data[i].size());
}
-
- f->close();
#endif
}
@@ -553,7 +562,7 @@ void ShaderGLES3::_clear_version(Version *p_version) {
for (int i = 0; i < variant_count; i++) {
for (OAHashMap<uint64_t, Version::Specialization>::Iterator it = p_version->variants[i].iter(); it.valid; it = p_version->variants[i].next_iter(it)) {
- if (it.valid) {
+ if (it.value->id != 0) {
glDeleteShader(it.value->vert_id);
glDeleteShader(it.value->frag_id);
glDeleteProgram(it.value->id);
@@ -576,7 +585,7 @@ void ShaderGLES3::_initialize_version(Version *p_version) {
}
}
-void ShaderGLES3::version_set_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines, const Vector<StringName> &p_texture_uniforms, bool p_initialize) {
+void ShaderGLES3::version_set_code(RID p_version, const HashMap<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines, const Vector<StringName> &p_texture_uniforms, bool p_initialize) {
Version *version = version_owner.get_or_null(p_version);
ERR_FAIL_COND(!version);
@@ -643,8 +652,8 @@ void ShaderGLES3::initialize(const String &p_general_defines, int p_base_texture
base_sha256 = hash_build.as_string().sha256_text();
- DirAccessRef d = DirAccess::open(shader_cache_dir);
- ERR_FAIL_COND(!d);
+ Ref<DirAccess> d = DirAccess::open(shader_cache_dir);
+ ERR_FAIL_COND(d.is_null());
if (d->change_dir(name) != OK) {
Error err = d->make_dir(name);
ERR_FAIL_COND(err != OK);
@@ -664,7 +673,7 @@ void ShaderGLES3::initialize(const String &p_general_defines, int p_base_texture
print_verbose("Shader '" + name + "' SHA256: " + base_sha256);
}
- glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_image_units);
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_image_units);
}
void ShaderGLES3::set_shader_cache_dir(const String &p_dir) {
diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h
index f344ea047f..2b72549b5b 100644
--- a/drivers/gles3/shader_gles3.h
+++ b/drivers/gles3/shader_gles3.h
@@ -28,14 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SHADER_OPENGL_H
-#define SHADER_OPENGL_H
+#ifndef SHADER_GLES3_H
+#define SHADER_GLES3_H
+#include "core/math/projection.h"
#include "core/os/mutex.h"
#include "core/string/string_builder.h"
#include "core/templates/hash_map.h"
#include "core/templates/local_vector.h"
-#include "core/templates/map.h"
+#include "core/templates/rb_map.h"
#include "core/templates/rid_owner.h"
#include "core/variant/variant.h"
#include "servers/rendering_server.h"
@@ -73,16 +74,17 @@ private:
//versions
CharString general_defines;
- // A version is a high-level construct which is a combination of built-in and user-defined shader code
- // Variants use #idefs to toggle behaviour on and off to change behaviour of the shader
+ // A version is a high-level construct which is a combination of built-in and user-defined shader code, Each user-created Shader makes one version
+ // Variants use #ifdefs to toggle behaviour on and off to change behaviour of the shader
+ // All variants are compiled each time a new version is created
// Specializations use #ifdefs to toggle behaviour on and off for performance, on supporting hardware, they will compile a version with everything enabled, and then compile more copies to improve performance
- // Use specializations to enable and disabled advanced features, use variants to toggle behaviour when different data may be used (e.g. using a samplerArray vs a sampler)
+ // Use specializations to enable and disabled advanced features, use variants to toggle behaviour when different data may be used (e.g. using a samplerArray vs a sampler, or doing a depth prepass vs a color pass)
struct Version {
Vector<StringName> texture_uniforms;
CharString uniforms;
CharString vertex_globals;
CharString fragment_globals;
- Map<StringName, CharString> code_sections;
+ HashMap<StringName, CharString> code_sections;
Vector<CharString> custom_defines;
struct Specialization {
@@ -91,7 +93,7 @@ private:
GLuint frag_id;
LocalVector<GLint> uniform_location;
LocalVector<GLint> texture_uniform_locations;
- Map<StringName, GLint> custom_uniform_locations;
+ HashMap<StringName, GLint> custom_uniform_locations;
bool build_queued = false;
bool ok = false;
Specialization() {
@@ -111,7 +113,7 @@ private:
void _clear_version(Version *p_version);
void _initialize_version(Version *p_version);
- RID_Owner<Version> version_owner;
+ RID_Owner<Version, true> version_owner;
struct StageTemplate {
struct Chunk {
@@ -141,7 +143,7 @@ private:
static bool shader_cache_save_debug;
bool shader_cache_dir_valid = false;
- GLint max_image_units;
+ GLint max_image_units = 0;
enum StageType {
STAGE_TYPE_VERTEX,
@@ -217,7 +219,11 @@ protected:
ERR_FAIL_INDEX_V(p_which, uniform_count, -1);
Version *version = version_owner.get_or_null(p_version);
ERR_FAIL_COND_V(!version, -1);
- return version->variants[p_variant].lookup_ptr(p_specialization)->uniform_location[p_which];
+ ERR_FAIL_INDEX_V(p_variant, int(version->variants.size()), -1);
+ Version::Specialization *spec = version->variants[p_variant].lookup_ptr(p_specialization);
+ ERR_FAIL_COND_V(!spec, -1);
+ ERR_FAIL_INDEX_V(p_which, int(spec->uniform_location.size()), -1);
+ return spec->uniform_location[p_which];
}
virtual void _init() = 0;
@@ -225,7 +231,7 @@ protected:
public:
RID version_create();
- void version_set_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines, const Vector<StringName> &p_texture_uniforms, bool p_initialize = false);
+ void version_set_code(RID p_version, const HashMap<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines, const Vector<StringName> &p_texture_uniforms, bool p_initialize = false);
bool version_is_valid(RID p_version);
@@ -242,5 +248,6 @@ public:
virtual ~ShaderGLES3();
};
-#endif // SHADER_OPENGL_H
-#endif
+#endif // GLES3_ENABLED
+
+#endif // SHADER_GLES3_H
diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub
index 2f56b77bdc..83ffe8b1e1 100644
--- a/drivers/gles3/shaders/SCsub
+++ b/drivers/gles3/shaders/SCsub
@@ -3,5 +3,17 @@
Import("env")
if "GLES3_GLSL" in env["BUILDERS"]:
+ # find all include files
+ gl_include_files = [str(f) for f in Glob("*_inc.glsl")]
+
+ # find all shader code(all glsl files excluding our include files)
+ glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
+
+ # make sure we recompile shaders if include files change
+ env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#gles3_builders.py"])
+
env.GLES3_GLSL("canvas.glsl")
env.GLES3_GLSL("copy.glsl")
+ env.GLES3_GLSL("scene.glsl")
+ env.GLES3_GLSL("sky.glsl")
+ env.GLES3_GLSL("cubemap_filter.glsl")
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index a18c451858..4df818cd4c 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -5,6 +5,7 @@ mode_quad =
mode_ninepatch = #define USE_NINEPATCH
mode_primitive = #define USE_PRIMITIVE
mode_attributes = #define USE_ATTRIBUTES
+mode_instanced = #define USE_ATTRIBUTES \n#define USE_INSTANCING
#[specializations]
@@ -20,6 +21,23 @@ layout(location = 4) in vec2 uv_attrib;
layout(location = 10) in uvec4 bone_attrib;
layout(location = 11) in vec4 weight_attrib;
+#ifdef USE_INSTANCING
+
+layout(location = 1) in highp vec4 instance_xform0;
+layout(location = 2) in highp vec4 instance_xform1;
+layout(location = 5) in highp uvec4 instance_color_custom_data; // Color packed into xy, custom_data packed into zw for compatibility with 3D
+
+#endif
+
+#endif
+
+// This needs to be outside clang-format so the ubo comment is in the right place
+#ifdef MATERIAL_UNIFORMS_USED
+layout(std140) uniform MaterialUniforms{ //ubo:4
+
+#MATERIAL_UNIFORMS
+
+};
#endif
/* clang-format on */
#include "canvas_uniforms_inc.glsl"
@@ -38,15 +56,6 @@ out vec2 pixel_size_interp;
#endif
-#ifdef MATERIAL_UNIFORMS_USED
-layout(std140) uniform MaterialUniforms{
-//ubo:4
-
-#MATERIAL_UNIFORMS
-
-};
-#endif
-
#GLOBALS
void main() {
@@ -77,13 +86,22 @@ void main() {
vec4 bone_weights = vec4(0.0);
#elif defined(USE_ATTRIBUTES)
-
+#ifdef USE_INSTANCING
+ draw_data_instance = 0;
+#endif
vec2 vertex = vertex_attrib;
vec4 color = color_attrib * draw_data[draw_data_instance].modulation;
vec2 uv = uv_attrib;
uvec4 bones = bone_attrib;
vec4 bone_weights = weight_attrib;
+
+#ifdef USE_INSTANCING
+ vec4 instance_color = vec4(unpackHalf2x16(instance_color_custom_data.x), unpackHalf2x16(instance_color_custom_data.y));
+ color *= instance_color;
+ instance_custom = vec4(unpackHalf2x16(instance_color_custom_data.z), unpackHalf2x16(instance_color_custom_data.w));
+#endif
+
#else
vec2 vertex_base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
@@ -96,83 +114,12 @@ void main() {
#endif
- mat4 world_matrix = mat4(vec4(draw_data[draw_data_instance].world_x, 0.0, 0.0), vec4(draw_data[draw_data_instance].world_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(draw_data[draw_data_instance].world_ofs, 0.0, 1.0));
-
- // MultiMeshes don't batch, so always read from draw_data[0]
- uint instancing = draw_data[0].flags & FLAGS_INSTANCING_MASK;
+ mat4 model_matrix = mat4(vec4(draw_data[draw_data_instance].world_x, 0.0, 0.0), vec4(draw_data[draw_data_instance].world_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(draw_data[draw_data_instance].world_ofs, 0.0, 1.0));
-#ifdef USE_ATTRIBUTES
-/*
- if (instancing > 1) {
- // trails
-
- uint stride = 2 + 1 + 1; //particles always uses this format
-
- uint trail_size = instancing;
-
- uint offset = trail_size * stride * gl_InstanceID;
-
- vec4 pcolor;
- vec2 new_vertex;
- {
- uint boffset = offset + bone_attrib.x * stride;
- new_vertex = (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.x;
- pcolor = transforms.data[boffset + 2] * weight_attrib.x;
- }
- if (weight_attrib.y > 0.001) {
- uint boffset = offset + bone_attrib.y * stride;
- new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.y;
- pcolor += transforms.data[boffset + 2] * weight_attrib.y;
- }
- if (weight_attrib.z > 0.001) {
- uint boffset = offset + bone_attrib.z * stride;
- new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.z;
- pcolor += transforms.data[boffset + 2] * weight_attrib.z;
- }
- if (weight_attrib.w > 0.001) {
- uint boffset = offset + bone_attrib.w * stride;
- new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.w;
- pcolor += transforms.data[boffset + 2] * weight_attrib.w;
- }
-
- instance_custom = transforms.data[offset + 3];
-
- vertex = new_vertex;
- color *= pcolor;
- } else*/
-#endif // USE_ATTRIBUTES
-/*
- {
- if (instancing == 1) {
- uint stride = 2;
- {
- if (bool(draw_data[0].flags & FLAGS_INSTANCING_HAS_COLORS)) {
- stride += 1;
- }
- if (bool(draw_data[0].flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
- stride += 1;
- }
- }
-
- uint offset = stride * gl_InstanceID;
-
- mat4 matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
- offset += 2;
+#ifdef USE_INSTANCING
+ model_matrix = model_matrix * transpose(mat4(instance_xform0, instance_xform1, vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)));
+#endif // USE_INSTANCING
- if (bool(draw_data[0].flags & FLAGS_INSTANCING_HAS_COLORS)) {
- color *= transforms.data[offset];
- offset += 1;
- }
-
- if (bool(draw_data[0].flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
- instance_custom = transforms.data[offset];
- }
-
- matrix = transpose(matrix);
- world_matrix = world_matrix * matrix;
- }
- }
-*/
#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
if (bool(draw_data[draw_data_instance].flags & FLAGS_USING_PARTICLES)) {
//scale by texture size
@@ -192,7 +139,7 @@ void main() {
#endif
#if !defined(SKIP_TRANSFORM_USED)
- vertex = (world_matrix * vec4(vertex, 0.0, 1.0)).xy;
+ vertex = (model_matrix * vec4(vertex, 0.0, 1.0)).xy;
#endif
color_interp = color;
@@ -286,7 +233,7 @@ in vec2 pixel_size_interp;
layout(location = 0) out vec4 frag_color;
#ifdef MATERIAL_UNIFORMS_USED
-uniform MaterialUniforms{
+layout(std140) uniform MaterialUniforms{
//ubo:4
#MATERIAL_UNIFORMS
@@ -478,10 +425,6 @@ float msdf_median(float r, float g, float b, float a) {
return min(max(min(r, g), min(max(r, g), b)), a);
}
-vec2 msdf_map(vec2 value, vec2 in_min, vec2 in_max, vec2 out_min, vec2 out_max) {
- return out_min + (out_max - out_min) * (value - in_min) / (in_max - in_min);
-}
-
void main() {
vec4 color = color_interp;
vec2 uv = uv_interp;
@@ -522,8 +465,8 @@ void main() {
float px_size = max(0.5 * dot((vec2(px_range) / msdf_size), dest_size), 1.0);
float d = msdf_median(msdf_sample.r, msdf_sample.g, msdf_sample.b, msdf_sample.a) - 0.5;
- if (outline_thickness > 0) {
- float cr = clamp(outline_thickness, 0.0, px_range / 2) / px_range;
+ if (outline_thickness > 0.0) {
+ float cr = clamp(outline_thickness, 0.0, px_range / 2.0) / px_range;
float a = clamp((d + cr) * px_size, 0.0, 1.0);
color.a = a * color.a;
} else {
@@ -714,8 +657,8 @@ void main() {
vec2 pos_rot = pos_norm * mat2(vec2(0.7071067811865476, -0.7071067811865476), vec2(0.7071067811865476, 0.7071067811865476)); //is there a faster way to 45 degrees rot?
float tex_ofs;
float distance;
- if (pos_rot.y > 0) {
- if (pos_rot.x > 0) {
+ if (pos_rot.y > 0.0) {
+ if (pos_rot.x > 0.0) {
tex_ofs = pos_box.y * 0.125 + 0.125;
distance = shadow_pos.x;
} else {
@@ -723,7 +666,7 @@ void main() {
distance = shadow_pos.y;
}
} else {
- if (pos_rot.x < 0) {
+ if (pos_rot.x < 0.0) {
tex_ofs = pos_box.y * -0.125 + (0.5 + 0.125);
distance = -shadow_pos.x;
} else {
diff --git a/drivers/gles3/shaders/canvas_shadow.glsl b/drivers/gles3/shaders/canvas_shadow.glsl
index 65389c211a..94485abd11 100644
--- a/drivers/gles3/shaders/canvas_shadow.glsl
+++ b/drivers/gles3/shaders/canvas_shadow.glsl
@@ -15,13 +15,13 @@ layout(location = 0) in highp vec3 vertex;
uniform highp mat4 projection_matrix;
/* clang-format on */
uniform highp mat4 light_matrix;
-uniform highp mat4 world_matrix;
+uniform highp mat4 model_matrix;
uniform highp float distance_norm;
out highp vec4 position_interp;
void main() {
- gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex, 1.0)));
+ gl_Position = projection_matrix * (light_matrix * (model_matrix * vec4(vertex, 1.0)));
position_interp = gl_Position;
}
diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
index e08a15e59d..852dccf415 100644
--- a/drivers/gles3/shaders/canvas_uniforms_inc.glsl
+++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
@@ -58,8 +58,8 @@ struct DrawData {
uvec4 lights;
};
-layout(std140) uniform GlobalVariableData { //ubo:1
- vec4 global_variables[MAX_GLOBAL_VARIABLES];
+layout(std140) uniform GlobalShaderUniformData { //ubo:1
+ vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
};
layout(std140) uniform CanvasData { //ubo:0
diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl
index 62332a15a7..ca2fc7e36d 100644
--- a/drivers/gles3/shaders/copy.glsl
+++ b/drivers/gles3/shaders/copy.glsl
@@ -1,204 +1,59 @@
/* clang-format off */
#[modes]
-mode_default =
-mode_cubemap = #define USE_CUBEMAP
-mode_panorama = #define USE_PANORAMA
+mode_default = #define MODE_SIMPLE_COPY
mode_copy_section = #define USE_COPY_SECTION
-mode_asym_pano = #define USE_ASYM_PANO
-mode_no_alpha = #define USE_NO_ALPHA
-mode_custom_alpha = #define USE_CUSTOM_ALPHA
-mode_multiplier = #define USE_MULTIPLIER
-mode_sep_cbcr_texture = #define USE_SEP_CBCR_TEXTURE
-mode_ycbcr_to_rgb = #define USE_YCBCR_TO_RGB
+mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR
+mode_mipmap = #define MODE_MIPMAP
+mode_simple_color = #define MODE_SIMPLE_COLOR \n#define USE_COPY_SECTION
#[specializations]
-
#[vertex]
-#ifdef USE_GLES_OVER_GL
-#define lowp
-#define mediump
-#define highp
-#else
-precision highp float;
-precision highp int;
-#endif
-
-layout(location = 0) in highp vec4 vertex_attrib;
-/* clang-format on */
-
-#if defined(USE_CUBEMAP) || defined(USE_PANORAMA)
-layout(location = 4) in vec3 cube_in;
-#else
-layout(location = 4) in vec2 uv_in;
-#endif
-
-layout(location = 5) in vec2 uv2_in;
+layout(location = 0) in vec2 vertex_attrib;
-#if defined(USE_CUBEMAP) || defined(USE_PANORAMA)
-out vec3 cube_interp;
-#else
out vec2 uv_interp;
-#endif
-out vec2 uv2_interp;
+/* clang-format on */
#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;
+ uv_interp = vertex_attrib * 0.5 + 0.5;
+ gl_Position = vec4(vertex_attrib, 1.0, 1.0);
#ifdef USE_COPY_SECTION
+ gl_Position.xy = (copy_section.xy + (uv_interp.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0;
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)
-in vec3 cube_interp;
-#else
in 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 USE_SEP_CBCR_TEXTURE
-uniform sampler2D CbCr; //texunit:1
-#endif
-
-in vec2 uv2_interp;
-
-#ifdef USE_MULTIPLIER
-uniform float multiplier;
+#ifdef MODE_SIMPLE_COLOR
+uniform vec4 color_in;
#endif
-#ifdef USE_CUSTOM_ALPHA
-uniform float custom_alpha;
+#ifdef MODE_GAUSSIAN_BLUR
+uniform highp vec2 pixel_size;
#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 texture(pano, st);
-}
-
-#endif
+uniform sampler2D source; // texunit:0
layout(location = 0) out vec4 frag_color;
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 = texture(source_cube, normalize(cube_interp));
-#elif defined(USE_SEP_CBCR_TEXTURE)
- vec4 color;
- color.r = texture(source, uv_interp).r;
- color.gb = texture(CbCr, uv_interp).rg - vec2(0.5, 0.5);
- color.a = 1.0;
-#else
+#ifdef MODE_SIMPLE_COPY
vec4 color = texture(source, uv_interp);
+ frag_color = color;
#endif
-#ifdef USE_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;
+#ifdef MODE_SIMPLE_COLOR
+ frag_color = color_in;
#endif
-
- frag_color = color;
}
diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl
index 2081abfef6..88464876f1 100644
--- a/drivers/gles3/shaders/cubemap_filter.glsl
+++ b/drivers/gles3/shaders/cubemap_filter.glsl
@@ -1,214 +1,122 @@
/* clang-format off */
-[vertex]
+#[modes]
-#ifdef USE_GLES_OVER_GL
-#define lowp
-#define mediump
-#define highp
-#else
-precision highp float;
-precision highp int;
-#endif
+mode_default =
+mode_copy = #define MODE_DIRECT_WRITE
+
+#[specializations]
-layout(location = 0) in highp vec2 vertex;
+#[vertex]
+
+layout(location = 0) in highp vec2 vertex_attrib;
/* clang-format on */
-layout(location = 4) in highp vec2 uv;
out highp vec2 uv_interp;
void main() {
- uv_interp = uv;
- gl_Position = vec4(vertex, 0, 1);
+ uv_interp = vertex_attrib;
+ gl_Position = vec4(uv_interp, 0.0, 1.0);
}
/* clang-format off */
-[fragment]
+#[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
+#define M_PI 3.14159265359
-#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;
-in 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
+#ifndef MODE_DIRECT_WRITE
+uniform int sample_count;
+uniform vec4 sample_directions_mip[MAX_SAMPLE_COUNT];
+uniform float weight;
#endif
-#ifdef USE_SOURCE_PANORAMA
-
-vec4 texturePanorama(sampler2D pano, vec3 normal) {
- vec2 st = vec2(
- atan(normal.x, normal.z),
- acos(normal.y));
+in highp vec2 uv_interp;
- if (st.x < 0.0)
- st.x += M_PI * 2.0;
+layout(location = 0) out vec4 frag_color;
- st /= vec2(M_PI * 2.0, M_PI);
+#define M_PI 3.14159265359
- return textureLod(pano, st, 0.0);
+// Don't include tonemap_inc.glsl because all we want is these functions, we don't want the uniforms
+vec3 linear_to_srgb(vec3 color) {
+ return max(vec3(1.055) * pow(color, vec3(0.416666667)) - vec3(0.055), vec3(0.0));
}
-#endif
+vec3 srgb_to_linear(vec3 color) {
+ return color * (color * (color * 0.305306011 + 0.682171111) + 0.012522878);
+}
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
+ 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
// +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
+ 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
// -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
+ 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
// +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
+ 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
// -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
+ 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
// +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
+ 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
// 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;
- }
- }
+ vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
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 texture(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;
-
-layout(location = 0) out vec4 frag_color;
-
void main() {
vec3 color = vec3(0.0);
-
- vec2 uv = (uv_interp * 2.0) - 1.0;
+ vec2 uv = uv_interp;
vec3 N = texelCoordToVec(uv, face_id);
-#ifdef USE_DIRECT_WRITE
-
-#ifdef USE_SOURCE_PANORAMA
-
- frag_color = vec4(texturePanorama(source_panorama, N).rgb, 1.0);
-#else
-
- frag_color = vec4(textureCube(source_cube, N).rgb, 1.0);
-#endif //USE_SOURCE_PANORAMA
-
+#ifdef MODE_DIRECT_WRITE
+ frag_color = vec4(textureLod(source_cube, N, 0.0).rgb, 1.0);
#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;
- }
+ vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
+ mat3 T;
+ T[0] = normalize(cross(UpVector, N));
+ T[1] = cross(N, T[0]);
+ T[2] = N;
+
+ for (int sample_num = 0; sample_num < sample_count; sample_num++) {
+ vec4 sample_direction_mip = sample_directions_mip[sample_num];
+ vec3 L = T * sample_direction_mip.xyz;
+ vec3 val = textureLod(source_cube, L, sample_direction_mip.w).rgb;
+ // Mix using linear
+ val = srgb_to_linear(val);
+ sum.rgb += val * sample_direction_mip.z;
}
- 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))));
+ sum /= weight;
+ sum.rgb = linear_to_srgb(sum.rgb);
frag_color = vec4(sum.rgb, 1.0);
#endif
}
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 98c92a1d99..84daf839e9 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -1,980 +1,532 @@
/* clang-format off */
-[vertex]
+#[modes]
-#ifdef USE_GLES_OVER_GL
-#define lowp
-#define mediump
-#define highp
-#else
-precision highp float;
-precision highp int;
-#endif
+mode_color = #define BASE_PASS
+mode_color_instancing = #define BASE_PASS \n#define USE_INSTANCING
+mode_additive = #define USE_ADDITIVE_LIGHTING
+mode_additive_instancing = #define USE_ADDITIVE_LIGHTING \n#define USE_INSTANCING
+mode_depth = #define MODE_RENDER_DEPTH
+mode_depth_instancing = #define MODE_RENDER_DEPTH \n#define USE_INSTANCING
-#define SHADER_IS_SRGB true //TODO remove
+#[specializations]
-#define M_PI 3.14159265359
+DISABLE_LIGHTMAP = false
+DISABLE_LIGHT_DIRECTIONAL = false
+DISABLE_LIGHT_OMNI = false
+DISABLE_LIGHT_SPOT = false
+DISABLE_FOG = false
+USE_RADIANCE_MAP = true
-//
-// attributes
-//
-layout(location = 0) in highp vec4 vertex_attrib;
-/* clang-format on */
-layout(location = 1) in vec3 normal_attrib;
+#[vertex]
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
-layout(location = 2) in vec4 tangent_attrib;
-#endif
+#define M_PI 3.14159265359
-#if defined(ENABLE_COLOR_INTERP)
-layout(location = 3) in vec4 color_attrib;
-#endif
+#define SHADER_IS_SRGB true
-#if defined(ENABLE_UV_INTERP)
-layout(location = 4) in vec2 uv_attrib;
-#endif
+#include "stdlib_inc.glsl"
-#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
-layout(location = 5) in vec2 uv2_attrib;
+#if !defined(MODE_RENDER_DEPTH) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) ||defined(LIGHT_CLEARCOAT_USED)
+#ifndef NORMAL_USED
+#define NORMAL_USED
+#endif
#endif
-#ifdef USE_SKELETON
-
-#ifdef USE_SKELETON_SOFTWARE
-
-layout(location = 13) in highp vec4 bone_transform_row_0;
-layout(location = 14) in highp vec4 bone_transform_row_1;
-layout(location = 15) in highp vec4 bone_transform_row_2;
-
-#else
+/*
+from RenderingServer:
+ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit)
+ARRAY_NORMAL = 1, // A2B10G10R10, A is ignored.
+ARRAY_TANGENT = 2, // A2B10G10R10, A flips sign of binormal.
+ARRAY_COLOR = 3, // RGBA8
+ARRAY_TEX_UV = 4, // RG32F
+ARRAY_TEX_UV2 = 5, // RG32F
+ARRAY_CUSTOM0 = 6, // Depends on ArrayCustomFormat.
+ARRAY_CUSTOM1 = 7,
+ARRAY_CUSTOM2 = 8,
+ARRAY_CUSTOM3 = 9,
+ARRAY_BONES = 10, // RGBA16UI (x2 if 8 weights)
+ARRAY_WEIGHTS = 11, // RGBA16UNORM (x2 if 8 weights)
+*/
-layout(location = 6) in vec4 bone_ids;
-layout(location = 7) in highp vec4 bone_weights;
+/* INPUT ATTRIBS */
-uniform highp sampler2D bone_transforms; // texunit:-1
-uniform ivec2 skeleton_texture_size;
+layout(location = 0) in highp vec3 vertex_attrib;
+/* clang-format on */
+#ifdef NORMAL_USED
+layout(location = 1) in vec3 normal_attrib;
#endif
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+layout(location = 2) in vec4 tangent_attrib;
#endif
-#ifdef USE_INSTANCING
-
-layout(location = 8) in highp vec4 instance_xform_row_0;
-layout(location = 9) in highp vec4 instance_xform_row_1;
-layout(location = 10) in highp vec4 instance_xform_row_2;
-
-layout(location = 11) in highp vec4 instance_color;
-layout(location = 12) in highp vec4 instance_custom_data;
-
+#if defined(COLOR_USED)
+layout(location = 3) in vec4 color_attrib;
#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;
+#ifdef UV_USED
+layout(location = 4) in vec2 uv_attrib;
#endif
-//
-// varyings
-//
-
-#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS)
-out highp vec4 position_interp;
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+layout(location = 5) in vec2 uv2_attrib;
#endif
-out highp vec3 vertex_interp;
-out vec3 normal_interp;
-
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
-out vec3 tangent_interp;
-out vec3 binormal_interp;
+#if defined(CUSTOM0_USED)
+layout(location = 6) in vec4 custom0_attrib;
#endif
-#if defined(ENABLE_COLOR_INTERP)
-out vec4 color_interp;
+#if defined(CUSTOM1_USED)
+layout(location = 7) in vec4 custom1_attrib;
#endif
-#if defined(ENABLE_UV_INTERP)
-out vec2 uv_interp;
+#if defined(CUSTOM2_USED)
+layout(location = 8) in vec4 custom2_attrib;
#endif
-#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
-out vec2 uv2_interp;
+#if defined(CUSTOM3_USED)
+layout(location = 9) in vec4 custom3_attrib;
#endif
-/* clang-format off */
-
-VERTEX_SHADER_GLOBALS
-
-/* clang-format on */
-
-#ifdef RENDER_DEPTH_DUAL_PARABOLOID
-
-out highp float dp_clip;
-uniform highp float shadow_dual_paraboloid_render_zfar;
-uniform highp float shadow_dual_paraboloid_render_side;
-
+#if defined(BONES_USED)
+layout(location = 10) in uvec4 bone_attrib;
#endif
-#if defined(USE_SHADOW) && defined(USE_LIGHTING)
-
-uniform highp mat4 light_shadow_matrix;
-out highp vec4 shadow_coord;
-
-#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4)
-uniform highp mat4 light_shadow_matrix2;
-out highp vec4 shadow_coord2;
+#if defined(WEIGHTS_USED)
+layout(location = 11) in vec4 weight_attrib;
#endif
-#if defined(LIGHT_USE_PSSM4)
-
-uniform highp mat4 light_shadow_matrix3;
-uniform highp mat4 light_shadow_matrix4;
-out highp vec4 shadow_coord3;
-out highp vec4 shadow_coord4;
-
+#ifdef USE_INSTANCING
+layout(location = 12) in highp vec4 instance_xform0;
+layout(location = 13) in highp vec4 instance_xform1;
+layout(location = 14) in highp vec4 instance_xform2;
+layout(location = 15) in highp uvec4 instance_color_custom_data; // Color packed into xy, Custom data into zw.
#endif
-#endif
+layout(std140) uniform GlobalShaderUniformData { //ubo:1
+ vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
+};
-#if defined(USE_VERTEX_LIGHTING) && defined(USE_LIGHTING)
+layout(std140) uniform SceneData { // ubo:2
+ highp mat4 projection_matrix;
+ highp mat4 inv_projection_matrix;
+ highp mat4 inv_view_matrix;
+ highp mat4 view_matrix;
-out highp vec3 diffuse_interp;
-out highp vec3 specular_interp;
+ vec2 viewport_size;
+ vec2 screen_pixel_size;
-// general for all lights
-uniform highp vec4 light_color;
-uniform highp vec4 shadow_color;
-uniform highp float light_specular;
+ mediump vec4 ambient_light_color_energy;
-// directional
-uniform highp vec3 light_direction;
+ mediump float ambient_color_sky_mix;
+ bool material_uv2_mode;
+ float pad2;
+ bool use_ambient_light;
+ bool use_ambient_cubemap;
+ bool use_reflection_cubemap;
-// omni
-uniform highp vec3 light_position;
+ float fog_aerial_perspective;
+ float time;
-uniform highp float light_range;
-uniform highp float light_attenuation;
+ mat3 radiance_inverse_xform;
-// spot
-uniform highp float light_spot_attenuation;
-uniform highp float light_spot_range;
-uniform highp float light_spot_angle;
+ uint directional_light_count;
+ float z_far;
+ float z_near;
+ float pad;
-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
+ bool fog_enabled;
+ float fog_density;
+ float fog_height;
+ float fog_height_density;
-//#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)
+ vec3 fog_light_color;
+ float fog_sun_scatter;
+}
+scene_data;
- float NdotL = dot(N, L);
- float cNdotL = max(NdotL, 0.0); // clamped NdotL
- float NdotV = dot(N, V);
- float cNdotV = max(NdotV, 0.0);
+uniform highp mat4 world_transform;
-#if defined(DIFFUSE_OREN_NAYAR)
- vec3 diffuse_brdf_NL;
-#else
- float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance
+#ifdef USE_LIGHTMAP
+uniform highp vec4 lightmap_uv_rect;
#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)
+/* Varyings */
- {
- // 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);
+out highp vec3 vertex_interp;
+#ifdef NORMAL_USED
+out vec3 normal_interp;
#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;
+#if defined(COLOR_USED)
+out vec4 color_interp;
#endif
- SRGB_APPROX(specular_brdf_NL)
- specular_interp += specular_brdf_NL * light_color * attenuation * (1.0 / M_PI);
- }
-}
-
+#if defined(UV_USED)
+out vec2 uv_interp;
#endif
-#ifdef USE_VERTEX_LIGHTING
-
-#ifdef USE_REFLECTION_PROBE1
-
-uniform highp mat4 refprobe1_local_matrix;
-out mediump vec4 refprobe1_reflection_normal_blend;
-uniform highp vec3 refprobe1_box_extents;
-
-#ifndef USE_LIGHTMAP
-out mediump vec3 refprobe1_ambient_normal;
+#if defined(UV2_USED)
+out vec2 uv2_interp;
+#else
+#ifdef USE_LIGHTMAP
+out vec2 uv2_interp;
+#endif
#endif
-#endif //reflection probe1
-
-#ifdef USE_REFLECTION_PROBE2
-
-uniform highp mat4 refprobe2_local_matrix;
-out mediump vec4 refprobe2_reflection_normal_blend;
-uniform highp vec3 refprobe2_box_extents;
-
-#ifndef USE_LIGHTMAP
-out mediump vec3 refprobe2_ambient_normal;
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+out vec3 tangent_interp;
+out vec3 binormal_interp;
#endif
-#endif //reflection probe2
+#if defined(MATERIAL_UNIFORMS_USED)
-#endif //vertex lighting for refprobes
+/* clang-format off */
+layout(std140) uniform MaterialUniforms { // ubo:3
-#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED)
+#MATERIAL_UNIFORMS
-out vec4 fog_interp;
+};
+/* clang-format on */
-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
+/* clang-format off */
-#ifdef FOG_HEIGHT_ENABLED
-uniform highp float fog_height_min;
-uniform highp float fog_height_max;
-uniform mediump float fog_height_curve;
-#endif
+#GLOBALS
-#endif //fog
+/* clang-format on */
+invariant gl_Position;
void main() {
- highp vec4 vertex = vertex_attrib;
-
- mat4 world_matrix = world_transform;
+ highp vec3 vertex = vertex_attrib;
+ highp mat4 model_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);
- }
-
+ highp mat4 m = mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0));
+ model_matrix = model_matrix * transpose(m);
#endif
- vec3 normal = normal_attrib;
+#ifdef NORMAL_USED
+ vec3 normal = normal_attrib * 2.0 - 1.0;
+#endif
+ highp mat3 model_normal_matrix = mat3(model_matrix);
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
- vec3 tangent = tangent_attrib.xyz;
- float binormalf = tangent_attrib.a;
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+ vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0;
+ float binormalf = tangent_attrib.a * 2.0 - 1.0;
vec3 binormal = normalize(cross(normal, tangent) * binormalf);
#endif
-#if defined(ENABLE_COLOR_INTERP)
+#if defined(COLOR_USED)
color_interp = color_attrib;
#ifdef USE_INSTANCING
+ vec4 instance_color = vec4(unpackHalf2x16(instance_color_custom_data.x), unpackHalf2x16(instance_color_custom_data.y));
color_interp *= instance_color;
#endif
#endif
-#if defined(ENABLE_UV_INTERP)
+#if defined(UV_USED)
uv_interp = uv_attrib;
#endif
-#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
+#ifdef USE_LIGHTMAP
+ uv2_interp = lightmap_uv_rect.zw * uv2_attrib + lightmap_uv_rect.xy;
+#else
+#if defined(UV2_USED)
uv2_interp = uv2_attrib;
#endif
+#endif
#if defined(OVERRIDE_POSITION)
highp vec4 position;
#endif
+ highp mat4 projection_matrix = scene_data.projection_matrix;
+ highp mat4 inv_projection_matrix = scene_data.inv_projection_matrix;
-#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);
-
+#ifdef USE_INSTANCING
+ vec4 instance_custom = vec4(unpackHalf2x16(instance_color_custom_data.z), unpackHalf2x16(instance_color_custom_data.w));
#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);
+ vec4 instance_custom = vec4(0.0);
+#endif
- 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));
+ // Using world coordinates
+#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
- bone_transform += transpose(b) * bone_weights[i];
- }
- }
+ vertex = (model_matrix * vec4(vertex, 1.0)).xyz;
+#ifdef NORMAL_USED
+ normal = model_normal_matrix * normal;
#endif
- world_matrix = world_matrix * bone_transform;
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-#endif
-
-#ifdef USE_INSTANCING
- vec4 instance_custom = instance_custom_data;
-#else
- vec4 instance_custom = vec4(0.0);
+ tangent = model_normal_matrix * tangent;
+ binormal = model_normal_matrix * binormal;
#endif
+#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
+ highp mat4 modelview = scene_data.view_matrix * model_matrix;
+ highp mat3 modelview_normal = mat3(scene_data.view_matrix) * model_normal_matrix;
float point_size = 1.0;
{
- /* clang-format off */
-
-VERTEX_SHADER_CODE
-
- /* clang-format on */
+#CODE : VERTEX
}
gl_PointSize = point_size;
- vec4 outvec = vertex;
- // use local coordinates
+ // Using local coordinates (default)
#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);
+ vertex = (modelview * vec4(vertex, 1.0)).xyz;
+#ifdef NORMAL_USED
+ normal = modelview_normal * normal;
#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);
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+ binormal = modelview_normal * binormal;
+ tangent = modelview_normal * tangent;
#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
+ // Using world coordinates
+#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
- refprobe1_ambient_normal = (refprobe1_local_matrix * vec4(normal_interp, 0.0)).xyz;
+ vertex = (scene_data.view_matrix * vec4(vertex, 1.0)).xyz;
+#ifdef NORMAL_USED
+ normal = (scene_data.view_matrix * vec4(normal, 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;
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+ binormal = (scene_data.view_matrix * vec4(binormal, 0.0)).xyz;
+ tangent = (scene_data.view_matrix * vec4(tangent, 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;
- }
+ vertex_interp = vertex;
+#ifdef NORMAL_USED
+ normal_interp = normal;
#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));
- }
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+ tangent_interp = tangent;
+ binormal_interp = binormal;
#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]
+#[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
-#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;
+// Default to SPECULAR_SCHLICK_GGX.
+#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_TOON)
+#define SPECULAR_SCHLICK_GGX
#endif
-#if defined(SCREEN_TEXTURE_USED)
-uniform highp sampler2D screen_texture; //texunit:-4
+#if !defined(MODE_RENDER_DEPTH) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) ||defined(LIGHT_CLEARCOAT_USED)
+#ifndef NORMAL_USED
+#define NORMAL_USED
#endif
-#if defined(DEPTH_TEXTURE_USED)
-uniform highp sampler2D depth_texture; //texunit:-4
#endif
-#ifdef USE_REFLECTION_PROBE1
+#include "tonemap_inc.glsl"
+#include "stdlib_inc.glsl"
-#ifdef USE_VERTEX_LIGHTING
+/* texture unit usage, N is max_texture_unity-N
-in mediump vec4 refprobe1_reflection_normal_blend;
-#ifndef USE_LIGHTMAP
-in mediump vec3 refprobe1_ambient_normal;
-#endif
+1-color correction // In tonemap_inc.glsl
+2-radiance
+3-directional_shadow
+4-positional_shadow
+5-screen
+6-depth
-#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;
+#define M_PI 3.14159265359
+/* clang-format on */
-#endif //USE_REFLECTION_PROBE1
+#define SHADER_IS_SRGB true
-#ifdef USE_REFLECTION_PROBE2
+/* Varyings */
-#ifdef USE_VERTEX_LIGHTING
+#if defined(COLOR_USED)
+in vec4 color_interp;
+#endif
-in mediump vec4 refprobe2_reflection_normal_blend;
-#ifndef USE_LIGHTMAP
-in mediump vec3 refprobe2_ambient_normal;
+#if defined(UV_USED)
+in vec2 uv_interp;
#endif
+#if defined(UV2_USED)
+in vec2 uv2_interp;
#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,
+#ifdef USE_LIGHTMAP
+in vec2 uv2_interp;
#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
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+in vec3 tangent_interp;
+in vec3 binormal_interp;
+#endif
- vec3 amb_normal = (local_matrix * vec4(normal, 0.0)).xyz;
+#ifdef NORMAL_USED
+in vec3 normal_interp;
#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);
- }
+in highp vec3 vertex_interp;
- ambient_out.a = blend;
- ambient_out.rgb *= blend;
- ambient_accum += ambient_out;
+#ifdef USE_RADIANCE_MAP
-#endif
-}
+#define RADIANCE_MAX_LOD 5.0
-#endif //use refprobe 1 or 2
+uniform samplerCube radiance_map; // texunit:-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;
+layout(std140) uniform GlobalShaderUniformData { //ubo:1
+ vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
+};
-#endif
+ /* Material Uniforms */
-#ifdef USE_RADIANCE_MAP
+#if defined(MATERIAL_UNIFORMS_USED)
-uniform samplerCube radiance_map; // texunit:-2
+/* clang-format off */
+layout(std140) uniform MaterialUniforms { // ubo:3
-uniform mat4 radiance_inverse_xform;
+#MATERIAL_UNIFORMS
-#endif
-
-uniform vec4 bg_color;
-uniform float bg_energy;
+};
+/* clang-format on */
-uniform float ambient_sky_contribution;
-uniform vec4 ambient_color;
-uniform float ambient_energy;
+#endif
-#ifdef USE_LIGHTING
+layout(std140) uniform SceneData { // ubo:2
+ highp mat4 projection_matrix;
+ highp mat4 inv_projection_matrix;
+ highp mat4 inv_view_matrix;
+ highp mat4 view_matrix;
-uniform highp vec4 shadow_color;
+ vec2 viewport_size;
+ vec2 screen_pixel_size;
-#ifdef USE_VERTEX_LIGHTING
+ mediump vec4 ambient_light_color_energy;
-//get from vertex
-in highp vec3 diffuse_interp;
-in highp vec3 specular_interp;
+ mediump float ambient_color_sky_mix;
+ bool material_uv2_mode;
+ float pad2;
+ bool use_ambient_light;
+ bool use_ambient_cubemap;
+ bool use_reflection_cubemap;
-uniform highp vec3 light_direction; //may be used by fog, so leave here
+ float fog_aerial_perspective;
+ float time;
-#else
-//done in fragment
-// general for all lights
-uniform highp vec4 light_color;
+ mat3 radiance_inverse_xform;
-uniform highp float light_specular;
+ uint directional_light_count;
+ float z_far;
+ float z_near;
+ float pad;
-// directional
-uniform highp vec3 light_direction;
-// omni
-uniform highp vec3 light_position;
+ bool fog_enabled;
+ float fog_density;
+ float fog_height;
+ float fog_height_density;
-uniform highp float light_attenuation;
+ vec3 fog_light_color;
+ float fog_sun_scatter;
+}
+scene_data;
-// spot
-uniform highp float light_spot_attenuation;
-uniform highp float light_spot_range;
-uniform highp float light_spot_angle;
-#endif
+/* clang-format off */
-//this is needed outside above if because dual paraboloid wants it
-uniform highp float light_range;
+#GLOBALS
-#ifdef USE_SHADOW
+/* clang-format on */
-uniform highp vec2 shadow_pixel_size;
+//directional light data
-#if defined(LIGHT_MODE_OMNI) || defined(LIGHT_MODE_SPOT)
-uniform highp sampler2D light_shadow_atlas; //texunit:-3
-#endif
+#ifndef DISABLE_LIGHT_DIRECTIONAL
-#ifdef LIGHT_MODE_DIRECTIONAL
-uniform highp sampler2D light_directional_shadow; // texunit:-3
-uniform highp vec4 light_split_offsets;
-#endif
+struct DirectionalLightData {
+ mediump vec3 direction;
+ mediump float energy;
+ mediump vec3 color;
+ mediump float size;
+ mediump vec3 pad;
+ mediump float specular;
+};
-in highp vec4 shadow_coord;
+layout(std140) uniform DirectionalLights { // ubo:7
+ DirectionalLightData directional_lights[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+};
-#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4)
-in highp vec4 shadow_coord2;
#endif
-#if defined(LIGHT_USE_PSSM4)
-
-in highp vec4 shadow_coord3;
-in highp vec4 shadow_coord4;
-
-#endif
+// omni and spot
+#if !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT)
+struct LightData { //this structure needs to be as packed as possible
+ highp vec3 position;
+ highp float inv_radius;
-uniform vec4 light_clamp;
+ mediump vec3 direction;
+ highp float size;
-#endif // light shadow
+ mediump vec3 color;
+ mediump float attenuation;
-// directional shadow
+ mediump float cone_attenuation;
+ mediump float cone_angle;
+ mediump float specular_amount;
+ mediump float shadow_opacity;
+};
+#ifndef DISABLE_LIGHT_OMNI
+layout(std140) uniform OmniLightData { // ubo:5
+ LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
+};
+uniform uint omni_light_indices[MAX_FORWARD_LIGHTS];
+uniform int omni_light_count;
#endif
-//
-// varyings
-//
-
-#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS)
-in highp vec4 position_interp;
-#endif
+#ifndef DISABLE_LIGHT_SPOT
-in highp vec3 vertex_interp;
-in vec3 normal_interp;
+layout(std140) uniform SpotLightData { // ubo:6
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
-in vec3 tangent_interp;
-in vec3 binormal_interp;
+ LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
+};
+uniform uint spot_light_indices[MAX_FORWARD_LIGHTS];
+uniform int spot_light_count;
#endif
-#if defined(ENABLE_COLOR_INTERP)
-in vec4 color_interp;
+#ifdef USE_ADDITIVE_LIGHTING
+uniform highp samplerCubeShadow positional_shadow; // texunit:-4
#endif
-#if defined(ENABLE_UV_INTERP)
-in vec2 uv_interp;
-#endif
+#endif // !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT)
-#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
-in vec2 uv2_interp;
-#endif
+uniform highp sampler2D screen_texture; // texunit:-5
+uniform highp sampler2D depth_buffer; // texunit:-6
-in vec3 view_interp;
+uniform highp mat4 world_transform;
+uniform mediump float opaque_prepass_threshold;
layout(location = 0) out vec4 frag_color;
@@ -985,95 +537,31 @@ vec3 F0(float metallic, float specular, vec3 albedo) {
return mix(vec3(dielectric), albedo, vec3(metallic));
}
-/* clang-format off */
-
-FRAGMENT_SHADER_GLOBALS
-
-/* clang-format on */
-
-#ifdef RENDER_DEPTH_DUAL_PARABOLOID
-
-in 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);
-}
-
+#if !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
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);
+ float a = cos_theta_m * alpha;
+ float k = alpha / (1.0 - cos_theta_m * cos_theta_m + a * a);
+ return k * k * (1.0 / M_PI);
}
-*/
-// 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);
+// From Earl Hammon, Jr. "PBR Diffuse Lighting for GGX+Smith Microsurfaces" https://www.gdcvault.com/play/1024478/PBR-Diffuse-Lighting-for-GGX
+float V_GGX(float NdotL, float NdotV, float alpha) {
+ return 0.5 / mix(2.0 * NdotL * NdotV, NdotL + NdotV, alpha);
}
-float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi, float NdotH) {
+float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) {
float alpha2 = alpha_x * alpha_y;
- highp vec3 v = vec3(alpha_y * cos_phi, alpha_x * sin_phi, alpha2 * NdotH);
+ highp vec3 v = vec3(alpha_y * cos_phi, alpha_x * sin_phi, alpha2 * cos_theta_m);
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 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 SchlickFresnel(float u) {
@@ -1082,109 +570,59 @@ float SchlickFresnel(float u) {
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)
+void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float attenuation, vec3 f0, float roughness, float metallic, float specular_amount, vec3 albedo, inout float alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+ vec3 backlight,
+#endif
+#ifdef LIGHT_RIM_USED
+ float rim, float rim_tint,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ float clearcoat, float clearcoat_roughness, vec3 vertex_normal,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ vec3 B, vec3 T, float anisotropy,
+#endif
+ inout vec3 diffuse_light, inout vec3 specular_light) {
#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
+
+#CODE : LIGHT
/* clang-format on */
#else
- float NdotL = dot(N, L);
+ float NdotL = min(A + dot(N, L), 1.0);
float cNdotL = max(NdotL, 0.0); // clamped NdotL
float NdotV = dot(N, V);
- float cNdotV = max(abs(NdotV), 1e-6);
+ float cNdotV = max(NdotV, 1e-4);
-#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT)
+#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
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);
+#if defined(SPECULAR_SCHLICK_GGX)
+ float cNdotH = clamp(A + dot(N, H), 0.0, 1.0);
#endif
-#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT)
- float cLdotH = max(dot(L, H), 0.0);
+#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
+ float cLdotH = clamp(A + dot(L, H), 0.0, 1.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);
@@ -1196,230 +634,253 @@ LIGHT_SHADER_CODE
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;
+ diffuse_light += light_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;
+#if defined(LIGHT_BACKLIGHT_USED)
+ diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation;
#endif
-#if defined(LIGHT_USE_RIM)
+#if defined(LIGHT_RIM_USED)
float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0));
- diffuse_light += rim_light * rim * mix(vec3(1.0), diffuse_color, rim_tint) * light_color;
+ diffuse_light += rim_light * rim * mix(vec3(1.0), albedo, rim_tint) * light_color;
#endif
}
- if (roughness > 0.0) {
+ if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely
-#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);
+ // D
-#elif defined(SPECULAR_TOON)
+#if 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;
+ float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid;
+ diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection
#elif defined(SPECULAR_DISABLED)
// none..
+
#elif defined(SPECULAR_SCHLICK_GGX)
// shlick+ggx as default
-
-#if defined(LIGHT_USE_ANISOTROPY)
float alpha_ggx = roughness * roughness;
+#if defined(LIGHT_ANISOTROPY_USED)
+
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 D = D_GGX_anisotropic(cNdotH, 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;
+#else // LIGHT_ANISOTROPY_USED
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);
+#endif // LIGHT_ANISOTROPY_USED
+ // F
float cLdotH5 = SchlickFresnel(cLdotH);
- vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0);
+ // Calculate Fresnel using cheap approximate specular occlusion term from Filament:
+ // https://google.github.io/filament/Filament.html#lighting/occlusion/specularocclusion
+ float f90 = clamp(50.0 * f0.g, 0.0, 1.0);
+ vec3 F = f0 + (f90 - f0) * cLdotH5;
- specular_brdf_NL = cNdotL * D * F * G;
+ vec3 specular_brdf_NL = cNdotL * D * F * G;
+ specular_light += specular_brdf_NL * light_color * attenuation * specular_amount;
#endif
- SRGB_APPROX(specular_brdf_NL)
- specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation;
-
-#if defined(LIGHT_USE_CLEARCOAT)
+#if defined(LIGHT_CLEARCOAT_USED)
+ // Clearcoat ignores normal_map, use vertex normal instead
+ float ccNdotL = max(min(A + dot(vertex_normal, L), 1.0), 0.0);
+ float ccNdotH = clamp(A + dot(vertex_normal, H), 0.0, 1.0);
+ float ccNdotV = max(dot(vertex_normal, V), 1e-4);
#if !defined(SPECULAR_SCHLICK_GGX)
float cLdotH5 = SchlickFresnel(cLdotH);
#endif
- float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss));
+ float Dr = D_GGX(ccNdotH, mix(0.001, 0.1, clearcoat_roughness));
+ float Gr = 0.25 / (cLdotH * cLdotH);
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;
+ float clearcoat_specular_brdf_NL = clearcoat * Gr * Fr * Dr * cNdotL;
- specular_light += clearcoat_specular_brdf_NL * light_color * specular_blob_intensity * attenuation;
-#endif
+ specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount;
+ // TODO: Clearcoat adds light to the scene right now (it is non-energy conserving), both diffuse and specular need to be scaled by (1.0 - FR)
+ // but to do so we need to rearrange this entire function
+#endif // LIGHT_CLEARCOAT_USED
}
#ifdef USE_SHADOW_TO_OPACITY
- alpha = min(alpha, clamp(1.0 - length(attenuation), 0.0, 1.0));
+ alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 1.0));
#endif
-#endif //defined(USE_LIGHT_SHADER_CODE)
+#endif //defined(LIGHT_CODE_USED)
}
-#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
+float get_omni_attenuation(float distance, float inv_range, float decay) {
+ float nd = distance * inv_range;
+ nd *= nd;
+ nd *= nd; // nd^4
+ nd = max(1.0 - nd, 0.0);
+ nd *= nd; // nd^2
+ return nd * pow(max(distance, 0.0001), -decay);
+}
+void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+ vec3 backlight,
#endif
-
-#define SAMPLE_SHADOW_TEXEL(p_shadow, p_pos, p_depth) step(p_depth, SHADOW_DEPTH(texture(p_shadow, p_pos)))
-#define SAMPLE_SHADOW_TEXEL_PROJ(p_shadow, p_pos) step(p_pos.z, SHADOW_DEPTH(textureProj(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);
+#ifdef LIGHT_RIM_USED
+ float rim, float rim_tint,
#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ float clearcoat, float clearcoat_roughness, vec3 vertex_normal,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ vec3 binormal, vec3 tangent, float anisotropy,
+#endif
+ inout vec3 diffuse_light, inout vec3 specular_light) {
+ vec3 light_rel_vec = omni_lights[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+ float omni_attenuation = get_omni_attenuation(light_length, omni_lights[idx].inv_radius, omni_lights[idx].attenuation);
+ vec3 color = omni_lights[idx].color;
+ float size_A = 0.0;
-#ifdef SHADOW_MODE_PCF_5
-
- spos.xyz /= spos.w;
- vec2 pos = spos.xy;
- float depth = spos.z;
+ if (omni_lights[idx].size > 0.0) {
+ float t = omni_lights[idx].size / max(0.001, light_length);
+ size_A = max(0.0, 1.0 - 1.0 / sqrt(1.0 + t * t));
+ }
- 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);
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, omni_attenuation, f0, roughness, metallic, omni_lights[idx].specular_amount, albedo, alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
+#endif
+#ifdef LIGHT_RIM_USED
+ rim * omni_attenuation, rim_tint,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_roughness, vertex_normal,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal, tangent, anisotropy,
+#endif
+ diffuse_light,
+ specular_light);
+}
+void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+ vec3 backlight,
+#endif
+#ifdef LIGHT_RIM_USED
+ float rim, float rim_tint,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ float clearcoat, float clearcoat_roughness, vec3 vertex_normal,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ vec3 binormal, vec3 tangent, float anisotropy,
#endif
+ inout vec3 diffuse_light,
+ inout vec3 specular_light) {
-#if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13)
+ vec3 light_rel_vec = spot_lights[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+ float spot_attenuation = get_omni_attenuation(light_length, spot_lights[idx].inv_radius, spot_lights[idx].attenuation);
+ vec3 spot_dir = spot_lights[idx].direction;
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights[idx].cone_angle);
+ float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights[idx].cone_angle));
+ spot_attenuation *= 1.0 - pow(spot_rim, spot_lights[idx].cone_attenuation);
+ vec3 color = spot_lights[idx].color;
+
+ float size_A = 0.0;
+
+ if (spot_lights[idx].size > 0.0) {
+ float t = spot_lights[idx].size / max(0.001, light_length);
+ size_A = max(0.0, 1.0 - 1.0 / sqrt(1.0 + t * t));
+ }
- return SAMPLE_SHADOW_TEXEL_PROJ(shadow, spos);
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, spot_attenuation, f0, roughness, metallic, spot_lights[idx].specular_amount, albedo, alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
+#endif
+#ifdef LIGHT_RIM_USED
+ rim * spot_attenuation, rim_tint,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_roughness, vertex_normal,
#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal, tangent, anisotropy,
+#endif
+ diffuse_light, specular_light);
}
+#endif // !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT)
-#endif
+#ifndef MODE_RENDER_DEPTH
+vec4 fog_process(vec3 vertex) {
+ vec3 fog_color = scene_data.fog_light_color;
-#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED)
+#ifdef USE_RADIANCE_MAP
+/*
+ if (scene_data.fog_aerial_perspective > 0.0) {
+ vec3 sky_fog_color = vec3(0.0);
+ vec3 cube_view = scene_data.radiance_inverse_xform * vertex;
+ // mip_level always reads from the second mipmap and higher so the fog is always slightly blurred
+ float mip_level = mix(1.0 / MAX_ROUGHNESS_LOD, 1.0, 1.0 - (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near));
-#if defined(USE_VERTEX_LIGHTING)
+ sky_fog_color = textureLod(radiance_map, cube_view, mip_level * RADIANCE_MAX_LOD).rgb;
-in vec4 fog_interp;
+ fog_color = mix(fog_color, sky_fog_color, scene_data.fog_aerial_perspective);
+ }
+ */
+#endif
+
+#ifndef DISABLE_LIGHT_DIRECTIONAL
+ if (scene_data.fog_sun_scatter > 0.001) {
+ vec4 sun_scatter = vec4(0.0);
+ float sun_total = 0.0;
+ vec3 view = normalize(vertex);
+ for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
+ vec3 light_color = directional_lights[i].color * directional_lights[i].energy;
+ float light_amount = pow(max(dot(view, directional_lights[i].direction), 0.0), 8.0);
+ fog_color += light_color * light_amount * scene_data.fog_sun_scatter;
+ }
+ }
+#endif // !DISABLE_LIGHT_DIRECTIONAL
-#else
-uniform mediump vec4 fog_color_base;
-#ifdef LIGHT_MODE_DIRECTIONAL
-uniform mediump vec4 fog_sun_color_amount;
-#endif
+ float fog_amount = 1.0 - exp(min(0.0, -length(vertex) * scene_data.fog_density));
-uniform bool fog_transmit_enabled;
-uniform mediump float fog_transmit_curve;
+ if (abs(scene_data.fog_height_density) >= 0.0001) {
+ float y = (scene_data.inv_view_matrix * vec4(vertex, 1.0)).y;
-#ifdef FOG_DEPTH_ENABLED
-uniform highp float fog_depth_begin;
-uniform mediump float fog_depth_curve;
-uniform mediump float fog_max_distance;
-#endif
+ float y_dist = y - scene_data.fog_height;
-#ifdef FOG_HEIGHT_ENABLED
-uniform highp float fog_height_min;
-uniform highp float fog_height_max;
-uniform mediump float fog_height_curve;
-#endif
+ float vfog_amount = 1.0 - exp(min(0.0, y_dist * scene_data.fog_height_density));
-#endif //vertex lit
-#endif //fog
+ fog_amount = max(vfog_amount, fog_amount);
+ }
-void main() {
-#ifdef RENDER_DEPTH_DUAL_PARABOLOID
+ return vec4(fog_color, fog_amount);
+}
- if (dp_clip > 0.0)
- discard;
-#endif
- highp vec3 vertex = vertex_interp;
+#endif // !MODE_RENDER_DEPTH
+
+void main() {
+ //lay out everything, whatever is unused is optimized away anyway
+ vec3 vertex = vertex_interp;
vec3 view = -normalize(vertex_interp);
vec3 albedo = vec3(1.0);
- vec3 transmission = vec3(0.0);
+ vec3 backlight = vec3(0.0);
+ vec4 transmittance_color = vec4(0.0, 0.0, 0.0, 1.0);
+ float transmittance_depth = 0.0;
+ float transmittance_boost = 0.0;
float metallic = 0.0;
float specular = 0.5;
vec3 emission = vec3(0.0);
@@ -1427,620 +888,308 @@ void main() {
float rim = 0.0;
float rim_tint = 0.0;
float clearcoat = 0.0;
- float clearcoat_gloss = 0.0;
+ float clearcoat_roughness = 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;
+ vec4 fog = vec4(0.0);
+#if defined(CUSTOM_RADIANCE_USED)
+ vec4 custom_radiance = vec4(0.0);
+#endif
+#if defined(CUSTOM_IRRADIANCE_USED)
+ vec4 custom_irradiance = vec4(0.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;
+ float alpha = 1.0;
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+ vec3 binormal = normalize(binormal_interp);
+ vec3 tangent = normalize(tangent_interp);
#else
vec3 binormal = vec3(0.0);
vec3 tangent = vec3(0.0);
#endif
- vec3 normal = normalize(normal_interp) * side;
-#if defined(ENABLE_NORMALMAP)
- vec3 normalmap = vec3(0.5);
+#ifdef NORMAL_USED
+ vec3 normal = normalize(normal_interp);
+
+#if defined(DO_SIDE_CHECK)
+ if (!gl_FrontFacing) {
+ normal = -normal;
+ }
#endif
- float normaldepth = 1.0;
-#if defined(ALPHA_SCISSOR_USED)
- float alpha_scissor = 0.5;
+#endif //NORMAL_USED
+
+#ifdef UV_USED
+ vec2 uv = uv_interp;
#endif
-#if defined(SCREEN_UV_USED)
- vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size;
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+ vec2 uv2 = uv2_interp;
#endif
- {
- /* clang-format off */
+#if defined(COLOR_USED)
+ vec4 color = color_interp;
+#endif
-FRAGMENT_SHADER_CODE
+#if defined(NORMAL_MAP_USED)
- /* clang-format on */
- }
+ vec3 normal_map = vec3(0.5);
+#endif
-#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)));
+ float normal_map_depth = 1.0;
- normal = normalize(mix(normal_interp, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)) * side;
- //normal = normalmap;
-#endif
+ vec2 screen_uv = gl_FragCoord.xy * scene_data.screen_pixel_size;
- normal = normalize(normal);
+ float sss_strength = 0.0;
- vec3 N = normal;
+#ifdef ALPHA_SCISSOR_USED
+ float alpha_scissor_threshold = 1.0;
+#endif // ALPHA_SCISSOR_USED
- 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);
+#ifdef ALPHA_HASH_USED
+ float alpha_hash_scale = 1.0;
+#endif // ALPHA_HASH_USED
- vec3 eye_position = view;
+#ifdef ALPHA_ANTIALIASING_EDGE_USED
+ float alpha_antialiasing_edge = 0.0;
+ vec2 alpha_texture_coordinate = vec2(0.0, 0.0);
+#endif // ALPHA_ANTIALIASING_EDGE_USED
+ {
+#CODE : FRAGMENT
+ }
-#if !defined(USE_SHADOW_TO_OPACITY)
+#ifndef USE_SHADOW_TO_OPACITY
#if defined(ALPHA_SCISSOR_USED)
- if (alpha < alpha_scissor) {
+ if (alpha < alpha_scissor_threshold) {
discard;
}
#endif // ALPHA_SCISSOR_USED
-#ifdef USE_DEPTH_PREPASS
- if (alpha < 0.1) {
+#ifdef USE_OPAQUE_PREPASS
+#if !defined(ALPHA_SCISSOR_USED)
+
+ if (alpha < opaque_prepass_threshold) {
discard;
}
-#endif // USE_DEPTH_PREPASS
-#endif // !USE_SHADOW_TO_OPACITY
-
-#ifdef BASE_PASS
+#endif // not ALPHA_SCISSOR_USED
+#endif // USE_OPAQUE_PREPASS
- // 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);
+#endif // !USE_SHADOW_TO_OPACITY
-#ifdef AMBIENT_LIGHT_DISABLED
- ambient_light = vec3(0.0, 0.0, 0.0);
-#else
+#ifdef NORMAL_MAP_USED
-#ifdef USE_RADIANCE_MAP
+ normal_map.xy = normal_map.xy * 2.0 - 1.0;
+ normal_map.z = sqrt(max(0.0, 1.0 - dot(normal_map.xy, normal_map.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc.
- vec3 ref_vec = reflect(-eye_position, N);
- ref_vec = normalize((radiance_inverse_xform * vec4(ref_vec, 0.0)).xyz);
+ normal = normalize(mix(normal, tangent * normal_map.x + binormal * normal_map.y + normal * normal_map.z, normal_map_depth));
- ref_vec.z *= -1.0;
+#endif
- 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;
+#ifdef LIGHT_ANISOTROPY_USED
- ambient_light = mix(ambient_color.rgb, env_ambient, ambient_sky_contribution);
+ if (anisotropy > 0.01) {
+ //rotation matrix
+ mat3 rot = mat3(tangent, binormal, normal);
+ //make local to space
+ tangent = normalize(rot * vec3(anisotropy_flow.x, anisotropy_flow.y, 0.0));
+ binormal = normalize(rot * vec3(-anisotropy_flow.y, anisotropy_flow.x, 0.0));
}
+
#endif
-#else
+#ifndef MODE_RENDER_DEPTH
- ambient_light = ambient_color.rgb;
- specular_light = bg_color.rgb * bg_energy;
+#ifndef CUSTOM_FOG_USED
+#ifndef DISABLE_FOG
+ // fog must be processed as early as possible and then packed.
+ // to maximize VGPR usage
-#endif
-#endif // AMBIENT_LIGHT_DISABLED
- ambient_light *= ambient_energy;
+ if (scene_data.fog_enabled) {
+ fog = fog_process(vertex);
+ }
+#endif // !DISABLE_FOG
+#endif //!CUSTOM_FOG_USED
-#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2)
+ uint fog_rg = packHalf2x16(fog.rg);
+ uint fog_ba = packHalf2x16(fog.ba);
- vec4 ambient_accum = vec4(0.0);
- vec4 reflection_accum = vec4(0.0);
+#endif //!MODE_RENDER_DEPTH
-#ifdef USE_REFLECTION_PROBE1
+#ifndef MODE_RENDER_DEPTH
- 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);
+ // Convert colors to linear
+ albedo = srgb_to_linear(albedo);
+ emission = srgb_to_linear(emission);
+ // TODO Backlight and transmittance when used
+#ifndef MODE_UNSHADED
+ vec3 f0 = F0(metallic, specular, albedo);
+ 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);
-#endif // USE_REFLECTION_PROBE1
+#ifdef BASE_PASS
+ /////////////////////// LIGHTING //////////////////////////////
-#ifdef USE_REFLECTION_PROBE2
+ // IBL precalculations
+ float ndotv = clamp(dot(normal, view), 0.0, 1.0);
+ vec3 F = f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(1.0 - ndotv, 5.0);
- 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,
+#ifdef USE_RADIANCE_MAP
+ if (scene_data.use_reflection_cubemap) {
+#ifdef LIGHT_ANISOTROPY_USED
+ // https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy
+ vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent;
+ vec3 anisotropic_tangent = cross(anisotropic_direction, view);
+ vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction);
+ vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0)));
+ vec3 ref_vec = reflect(-view, bent_normal);
#else
- normal_interp, vertex_interp, refprobe2_local_matrix,
- refprobe2_use_box_project, refprobe2_box_extents, refprobe2_box_offset,
+ vec3 ref_vec = reflect(-view, normal);
+#endif
+ ref_vec = mix(ref_vec, normal, roughness * roughness);
+ float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
+ ref_vec = scene_data.radiance_inverse_xform * ref_vec;
+ specular_light = textureLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).rgb;
+ specular_light = srgb_to_linear(specular_light);
+ specular_light *= horizon * horizon;
+ specular_light *= scene_data.ambient_light_color_energy.a;
+ }
#endif
- refprobe2_exterior, refprobe2_intensity, refprobe2_ambient, roughness,
- ambient_light, specular_light, reflection_accum, ambient_accum);
-#endif // USE_REFLECTION_PROBE2
+ // Calculate Reflection probes
+ // Calculate Lightmaps
- if (reflection_accum.a > 0.0) {
- specular_light = reflection_accum.rgb / reflection_accum.a;
- }
+#if defined(CUSTOM_RADIANCE_USED)
+ specular_light = mix(specular_light, custom_radiance.rgb, custom_radiance.a);
+#endif // CUSTOM_RADIANCE_USED
#ifndef USE_LIGHTMAP
- if (ambient_accum.a > 0.0) {
- ambient_light = ambient_accum.rgb / ambient_accum.a;
- }
+ //lightmap overrides everything
+ if (scene_data.use_ambient_light) {
+ ambient_light = scene_data.ambient_light_color_energy.rgb;
+#ifdef USE_RADIANCE_MAP
+ if (scene_data.use_ambient_cubemap) {
+ vec3 ambient_dir = scene_data.radiance_inverse_xform * normal;
+ vec3 cubemap_ambient = textureLod(radiance_map, ambient_dir, RADIANCE_MAX_LOD).rgb;
+ cubemap_ambient = srgb_to_linear(cubemap_ambient);
+ ambient_light = mix(ambient_light, cubemap_ambient * scene_data.ambient_light_color_energy.a, scene_data.ambient_color_sky_mix);
+ }
#endif
+ }
+#endif // USE_LIGHTMAP
-#endif // defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2)
+#if defined(CUSTOM_IRRADIANCE_USED)
+ ambient_light = mix(ambient_light, custom_irradiance.rgb, custom_irradiance.a);
+#endif // CUSTOM_IRRADIANCE_USED
+ ambient_light *= albedo.rgb;
+
+ ambient_light *= ao;
+
+ // convert ao to direct light ao
+ ao = mix(1.0, ao, ao_light_affect);
- // 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 computed before lighting happens,
- // but after environment and reflection probes are added
- //TODO: this curve is not really designed for gammaspace, should be adjusted
+ // scales the specular reflections, needs to be be computed before lighting happens,
+ // but after environment, GI, and reflection probes are added
+ // Environment brdf approximation (Lazarov 2013)
+ // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
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 ndotv = clamp(dot(normal, view), 0.0, 1.0);
+
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 = texture(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;
- }
- }
+ specular_light *= env.x * f0 + env.y * clamp(50.0 * f0.g, 0.0, 1.0);
#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);
+#endif // BASE_PASS
- 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;
+#ifndef DISABLE_LIGHT_DIRECTIONAL
+ //diffuse_light = normal; //
+ for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
+ light_compute(normal, normalize(directional_lights[i].direction), normalize(view), directional_lights[i].size, directional_lights[i].color * directional_lights[i].energy, 1.0, f0, roughness, metallic, 1.0, albedo, alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
#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);
+#ifdef LIGHT_RIM_USED
+ rim, rim_tint,
#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);
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_roughness, normalize(normal_interp),
#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);
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal,
+ tangent, anisotropy,
#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);
+ diffuse_light,
+ specular_light);
}
+#endif //!DISABLE_LIGHT_DIRECTIONAL
-#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);
+#ifndef DISABLE_LIGHT_OMNI
+ for (int i = 0; i < MAX_FORWARD_LIGHTS; i++) {
+ if (i >= omni_light_count) {
+ break;
}
+ light_process_omni(omni_light_indices[i], vertex, view, normal, f0, roughness, metallic, 0.0, albedo, alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
#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;
+#ifdef LIGHT_RIM_USED
+ rim,
+ rim_tint,
#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);
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_roughness, normalize(normal_interp),
#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);
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal, tangent, anisotropy,
#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;
+ diffuse_light, specular_light);
+ }
+#endif // !DISABLE_LIGHT_OMNI
-#ifdef LIGHT_USE_PSSM_BLEND
- pssm_coord2 = shadow_coord2;
- pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z);
+#ifndef DISABLE_LIGHT_SPOT
+ for (int i = 0; i < MAX_FORWARD_LIGHTS; i++) {
+ if (i >= spot_light_count) {
+ break;
+ }
+ light_process_spot(spot_light_indices[i], vertex, view, normal, f0, roughness, metallic, 0.0, albedo, alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
#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;
+#ifdef LIGHT_RIM_USED
+ rim,
+ rim_tint,
#endif
- }
-
-#endif // LIGHT_USE_PSSM2
-
-#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2)
- {
- pssm_coord = shadow_coord;
- }
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_roughness, normalize(normal_interp),
#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);
- }
+#ifdef LIGHT_ANISOTROPY_USED
+ tangent,
+ binormal, anisotropy,
#endif
-
- light_att *= mix(shadow_color.rgb, vec3(1.0), shadow);
- }
+ diffuse_light, specular_light);
}
-#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
+#endif // !DISABLE_LIGHT_SPOT
+#endif // !MODE_UNSHADED
+#endif // !MODE_RENDER_DEPTH
+#if defined(USE_SHADOW_TO_OPACITY)
alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0));
#if defined(ALPHA_SCISSOR_USED)
@@ -2049,105 +1198,60 @@ FRAGMENT_SHADER_CODE
}
#endif // ALPHA_SCISSOR_USED
-#ifdef USE_DEPTH_PREPASS
- if (alpha < 0.1) {
+#ifdef USE_OPAQUE_PREPASS
+#if !defined(ALPHA_SCISSOR_USED)
+
+ if (alpha < opaque_prepass_threshold) {
discard;
}
-#endif // USE_DEPTH_PREPASS
-#endif // !USE_SHADOW_TO_OPACITY
+#endif // not ALPHA_SCISSOR_USED
+#endif // USE_OPAQUE_PREPASS
-#ifndef RENDER_DEPTH
+#endif // USE_SHADOW_TO_OPACITY
-#ifdef SHADELESS
+#ifdef MODE_RENDER_DEPTH
+//nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
+#else // !MODE_RENDER_DEPTH
+#ifdef MODE_UNSHADED
frag_color = 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 *= albedo;
diffuse_light *= 1.0 - metallic;
ambient_light *= 1.0 - metallic;
- frag_color = vec4(ambient_light + diffuse_light + specular_light, alpha);
-
- //add emission if in base pass
+ frag_color = vec4(diffuse_light + specular_light, alpha);
#ifdef BASE_PASS
- frag_color.rgb += emission;
+ frag_color.rgb += emission + ambient_light;
#endif
- // frag_color = vec4(normal, 1.0);
-
-//apply fog
-#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED)
-
-#if defined(USE_VERTEX_LIGHTING)
+#endif //MODE_UNSHADED
+ fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba));
-#if defined(BASE_PASS)
- frag_color.rgb = mix(frag_color.rgb, fog_interp.rgb, fog_interp.a);
+#ifndef DISABLE_FOG
+ if (scene_data.fog_enabled) {
+#ifdef BASE_PASS
+ frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
#else
- frag_color.rgb *= (1.0 - fog_interp.a);
+ frag_color.rgb *= (1.0 - fog.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));
+ // Tonemap before writing as we are writing to an sRGB framebuffer
+ frag_color.rgb *= exposure;
+ frag_color.rgb = apply_tonemapping(frag_color.rgb, white);
+ frag_color.rgb = linear_to_srgb(frag_color.rgb);
- fog_amount = pow(fog_z, fog_depth_curve) * fog_color_base.a;
-
- if (fog_transmit_enabled) {
- vec3 total_light = frag_color.rgb;
- float transmit = pow(fog_z, fog_transmit_curve);
- fog_color = mix(max(total_light, fog_color), fog_color, transmit);
- }
- }
+#ifdef USE_BCS
+ frag_color.rgb = apply_bcs(frag_color.rgb, bcs);
#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));
- }
+#ifdef USE_COLOR_CORRECTION
+ frag_color.rgb = apply_color_correction(frag_color.rgb, color_correction);
#endif
-#if defined(BASE_PASS)
- frag_color.rgb = mix(frag_color.rgb, fog_color, fog_amount);
-#else
- frag_color.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);
- frag_color = comp;
-
-#endif
-#endif
+#endif //!MODE_RENDER_DEPTH
}
diff --git a/drivers/gles3/shaders/sky.glsl b/drivers/gles3/shaders/sky.glsl
new file mode 100644
index 0000000000..eb1befe38e
--- /dev/null
+++ b/drivers/gles3/shaders/sky.glsl
@@ -0,0 +1,168 @@
+/* clang-format off */
+#[modes]
+
+mode_background =
+mode_half_res = #define USE_HALF_RES_PASS
+mode_quarter_res = #define USE_QUARTER_RES_PASS
+mode_cubemap = #define USE_CUBEMAP_PASS
+mode_cubemap_half_res = #define USE_CUBEMAP_PASS \n#define USE_HALF_RES_PASS
+mode_cubemap_quarter_res = #define USE_CUBEMAP_PASS \n#define USE_QUARTER_RES_PASS
+
+#[specializations]
+
+#[vertex]
+
+layout(location = 0) in vec2 vertex_attrib;
+
+out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+ uv_interp = vertex_attrib;
+ gl_Position = vec4(uv_interp, 1.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#define M_PI 3.14159265359
+
+#include "tonemap_inc.glsl"
+
+in vec2 uv_interp;
+
+/* clang-format on */
+
+uniform samplerCube radiance; //texunit:-1
+#ifdef USE_CUBEMAP_PASS
+uniform samplerCube half_res; //texunit:-2
+uniform samplerCube quarter_res; //texunit:-3
+#else
+uniform sampler2D half_res; //texunit:-2
+uniform sampler2D quarter_res; //texunit:-3
+#endif
+
+layout(std140) uniform GlobalShaderUniformData { //ubo:1
+ vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
+};
+
+struct DirectionalLightData {
+ vec4 direction_energy;
+ vec4 color_size;
+ bool enabled;
+};
+
+layout(std140) uniform DirectionalLights { //ubo:4
+ DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+}
+directional_lights;
+
+/* clang-format off */
+
+#ifdef MATERIAL_UNIFORMS_USED
+layout(std140) uniform MaterialUniforms{ //ubo:3
+
+#MATERIAL_UNIFORMS
+
+};
+#endif
+/* clang-format on */
+#GLOBALS
+
+#ifdef USE_CUBEMAP_PASS
+#define AT_CUBEMAP_PASS true
+#else
+#define AT_CUBEMAP_PASS false
+#endif
+
+#ifdef USE_HALF_RES_PASS
+#define AT_HALF_RES_PASS true
+#else
+#define AT_HALF_RES_PASS false
+#endif
+
+#ifdef USE_QUARTER_RES_PASS
+#define AT_QUARTER_RES_PASS true
+#else
+#define AT_QUARTER_RES_PASS false
+#endif
+
+// mat4 is a waste of space, but we don't have an easy way to set a mat3 uniform for now
+uniform mat4 orientation;
+uniform vec4 projection;
+uniform vec3 position;
+uniform float time;
+
+uniform float fog_aerial_perspective;
+uniform vec3 fog_light_color;
+uniform float fog_sun_scatter;
+uniform bool fog_enabled;
+uniform float fog_density;
+uniform float z_far;
+uniform uint directional_light_count;
+
+layout(location = 0) out vec4 frag_color;
+
+void main() {
+ vec3 cube_normal;
+ cube_normal.z = -1.0;
+ cube_normal.x = (uv_interp.x + projection.x) / projection.y;
+ cube_normal.y = (-uv_interp.y - projection.z) / projection.w;
+ cube_normal = mat3(orientation) * cube_normal;
+ cube_normal = normalize(cube_normal);
+
+ vec2 uv = gl_FragCoord.xy; // uv_interp * 0.5 + 0.5;
+
+ vec2 panorama_coords = vec2(atan(cube_normal.x, -cube_normal.z), acos(cube_normal.y));
+
+ if (panorama_coords.x < 0.0) {
+ panorama_coords.x += M_PI * 2.0;
+ }
+
+ panorama_coords /= vec2(M_PI * 2.0, M_PI);
+
+ vec3 color = vec3(0.0, 0.0, 0.0);
+ float alpha = 1.0; // Only available to subpasses
+ vec4 half_res_color = vec4(1.0);
+ vec4 quarter_res_color = vec4(1.0);
+ vec4 custom_fog = vec4(0.0);
+
+#ifdef USE_CUBEMAP_PASS
+#ifdef USES_HALF_RES_COLOR
+ half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal);
+#endif
+#ifdef USES_QUARTER_RES_COLOR
+ quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal);
+#endif
+#else
+#ifdef USES_HALF_RES_COLOR
+ half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
+#endif
+#ifdef USES_QUARTER_RES_COLOR
+ quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
+#endif
+#endif
+
+ {
+
+#CODE : SKY
+
+ }
+
+ // Convert to Linear for tonemapping so color matches scene shader better
+ color = srgb_to_linear(color);
+ color *= exposure;
+ color = apply_tonemapping(color, white);
+ color = linear_to_srgb(color);
+
+#ifdef USE_BCS
+ color = apply_bcs(color, bcs);
+#endif
+
+#ifdef USE_COLOR_CORRECTION
+ color = apply_color_correction(color, color_correction);
+#endif
+
+ frag_color.rgb = color;
+ frag_color.a = alpha;
+}
diff --git a/drivers/gles3/shaders/stdlib_inc.glsl b/drivers/gles3/shaders/stdlib_inc.glsl
index 2eddf9d479..d5051760d7 100644
--- a/drivers/gles3/shaders/stdlib_inc.glsl
+++ b/drivers/gles3/shaders/stdlib_inc.glsl
@@ -1,5 +1,6 @@
-//TODO: only needed by GLES_OVER_GL
+#ifdef USE_GLES_OVER_GL
+// Floating point pack/unpack functions are part of the GLSL ES 300 specification used by web and mobile.
uint float2half(uint f) {
return ((f >> uint(16)) & uint(0x8000)) |
((((f & uint(0x7f800000)) - uint(0x38000000)) >> uint(13)) & uint(0x7c00)) |
@@ -37,14 +38,15 @@ vec2 unpackSnorm2x16(uint p) {
vec2 v = vec2(float(p & uint(0xffff)), float(p >> uint(16)));
return clamp((v - 32767.0) * vec2(0.00003051851), vec2(-1.0), vec2(1.0));
}
+#endif
uint packUnorm4x8(vec4 v) {
uvec4 uv = uvec4(round(clamp(v, vec4(0.0), vec4(1.0)) * 255.0));
- return uv.x | uv.y << uint(8) | uv.z << uint(16) | uv.w << uint(24);
+ return uv.x | (uv.y << uint(8)) | (uv.z << uint(16)) | (uv.w << uint(24));
}
vec4 unpackUnorm4x8(uint p) {
- return vec4(float(p & uint(0xffff)), float((p >> uint(8)) & uint(0xffff)), float((p >> uint(16)) & uint(0xffff)), float(p >> uint(24))) * 0.00392156862; // 1.0 / 255.0
+ return vec4(float(p & uint(0xff)), float((p >> uint(8)) & uint(0xff)), float((p >> uint(16)) & uint(0xff)), float(p >> uint(24))) * 0.00392156862; // 1.0 / 255.0
}
uint packSnorm4x8(vec4 v) {
@@ -53,6 +55,6 @@ uint packSnorm4x8(vec4 v) {
}
vec4 unpackSnorm4x8(uint p) {
- vec4 v = vec4(float(p & uint(0xffff)), float((p >> uint(8)) & uint(0xffff)), float((p >> uint(16)) & uint(0xffff)), float(p >> uint(24)));
+ vec4 v = vec4(float(p & uint(0xff)), float((p >> uint(8)) & uint(0xff)), float((p >> uint(16)) & uint(0xff)), float(p >> uint(24)));
return clamp((v - vec4(127.0)) * vec4(0.00787401574), vec4(-1.0), vec4(1.0));
}
diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl
index 4f962626a3..a478cf9170 100644
--- a/drivers/gles3/shaders/tonemap.glsl
+++ b/drivers/gles3/shaders/tonemap.glsl
@@ -231,10 +231,10 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) {
}
void main() {
- vec3 color = textureLod(source, uv_interp, 0.0).rgb;
+ vec4 color = textureLod(source, uv_interp, 0.0);
#ifdef USE_FXAA
- color = apply_fxaa(color, uv_interp, pixel_size);
+ color.rgb = apply_fxaa(color.rgb, uv_interp, pixel_size);
#endif
// Glow
@@ -296,18 +296,18 @@ void main() {
#endif //USE_MULTI_TEXTURE_GLOW
glow *= glow_intensity;
- color = apply_glow(color, glow);
+ color.rgb = apply_glow(color.rgb, glow);
#endif
// Additional effects
#ifdef USE_BCS
- color = apply_bcs(color, bcs);
+ color.rgb = apply_bcs(color.rgb, bcs);
#endif
#ifdef USE_COLOR_CORRECTION
- color = apply_color_correction(color, color_correction);
+ color.rgb = apply_color_correction(color.rgb, color_correction);
#endif
- frag_color = vec4(color, 1.0);
+ frag_color = color;
}
diff --git a/drivers/gles3/shaders/tonemap_inc.glsl b/drivers/gles3/shaders/tonemap_inc.glsl
new file mode 100644
index 0000000000..f8f12760ec
--- /dev/null
+++ b/drivers/gles3/shaders/tonemap_inc.glsl
@@ -0,0 +1,127 @@
+#ifdef USE_BCS
+uniform vec3 bcs;
+#endif
+
+#ifdef USE_COLOR_CORRECTION
+#ifdef USE_1D_LUT
+uniform sampler2D source_color_correction; //texunit:-1
+#else
+uniform sampler3D source_color_correction; //texunit:-1
+#endif
+#endif
+
+layout(std140) uniform TonemapData { //ubo:0
+ float exposure;
+ float white;
+ int tonemapper;
+ int pad;
+};
+
+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;
+}
+#ifdef USE_COLOR_CORRECTION
+#ifdef USE_1D_LUT
+vec3 apply_color_correction(vec3 color) {
+ color.r = texture(source_color_correction, vec2(color.r, 0.0f)).r;
+ color.g = texture(source_color_correction, vec2(color.g, 0.0f)).g;
+ color.b = texture(source_color_correction, vec2(color.b, 0.0f)).b;
+ return color;
+}
+#else
+vec3 apply_color_correction(vec3 color) {
+ return textureLod(source_color_correction, color, 0.0).rgb;
+}
+#endif
+#endif
+
+vec3 tonemap_filmic(vec3 color, float p_white) {
+ // exposure bias: input scale (color *= bias, white *= bias) to make the brightness consistent with other tonemappers
+ // also useful to scale the input to the range that the tonemapper is designed for (some require very high input values)
+ // has no effect on the curve's general shape or visual properties
+ const float exposure_bias = 2.0f;
+ const float A = 0.22f * exposure_bias * exposure_bias; // bias baked into constants for performance
+ const float B = 0.30f * exposure_bias;
+ const float C = 0.10f;
+ const float D = 0.20f;
+ const float E = 0.01f;
+ const float F = 0.30f;
+
+ vec3 color_tonemapped = ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F;
+ float p_white_tonemapped = ((p_white * (A * p_white + C * B) + D * E) / (p_white * (A * p_white + B) + D * F)) - E / F;
+
+ return color_tonemapped / p_white_tonemapped;
+}
+
+// Adapted from https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
+// (MIT License).
+vec3 tonemap_aces(vec3 color, float p_white) {
+ const float exposure_bias = 1.8f;
+ const float A = 0.0245786f;
+ const float B = 0.000090537f;
+ const float C = 0.983729f;
+ const float D = 0.432951f;
+ const float E = 0.238081f;
+
+ // Exposure bias baked into transform to save shader instructions. Equivalent to `color *= exposure_bias`
+ const mat3 rgb_to_rrt = mat3(
+ vec3(0.59719f * exposure_bias, 0.35458f * exposure_bias, 0.04823f * exposure_bias),
+ vec3(0.07600f * exposure_bias, 0.90834f * exposure_bias, 0.01566f * exposure_bias),
+ vec3(0.02840f * exposure_bias, 0.13383f * exposure_bias, 0.83777f * exposure_bias));
+
+ const mat3 odt_to_rgb = mat3(
+ vec3(1.60475f, -0.53108f, -0.07367f),
+ vec3(-0.10208f, 1.10813f, -0.00605f),
+ vec3(-0.00327f, -0.07276f, 1.07602f));
+
+ color *= rgb_to_rrt;
+ vec3 color_tonemapped = (color * (color + A) - B) / (color * (C * color + D) + E);
+ color_tonemapped *= odt_to_rgb;
+
+ p_white *= exposure_bias;
+ float p_white_tonemapped = (p_white * (p_white + A) - B) / (p_white * (C * p_white + D) + E);
+
+ return color_tonemapped / p_white_tonemapped;
+}
+
+vec3 tonemap_reinhard(vec3 color, float p_white) {
+ return (p_white * color + color) / (color * p_white + p_white);
+}
+
+// This expects 0-1 range input.
+vec3 linear_to_srgb(vec3 color) {
+ //color = clamp(color, vec3(0.0), vec3(1.0));
+ //const vec3 a = vec3(0.055f);
+ //return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f)));
+ // Approximation from http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
+ return max(vec3(1.055) * pow(color, vec3(0.416666667)) - vec3(0.055), vec3(0.0));
+}
+
+// This expects 0-1 range input, outside that range it behaves poorly.
+vec3 srgb_to_linear(vec3 color) {
+ // Approximation from http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
+ return color * (color * (color * 0.305306011 + 0.682171111) + 0.012522878);
+}
+
+#define TONEMAPPER_LINEAR 0
+#define TONEMAPPER_REINHARD 1
+#define TONEMAPPER_FILMIC 2
+#define TONEMAPPER_ACES 3
+
+vec3 apply_tonemapping(vec3 color, float p_white) { // inputs are LINEAR, always outputs clamped [0;1] color
+ // Ensure color values passed to tonemappers are positive.
+ // They can be negative in the case of negative lights, which leads to undesired behavior.
+ if (tonemapper == TONEMAPPER_LINEAR) {
+ return color;
+ } else if (tonemapper == TONEMAPPER_REINHARD) {
+ return tonemap_reinhard(max(vec3(0.0f), color), p_white);
+ } else if (tonemapper == TONEMAPPER_FILMIC) {
+ return tonemap_filmic(max(vec3(0.0f), color), p_white);
+ } else { // TONEMAPPER_ACES
+ return tonemap_aces(max(vec3(0.0f), color), p_white);
+ }
+}
diff --git a/drivers/gles3/storage/SCsub b/drivers/gles3/storage/SCsub
new file mode 100644
index 0000000000..91e1140b75
--- /dev/null
+++ b/drivers/gles3/storage/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp
new file mode 100644
index 0000000000..6cc65e7bb2
--- /dev/null
+++ b/drivers/gles3/storage/config.cpp
@@ -0,0 +1,128 @@
+/*************************************************************************/
+/* config.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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. */
+/*************************************************************************/
+
+#ifdef GLES3_ENABLED
+
+#include "config.h"
+#include "core/config/project_settings.h"
+#include "core/templates/vector.h"
+
+using namespace GLES3;
+
+#define _GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+
+Config *Config::singleton = nullptr;
+
+Config::Config() {
+ singleton = this;
+
+ {
+ GLint max_extensions = 0;
+ glGetIntegerv(GL_NUM_EXTENSIONS, &max_extensions);
+ for (int i = 0; i < max_extensions; i++) {
+ const GLubyte *s = glGetStringi(GL_EXTENSIONS, i);
+ if (!s) {
+ break;
+ }
+ extensions.insert((const char *)s);
+ }
+ }
+
+ bptc_supported = extensions.has("GL_ARB_texture_compression_bptc") || extensions.has("EXT_texture_compression_bptc");
+#ifdef GLES_OVER_GL
+ float_texture_supported = true;
+ etc2_supported = false;
+ s3tc_supported = true;
+ rgtc_supported = true; //RGTC - core since OpenGL version 3.0
+#else
+ float_texture_supported = extensions.has("GL_ARB_texture_float") || extensions.has("GL_OES_texture_float");
+ etc2_supported = true;
+#if defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
+ // Some Android devices report support for S3TC but we don't expect that and don't export the textures.
+ // This could be fixed but so few devices support it that it doesn't seem useful (and makes bigger APKs).
+ // For good measure we do the same hack for iOS, just in case.
+ s3tc_supported = false;
+#else
+ s3tc_supported = extensions.has("GL_EXT_texture_compression_dxt1") || extensions.has("GL_EXT_texture_compression_s3tc") || extensions.has("WEBGL_compressed_texture_s3tc");
+#endif
+ rgtc_supported = extensions.has("GL_EXT_texture_compression_rgtc") || extensions.has("GL_ARB_texture_compression_rgtc") || extensions.has("EXT_texture_compression_rgtc");
+#endif
+
+#ifdef GLES_OVER_GL
+ use_rgba_2d_shadows = false;
+#else
+ use_rgba_2d_shadows = !(float_texture_supported && extensions.has("GL_EXT_texture_rg"));
+#endif
+
+ glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &max_vertex_texture_image_units);
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_image_units);
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
+ glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_uniform_buffer_size);
+
+ // the use skeleton software path should be used if either float texture is not supported,
+ // OR max_vertex_texture_image_units is zero
+ use_skeleton_software = (float_texture_supported == false) || (max_vertex_texture_image_units == 0);
+
+ support_anisotropic_filter = extensions.has("GL_EXT_texture_filter_anisotropic");
+ if (support_anisotropic_filter) {
+ glGetFloatv(_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropic_level);
+ anisotropic_level = MIN(float(1 << int(ProjectSettings::get_singleton()->get("rendering/textures/default_filters/anisotropic_filtering_level"))), anisotropic_level);
+ }
+
+ force_vertex_shading = false; //GLOBAL_GET("rendering/quality/shading/force_vertex_shading");
+ use_nearest_mip_filter = GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter");
+
+ use_depth_prepass = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable"));
+ if (use_depth_prepass) {
+ String vendors = GLOBAL_GET("rendering/driver/depth_prepass/disable_for_vendors");
+ Vector<String> vendor_match = vendors.split(",");
+ String renderer = (const char *)glGetString(GL_RENDERER);
+ for (int i = 0; i < vendor_match.size(); i++) {
+ String v = vendor_match[i].strip_edges();
+ if (v == String()) {
+ continue;
+ }
+
+ if (renderer.findn(v) != -1) {
+ use_depth_prepass = false;
+ }
+ }
+ }
+
+ max_renderable_elements = GLOBAL_GET("rendering/limits/opengl/max_renderable_elements");
+ max_renderable_lights = GLOBAL_GET("rendering/limits/opengl/max_renderable_lights");
+ max_lights_per_object = GLOBAL_GET("rendering/limits/opengl/max_lights_per_object");
+}
+
+Config::~Config() {
+ singleton = nullptr;
+}
+
+#endif // GLES3_ENABLED
diff --git a/drivers/gles3/texture_loader_gles3.cpp b/drivers/gles3/storage/config.h
index 1cbda02121..b83c83f425 100644
--- a/drivers/gles3/texture_loader_gles3.cpp
+++ b/drivers/gles3/storage/config.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* texture_loader_gles3.cpp */
+/* config.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,84 +28,66 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "texture_loader_gles3.h"
+#ifndef CONFIG_GLES3_H
+#define CONFIG_GLES3_H
+
#ifdef GLES3_ENABLED
-#include "core/io/file_access.h"
-#include "core/string/print_string.h"
-
-#include <string.h>
-
-RES ResourceFormatGLES2Texture::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- unsigned int width = 8;
- unsigned int height = 8;
-
- //We just use some format
- Image::Format fmt = Image::FORMAT_RGB8;
- int rowsize = 3 * width;
-
- Vector<uint8_t> dstbuff;
-
- dstbuff.resize(rowsize * height);
-
- uint8_t **row_p = memnew_arr(uint8_t *, height);
-
- for (unsigned int i = 0; i < height; i++) {
- row_p[i] = 0; //No colors any more, I want them to turn black
- }
-
- memdelete_arr(row_p);
-
- Ref<Image> img = memnew(Image(width, height, 0, fmt, dstbuff));
-
- Ref<ImageTexture> texture = memnew(ImageTexture);
- texture->create_from_image(img);
-
- if (r_error) {
- *r_error = OK;
- }
-
- return texture;
-}
-
-void ResourceFormatGLES2Texture::get_recognized_extensions(List<String> *p_extensions) const {
- p_extensions->push_back("bmp");
- p_extensions->push_back("dds");
- p_extensions->push_back("exr");
- p_extensions->push_back("jpeg");
- p_extensions->push_back("jpg");
- p_extensions->push_back("hdr");
- p_extensions->push_back("pkm");
- p_extensions->push_back("png");
- p_extensions->push_back("pvr");
- p_extensions->push_back("svg");
- p_extensions->push_back("tga");
- p_extensions->push_back("webp");
-}
-
-bool ResourceFormatGLES2Texture::handles_type(const String &p_type) const {
- return ClassDB::is_parent_class(p_type, "Texture2D");
-}
-
-String ResourceFormatGLES2Texture::get_resource_type(const String &p_path) const {
- String extension = p_path.get_extension().to_lower();
- if (
- extension == "bmp" ||
- extension == "dds" ||
- extension == "exr" ||
- extension == "jpeg" ||
- extension == "jpg" ||
- extension == "hdr" ||
- extension == "pkm" ||
- extension == "png" ||
- extension == "pvr" ||
- extension == "svg" ||
- extension == "tga" ||
- extension == "webp") {
- return "ImageTexture";
- }
-
- return "";
-}
+#include "core/string/ustring.h"
+#include "core/templates/hash_set.h"
+// This must come first to avoid windows.h mess
+#include "platform_config.h"
+#ifndef OPENGL_INCLUDE_H
+#include <GLES3/gl3.h>
+#else
+#include OPENGL_INCLUDE_H
#endif
+
+namespace GLES3 {
+
+class Config {
+private:
+ static Config *singleton;
+
+public:
+ bool use_nearest_mip_filter = false;
+ bool use_skeleton_software = false;
+ bool use_depth_prepass = true;
+ bool use_rgba_2d_shadows = false;
+
+ int max_vertex_texture_image_units = 0;
+ int max_texture_image_units = 0;
+ int max_texture_size = 0;
+ int max_uniform_buffer_size = 0;
+ int max_renderable_elements = 0;
+ int max_renderable_lights = 0;
+ int max_lights_per_object = 0;
+
+ // TODO implement wireframe in OpenGL
+ // bool generate_wireframes;
+
+ HashSet<String> extensions;
+
+ bool float_texture_supported = false;
+ bool s3tc_supported = false;
+ bool rgtc_supported = false;
+ bool bptc_supported = false;
+ bool etc2_supported = false;
+
+ bool force_vertex_shading = false;
+
+ bool support_anisotropic_filter = false;
+ float anisotropic_level = 0.0f;
+
+ static Config *get_singleton() { return singleton; };
+
+ Config();
+ ~Config();
+};
+
+} // namespace GLES3
+
+#endif // GLES3_ENABLED
+
+#endif // CONFIG_GLES3_H
diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp
new file mode 100644
index 0000000000..2e4bfdc15b
--- /dev/null
+++ b/drivers/gles3/storage/light_storage.cpp
@@ -0,0 +1,580 @@
+/*************************************************************************/
+/* light_storage.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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. */
+/*************************************************************************/
+
+#ifdef GLES3_ENABLED
+
+#include "light_storage.h"
+#include "config.h"
+#include "texture_storage.h"
+
+using namespace GLES3;
+
+LightStorage *LightStorage::singleton = nullptr;
+
+LightStorage *LightStorage::get_singleton() {
+ return singleton;
+}
+
+LightStorage::LightStorage() {
+ singleton = this;
+}
+
+LightStorage::~LightStorage() {
+ singleton = nullptr;
+}
+
+/* Light API */
+
+void LightStorage::_light_initialize(RID p_light, RS::LightType p_type) {
+ Light 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_SIZE] = 0.0;
+ light.param[RS::LIGHT_PARAM_ATTENUATION] = 1.0;
+ light.param[RS::LIGHT_PARAM_SPOT_ANGLE] = 45;
+ light.param[RS::LIGHT_PARAM_SPOT_ATTENUATION] = 1.0;
+ light.param[RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE] = 0;
+ light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET] = 0.1;
+ light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET] = 0.3;
+ light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6;
+ light.param[RS::LIGHT_PARAM_SHADOW_FADE_START] = 0.8;
+ light.param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 1.0;
+ light.param[RS::LIGHT_PARAM_SHADOW_OPACITY] = 1.0;
+ light.param[RS::LIGHT_PARAM_SHADOW_BIAS] = 0.02;
+ light.param[RS::LIGHT_PARAM_SHADOW_BLUR] = 0;
+ light.param[RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE] = 20.0;
+ light.param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE] = 0.1;
+ light.param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] = 0.05;
+
+ light_owner.initialize_rid(p_light, light);
+}
+
+RID LightStorage::directional_light_allocate() {
+ return light_owner.allocate_rid();
+}
+
+void LightStorage::directional_light_initialize(RID p_rid) {
+ _light_initialize(p_rid, RS::LIGHT_DIRECTIONAL);
+}
+
+RID LightStorage::omni_light_allocate() {
+ return light_owner.allocate_rid();
+}
+
+void LightStorage::omni_light_initialize(RID p_rid) {
+ _light_initialize(p_rid, RS::LIGHT_OMNI);
+}
+
+RID LightStorage::spot_light_allocate() {
+ return light_owner.allocate_rid();
+}
+
+void LightStorage::spot_light_initialize(RID p_rid) {
+ _light_initialize(p_rid, RS::LIGHT_SPOT);
+}
+
+void LightStorage::light_free(RID p_rid) {
+ light_set_projector(p_rid, RID()); //clear projector
+
+ // delete the texture
+ Light *light = light_owner.get_or_null(p_rid);
+ light->dependency.deleted_notify(p_rid);
+ light_owner.free(p_rid);
+}
+
+void LightStorage::light_set_color(RID p_light, const Color &p_color) {
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->color = p_color;
+}
+
+void LightStorage::light_set_param(RID p_light, RS::LightParam p_param, float p_value) {
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND(!light);
+ ERR_FAIL_INDEX(p_param, RS::LIGHT_PARAM_MAX);
+
+ if (light->param[p_param] == p_value) {
+ return;
+ }
+
+ 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_PANCAKE_SIZE:
+ case RS::LIGHT_PARAM_SHADOW_BIAS: {
+ light->version++;
+ light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT);
+ } break;
+ case RS::LIGHT_PARAM_SIZE: {
+ if ((light->param[p_param] > CMP_EPSILON) != (p_value > CMP_EPSILON)) {
+ //changing from no size to size and the opposite
+ light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR);
+ }
+ } break;
+ default: {
+ }
+ }
+
+ light->param[p_param] = p_value;
+}
+
+void LightStorage::light_set_shadow(RID p_light, bool p_enabled) {
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND(!light);
+ light->shadow = p_enabled;
+
+ light->version++;
+ light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT);
+}
+
+void LightStorage::light_set_projector(RID p_light, RID p_texture) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND(!light);
+
+ if (light->projector == p_texture) {
+ return;
+ }
+
+ if (light->type != RS::LIGHT_DIRECTIONAL && light->projector.is_valid()) {
+ texture_storage->texture_remove_from_decal_atlas(light->projector, light->type == RS::LIGHT_OMNI);
+ }
+
+ light->projector = p_texture;
+
+ if (light->type != RS::LIGHT_DIRECTIONAL) {
+ if (light->projector.is_valid()) {
+ texture_storage->texture_add_to_decal_atlas(light->projector, light->type == RS::LIGHT_OMNI);
+ }
+ light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR);
+ }
+}
+
+void LightStorage::light_set_negative(RID p_light, bool p_enable) {
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->negative = p_enable;
+}
+
+void LightStorage::light_set_cull_mask(RID p_light, uint32_t p_mask) {
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->cull_mask = p_mask;
+
+ light->version++;
+ light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT);
+}
+
+void LightStorage::light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) {
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->distance_fade = p_enabled;
+ light->distance_fade_begin = p_begin;
+ light->distance_fade_shadow = p_shadow;
+ light->distance_fade_length = p_length;
+}
+
+void LightStorage::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) {
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->reverse_cull = p_enabled;
+
+ light->version++;
+ light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT);
+}
+
+void LightStorage::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) {
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->bake_mode = p_bake_mode;
+
+ light->version++;
+ light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT);
+}
+
+void LightStorage::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) {
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->omni_shadow_mode = p_mode;
+
+ light->version++;
+ light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT);
+}
+
+RS::LightOmniShadowMode LightStorage::light_omni_get_shadow_mode(RID p_light) {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_OMNI_SHADOW_CUBE);
+
+ return light->omni_shadow_mode;
+}
+
+void LightStorage::light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) {
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->directional_shadow_mode = p_mode;
+ light->version++;
+ light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT);
+}
+
+void LightStorage::light_directional_set_blend_splits(RID p_light, bool p_enable) {
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->directional_blend_splits = p_enable;
+ light->version++;
+ light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT);
+}
+
+bool LightStorage::light_directional_get_blend_splits(RID p_light) const {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, false);
+
+ return light->directional_blend_splits;
+}
+
+void LightStorage::light_directional_set_sky_mode(RID p_light, RS::LightDirectionalSkyMode p_mode) {
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->directional_sky_mode = p_mode;
+}
+
+RS::LightDirectionalSkyMode LightStorage::light_directional_get_sky_mode(RID p_light) const {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_AND_SKY);
+
+ return light->directional_sky_mode;
+}
+
+RS::LightDirectionalShadowMode LightStorage::light_directional_get_shadow_mode(RID p_light) {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
+
+ return light->directional_shadow_mode;
+}
+
+RS::LightBakeMode LightStorage::light_get_bake_mode(RID p_light) {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_BAKE_DISABLED);
+
+ return light->bake_mode;
+}
+
+uint64_t LightStorage::light_get_version(RID p_light) const {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, 0);
+
+ return light->version;
+}
+
+AABB LightStorage::light_get_aabb(RID p_light) const {
+ const Light *light = light_owner.get_or_null(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 LightStorage::reflection_probe_allocate() {
+ return RID();
+}
+
+void LightStorage::reflection_probe_initialize(RID p_rid) {
+}
+
+void LightStorage::reflection_probe_free(RID p_rid) {
+}
+
+void LightStorage::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) {
+}
+
+void LightStorage::reflection_probe_set_intensity(RID p_probe, float p_intensity) {
+}
+
+void LightStorage::reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) {
+}
+
+void LightStorage::reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) {
+}
+
+void LightStorage::reflection_probe_set_ambient_energy(RID p_probe, float p_energy) {
+}
+
+void LightStorage::reflection_probe_set_max_distance(RID p_probe, float p_distance) {
+}
+
+void LightStorage::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) {
+}
+
+void LightStorage::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) {
+}
+
+void LightStorage::reflection_probe_set_as_interior(RID p_probe, bool p_enable) {
+}
+
+void LightStorage::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {
+}
+
+void LightStorage::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) {
+}
+
+void LightStorage::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) {
+}
+
+void LightStorage::reflection_probe_set_resolution(RID p_probe, int p_resolution) {
+}
+
+AABB LightStorage::reflection_probe_get_aabb(RID p_probe) const {
+ return AABB();
+}
+
+RS::ReflectionProbeUpdateMode LightStorage::reflection_probe_get_update_mode(RID p_probe) const {
+ return RenderingServer::REFLECTION_PROBE_UPDATE_ONCE;
+}
+
+uint32_t LightStorage::reflection_probe_get_cull_mask(RID p_probe) const {
+ return 0;
+}
+
+Vector3 LightStorage::reflection_probe_get_extents(RID p_probe) const {
+ return Vector3();
+}
+
+Vector3 LightStorage::reflection_probe_get_origin_offset(RID p_probe) const {
+ return Vector3();
+}
+
+float LightStorage::reflection_probe_get_origin_max_distance(RID p_probe) const {
+ return 0.0;
+}
+
+bool LightStorage::reflection_probe_renders_shadows(RID p_probe) const {
+ return false;
+}
+
+void LightStorage::reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) {
+}
+
+float LightStorage::reflection_probe_get_mesh_lod_threshold(RID p_probe) const {
+ return 0.0;
+}
+
+/* LIGHTMAP CAPTURE */
+
+RID LightStorage::lightmap_allocate() {
+ return RID();
+}
+
+void LightStorage::lightmap_initialize(RID p_rid) {
+}
+
+void LightStorage::lightmap_free(RID p_rid) {
+}
+
+void LightStorage::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) {
+}
+
+void LightStorage::lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) {
+}
+
+void LightStorage::lightmap_set_probe_interior(RID p_lightmap, bool p_interior) {
+}
+
+void LightStorage::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) {
+}
+
+PackedVector3Array LightStorage::lightmap_get_probe_capture_points(RID p_lightmap) const {
+ return PackedVector3Array();
+}
+
+PackedColorArray LightStorage::lightmap_get_probe_capture_sh(RID p_lightmap) const {
+ return PackedColorArray();
+}
+
+PackedInt32Array LightStorage::lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const {
+ return PackedInt32Array();
+}
+
+PackedInt32Array LightStorage::lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const {
+ return PackedInt32Array();
+}
+
+AABB LightStorage::lightmap_get_aabb(RID p_lightmap) const {
+ return AABB();
+}
+
+void LightStorage::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) {
+}
+
+bool LightStorage::lightmap_is_interior(RID p_lightmap) const {
+ return false;
+}
+
+void LightStorage::lightmap_set_probe_capture_update_speed(float p_speed) {
+}
+
+float LightStorage::lightmap_get_probe_capture_update_speed() const {
+ return 0;
+}
+
+/* LIGHT SHADOW MAPPING */
+/*
+
+RID LightStorage::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 LightStorage::canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines) {
+ CanvasOccluder *co = canvas_occluder_owner.get(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()) {
+ PoolVector<float> geometry;
+ PoolVector<uint16_t> indices;
+ int lc = p_lines.size();
+
+ geometry.resize(lc * 6);
+ indices.resize(lc * 3);
+
+ PoolVector<float>::Write vw = geometry.write();
+ PoolVector<uint16_t>::Write iw = indices.write();
+
+ PoolVector<Vector2>::Read lr = p_lines.read();
+
+ 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;
+ }
+}
+*/
+
+#endif // !GLES3_ENABLED
diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h
new file mode 100644
index 0000000000..857a0261fa
--- /dev/null
+++ b/drivers/gles3/storage/light_storage.h
@@ -0,0 +1,347 @@
+/*************************************************************************/
+/* light_storage.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef LIGHT_STORAGE_GLES3_H
+#define LIGHT_STORAGE_GLES3_H
+
+#ifdef GLES3_ENABLED
+
+#include "core/templates/local_vector.h"
+#include "core/templates/rid_owner.h"
+#include "core/templates/self_list.h"
+#include "servers/rendering/renderer_compositor.h"
+#include "servers/rendering/storage/light_storage.h"
+#include "servers/rendering/storage/utilities.h"
+
+#include "platform_config.h"
+#ifndef OPENGL_INCLUDE_H
+#include <GLES3/gl3.h>
+#else
+#include OPENGL_INCLUDE_H
+#endif
+
+namespace GLES3 {
+
+/* LIGHT */
+
+struct Light {
+ RS::LightType type;
+ float param[RS::LIGHT_PARAM_MAX];
+ Color color = Color(1, 1, 1, 1);
+ RID projector;
+ bool shadow = false;
+ bool negative = false;
+ bool reverse_cull = false;
+ RS::LightBakeMode bake_mode = RS::LIGHT_BAKE_DYNAMIC;
+ uint32_t max_sdfgi_cascade = 2;
+ uint32_t cull_mask = 0xFFFFFFFF;
+ bool distance_fade = false;
+ real_t distance_fade_begin = 40.0;
+ real_t distance_fade_shadow = 50.0;
+ real_t distance_fade_length = 10.0;
+ RS::LightOmniShadowMode omni_shadow_mode = RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
+ RS::LightDirectionalShadowMode directional_shadow_mode = RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
+ bool directional_blend_splits = false;
+ RS::LightDirectionalSkyMode directional_sky_mode = RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_AND_SKY;
+ uint64_t version = 0;
+
+ Dependency dependency;
+};
+
+/* REFLECTION PROBE */
+
+struct ReflectionProbe {
+ RS::ReflectionProbeUpdateMode update_mode = RS::REFLECTION_PROBE_UPDATE_ONCE;
+ int resolution = 256;
+ float intensity = 1.0;
+ RS::ReflectionProbeAmbientMode ambient_mode = RS::REFLECTION_PROBE_AMBIENT_ENVIRONMENT;
+ Color ambient_color;
+ float ambient_color_energy = 1.0;
+ float max_distance = 0;
+ Vector3 extents = Vector3(1, 1, 1);
+ Vector3 origin_offset;
+ bool interior = false;
+ bool box_projection = false;
+ bool enable_shadows = false;
+ uint32_t cull_mask = (1 << 20) - 1;
+ float mesh_lod_threshold = 0.01;
+
+ Dependency dependency;
+};
+
+/* LIGHTMAP */
+
+struct Lightmap {
+ RID light_texture;
+ bool uses_spherical_harmonics = false;
+ bool interior = false;
+ AABB bounds = AABB(Vector3(), Vector3(1, 1, 1));
+ int32_t array_index = -1; //unassigned
+ PackedVector3Array points;
+ PackedColorArray point_sh;
+ PackedInt32Array tetrahedra;
+ PackedInt32Array bsp_tree;
+
+ struct BSP {
+ static const int32_t EMPTY_LEAF = INT32_MIN;
+ float plane[4];
+ int32_t over = EMPTY_LEAF, under = EMPTY_LEAF;
+ };
+
+ Dependency dependency;
+};
+
+class LightStorage : public RendererLightStorage {
+private:
+ static LightStorage *singleton;
+
+ /* LIGHT */
+ mutable RID_Owner<Light, true> light_owner;
+
+ /* REFLECTION PROBE */
+ mutable RID_Owner<ReflectionProbe, true> reflection_probe_owner;
+
+ /* LIGHTMAP */
+
+ Vector<RID> lightmap_textures;
+
+ mutable RID_Owner<Lightmap, true> lightmap_owner;
+
+public:
+ static LightStorage *get_singleton();
+
+ LightStorage();
+ virtual ~LightStorage();
+
+ /* Light API */
+
+ Light *get_light(RID p_rid) { return light_owner.get_or_null(p_rid); };
+ bool owns_light(RID p_rid) { return light_owner.owns(p_rid); };
+
+ void _light_initialize(RID p_rid, RS::LightType p_type);
+
+ virtual RID directional_light_allocate() override;
+ virtual void directional_light_initialize(RID p_rid) override;
+ virtual RID omni_light_allocate() override;
+ virtual void omni_light_initialize(RID p_rid) override;
+ virtual RID spot_light_allocate() override;
+ virtual void spot_light_initialize(RID p_rid) override;
+
+ virtual void light_free(RID p_rid) override;
+
+ virtual void light_set_color(RID p_light, const Color &p_color) override;
+ virtual void light_set_param(RID p_light, RS::LightParam p_param, float p_value) override;
+ virtual void light_set_shadow(RID p_light, bool p_enabled) override;
+ virtual void light_set_projector(RID p_light, RID p_texture) override;
+ virtual void light_set_negative(RID p_light, bool p_enable) override;
+ virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) override;
+ virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) override;
+ virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) override;
+ virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) override;
+ virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) override {}
+
+ virtual void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) override;
+
+ virtual void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) override;
+ virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) override;
+ virtual bool light_directional_get_blend_splits(RID p_light) const override;
+ virtual void light_directional_set_sky_mode(RID p_light, RS::LightDirectionalSkyMode p_mode) override;
+ virtual RS::LightDirectionalSkyMode light_directional_get_sky_mode(RID p_light) const override;
+
+ virtual RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) override;
+ virtual RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) override;
+ virtual RS::LightType light_get_type(RID p_light) const override {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+
+ return light->type;
+ }
+ virtual AABB light_get_aabb(RID p_light) const override;
+
+ virtual float light_get_param(RID p_light, RS::LightParam p_param) override {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, 0);
+
+ return light->param[p_param];
+ }
+
+ _FORCE_INLINE_ RID light_get_projector(RID p_light) {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, RID());
+
+ return light->projector;
+ }
+
+ virtual Color light_get_color(RID p_light) override {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, Color());
+
+ return light->color;
+ }
+
+ _FORCE_INLINE_ uint32_t light_get_cull_mask(RID p_light) {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, 0);
+
+ return light->cull_mask;
+ }
+
+ _FORCE_INLINE_ bool light_is_distance_fade_enabled(RID p_light) {
+ const Light *light = light_owner.get_or_null(p_light);
+ return light->distance_fade;
+ }
+
+ _FORCE_INLINE_ float light_get_distance_fade_begin(RID p_light) {
+ const Light *light = light_owner.get_or_null(p_light);
+ return light->distance_fade_begin;
+ }
+
+ _FORCE_INLINE_ float light_get_distance_fade_shadow(RID p_light) {
+ const Light *light = light_owner.get_or_null(p_light);
+ return light->distance_fade_shadow;
+ }
+
+ _FORCE_INLINE_ float light_get_distance_fade_length(RID p_light) {
+ const Light *light = light_owner.get_or_null(p_light);
+ return light->distance_fade_length;
+ }
+
+ virtual bool light_has_shadow(RID p_light) const override {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+
+ return light->shadow;
+ }
+
+ virtual bool light_has_projector(RID p_light) const override {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+
+ return light_owner.owns(light->projector);
+ }
+
+ _FORCE_INLINE_ bool light_is_negative(RID p_light) const {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+
+ return light->negative;
+ }
+
+ _FORCE_INLINE_ float light_get_transmittance_bias(RID p_light) const {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, 0.0);
+
+ return light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS];
+ }
+
+ _FORCE_INLINE_ float light_get_shadow_volumetric_fog_fade(RID p_light) const {
+ const Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND_V(!light, 0.0);
+
+ return light->param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE];
+ }
+
+ virtual RS::LightBakeMode light_get_bake_mode(RID p_light) override;
+ virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) override { return 0; }
+ virtual uint64_t light_get_version(RID p_light) const override;
+
+ /* PROBE API */
+
+ virtual RID reflection_probe_allocate() override;
+ virtual void reflection_probe_initialize(RID p_rid) override;
+ virtual void reflection_probe_free(RID p_rid) override;
+
+ virtual void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) override;
+ virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity) override;
+ virtual void reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) override;
+ virtual void reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) override;
+ virtual void reflection_probe_set_ambient_energy(RID p_probe, float p_energy) override;
+ virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance) override;
+ virtual void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) override;
+ virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) override;
+ virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable) override;
+ virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) override;
+ virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) override;
+ virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) override;
+ virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) override;
+ virtual void reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) override;
+ virtual float reflection_probe_get_mesh_lod_threshold(RID p_probe) const override;
+
+ virtual AABB reflection_probe_get_aabb(RID p_probe) const override;
+ virtual RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const override;
+ virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const override;
+ virtual Vector3 reflection_probe_get_extents(RID p_probe) const override;
+ virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const override;
+ virtual float reflection_probe_get_origin_max_distance(RID p_probe) const override;
+ virtual bool reflection_probe_renders_shadows(RID p_probe) const override;
+
+ /* LIGHTMAP CAPTURE */
+
+ virtual RID lightmap_allocate() override;
+ virtual void lightmap_initialize(RID p_rid) override;
+ virtual void lightmap_free(RID p_rid) override;
+
+ virtual void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) override;
+ virtual void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) override;
+ virtual void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) override;
+ virtual void lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) override;
+ virtual PackedVector3Array lightmap_get_probe_capture_points(RID p_lightmap) const override;
+ virtual PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const override;
+ virtual PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const override;
+ virtual PackedInt32Array lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const override;
+ virtual AABB lightmap_get_aabb(RID p_lightmap) const override;
+ virtual void lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) override;
+ virtual bool lightmap_is_interior(RID p_lightmap) const override;
+ virtual void lightmap_set_probe_capture_update_speed(float p_speed) override;
+ virtual float lightmap_get_probe_capture_update_speed() const override;
+
+ /* LIGHT SHADOW MAPPING */
+ /*
+ struct CanvasOccluder {
+ RID self;
+
+ GLuint vertex_id; // 0 means, unconfigured
+ GLuint index_id; // 0 means, unconfigured
+ LocalVector<Vector2> lines;
+ int len;
+ };
+
+ RID_Owner<CanvasOccluder> canvas_occluder_owner;
+
+ RID canvas_light_occluder_create();
+ void canvas_light_occluder_set_polylines(RID p_occluder, const LocalVector<Vector2> &p_lines);
+ */
+};
+
+} // namespace GLES3
+
+#endif // GLES3_ENABLED
+
+#endif // LIGHT_STORAGE_GLES3_H
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
new file mode 100644
index 0000000000..26441fc726
--- /dev/null
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -0,0 +1,3577 @@
+/*************************************************************************/
+/* material_storage.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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. */
+/*************************************************************************/
+
+#ifdef GLES3_ENABLED
+
+#include "core/config/project_settings.h"
+
+#include "config.h"
+#include "material_storage.h"
+#include "texture_storage.h"
+
+#include "drivers/gles3/rasterizer_canvas_gles3.h"
+
+using namespace GLES3;
+
+///////////////////////////////////////////////////////////////////////////
+// UBI helper functions
+
+_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, int p_array_size, const Variant &value, uint8_t *data) {
+ switch (type) {
+ case ShaderLanguage::TYPE_BOOL: {
+ uint32_t *gui = (uint32_t *)data;
+
+ if (p_array_size > 0) {
+ const PackedInt32Array &ba = value;
+ int s = ba.size();
+ const int *r = ba.ptr();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = (r[i] != 0) ? 1 : 0;
+ } else {
+ gui[j] = 0;
+ }
+ gui[j + 1] = 0; // ignored
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ bool v = value;
+ gui[0] = v ? 1 : 0;
+ }
+ } break;
+ case ShaderLanguage::TYPE_BVEC2: {
+ uint32_t *gui = (uint32_t *)data;
+
+ if (p_array_size > 0) {
+ const PackedInt32Array &ba = value;
+ int s = ba.size();
+ const int *r = ba.ptr();
+ int count = 2 * p_array_size;
+
+ for (int i = 0, j = 0; i < count; i += 2, j += 4) {
+ if (i < s) {
+ gui[j] = r[i] ? 1 : 0;
+ gui[j + 1] = r[i + 1] ? 1 : 0;
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ }
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ int v = value;
+ gui[0] = v & 1 ? 1 : 0;
+ gui[1] = v & 2 ? 1 : 0;
+ }
+ } break;
+ case ShaderLanguage::TYPE_BVEC3: {
+ uint32_t *gui = (uint32_t *)data;
+
+ if (p_array_size > 0) {
+ const PackedInt32Array &ba = value;
+ int s = ba.size();
+ const int *r = ba.ptr();
+ int count = 3 * p_array_size;
+
+ for (int i = 0, j = 0; i < count; i += 3, j += 4) {
+ if (i < s) {
+ gui[j] = r[i] ? 1 : 0;
+ gui[j + 1] = r[i + 1] ? 1 : 0;
+ gui[j + 2] = r[i + 2] ? 1 : 0;
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
+ }
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ int v = value;
+ gui[0] = (v & 1) ? 1 : 0;
+ gui[1] = (v & 2) ? 1 : 0;
+ gui[2] = (v & 4) ? 1 : 0;
+ }
+ } break;
+ case ShaderLanguage::TYPE_BVEC4: {
+ uint32_t *gui = (uint32_t *)data;
+
+ if (p_array_size > 0) {
+ const PackedInt32Array &ba = value;
+ int s = ba.size();
+ const int *r = ba.ptr();
+ int count = 4 * p_array_size;
+
+ for (int i = 0; i < count; i += 4) {
+ if (i < s) {
+ gui[i] = r[i] ? 1 : 0;
+ gui[i + 1] = r[i + 1] ? 1 : 0;
+ gui[i + 2] = r[i + 2] ? 1 : 0;
+ gui[i + 3] = r[i + 3] ? 1 : 0;
+ } else {
+ gui[i] = 0;
+ gui[i + 1] = 0;
+ gui[i + 2] = 0;
+ gui[i + 3] = 0;
+ }
+ }
+ } else {
+ int v = value;
+ gui[0] = (v & 1) ? 1 : 0;
+ gui[1] = (v & 2) ? 1 : 0;
+ gui[2] = (v & 4) ? 1 : 0;
+ gui[3] = (v & 8) ? 1 : 0;
+ }
+ } break;
+ case ShaderLanguage::TYPE_INT: {
+ int32_t *gui = (int32_t *)data;
+
+ if (p_array_size > 0) {
+ Vector<int> iv = value;
+ int s = iv.size();
+ const int *r = iv.ptr();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = r[i];
+ } else {
+ gui[j] = 0;
+ }
+ gui[j + 1] = 0; // ignored
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ int v = value;
+ gui[0] = v;
+ }
+ } break;
+ case ShaderLanguage::TYPE_IVEC2: {
+ int32_t *gui = (int32_t *)data;
+ if (p_array_size > 0) {
+ Vector<int> iv = value;
+ int s = iv.size();
+ int count = 2 * p_array_size;
+
+ const int *r = iv.ptr();
+ for (int i = 0, j = 0; i < count; i += 2, j += 4) {
+ if (i < s) {
+ gui[j] = r[i];
+ gui[j + 1] = r[i + 1];
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ }
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ Vector2i v = value;
+ gui[0] = v.x;
+ gui[1] = v.y;
+ }
+ } break;
+ case ShaderLanguage::TYPE_IVEC3: {
+ int32_t *gui = (int32_t *)data;
+
+ if (p_array_size > 0) {
+ Vector<int> iv = value;
+ int s = iv.size();
+ int count = 3 * p_array_size;
+
+ const int *r = iv.ptr();
+ for (int i = 0, j = 0; i < count; i += 3, j += 4) {
+ if (i < s) {
+ gui[j] = r[i];
+ gui[j + 1] = r[i + 1];
+ gui[j + 2] = r[i + 2];
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
+ }
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ Vector3i v = value;
+ gui[0] = v.x;
+ gui[1] = v.y;
+ gui[2] = v.z;
+ }
+ } break;
+ case ShaderLanguage::TYPE_IVEC4: {
+ int32_t *gui = (int32_t *)data;
+
+ if (p_array_size > 0) {
+ Vector<int> iv = value;
+ int s = iv.size();
+ int count = 4 * p_array_size;
+
+ const int *r = iv.ptr();
+ for (int i = 0; i < count; i += 4) {
+ if (i < s) {
+ gui[i] = r[i];
+ gui[i + 1] = r[i + 1];
+ gui[i + 2] = r[i + 2];
+ gui[i + 3] = r[i + 3];
+ } else {
+ gui[i] = 0;
+ gui[i + 1] = 0;
+ gui[i + 2] = 0;
+ gui[i + 3] = 0;
+ }
+ }
+ } else {
+ Vector4i v = value;
+ gui[0] = v.x;
+ gui[1] = v.y;
+ gui[2] = v.z;
+ gui[3] = v.w;
+ }
+ } break;
+ case ShaderLanguage::TYPE_UINT: {
+ uint32_t *gui = (uint32_t *)data;
+
+ if (p_array_size > 0) {
+ Vector<int> iv = value;
+ int s = iv.size();
+ const int *r = iv.ptr();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = r[i];
+ } else {
+ gui[j] = 0;
+ }
+ gui[j + 1] = 0; // ignored
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ int v = value;
+ gui[0] = v;
+ }
+ } break;
+ case ShaderLanguage::TYPE_UVEC2: {
+ uint32_t *gui = (uint32_t *)data;
+ if (p_array_size > 0) {
+ Vector<int> iv = value;
+ int s = iv.size();
+ int count = 2 * p_array_size;
+
+ const int *r = iv.ptr();
+ for (int i = 0, j = 0; i < count; i += 2, j += 4) {
+ if (i < s) {
+ gui[j] = r[i];
+ gui[j + 1] = r[i + 1];
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ }
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ Vector2i v = value;
+ gui[0] = v.x;
+ gui[1] = v.y;
+ }
+ } break;
+ case ShaderLanguage::TYPE_UVEC3: {
+ uint32_t *gui = (uint32_t *)data;
+
+ if (p_array_size > 0) {
+ Vector<int> iv = value;
+ int s = iv.size();
+ int count = 3 * p_array_size;
+
+ const int *r = iv.ptr();
+ for (int i = 0, j = 0; i < count; i += 3, j += 4) {
+ if (i < s) {
+ gui[j] = r[i];
+ gui[j + 1] = r[i + 1];
+ gui[j + 2] = r[i + 2];
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
+ }
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ Vector3i v = value;
+ gui[0] = v.x;
+ gui[1] = v.y;
+ gui[2] = v.z;
+ }
+ } break;
+ case ShaderLanguage::TYPE_UVEC4: {
+ uint32_t *gui = (uint32_t *)data;
+
+ if (p_array_size > 0) {
+ Vector<int> iv = value;
+ int s = iv.size();
+ int count = 4 * p_array_size;
+
+ const int *r = iv.ptr();
+ for (int i = 0; i < count; i++) {
+ if (i < s) {
+ gui[i] = r[i];
+ gui[i + 1] = r[i + 1];
+ gui[i + 2] = r[i + 2];
+ gui[i + 3] = r[i + 3];
+ } else {
+ gui[i] = 0;
+ gui[i + 1] = 0;
+ gui[i + 2] = 0;
+ gui[i + 3] = 0;
+ }
+ }
+ } else {
+ Vector4i v = value;
+ gui[0] = v.x;
+ gui[1] = v.y;
+ gui[2] = v.z;
+ gui[3] = v.w;
+ }
+ } break;
+ case ShaderLanguage::TYPE_FLOAT: {
+ float *gui = (float *)data;
+
+ if (p_array_size > 0) {
+ const PackedFloat32Array &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = a[i];
+ } else {
+ gui[j] = 0;
+ }
+ gui[j + 1] = 0; // ignored
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ float v = value;
+ gui[0] = v;
+ }
+ } break;
+ case ShaderLanguage::TYPE_VEC2: {
+ float *gui = (float *)data;
+
+ if (p_array_size > 0) {
+ const PackedVector2Array &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = a[i].x;
+ gui[j + 1] = a[i].y;
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ }
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ Vector2 v = value;
+ gui[0] = v.x;
+ gui[1] = v.y;
+ }
+ } break;
+ case ShaderLanguage::TYPE_VEC3: {
+ float *gui = (float *)data;
+
+ if (p_array_size > 0) {
+ if (value.get_type() == Variant::PACKED_COLOR_ARRAY) {
+ const PackedColorArray &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ Color color = a[i];
+ gui[j] = color.r;
+ gui[j + 1] = color.g;
+ gui[j + 2] = color.b;
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
+ }
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ const PackedVector3Array &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = a[i].x;
+ gui[j + 1] = a[i].y;
+ gui[j + 2] = a[i].z;
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
+ }
+ gui[j + 3] = 0; // ignored
+ }
+ }
+ } else {
+ if (value.get_type() == Variant::COLOR) {
+ Color v = value;
+
+ gui[0] = v.r;
+ gui[1] = v.g;
+ gui[2] = v.b;
+ } else {
+ Vector3 v = value;
+ gui[0] = v.x;
+ gui[1] = v.y;
+ gui[2] = v.z;
+ }
+ }
+ } break;
+ case ShaderLanguage::TYPE_VEC4: {
+ float *gui = (float *)data;
+
+ if (p_array_size > 0) {
+ if (value.get_type() == Variant::PACKED_COLOR_ARRAY) {
+ const PackedColorArray &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ Color color = a[i];
+ gui[j] = color.r;
+ gui[j + 1] = color.g;
+ gui[j + 2] = color.b;
+ gui[j + 3] = color.a;
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
+ gui[j + 3] = 0;
+ }
+ }
+ } else {
+ const PackedFloat32Array &a = value;
+ int s = a.size();
+ int count = 4 * p_array_size;
+
+ for (int i = 0; i < count; i += 4) {
+ if (i + 3 < s) {
+ gui[i] = a[i];
+ gui[i + 1] = a[i + 1];
+ gui[i + 2] = a[i + 2];
+ gui[i + 3] = a[i + 3];
+ } else {
+ gui[i] = 0;
+ gui[i + 1] = 0;
+ gui[i + 2] = 0;
+ gui[i + 3] = 0;
+ }
+ }
+ }
+ } else {
+ if (value.get_type() == Variant::COLOR) {
+ Color v = value;
+
+ gui[0] = v.r;
+ gui[1] = v.g;
+ gui[2] = v.b;
+ gui[3] = v.a;
+ } else if (value.get_type() == Variant::RECT2) {
+ Rect2 v = value;
+
+ gui[0] = v.position.x;
+ gui[1] = v.position.y;
+ gui[2] = v.size.x;
+ gui[3] = v.size.y;
+ } else if (value.get_type() == Variant::QUATERNION) {
+ Quaternion v = value;
+
+ gui[0] = v.x;
+ gui[1] = v.y;
+ gui[2] = v.z;
+ gui[3] = v.w;
+ } else if (value.get_type() == Variant::VECTOR4) {
+ Vector4 v = value;
+
+ gui[0] = v.x;
+ gui[1] = v.y;
+ gui[2] = v.z;
+ gui[3] = v.w;
+ } else {
+ Plane v = value;
+
+ gui[0] = v.normal.x;
+ gui[1] = v.normal.y;
+ gui[2] = v.normal.z;
+ gui[3] = v.d;
+ }
+ }
+ } break;
+ case ShaderLanguage::TYPE_MAT2: {
+ float *gui = (float *)data;
+
+ if (p_array_size > 0) {
+ const PackedFloat32Array &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size * 4; i += 4, j += 8) {
+ if (i + 3 < s) {
+ gui[j] = a[i];
+ gui[j + 1] = a[i + 1];
+
+ gui[j + 4] = a[i + 2];
+ gui[j + 5] = a[i + 3];
+ } else {
+ gui[j] = 1;
+ gui[j + 1] = 0;
+
+ gui[j + 4] = 0;
+ gui[j + 5] = 1;
+ }
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ gui[j + 6] = 0; // ignored
+ gui[j + 7] = 0; // ignored
+ }
+ } else {
+ Transform2D v = value;
+
+ //in std140 members of mat2 are treated as vec4s
+ gui[0] = v.columns[0][0];
+ gui[1] = v.columns[0][1];
+ gui[2] = 0; // ignored
+ gui[3] = 0; // ignored
+
+ gui[4] = v.columns[1][0];
+ gui[5] = v.columns[1][1];
+ gui[6] = 0; // ignored
+ gui[7] = 0; // ignored
+ }
+ } break;
+ case ShaderLanguage::TYPE_MAT3: {
+ float *gui = (float *)data;
+
+ if (p_array_size > 0) {
+ const PackedFloat32Array &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size * 9; i += 9, j += 12) {
+ if (i + 8 < s) {
+ gui[j] = a[i];
+ gui[j + 1] = a[i + 1];
+ gui[j + 2] = a[i + 2];
+
+ gui[j + 4] = a[i + 3];
+ gui[j + 5] = a[i + 4];
+ gui[j + 6] = a[i + 5];
+
+ gui[j + 8] = a[i + 6];
+ gui[j + 9] = a[i + 7];
+ gui[j + 10] = a[i + 8];
+ } else {
+ gui[j] = 1;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
+
+ gui[j + 4] = 0;
+ gui[j + 5] = 1;
+ gui[j + 6] = 0;
+
+ gui[j + 8] = 0;
+ gui[j + 9] = 0;
+ gui[j + 10] = 1;
+ }
+ gui[j + 3] = 0; // ignored
+ gui[j + 7] = 0; // ignored
+ gui[j + 11] = 0; // ignored
+ }
+ } else {
+ Basis v = value;
+ gui[0] = v.rows[0][0];
+ gui[1] = v.rows[1][0];
+ gui[2] = v.rows[2][0];
+ gui[3] = 0; // ignored
+
+ gui[4] = v.rows[0][1];
+ gui[5] = v.rows[1][1];
+ gui[6] = v.rows[2][1];
+ gui[7] = 0; // ignored
+
+ gui[8] = v.rows[0][2];
+ gui[9] = v.rows[1][2];
+ gui[10] = v.rows[2][2];
+ gui[11] = 0; // ignored
+ }
+ } break;
+ case ShaderLanguage::TYPE_MAT4: {
+ float *gui = (float *)data;
+
+ if (p_array_size > 0) {
+ const PackedFloat32Array &a = value;
+ int s = a.size();
+
+ for (int i = 0; i < p_array_size * 16; i += 16) {
+ if (i + 15 < s) {
+ gui[i] = a[i];
+ gui[i + 1] = a[i + 1];
+ gui[i + 2] = a[i + 2];
+ gui[i + 3] = a[i + 3];
+
+ gui[i + 4] = a[i + 4];
+ gui[i + 5] = a[i + 5];
+ gui[i + 6] = a[i + 6];
+ gui[i + 7] = a[i + 7];
+
+ gui[i + 8] = a[i + 8];
+ gui[i + 9] = a[i + 9];
+ gui[i + 10] = a[i + 10];
+ gui[i + 11] = a[i + 11];
+
+ gui[i + 12] = a[i + 12];
+ gui[i + 13] = a[i + 13];
+ gui[i + 14] = a[i + 14];
+ gui[i + 15] = a[i + 15];
+ } else {
+ gui[i] = 1;
+ gui[i + 1] = 0;
+ gui[i + 2] = 0;
+ gui[i + 3] = 0;
+
+ gui[i + 4] = 0;
+ gui[i + 5] = 1;
+ gui[i + 6] = 0;
+ gui[i + 7] = 0;
+
+ gui[i + 8] = 0;
+ gui[i + 9] = 0;
+ gui[i + 10] = 1;
+ gui[i + 11] = 0;
+
+ gui[i + 12] = 0;
+ gui[i + 13] = 0;
+ gui[i + 14] = 0;
+ gui[i + 15] = 1;
+ }
+ }
+ } else if (value.get_type() == Variant::TRANSFORM3D) {
+ Transform3D v = value;
+ gui[0] = v.basis.rows[0][0];
+ gui[1] = v.basis.rows[1][0];
+ gui[2] = v.basis.rows[2][0];
+ gui[3] = 0;
+
+ gui[4] = v.basis.rows[0][1];
+ gui[5] = v.basis.rows[1][1];
+ gui[6] = v.basis.rows[2][1];
+ gui[7] = 0;
+
+ gui[8] = v.basis.rows[0][2];
+ gui[9] = v.basis.rows[1][2];
+ gui[10] = v.basis.rows[2][2];
+ gui[11] = 0;
+
+ gui[12] = v.origin.x;
+ gui[13] = v.origin.y;
+ gui[14] = v.origin.z;
+ gui[15] = 1;
+ } else {
+ Projection v = value;
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ gui[i * 4 + j] = v.matrix[i][j];
+ }
+ }
+ }
+ } break;
+ default: {
+ }
+ }
+}
+
+_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector<ShaderLanguage::ConstantNode::Value> &value, uint8_t *data) {
+ switch (type) {
+ case ShaderLanguage::TYPE_BOOL: {
+ uint32_t *gui = (uint32_t *)data;
+ *gui = value[0].boolean ? 1 : 0;
+ } break;
+ case ShaderLanguage::TYPE_BVEC2: {
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = value[0].boolean ? 1 : 0;
+ gui[1] = value[1].boolean ? 1 : 0;
+
+ } break;
+ case ShaderLanguage::TYPE_BVEC3: {
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = value[0].boolean ? 1 : 0;
+ gui[1] = value[1].boolean ? 1 : 0;
+ gui[2] = value[2].boolean ? 1 : 0;
+
+ } break;
+ case ShaderLanguage::TYPE_BVEC4: {
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = value[0].boolean ? 1 : 0;
+ gui[1] = value[1].boolean ? 1 : 0;
+ gui[2] = value[2].boolean ? 1 : 0;
+ gui[3] = value[3].boolean ? 1 : 0;
+
+ } break;
+ case ShaderLanguage::TYPE_INT: {
+ int32_t *gui = (int32_t *)data;
+ gui[0] = value[0].sint;
+
+ } break;
+ case ShaderLanguage::TYPE_IVEC2: {
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 2; i++) {
+ gui[i] = value[i].sint;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_IVEC3: {
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 3; i++) {
+ gui[i] = value[i].sint;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_IVEC4: {
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 4; i++) {
+ gui[i] = value[i].sint;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_UINT: {
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = value[0].uint;
+
+ } break;
+ case ShaderLanguage::TYPE_UVEC2: {
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 2; i++) {
+ gui[i] = value[i].uint;
+ }
+ } break;
+ case ShaderLanguage::TYPE_UVEC3: {
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 3; i++) {
+ gui[i] = value[i].uint;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_UVEC4: {
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 4; i++) {
+ gui[i] = value[i].uint;
+ }
+ } break;
+ case ShaderLanguage::TYPE_FLOAT: {
+ float *gui = (float *)data;
+ gui[0] = value[0].real;
+
+ } break;
+ case ShaderLanguage::TYPE_VEC2: {
+ float *gui = (float *)data;
+
+ for (int i = 0; i < 2; i++) {
+ gui[i] = value[i].real;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_VEC3: {
+ float *gui = (float *)data;
+
+ for (int i = 0; i < 3; i++) {
+ gui[i] = value[i].real;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_VEC4: {
+ float *gui = (float *)data;
+
+ for (int i = 0; i < 4; i++) {
+ gui[i] = value[i].real;
+ }
+ } break;
+ case ShaderLanguage::TYPE_MAT2: {
+ float *gui = (float *)data;
+
+ //in std140 members of mat2 are treated as vec4s
+ gui[0] = value[0].real;
+ gui[1] = value[1].real;
+ gui[2] = 0;
+ gui[3] = 0;
+ gui[4] = value[2].real;
+ gui[5] = value[3].real;
+ gui[6] = 0;
+ gui[7] = 0;
+ } break;
+ case ShaderLanguage::TYPE_MAT3: {
+ float *gui = (float *)data;
+
+ gui[0] = value[0].real;
+ gui[1] = value[1].real;
+ gui[2] = value[2].real;
+ gui[3] = 0;
+ gui[4] = value[3].real;
+ gui[5] = value[4].real;
+ gui[6] = value[5].real;
+ gui[7] = 0;
+ gui[8] = value[6].real;
+ gui[9] = value[7].real;
+ gui[10] = value[8].real;
+ gui[11] = 0;
+ } break;
+ case ShaderLanguage::TYPE_MAT4: {
+ float *gui = (float *)data;
+
+ for (int i = 0; i < 16; i++) {
+ gui[i] = value[i].real;
+ }
+ } break;
+ default: {
+ }
+ }
+}
+
+_FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, int p_array_size, uint8_t *data) {
+ if (p_array_size <= 0) {
+ p_array_size = 1;
+ }
+
+ switch (type) {
+ case ShaderLanguage::TYPE_BOOL:
+ case ShaderLanguage::TYPE_INT:
+ case ShaderLanguage::TYPE_UINT:
+ case ShaderLanguage::TYPE_FLOAT: {
+ memset(data, 0, 4 * p_array_size);
+ } break;
+ case ShaderLanguage::TYPE_BVEC2:
+ case ShaderLanguage::TYPE_IVEC2:
+ case ShaderLanguage::TYPE_UVEC2:
+ case ShaderLanguage::TYPE_VEC2: {
+ memset(data, 0, 8 * p_array_size);
+ } break;
+ case ShaderLanguage::TYPE_BVEC3:
+ case ShaderLanguage::TYPE_IVEC3:
+ case ShaderLanguage::TYPE_UVEC3:
+ case ShaderLanguage::TYPE_VEC3:
+ case ShaderLanguage::TYPE_BVEC4:
+ case ShaderLanguage::TYPE_IVEC4:
+ case ShaderLanguage::TYPE_UVEC4:
+ case ShaderLanguage::TYPE_VEC4: {
+ memset(data, 0, 16 * p_array_size);
+ } break;
+ case ShaderLanguage::TYPE_MAT2: {
+ memset(data, 0, 32 * p_array_size);
+ } break;
+ case ShaderLanguage::TYPE_MAT3: {
+ memset(data, 0, 48 * p_array_size);
+ } break;
+ case ShaderLanguage::TYPE_MAT4: {
+ memset(data, 0, 64 * p_array_size);
+ } break;
+
+ default: {
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// MaterialData
+
+// Look up table to translate ShaderLanguage::DataType to GL_TEXTURE_*
+static const GLenum target_from_type[ShaderLanguage::TYPE_MAX] = {
+ GL_TEXTURE_2D, // TYPE_VOID,
+ GL_TEXTURE_2D, // TYPE_BOOL,
+ GL_TEXTURE_2D, // TYPE_BVEC2,
+ GL_TEXTURE_2D, // TYPE_BVEC3,
+ GL_TEXTURE_2D, // TYPE_BVEC4,
+ GL_TEXTURE_2D, // TYPE_INT,
+ GL_TEXTURE_2D, // TYPE_IVEC2,
+ GL_TEXTURE_2D, // TYPE_IVEC3,
+ GL_TEXTURE_2D, // TYPE_IVEC4,
+ GL_TEXTURE_2D, // TYPE_UINT,
+ GL_TEXTURE_2D, // TYPE_UVEC2,
+ GL_TEXTURE_2D, // TYPE_UVEC3,
+ GL_TEXTURE_2D, // TYPE_UVEC4,
+ GL_TEXTURE_2D, // TYPE_FLOAT,
+ GL_TEXTURE_2D, // TYPE_VEC2,
+ GL_TEXTURE_2D, // TYPE_VEC3,
+ GL_TEXTURE_2D, // TYPE_VEC4,
+ GL_TEXTURE_2D, // TYPE_MAT2,
+ GL_TEXTURE_2D, // TYPE_MAT3,
+ GL_TEXTURE_2D, // TYPE_MAT4,
+ GL_TEXTURE_2D, // TYPE_SAMPLER2D,
+ GL_TEXTURE_2D, // TYPE_ISAMPLER2D,
+ GL_TEXTURE_2D, // TYPE_USAMPLER2D,
+ GL_TEXTURE_2D_ARRAY, // TYPE_SAMPLER2DARRAY,
+ GL_TEXTURE_2D_ARRAY, // TYPE_ISAMPLER2DARRAY,
+ GL_TEXTURE_2D_ARRAY, // TYPE_USAMPLER2DARRAY,
+ GL_TEXTURE_3D, // TYPE_SAMPLER3D,
+ GL_TEXTURE_3D, // TYPE_ISAMPLER3D,
+ GL_TEXTURE_3D, // TYPE_USAMPLER3D,
+ GL_TEXTURE_CUBE_MAP, // TYPE_SAMPLERCUBE,
+ GL_TEXTURE_CUBE_MAP, // TYPE_SAMPLERCUBEARRAY,
+ GL_TEXTURE_2D, // TYPE_STRUCT
+};
+
+void MaterialData::update_uniform_buffer(const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const HashMap<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) {
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+ bool uses_global_buffer = false;
+
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : p_uniforms) {
+ if (E.value.order < 0) {
+ continue; // texture, does not go here
+ }
+
+ if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue; //instance uniforms don't appear in the buffer
+ }
+
+ if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) {
+ //this is a global variable, get the index to it
+ GlobalShaderUniforms::Variable *gv = material_storage->global_shader_uniforms.variables.getptr(E.key);
+ uint32_t index = 0;
+ if (gv) {
+ index = gv->buffer_index;
+ } else {
+ WARN_PRINT("Shader uses global uniform '" + E.key + "', but it was removed at some point. Material will not display correctly.");
+ }
+
+ uint32_t offset = p_uniform_offsets[E.value.order];
+ uint32_t *intptr = (uint32_t *)&p_buffer[offset];
+ *intptr = index;
+ uses_global_buffer = true;
+ continue;
+ }
+
+ //regular uniform
+ uint32_t offset = p_uniform_offsets[E.value.order];
+#ifdef DEBUG_ENABLED
+ uint32_t size = 0U;
+ // The following code enforces a 16-byte alignment of uniform arrays.
+ if (E.value.array_size > 0) {
+ size = ShaderLanguage::get_datatype_size(E.value.type) * E.value.array_size;
+ int m = (16 * E.value.array_size);
+ if ((size % m) != 0U) {
+ size += m - (size % m);
+ }
+ } else {
+ size = ShaderLanguage::get_datatype_size(E.value.type);
+ }
+ ERR_CONTINUE(offset + size > p_buffer_size);
+#endif
+ uint8_t *data = &p_buffer[offset];
+ HashMap<StringName, Variant>::ConstIterator V = p_parameters.find(E.key);
+
+ if (V) {
+ //user provided
+ _fill_std140_variant_ubo_value(E.value.type, E.value.array_size, V->value, data);
+
+ } else if (E.value.default_value.size()) {
+ //default value
+ _fill_std140_ubo_value(E.value.type, E.value.default_value, data);
+ //value=E.value.default_value;
+ } else {
+ //zero because it was not provided
+ if ((E.value.type == ShaderLanguage::TYPE_VEC3 || E.value.type == ShaderLanguage::TYPE_VEC4) && E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SOURCE_COLOR) {
+ //colors must be set as black, with alpha as 1.0
+ _fill_std140_variant_ubo_value(E.value.type, E.value.array_size, Color(0, 0, 0, 1), data);
+ } else {
+ //else just zero it out
+ _fill_std140_ubo_empty(E.value.type, E.value.array_size, data);
+ }
+ }
+ }
+
+ if (uses_global_buffer != (global_buffer_E != nullptr)) {
+ if (uses_global_buffer) {
+ global_buffer_E = material_storage->global_shader_uniforms.materials_using_buffer.push_back(self);
+ } else {
+ material_storage->global_shader_uniforms.materials_using_buffer.erase(global_buffer_E);
+ global_buffer_E = nullptr;
+ }
+ }
+}
+
+MaterialData::~MaterialData() {
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+
+ if (global_buffer_E) {
+ //unregister global buffers
+ material_storage->global_shader_uniforms.materials_using_buffer.erase(global_buffer_E);
+ }
+
+ if (global_texture_E) {
+ //unregister global textures
+
+ for (const KeyValue<StringName, uint64_t> &E : used_global_textures) {
+ GlobalShaderUniforms::Variable *v = material_storage->global_shader_uniforms.variables.getptr(E.key);
+ if (v) {
+ v->texture_materials.erase(self);
+ }
+ }
+ //unregister material from those using global textures
+ material_storage->global_shader_uniforms.materials_using_texture.erase(global_texture_E);
+ }
+
+ if (uniform_buffer) {
+ glDeleteBuffers(1, &uniform_buffer);
+ uniform_buffer = 0;
+ }
+}
+
+void MaterialData::update_textures(const HashMap<StringName, Variant> &p_parameters, const HashMap<StringName, HashMap<int, RID>> &p_default_textures, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) {
+ TextureStorage *texture_storage = TextureStorage::get_singleton();
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+
+#ifdef TOOLS_ENABLED
+ Texture *roughness_detect_texture = nullptr;
+ RS::TextureDetectRoughnessChannel roughness_channel = RS::TEXTURE_DETECT_ROUGHNESS_R;
+ Texture *normal_detect_texture = nullptr;
+#endif
+
+ bool uses_global_textures = false;
+ global_textures_pass++;
+
+ for (int i = 0, k = 0; i < p_texture_uniforms.size(); i++) {
+ const StringName &uniform_name = p_texture_uniforms[i].name;
+ int uniform_array_size = p_texture_uniforms[i].array_size;
+
+ Vector<RID> textures;
+
+ if (p_texture_uniforms[i].global) {
+ uses_global_textures = true;
+
+ GlobalShaderUniforms::Variable *v = material_storage->global_shader_uniforms.variables.getptr(uniform_name);
+ if (v) {
+ if (v->buffer_index >= 0) {
+ WARN_PRINT("Shader uses global uniform texture '" + String(uniform_name) + "', but it changed type and is no longer a texture!.");
+
+ } else {
+ HashMap<StringName, uint64_t>::Iterator E = used_global_textures.find(uniform_name);
+ if (!E) {
+ E = used_global_textures.insert(uniform_name, global_textures_pass);
+ v->texture_materials.insert(self);
+ } else {
+ E->value = global_textures_pass;
+ }
+
+ textures.push_back(v->override.get_type() != Variant::NIL ? v->override : v->value);
+ }
+
+ } else {
+ WARN_PRINT("Shader uses global uniform texture '" + String(uniform_name) + "', but it was removed at some point. Material will not display correctly.");
+ }
+ } else {
+ HashMap<StringName, Variant>::ConstIterator V = p_parameters.find(uniform_name);
+ if (V) {
+ if (V->value.is_array()) {
+ Array array = (Array)V->value;
+ if (uniform_array_size > 0) {
+ for (int j = 0; j < array.size(); j++) {
+ textures.push_back(array[j]);
+ }
+ } else {
+ if (array.size() > 0) {
+ textures.push_back(array[0]);
+ }
+ }
+ } else {
+ textures.push_back(V->value);
+ }
+ }
+
+ if (uniform_array_size > 0) {
+ if (textures.size() < uniform_array_size) {
+ HashMap<StringName, HashMap<int, RID>>::ConstIterator W = p_default_textures.find(uniform_name);
+ for (int j = textures.size(); j < uniform_array_size; j++) {
+ if (W && W->value.has(j)) {
+ textures.push_back(W->value[j]);
+ } else {
+ textures.push_back(RID());
+ }
+ }
+ }
+ } else if (textures.is_empty()) {
+ HashMap<StringName, HashMap<int, RID>>::ConstIterator W = p_default_textures.find(uniform_name);
+ if (W && W->value.has(0)) {
+ textures.push_back(W->value[0]);
+ }
+ }
+ }
+
+ RID gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_WHITE);
+
+ if (textures.is_empty()) {
+ //check default usage
+ switch (p_texture_uniforms[i].type) {
+ case ShaderLanguage::TYPE_ISAMPLER2D:
+ case ShaderLanguage::TYPE_USAMPLER2D:
+ case ShaderLanguage::TYPE_SAMPLER2D: {
+ switch (p_texture_uniforms[i].hint) {
+ case ShaderLanguage::ShaderNode::Uniform::HINT_DEFAULT_BLACK: {
+ gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_BLACK);
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_DEFAULT_TRANSPARENT: {
+ gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_TRANSPARENT);
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_ANISOTROPY: {
+ gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_ANISO);
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: {
+ gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_NORMAL);
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL: {
+ gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_NORMAL);
+ } break;
+ default: {
+ gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_WHITE);
+ } break;
+ }
+ } break;
+
+ case ShaderLanguage::TYPE_SAMPLERCUBE: {
+ switch (p_texture_uniforms[i].hint) {
+ case ShaderLanguage::ShaderNode::Uniform::HINT_DEFAULT_BLACK: {
+ gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_CUBEMAP_BLACK);
+ } break;
+ default: {
+ gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_CUBEMAP_WHITE);
+ } break;
+ }
+ } break;
+ case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: {
+ ERR_PRINT_ONCE("Type: SamplerCubeArray not supported in OpenGL renderer, please use another type.");
+ } break;
+
+ case ShaderLanguage::TYPE_ISAMPLER3D:
+ case ShaderLanguage::TYPE_USAMPLER3D:
+ case ShaderLanguage::TYPE_SAMPLER3D: {
+ switch (p_texture_uniforms[i].hint) {
+ case ShaderLanguage::ShaderNode::Uniform::HINT_DEFAULT_BLACK: {
+ gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_3D_BLACK);
+ } break;
+ default: {
+ gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_3D_WHITE);
+ } break;
+ }
+ } break;
+
+ case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
+ case ShaderLanguage::TYPE_USAMPLER2DARRAY:
+ case ShaderLanguage::TYPE_SAMPLER2DARRAY: {
+ gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_2D_ARRAY_WHITE);
+ } break;
+
+ default: {
+ }
+ }
+#ifdef TOOLS_ENABLED
+ if (roughness_detect_texture && normal_detect_texture && !normal_detect_texture->path.is_empty()) {
+ roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel);
+ }
+#endif
+ if (uniform_array_size > 0) {
+ for (int j = 0; j < uniform_array_size; j++) {
+ p_textures[k++] = gl_texture;
+ }
+ } else {
+ p_textures[k++] = gl_texture;
+ }
+ } else {
+ for (int j = 0; j < textures.size(); j++) {
+ Texture *tex = TextureStorage::get_singleton()->get_texture(textures[j]);
+
+ if (tex) {
+ gl_texture = textures[j];
+#ifdef TOOLS_ENABLED
+ if (tex->detect_3d_callback && p_use_linear_color) {
+ tex->detect_3d_callback(tex->detect_3d_callback_ud);
+ }
+ if (tex->detect_normal_callback && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL)) {
+ if (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL) {
+ normal_detect_texture = tex;
+ }
+ tex->detect_normal_callback(tex->detect_normal_callback_ud);
+ }
+ if (tex->detect_roughness_callback && (p_texture_uniforms[i].hint >= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R || p_texture_uniforms[i].hint <= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_GRAY)) {
+ //find the normal texture
+ roughness_detect_texture = tex;
+ roughness_channel = RS::TextureDetectRoughnessChannel(p_texture_uniforms[i].hint - ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R);
+ }
+#endif
+ }
+#ifdef TOOLS_ENABLED
+ if (roughness_detect_texture && normal_detect_texture && !normal_detect_texture->path.is_empty()) {
+ roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel);
+ }
+#endif
+ p_textures[k++] = gl_texture;
+ }
+ }
+ }
+ {
+ //for textures no longer used, unregister them
+ List<StringName> to_delete;
+ for (KeyValue<StringName, uint64_t> &E : used_global_textures) {
+ if (E.value != global_textures_pass) {
+ to_delete.push_back(E.key);
+
+ GlobalShaderUniforms::Variable *v = material_storage->global_shader_uniforms.variables.getptr(E.key);
+ if (v) {
+ v->texture_materials.erase(self);
+ }
+ }
+ }
+
+ while (to_delete.front()) {
+ used_global_textures.erase(to_delete.front()->get());
+ to_delete.pop_front();
+ }
+ //handle registering/unregistering global textures
+ if (uses_global_textures != (global_texture_E != nullptr)) {
+ if (uses_global_textures) {
+ global_texture_E = material_storage->global_shader_uniforms.materials_using_texture.push_back(self);
+ } else {
+ material_storage->global_shader_uniforms.materials_using_texture.erase(global_texture_E);
+ global_texture_E = nullptr;
+ }
+ }
+ }
+}
+
+void MaterialData::update_parameters_internal(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size) {
+ if ((uint32_t)ubo_data.size() != p_ubo_size) {
+ p_uniform_dirty = true;
+ if (!uniform_buffer) {
+ glGenBuffers(1, &uniform_buffer);
+ }
+
+ ubo_data.resize(p_ubo_size);
+ if (ubo_data.size()) {
+ memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
+ }
+ }
+
+ //check whether buffer changed
+ if (p_uniform_dirty && ubo_data.size()) {
+ update_uniform_buffer(p_uniforms, p_uniform_offsets, p_parameters, ubo_data.ptrw(), ubo_data.size(), true);
+ glBindBuffer(GL_UNIFORM_BUFFER, uniform_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, ubo_data.size(), ubo_data.ptrw(), GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ }
+
+ uint32_t tex_uniform_count = 0U;
+ for (int i = 0; i < p_texture_uniforms.size(); i++) {
+ tex_uniform_count += uint32_t(p_texture_uniforms[i].array_size > 0 ? p_texture_uniforms[i].array_size : 1);
+ }
+
+ if ((uint32_t)texture_cache.size() != tex_uniform_count || p_textures_dirty) {
+ texture_cache.resize(tex_uniform_count);
+ p_textures_dirty = true;
+ }
+
+ if (p_textures_dirty && tex_uniform_count) {
+ update_textures(p_parameters, p_default_texture_params, p_texture_uniforms, texture_cache.ptrw(), true);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Material Storage
+
+MaterialStorage *MaterialStorage::singleton = nullptr;
+
+MaterialStorage *MaterialStorage::get_singleton() {
+ return singleton;
+}
+
+MaterialStorage::MaterialStorage() {
+ singleton = this;
+
+ shader_data_request_func[RS::SHADER_SPATIAL] = _create_scene_shader_func;
+ shader_data_request_func[RS::SHADER_CANVAS_ITEM] = _create_canvas_shader_func;
+ shader_data_request_func[RS::SHADER_PARTICLES] = nullptr;
+ shader_data_request_func[RS::SHADER_SKY] = _create_sky_shader_func;
+ shader_data_request_func[RS::SHADER_FOG] = nullptr;
+
+ material_data_request_func[RS::SHADER_SPATIAL] = _create_scene_material_func;
+ material_data_request_func[RS::SHADER_CANVAS_ITEM] = _create_canvas_material_func;
+ material_data_request_func[RS::SHADER_PARTICLES] = nullptr;
+ material_data_request_func[RS::SHADER_SKY] = _create_sky_material_func;
+ material_data_request_func[RS::SHADER_FOG] = nullptr;
+
+ static_assert(sizeof(GlobalShaderUniforms::Value) == 16);
+
+ global_shader_uniforms.buffer_size = MAX(4096, (int)GLOBAL_GET("rendering/limits/global_shader_variables/buffer_size"));
+ if (global_shader_uniforms.buffer_size > uint32_t(Config::get_singleton()->max_uniform_buffer_size)) {
+ global_shader_uniforms.buffer_size = uint32_t(Config::get_singleton()->max_uniform_buffer_size);
+ WARN_PRINT("Project setting: rendering/limits/global_shader_variables/buffer_size exceeds maximum uniform buffer size of: " + itos(Config::get_singleton()->max_uniform_buffer_size));
+ }
+
+ global_shader_uniforms.buffer_values = memnew_arr(GlobalShaderUniforms::Value, global_shader_uniforms.buffer_size);
+ memset(global_shader_uniforms.buffer_values, 0, sizeof(GlobalShaderUniforms::Value) * global_shader_uniforms.buffer_size);
+ global_shader_uniforms.buffer_usage = memnew_arr(GlobalShaderUniforms::ValueUsage, global_shader_uniforms.buffer_size);
+ global_shader_uniforms.buffer_dirty_regions = memnew_arr(bool, global_shader_uniforms.buffer_size / GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE);
+ memset(global_shader_uniforms.buffer_dirty_regions, 0, sizeof(bool) * global_shader_uniforms.buffer_size / GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE);
+ glGenBuffers(1, &global_shader_uniforms.buffer);
+ glBindBuffer(GL_UNIFORM_BUFFER, global_shader_uniforms.buffer);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(GlobalShaderUniforms::Value) * global_shader_uniforms.buffer_size, nullptr, GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+ {
+ // Setup CanvasItem compiler
+ ShaderCompiler::DefaultIdentifierActions actions;
+
+ actions.renames["VERTEX"] = "vertex";
+ actions.renames["LIGHT_VERTEX"] = "light_vertex";
+ actions.renames["SHADOW_VERTEX"] = "shadow_vertex";
+ actions.renames["UV"] = "uv";
+ actions.renames["POINT_SIZE"] = "gl_PointSize";
+
+ actions.renames["MODEL_MATRIX"] = "model_matrix";
+ actions.renames["CANVAS_MATRIX"] = "canvas_data.canvas_transform";
+ actions.renames["SCREEN_MATRIX"] = "canvas_data.screen_transform";
+ actions.renames["TIME"] = "canvas_data.time";
+ actions.renames["PI"] = _MKSTR(Math_PI);
+ actions.renames["TAU"] = _MKSTR(Math_TAU);
+ actions.renames["E"] = _MKSTR(Math_E);
+ actions.renames["AT_LIGHT_PASS"] = "false";
+ actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
+
+ actions.renames["COLOR"] = "color";
+ actions.renames["NORMAL"] = "normal";
+ actions.renames["NORMAL_MAP"] = "normal_map";
+ actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth";
+ actions.renames["TEXTURE"] = "color_texture";
+ actions.renames["TEXTURE_PIXEL_SIZE"] = "draw_data.color_texture_pixel_size";
+ actions.renames["NORMAL_TEXTURE"] = "normal_texture";
+ actions.renames["SPECULAR_SHININESS_TEXTURE"] = "specular_texture";
+ actions.renames["SPECULAR_SHININESS"] = "specular_shininess";
+ actions.renames["SCREEN_UV"] = "screen_uv";
+ actions.renames["SCREEN_TEXTURE"] = "screen_texture";
+ actions.renames["SCREEN_PIXEL_SIZE"] = "canvas_data.screen_pixel_size";
+ actions.renames["FRAGCOORD"] = "gl_FragCoord";
+ actions.renames["POINT_COORD"] = "gl_PointCoord";
+ actions.renames["INSTANCE_ID"] = "gl_InstanceIndex";
+ actions.renames["VERTEX_ID"] = "gl_VertexIndex";
+
+ actions.renames["LIGHT_POSITION"] = "light_position";
+ actions.renames["LIGHT_COLOR"] = "light_color";
+ actions.renames["LIGHT_ENERGY"] = "light_energy";
+ actions.renames["LIGHT"] = "light";
+ actions.renames["SHADOW_MODULATE"] = "shadow_modulate";
+
+ actions.renames["texture_sdf"] = "texture_sdf";
+ actions.renames["texture_sdf_normal"] = "texture_sdf_normal";
+ actions.renames["sdf_to_screen_uv"] = "sdf_to_screen_uv";
+ actions.renames["screen_uv_to_sdf"] = "screen_uv_to_sdf";
+
+ actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
+ actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
+ actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
+ actions.usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV";
+ actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
+ actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
+ actions.usage_defines["LIGHT"] = "#define LIGHT_SHADER_CODE_USED\n";
+ actions.usage_defines["SPECULAR_SHININESS"] = "#define SPECULAR_SHININESS_USED\n";
+
+ actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
+ actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
+ actions.render_mode_defines["light_only"] = "#define MODE_LIGHT_ONLY\n";
+
+ shaders.compiler_canvas.initialize(actions);
+ }
+
+ {
+ // Setup Scene compiler
+
+ //shader compiler
+ ShaderCompiler::DefaultIdentifierActions actions;
+
+ actions.renames["MODEL_MATRIX"] = "model_matrix";
+ actions.renames["MODEL_NORMAL_MATRIX"] = "model_normal_matrix";
+ actions.renames["VIEW_MATRIX"] = "scene_data.view_matrix";
+ actions.renames["INV_VIEW_MATRIX"] = "scene_data.inv_view_matrix";
+ actions.renames["PROJECTION_MATRIX"] = "projection_matrix";
+ actions.renames["INV_PROJECTION_MATRIX"] = "inv_projection_matrix";
+ actions.renames["MODELVIEW_MATRIX"] = "modelview";
+ actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal";
+
+ actions.renames["VERTEX"] = "vertex";
+ actions.renames["NORMAL"] = "normal";
+ actions.renames["TANGENT"] = "tangent";
+ actions.renames["BINORMAL"] = "binormal";
+ actions.renames["POSITION"] = "position";
+ actions.renames["UV"] = "uv_interp";
+ actions.renames["UV2"] = "uv2_interp";
+ actions.renames["COLOR"] = "color_interp";
+ actions.renames["POINT_SIZE"] = "gl_PointSize";
+ actions.renames["INSTANCE_ID"] = "gl_InstanceIndex";
+ actions.renames["VERTEX_ID"] = "gl_VertexIndex";
+
+ actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold";
+ actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale";
+ actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge";
+ actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate";
+
+ //builtins
+
+ actions.renames["TIME"] = "scene_data.time";
+ actions.renames["PI"] = _MKSTR(Math_PI);
+ actions.renames["TAU"] = _MKSTR(Math_TAU);
+ actions.renames["E"] = _MKSTR(Math_E);
+ actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size";
+
+ actions.renames["FRAGCOORD"] = "gl_FragCoord";
+ actions.renames["FRONT_FACING"] = "gl_FrontFacing";
+ actions.renames["NORMAL_MAP"] = "normal_map";
+ actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth";
+ actions.renames["ALBEDO"] = "albedo";
+ actions.renames["ALPHA"] = "alpha";
+ actions.renames["METALLIC"] = "metallic";
+ actions.renames["SPECULAR"] = "specular";
+ actions.renames["ROUGHNESS"] = "roughness";
+ actions.renames["RIM"] = "rim";
+ actions.renames["RIM_TINT"] = "rim_tint";
+ actions.renames["CLEARCOAT"] = "clearcoat";
+ actions.renames["CLEARCOAT_ROUGHNESS"] = "clearcoat_roughness";
+ actions.renames["ANISOTROPY"] = "anisotropy";
+ actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
+ actions.renames["SSS_STRENGTH"] = "sss_strength";
+ actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color";
+ actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth";
+ actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost";
+ actions.renames["BACKLIGHT"] = "backlight";
+ actions.renames["AO"] = "ao";
+ actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
+ actions.renames["EMISSION"] = "emission";
+ actions.renames["POINT_COORD"] = "gl_PointCoord";
+ actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
+ actions.renames["SCREEN_UV"] = "screen_uv";
+ actions.renames["SCREEN_TEXTURE"] = "color_buffer";
+ actions.renames["DEPTH_TEXTURE"] = "depth_buffer";
+ actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer";
+ actions.renames["DEPTH"] = "gl_FragDepth";
+ actions.renames["OUTPUT_IS_SRGB"] = "true";
+ actions.renames["FOG"] = "fog";
+ actions.renames["RADIANCE"] = "custom_radiance";
+ actions.renames["IRRADIANCE"] = "custom_irradiance";
+ actions.renames["BONE_INDICES"] = "bone_attrib";
+ actions.renames["BONE_WEIGHTS"] = "weight_attrib";
+ actions.renames["CUSTOM0"] = "custom0_attrib";
+ actions.renames["CUSTOM1"] = "custom1_attrib";
+ actions.renames["CUSTOM2"] = "custom2_attrib";
+ actions.renames["CUSTOM3"] = "custom3_attrib";
+ actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+
+ actions.renames["NODE_POSITION_WORLD"] = "model_matrix[3].xyz";
+ actions.renames["CAMERA_POSITION_WORLD"] = "scene_data.inv_view_matrix[3].xyz";
+ actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data.view_matrix[3].xyz";
+ actions.renames["NODE_POSITION_VIEW"] = "(model_matrix * scene_data.view_matrix)[3].xyz";
+
+ actions.renames["VIEW_INDEX"] = "ViewIndex";
+ actions.renames["VIEW_MONO_LEFT"] = "0";
+ actions.renames["VIEW_RIGHT"] = "1";
+
+ //for light
+ actions.renames["VIEW"] = "view";
+ actions.renames["LIGHT_COLOR"] = "light_color";
+ actions.renames["LIGHT"] = "light";
+ actions.renames["ATTENUATION"] = "attenuation";
+ actions.renames["DIFFUSE_LIGHT"] = "diffuse_light";
+ actions.renames["SPECULAR_LIGHT"] = "specular_light";
+
+ actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
+ actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n";
+ actions.usage_defines["BINORMAL"] = "@TANGENT";
+ actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n";
+ actions.usage_defines["RIM_TINT"] = "@RIM";
+ actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n";
+ actions.usage_defines["CLEARCOAT_ROUGHNESS"] = "@CLEARCOAT";
+ actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n";
+ actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
+ actions.usage_defines["AO"] = "#define AO_USED\n";
+ actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n";
+ actions.usage_defines["UV"] = "#define UV_USED\n";
+ actions.usage_defines["UV2"] = "#define UV2_USED\n";
+ actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";
+ actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n";
+ actions.usage_defines["CUSTOM0"] = "#define CUSTOM0_USED\n";
+ actions.usage_defines["CUSTOM1"] = "#define CUSTOM1_USED\n";
+ actions.usage_defines["CUSTOM2"] = "#define CUSTOM2_USED\n";
+ actions.usage_defines["CUSTOM3"] = "#define CUSTOM3_USED\n";
+ actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
+ actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP";
+ actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
+ actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
+ actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
+
+ actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n";
+ actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n";
+ actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n";
+ actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE";
+
+ actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
+ actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n";
+ actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
+ actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
+ actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
+
+ actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+ actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+
+ actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n";
+ actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n";
+ actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n";
+
+ actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
+ actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
+ actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
+ actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
+ actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
+ actions.render_mode_defines["particle_trails"] = "#define USE_PARTICLE_TRAILS\n";
+ actions.render_mode_defines["depth_draw_opaque"] = "#define USE_OPAQUE_PREPASS\n";
+
+ bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley");
+
+ if (!force_lambert) {
+ actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
+ }
+
+ actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
+ actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
+
+ actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n";
+
+ actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
+ actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
+ actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
+ actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
+ actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
+ actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
+ actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
+
+ actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
+ actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
+
+ shaders.compiler_scene.initialize(actions);
+ }
+
+ {
+ // Setup Particles compiler
+ /*
+ShaderCompiler::DefaultIdentifierActions actions;
+
+ actions.renames["COLOR"] = "PARTICLE.color";
+ actions.renames["VELOCITY"] = "PARTICLE.velocity";
+ //actions.renames["MASS"] = "mass"; ?
+ actions.renames["ACTIVE"] = "particle_active";
+ actions.renames["RESTART"] = "restart";
+ actions.renames["CUSTOM"] = "PARTICLE.custom";
+ for (int i = 0; i < ParticlesShader::MAX_USERDATAS; i++) {
+ String udname = "USERDATA" + itos(i + 1);
+ actions.renames[udname] = "PARTICLE.userdata" + itos(i + 1);
+ actions.usage_defines[udname] = "#define USERDATA" + itos(i + 1) + "_USED\n";
+ }
+ actions.renames["TRANSFORM"] = "PARTICLE.xform";
+ actions.renames["TIME"] = "frame_history.data[0].time";
+ actions.renames["PI"] = _MKSTR(Math_PI);
+ actions.renames["TAU"] = _MKSTR(Math_TAU);
+ actions.renames["E"] = _MKSTR(Math_E);
+ actions.renames["LIFETIME"] = "params.lifetime";
+ actions.renames["DELTA"] = "local_delta";
+ actions.renames["NUMBER"] = "particle_number";
+ actions.renames["INDEX"] = "index";
+ //actions.renames["GRAVITY"] = "current_gravity";
+ actions.renames["EMISSION_TRANSFORM"] = "FRAME.emission_transform";
+ actions.renames["RANDOM_SEED"] = "FRAME.random_seed";
+ actions.renames["FLAG_EMIT_POSITION"] = "EMISSION_FLAG_HAS_POSITION";
+ actions.renames["FLAG_EMIT_ROT_SCALE"] = "EMISSION_FLAG_HAS_ROTATION_SCALE";
+ actions.renames["FLAG_EMIT_VELOCITY"] = "EMISSION_FLAG_HAS_VELOCITY";
+ actions.renames["FLAG_EMIT_COLOR"] = "EMISSION_FLAG_HAS_COLOR";
+ actions.renames["FLAG_EMIT_CUSTOM"] = "EMISSION_FLAG_HAS_CUSTOM";
+ actions.renames["RESTART_POSITION"] = "restart_position";
+ actions.renames["RESTART_ROT_SCALE"] = "restart_rotation_scale";
+ actions.renames["RESTART_VELOCITY"] = "restart_velocity";
+ actions.renames["RESTART_COLOR"] = "restart_color";
+ actions.renames["RESTART_CUSTOM"] = "restart_custom";
+ actions.renames["emit_subparticle"] = "emit_subparticle";
+ actions.renames["COLLIDED"] = "collided";
+ actions.renames["COLLISION_NORMAL"] = "collision_normal";
+ actions.renames["COLLISION_DEPTH"] = "collision_depth";
+ actions.renames["ATTRACTOR_FORCE"] = "attractor_force";
+
+ actions.render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n";
+ actions.render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n";
+ actions.render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n";
+ actions.render_mode_defines["collision_use_scale"] = "#define USE_COLLISON_SCALE\n";
+
+ actions.sampler_array_name = "material_samplers";
+ actions.base_texture_binding_index = 1;
+ actions.texture_layout_set = 3;
+ actions.base_uniform_string = "material.";
+ actions.base_varying_index = 10;
+
+ actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
+ actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
+ actions.global_buffer_array_variable = "global_shader_uniforms.data";
+
+ particles_shader.compiler.initialize(actions);
+ */
+ }
+
+ {
+ // Setup Sky compiler
+ ShaderCompiler::DefaultIdentifierActions actions;
+
+ actions.renames["COLOR"] = "color";
+ actions.renames["ALPHA"] = "alpha";
+ actions.renames["EYEDIR"] = "cube_normal";
+ actions.renames["POSITION"] = "position";
+ actions.renames["SKY_COORDS"] = "panorama_coords";
+ actions.renames["SCREEN_UV"] = "uv";
+ actions.renames["TIME"] = "time";
+ actions.renames["FRAGCOORD"] = "gl_FragCoord";
+ actions.renames["PI"] = _MKSTR(Math_PI);
+ actions.renames["TAU"] = _MKSTR(Math_TAU);
+ actions.renames["E"] = _MKSTR(Math_E);
+ actions.renames["HALF_RES_COLOR"] = "half_res_color";
+ actions.renames["QUARTER_RES_COLOR"] = "quarter_res_color";
+ actions.renames["RADIANCE"] = "radiance";
+ actions.renames["FOG"] = "custom_fog";
+ actions.renames["LIGHT0_ENABLED"] = "directional_lights.data[0].enabled";
+ actions.renames["LIGHT0_DIRECTION"] = "directional_lights.data[0].direction_energy.xyz";
+ actions.renames["LIGHT0_ENERGY"] = "directional_lights.data[0].direction_energy.w";
+ actions.renames["LIGHT0_COLOR"] = "directional_lights.data[0].color_size.xyz";
+ actions.renames["LIGHT0_SIZE"] = "directional_lights.data[0].color_size.w";
+ actions.renames["LIGHT1_ENABLED"] = "directional_lights.data[1].enabled";
+ actions.renames["LIGHT1_DIRECTION"] = "directional_lights.data[1].direction_energy.xyz";
+ actions.renames["LIGHT1_ENERGY"] = "directional_lights.data[1].direction_energy.w";
+ actions.renames["LIGHT1_COLOR"] = "directional_lights.data[1].color_size.xyz";
+ actions.renames["LIGHT1_SIZE"] = "directional_lights.data[1].color_size.w";
+ actions.renames["LIGHT2_ENABLED"] = "directional_lights.data[2].enabled";
+ actions.renames["LIGHT2_DIRECTION"] = "directional_lights.data[2].direction_energy.xyz";
+ actions.renames["LIGHT2_ENERGY"] = "directional_lights.data[2].direction_energy.w";
+ actions.renames["LIGHT2_COLOR"] = "directional_lights.data[2].color_size.xyz";
+ actions.renames["LIGHT2_SIZE"] = "directional_lights.data[2].color_size.w";
+ actions.renames["LIGHT3_ENABLED"] = "directional_lights.data[3].enabled";
+ actions.renames["LIGHT3_DIRECTION"] = "directional_lights.data[3].direction_energy.xyz";
+ actions.renames["LIGHT3_ENERGY"] = "directional_lights.data[3].direction_energy.w";
+ actions.renames["LIGHT3_COLOR"] = "directional_lights.data[3].color_size.xyz";
+ actions.renames["LIGHT3_SIZE"] = "directional_lights.data[3].color_size.w";
+ actions.renames["AT_CUBEMAP_PASS"] = "AT_CUBEMAP_PASS";
+ actions.renames["AT_HALF_RES_PASS"] = "AT_HALF_RES_PASS";
+ actions.renames["AT_QUARTER_RES_PASS"] = "AT_QUARTER_RES_PASS";
+ actions.usage_defines["HALF_RES_COLOR"] = "\n#define USES_HALF_RES_COLOR\n";
+ actions.usage_defines["QUARTER_RES_COLOR"] = "\n#define USES_QUARTER_RES_COLOR\n";
+ actions.render_mode_defines["disable_fog"] = "#define DISABLE_FOG\n";
+
+ actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
+ actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
+
+ shaders.compiler_sky.initialize(actions);
+ }
+}
+
+MaterialStorage::~MaterialStorage() {
+ //shaders.copy.version_free(shaders.copy_version);
+
+ memdelete_arr(global_shader_uniforms.buffer_values);
+ memdelete_arr(global_shader_uniforms.buffer_usage);
+ memdelete_arr(global_shader_uniforms.buffer_dirty_regions);
+ glDeleteBuffers(1, &global_shader_uniforms.buffer);
+
+ singleton = nullptr;
+}
+
+/* GLOBAL SHADER UNIFORM API */
+
+int32_t MaterialStorage::_global_shader_uniform_allocate(uint32_t p_elements) {
+ int32_t idx = 0;
+ while (idx + p_elements <= global_shader_uniforms.buffer_size) {
+ if (global_shader_uniforms.buffer_usage[idx].elements == 0) {
+ bool valid = true;
+ for (uint32_t i = 1; i < p_elements; i++) {
+ if (global_shader_uniforms.buffer_usage[idx + i].elements > 0) {
+ valid = false;
+ idx += i + global_shader_uniforms.buffer_usage[idx + i].elements;
+ break;
+ }
+ }
+
+ if (!valid) {
+ continue; //if not valid, idx is in new position
+ }
+
+ return idx;
+ } else {
+ idx += global_shader_uniforms.buffer_usage[idx].elements;
+ }
+ }
+
+ return -1;
+}
+
+void MaterialStorage::_global_shader_uniform_store_in_buffer(int32_t p_index, RS::GlobalShaderUniformType p_type, const Variant &p_value) {
+ switch (p_type) {
+ case RS::GLOBAL_VAR_TYPE_BOOL: {
+ GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index];
+ bool b = p_value;
+ bv.x = b ? 1.0 : 0.0;
+ bv.y = 0.0;
+ bv.z = 0.0;
+ bv.w = 0.0;
+
+ } break;
+ case RS::GLOBAL_VAR_TYPE_BVEC2: {
+ GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index];
+ uint32_t bvec = p_value;
+ bv.x = (bvec & 1) ? 1.0 : 0.0;
+ bv.y = (bvec & 2) ? 1.0 : 0.0;
+ bv.z = 0.0;
+ bv.w = 0.0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_BVEC3: {
+ GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index];
+ uint32_t bvec = p_value;
+ bv.x = (bvec & 1) ? 1.0 : 0.0;
+ bv.y = (bvec & 2) ? 1.0 : 0.0;
+ bv.z = (bvec & 4) ? 1.0 : 0.0;
+ bv.w = 0.0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_BVEC4: {
+ GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index];
+ uint32_t bvec = p_value;
+ bv.x = (bvec & 1) ? 1.0 : 0.0;
+ bv.y = (bvec & 2) ? 1.0 : 0.0;
+ bv.z = (bvec & 4) ? 1.0 : 0.0;
+ bv.w = (bvec & 8) ? 1.0 : 0.0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_INT: {
+ GlobalShaderUniforms::ValueInt &bv = *(GlobalShaderUniforms::ValueInt *)&global_shader_uniforms.buffer_values[p_index];
+ int32_t v = p_value;
+ bv.x = v;
+ bv.y = 0;
+ bv.z = 0;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_IVEC2: {
+ GlobalShaderUniforms::ValueInt &bv = *(GlobalShaderUniforms::ValueInt *)&global_shader_uniforms.buffer_values[p_index];
+ Vector2i v = p_value;
+ bv.x = v.x;
+ bv.y = v.y;
+ bv.z = 0;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_IVEC3: {
+ GlobalShaderUniforms::ValueInt &bv = *(GlobalShaderUniforms::ValueInt *)&global_shader_uniforms.buffer_values[p_index];
+ Vector3i v = p_value;
+ bv.x = v.x;
+ bv.y = v.y;
+ bv.z = v.z;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_IVEC4: {
+ GlobalShaderUniforms::ValueInt &bv = *(GlobalShaderUniforms::ValueInt *)&global_shader_uniforms.buffer_values[p_index];
+ Vector<int32_t> v = p_value;
+ bv.x = v.size() >= 1 ? v[0] : 0;
+ bv.y = v.size() >= 2 ? v[1] : 0;
+ bv.z = v.size() >= 3 ? v[2] : 0;
+ bv.w = v.size() >= 4 ? v[3] : 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_RECT2I: {
+ GlobalShaderUniforms::ValueInt &bv = *(GlobalShaderUniforms::ValueInt *)&global_shader_uniforms.buffer_values[p_index];
+ Rect2i v = p_value;
+ bv.x = v.position.x;
+ bv.y = v.position.y;
+ bv.z = v.size.x;
+ bv.w = v.size.y;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_UINT: {
+ GlobalShaderUniforms::ValueUInt &bv = *(GlobalShaderUniforms::ValueUInt *)&global_shader_uniforms.buffer_values[p_index];
+ uint32_t v = p_value;
+ bv.x = v;
+ bv.y = 0;
+ bv.z = 0;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_UVEC2: {
+ GlobalShaderUniforms::ValueUInt &bv = *(GlobalShaderUniforms::ValueUInt *)&global_shader_uniforms.buffer_values[p_index];
+ Vector2i v = p_value;
+ bv.x = v.x;
+ bv.y = v.y;
+ bv.z = 0;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_UVEC3: {
+ GlobalShaderUniforms::ValueUInt &bv = *(GlobalShaderUniforms::ValueUInt *)&global_shader_uniforms.buffer_values[p_index];
+ Vector3i v = p_value;
+ bv.x = v.x;
+ bv.y = v.y;
+ bv.z = v.z;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_UVEC4: {
+ GlobalShaderUniforms::ValueUInt &bv = *(GlobalShaderUniforms::ValueUInt *)&global_shader_uniforms.buffer_values[p_index];
+ Vector<int32_t> v = p_value;
+ bv.x = v.size() >= 1 ? v[0] : 0;
+ bv.y = v.size() >= 2 ? v[1] : 0;
+ bv.z = v.size() >= 3 ? v[2] : 0;
+ bv.w = v.size() >= 4 ? v[3] : 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_FLOAT: {
+ GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index];
+ float v = p_value;
+ bv.x = v;
+ bv.y = 0;
+ bv.z = 0;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_VEC2: {
+ GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index];
+ Vector2 v = p_value;
+ bv.x = v.x;
+ bv.y = v.y;
+ bv.z = 0;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_VEC3: {
+ GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index];
+ Vector3 v = p_value;
+ bv.x = v.x;
+ bv.y = v.y;
+ bv.z = v.z;
+ bv.w = 0;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_VEC4: {
+ GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index];
+ Plane v = p_value;
+ bv.x = v.normal.x;
+ bv.y = v.normal.y;
+ bv.z = v.normal.z;
+ bv.w = v.d;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_COLOR: {
+ GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index];
+ Color v = p_value;
+ bv.x = v.r;
+ bv.y = v.g;
+ bv.z = v.b;
+ bv.w = v.a;
+
+ GlobalShaderUniforms::Value &bv_linear = global_shader_uniforms.buffer_values[p_index + 1];
+ //v = v.srgb_to_linear();
+ bv_linear.x = v.r;
+ bv_linear.y = v.g;
+ bv_linear.z = v.b;
+ bv_linear.w = v.a;
+
+ } break;
+ case RS::GLOBAL_VAR_TYPE_RECT2: {
+ GlobalShaderUniforms::Value &bv = global_shader_uniforms.buffer_values[p_index];
+ Rect2 v = p_value;
+ bv.x = v.position.x;
+ bv.y = v.position.y;
+ bv.z = v.size.x;
+ bv.w = v.size.y;
+ } break;
+ case RS::GLOBAL_VAR_TYPE_MAT2: {
+ GlobalShaderUniforms::Value *bv = &global_shader_uniforms.buffer_values[p_index];
+ Vector<float> m2 = p_value;
+ if (m2.size() < 4) {
+ m2.resize(4);
+ }
+ bv[0].x = m2[0];
+ bv[0].y = m2[1];
+ bv[0].z = 0;
+ bv[0].w = 0;
+
+ bv[1].x = m2[2];
+ bv[1].y = m2[3];
+ bv[1].z = 0;
+ bv[1].w = 0;
+
+ } break;
+ case RS::GLOBAL_VAR_TYPE_MAT3: {
+ GlobalShaderUniforms::Value *bv = &global_shader_uniforms.buffer_values[p_index];
+ Basis v = p_value;
+ bv[0].x = v.rows[0][0];
+ bv[0].y = v.rows[1][0];
+ bv[0].z = v.rows[2][0];
+ bv[0].w = 0;
+
+ bv[1].x = v.rows[0][1];
+ bv[1].y = v.rows[1][1];
+ bv[1].z = v.rows[2][1];
+ bv[1].w = 0;
+
+ bv[2].x = v.rows[0][2];
+ bv[2].y = v.rows[1][2];
+ bv[2].z = v.rows[2][2];
+ bv[2].w = 0;
+
+ } break;
+ case RS::GLOBAL_VAR_TYPE_MAT4: {
+ GlobalShaderUniforms::Value *bv = &global_shader_uniforms.buffer_values[p_index];
+
+ Vector<float> m2 = p_value;
+ if (m2.size() < 16) {
+ m2.resize(16);
+ }
+
+ bv[0].x = m2[0];
+ bv[0].y = m2[1];
+ bv[0].z = m2[2];
+ bv[0].w = m2[3];
+
+ bv[1].x = m2[4];
+ bv[1].y = m2[5];
+ bv[1].z = m2[6];
+ bv[1].w = m2[7];
+
+ bv[2].x = m2[8];
+ bv[2].y = m2[9];
+ bv[2].z = m2[10];
+ bv[2].w = m2[11];
+
+ bv[3].x = m2[12];
+ bv[3].y = m2[13];
+ bv[3].z = m2[14];
+ bv[3].w = m2[15];
+
+ } break;
+ case RS::GLOBAL_VAR_TYPE_TRANSFORM_2D: {
+ GlobalShaderUniforms::Value *bv = &global_shader_uniforms.buffer_values[p_index];
+ Transform2D v = p_value;
+ bv[0].x = v.columns[0][0];
+ bv[0].y = v.columns[0][1];
+ bv[0].z = 0;
+ bv[0].w = 0;
+
+ bv[1].x = v.columns[1][0];
+ bv[1].y = v.columns[1][1];
+ bv[1].z = 0;
+ bv[1].w = 0;
+
+ bv[2].x = v.columns[2][0];
+ bv[2].y = v.columns[2][1];
+ bv[2].z = 1;
+ bv[2].w = 0;
+
+ } break;
+ case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
+ GlobalShaderUniforms::Value *bv = &global_shader_uniforms.buffer_values[p_index];
+ Transform3D v = p_value;
+ bv[0].x = v.basis.rows[0][0];
+ bv[0].y = v.basis.rows[1][0];
+ bv[0].z = v.basis.rows[2][0];
+ bv[0].w = 0;
+
+ bv[1].x = v.basis.rows[0][1];
+ bv[1].y = v.basis.rows[1][1];
+ bv[1].z = v.basis.rows[2][1];
+ bv[1].w = 0;
+
+ bv[2].x = v.basis.rows[0][2];
+ bv[2].y = v.basis.rows[1][2];
+ bv[2].z = v.basis.rows[2][2];
+ bv[2].w = 0;
+
+ bv[3].x = v.origin.x;
+ bv[3].y = v.origin.y;
+ bv[3].z = v.origin.z;
+ bv[3].w = 1;
+
+ } break;
+ default: {
+ ERR_FAIL();
+ }
+ }
+}
+
+void MaterialStorage::_global_shader_uniform_mark_buffer_dirty(int32_t p_index, int32_t p_elements) {
+ int32_t prev_chunk = -1;
+
+ for (int32_t i = 0; i < p_elements; i++) {
+ int32_t chunk = (p_index + i) / GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE;
+ if (chunk != prev_chunk) {
+ if (!global_shader_uniforms.buffer_dirty_regions[chunk]) {
+ global_shader_uniforms.buffer_dirty_regions[chunk] = true;
+ global_shader_uniforms.buffer_dirty_region_count++;
+ }
+ }
+
+ prev_chunk = chunk;
+ }
+}
+
+void MaterialStorage::global_shader_uniform_add(const StringName &p_name, RS::GlobalShaderUniformType p_type, const Variant &p_value) {
+ ERR_FAIL_COND(global_shader_uniforms.variables.has(p_name));
+ GlobalShaderUniforms::Variable gv;
+ gv.type = p_type;
+ gv.value = p_value;
+ gv.buffer_index = -1;
+
+ if (p_type >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) {
+ //is texture
+ global_shader_uniforms.must_update_texture_materials = true; //normally there are none
+ } else {
+ gv.buffer_elements = 1;
+ if (p_type == RS::GLOBAL_VAR_TYPE_COLOR || p_type == RS::GLOBAL_VAR_TYPE_MAT2) {
+ //color needs to elements to store srgb and linear
+ gv.buffer_elements = 2;
+ }
+ if (p_type == RS::GLOBAL_VAR_TYPE_MAT3 || p_type == RS::GLOBAL_VAR_TYPE_TRANSFORM_2D) {
+ //color needs to elements to store srgb and linear
+ gv.buffer_elements = 3;
+ }
+ if (p_type == RS::GLOBAL_VAR_TYPE_MAT4 || p_type == RS::GLOBAL_VAR_TYPE_TRANSFORM) {
+ //color needs to elements to store srgb and linear
+ gv.buffer_elements = 4;
+ }
+
+ //is vector, allocate in buffer and update index
+ gv.buffer_index = _global_shader_uniform_allocate(gv.buffer_elements);
+ ERR_FAIL_COND_MSG(gv.buffer_index < 0, vformat("Failed allocating global variable '%s' out of buffer memory. Consider increasing it in the Project Settings.", String(p_name)));
+ global_shader_uniforms.buffer_usage[gv.buffer_index].elements = gv.buffer_elements;
+ _global_shader_uniform_store_in_buffer(gv.buffer_index, gv.type, gv.value);
+ _global_shader_uniform_mark_buffer_dirty(gv.buffer_index, gv.buffer_elements);
+
+ global_shader_uniforms.must_update_buffer_materials = true; //normally there are none
+ }
+
+ global_shader_uniforms.variables[p_name] = gv;
+}
+
+void MaterialStorage::global_shader_uniform_remove(const StringName &p_name) {
+ if (!global_shader_uniforms.variables.has(p_name)) {
+ return;
+ }
+ GlobalShaderUniforms::Variable &gv = global_shader_uniforms.variables[p_name];
+
+ if (gv.buffer_index >= 0) {
+ global_shader_uniforms.buffer_usage[gv.buffer_index].elements = 0;
+ global_shader_uniforms.must_update_buffer_materials = true;
+ } else {
+ global_shader_uniforms.must_update_texture_materials = true;
+ }
+
+ global_shader_uniforms.variables.erase(p_name);
+}
+
+Vector<StringName> MaterialStorage::global_shader_uniform_get_list() const {
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ ERR_FAIL_V_MSG(Vector<StringName>(), "This function should never be used outside the editor, it can severely damage performance.");
+ }
+
+ Vector<StringName> names;
+ for (const KeyValue<StringName, GlobalShaderUniforms::Variable> &E : global_shader_uniforms.variables) {
+ names.push_back(E.key);
+ }
+ names.sort_custom<StringName::AlphCompare>();
+ return names;
+}
+
+void MaterialStorage::global_shader_uniform_set(const StringName &p_name, const Variant &p_value) {
+ ERR_FAIL_COND(!global_shader_uniforms.variables.has(p_name));
+ GlobalShaderUniforms::Variable &gv = global_shader_uniforms.variables[p_name];
+ gv.value = p_value;
+ if (gv.override.get_type() == Variant::NIL) {
+ if (gv.buffer_index >= 0) {
+ //buffer
+ _global_shader_uniform_store_in_buffer(gv.buffer_index, gv.type, gv.value);
+ _global_shader_uniform_mark_buffer_dirty(gv.buffer_index, gv.buffer_elements);
+ } else {
+ //texture
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+ for (const RID &E : gv.texture_materials) {
+ Material *material = material_storage->get_material(E);
+ ERR_CONTINUE(!material);
+ material_storage->_material_queue_update(material, false, true);
+ }
+ }
+ }
+}
+
+void MaterialStorage::global_shader_uniform_set_override(const StringName &p_name, const Variant &p_value) {
+ if (!global_shader_uniforms.variables.has(p_name)) {
+ return; //variable may not exist
+ }
+
+ ERR_FAIL_COND(p_value.get_type() == Variant::OBJECT);
+
+ GlobalShaderUniforms::Variable &gv = global_shader_uniforms.variables[p_name];
+
+ gv.override = p_value;
+
+ if (gv.buffer_index >= 0) {
+ //buffer
+ if (gv.override.get_type() == Variant::NIL) {
+ _global_shader_uniform_store_in_buffer(gv.buffer_index, gv.type, gv.value);
+ } else {
+ _global_shader_uniform_store_in_buffer(gv.buffer_index, gv.type, gv.override);
+ }
+
+ _global_shader_uniform_mark_buffer_dirty(gv.buffer_index, gv.buffer_elements);
+ } else {
+ //texture
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+ for (const RID &E : gv.texture_materials) {
+ Material *material = material_storage->get_material(E);
+ ERR_CONTINUE(!material);
+ material_storage->_material_queue_update(material, false, true);
+ }
+ }
+}
+
+Variant MaterialStorage::global_shader_uniform_get(const StringName &p_name) const {
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ ERR_FAIL_V_MSG(Variant(), "This function should never be used outside the editor, it can severely damage performance.");
+ }
+
+ if (!global_shader_uniforms.variables.has(p_name)) {
+ return Variant();
+ }
+
+ return global_shader_uniforms.variables[p_name].value;
+}
+
+RS::GlobalShaderUniformType MaterialStorage::global_shader_uniform_get_type_internal(const StringName &p_name) const {
+ if (!global_shader_uniforms.variables.has(p_name)) {
+ return RS::GLOBAL_VAR_TYPE_MAX;
+ }
+
+ return global_shader_uniforms.variables[p_name].type;
+}
+
+RS::GlobalShaderUniformType MaterialStorage::global_shader_uniform_get_type(const StringName &p_name) const {
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ ERR_FAIL_V_MSG(RS::GLOBAL_VAR_TYPE_MAX, "This function should never be used outside the editor, it can severely damage performance.");
+ }
+
+ return global_shader_uniform_get_type_internal(p_name);
+}
+
+void MaterialStorage::global_shader_uniforms_load_settings(bool p_load_textures) {
+ List<PropertyInfo> settings;
+ ProjectSettings::get_singleton()->get_property_list(&settings);
+
+ for (const PropertyInfo &E : settings) {
+ if (E.name.begins_with("shader_globals/")) {
+ StringName name = E.name.get_slice("/", 1);
+ Dictionary d = ProjectSettings::get_singleton()->get(E.name);
+
+ ERR_CONTINUE(!d.has("type"));
+ ERR_CONTINUE(!d.has("value"));
+
+ String type = d["type"];
+
+ static const char *global_var_type_names[RS::GLOBAL_VAR_TYPE_MAX] = {
+ "bool",
+ "bvec2",
+ "bvec3",
+ "bvec4",
+ "int",
+ "ivec2",
+ "ivec3",
+ "ivec4",
+ "rect2i",
+ "uint",
+ "uvec2",
+ "uvec3",
+ "uvec4",
+ "float",
+ "vec2",
+ "vec3",
+ "vec4",
+ "color",
+ "rect2",
+ "mat2",
+ "mat3",
+ "mat4",
+ "transform_2d",
+ "transform",
+ "sampler2D",
+ "sampler2DArray",
+ "sampler3D",
+ "samplerCube",
+ };
+
+ RS::GlobalShaderUniformType gvtype = RS::GLOBAL_VAR_TYPE_MAX;
+
+ for (int i = 0; i < RS::GLOBAL_VAR_TYPE_MAX; i++) {
+ if (global_var_type_names[i] == type) {
+ gvtype = RS::GlobalShaderUniformType(i);
+ break;
+ }
+ }
+
+ ERR_CONTINUE(gvtype == RS::GLOBAL_VAR_TYPE_MAX); //type invalid
+
+ Variant value = d["value"];
+
+ if (gvtype >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) {
+ //textire
+ if (!p_load_textures) {
+ value = RID();
+ continue;
+ }
+
+ String path = value;
+ Ref<Resource> resource = ResourceLoader::load(path);
+ ERR_CONTINUE(resource.is_null());
+ value = resource;
+ }
+
+ if (global_shader_uniforms.variables.has(name)) {
+ //has it, update it
+ global_shader_uniform_set(name, value);
+ } else {
+ global_shader_uniform_add(name, gvtype, value);
+ }
+ }
+ }
+}
+
+void MaterialStorage::global_shader_uniforms_clear() {
+ global_shader_uniforms.variables.clear();
+}
+
+GLuint MaterialStorage::global_shader_uniforms_get_uniform_buffer() const {
+ return global_shader_uniforms.buffer;
+}
+
+int32_t MaterialStorage::global_shader_uniforms_instance_allocate(RID p_instance) {
+ ERR_FAIL_COND_V(global_shader_uniforms.instance_buffer_pos.has(p_instance), -1);
+ int32_t pos = _global_shader_uniform_allocate(ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES);
+ global_shader_uniforms.instance_buffer_pos[p_instance] = pos; //save anyway
+ ERR_FAIL_COND_V_MSG(pos < 0, -1, "Too many instances using shader instance variables. Increase buffer size in Project Settings.");
+ global_shader_uniforms.buffer_usage[pos].elements = ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES;
+ return pos;
+}
+
+void MaterialStorage::global_shader_uniforms_instance_free(RID p_instance) {
+ ERR_FAIL_COND(!global_shader_uniforms.instance_buffer_pos.has(p_instance));
+ int32_t pos = global_shader_uniforms.instance_buffer_pos[p_instance];
+ if (pos >= 0) {
+ global_shader_uniforms.buffer_usage[pos].elements = 0;
+ }
+ global_shader_uniforms.instance_buffer_pos.erase(p_instance);
+}
+
+void MaterialStorage::global_shader_uniforms_instance_update(RID p_instance, int p_index, const Variant &p_value) {
+ if (!global_shader_uniforms.instance_buffer_pos.has(p_instance)) {
+ return; //just not allocated, ignore
+ }
+ int32_t pos = global_shader_uniforms.instance_buffer_pos[p_instance];
+
+ if (pos < 0) {
+ return; //again, not allocated, ignore
+ }
+ ERR_FAIL_INDEX(p_index, ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES);
+ ERR_FAIL_COND_MSG(p_value.get_type() > Variant::COLOR, "Unsupported variant type for instance parameter: " + Variant::get_type_name(p_value.get_type())); //anything greater not supported
+
+ ShaderLanguage::DataType datatype_from_value[Variant::COLOR + 1] = {
+ ShaderLanguage::TYPE_MAX, //nil
+ ShaderLanguage::TYPE_BOOL, //bool
+ ShaderLanguage::TYPE_INT, //int
+ ShaderLanguage::TYPE_FLOAT, //float
+ ShaderLanguage::TYPE_MAX, //string
+ ShaderLanguage::TYPE_VEC2, //vec2
+ ShaderLanguage::TYPE_IVEC2, //vec2i
+ ShaderLanguage::TYPE_VEC4, //rect2
+ ShaderLanguage::TYPE_IVEC4, //rect2i
+ ShaderLanguage::TYPE_VEC3, // vec3
+ ShaderLanguage::TYPE_IVEC3, //vec3i
+ ShaderLanguage::TYPE_MAX, //xform2d not supported here
+ ShaderLanguage::TYPE_VEC4, //vec4
+ ShaderLanguage::TYPE_IVEC4, //vec4i
+ ShaderLanguage::TYPE_VEC4, //plane
+ ShaderLanguage::TYPE_VEC4, //quat
+ ShaderLanguage::TYPE_MAX, //aabb not supported here
+ ShaderLanguage::TYPE_MAX, //basis not supported here
+ ShaderLanguage::TYPE_MAX, //xform not supported here
+ ShaderLanguage::TYPE_MAX, //projection not supported here
+ ShaderLanguage::TYPE_VEC4 //color
+ };
+
+ ShaderLanguage::DataType datatype = datatype_from_value[p_value.get_type()];
+
+ ERR_FAIL_COND_MSG(datatype == ShaderLanguage::TYPE_MAX, "Unsupported variant type for instance parameter: " + Variant::get_type_name(p_value.get_type())); //anything greater not supported
+
+ pos += p_index;
+
+ _fill_std140_variant_ubo_value(datatype, 0, p_value, (uint8_t *)&global_shader_uniforms.buffer_values[pos]);
+ _global_shader_uniform_mark_buffer_dirty(pos, 1);
+}
+
+void MaterialStorage::_update_global_shader_uniforms() {
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+ if (global_shader_uniforms.buffer_dirty_region_count > 0) {
+ uint32_t total_regions = global_shader_uniforms.buffer_size / GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE;
+ if (total_regions / global_shader_uniforms.buffer_dirty_region_count <= 4) {
+ // 25% of regions dirty, just update all buffer
+ glBindBuffer(GL_UNIFORM_BUFFER, global_shader_uniforms.buffer);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(GlobalShaderUniforms::Value) * global_shader_uniforms.buffer_size, global_shader_uniforms.buffer_values, GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ memset(global_shader_uniforms.buffer_dirty_regions, 0, sizeof(bool) * total_regions);
+ } else {
+ uint32_t region_byte_size = sizeof(GlobalShaderUniforms::Value) * GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE;
+ glBindBuffer(GL_UNIFORM_BUFFER, global_shader_uniforms.buffer);
+ for (uint32_t i = 0; i < total_regions; i++) {
+ if (global_shader_uniforms.buffer_dirty_regions[i]) {
+ glBufferSubData(GL_UNIFORM_BUFFER, i * region_byte_size, region_byte_size, &global_shader_uniforms.buffer_values[i * GlobalShaderUniforms::BUFFER_DIRTY_REGION_SIZE]);
+ global_shader_uniforms.buffer_dirty_regions[i] = false;
+ }
+ }
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ }
+
+ global_shader_uniforms.buffer_dirty_region_count = 0;
+ }
+
+ if (global_shader_uniforms.must_update_buffer_materials) {
+ // only happens in the case of a buffer variable added or removed,
+ // so not often.
+ for (const RID &E : global_shader_uniforms.materials_using_buffer) {
+ Material *material = material_storage->get_material(E);
+ ERR_CONTINUE(!material); //wtf
+
+ material_storage->_material_queue_update(material, true, false);
+ }
+
+ global_shader_uniforms.must_update_buffer_materials = false;
+ }
+
+ if (global_shader_uniforms.must_update_texture_materials) {
+ // only happens in the case of a buffer variable added or removed,
+ // so not often.
+ for (const RID &E : global_shader_uniforms.materials_using_texture) {
+ Material *material = material_storage->get_material(E);
+ ERR_CONTINUE(!material); //wtf
+
+ material_storage->_material_queue_update(material, false, true);
+ }
+
+ global_shader_uniforms.must_update_texture_materials = false;
+ }
+}
+
+/* SHADER API */
+
+RID MaterialStorage::shader_allocate() {
+ return shader_owner.allocate_rid();
+}
+
+void MaterialStorage::shader_initialize(RID p_rid) {
+ Shader shader;
+ shader.data = nullptr;
+ shader.mode = RS::SHADER_MAX;
+
+ shader_owner.initialize_rid(p_rid, shader);
+}
+
+void MaterialStorage::shader_free(RID p_rid) {
+ GLES3::Shader *shader = shader_owner.get_or_null(p_rid);
+ ERR_FAIL_COND(!shader);
+
+ //make material unreference this
+ while (shader->owners.size()) {
+ material_set_shader((*shader->owners.begin())->self, RID());
+ }
+
+ //clear data if exists
+ if (shader->data) {
+ memdelete(shader->data);
+ }
+ shader_owner.free(p_rid);
+}
+
+void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) {
+ GLES3::Shader *shader = shader_owner.get_or_null(p_shader);
+ ERR_FAIL_COND(!shader);
+
+ shader->code = p_code;
+
+ String mode_string = ShaderLanguage::get_shader_type(p_code);
+
+ RS::ShaderMode new_mode;
+ if (mode_string == "canvas_item") {
+ new_mode = RS::SHADER_CANVAS_ITEM;
+ //} else if (mode_string == "particles") {
+ // new_mode = RS::SHADER_PARTICLES;
+ } else if (mode_string == "spatial") {
+ new_mode = RS::SHADER_SPATIAL;
+ } else if (mode_string == "sky") {
+ new_mode = RS::SHADER_SKY;
+ //} else if (mode_string == "fog") {
+ // new_mode = RS::SHADER_FOG;
+ } else {
+ new_mode = RS::SHADER_MAX;
+ ERR_PRINT("shader type " + mode_string + " not supported in OpenGL renderer");
+ }
+
+ if (new_mode != shader->mode) {
+ if (shader->data) {
+ memdelete(shader->data);
+ shader->data = nullptr;
+ }
+
+ for (Material *E : shader->owners) {
+ Material *material = E;
+ material->shader_mode = new_mode;
+ if (material->data) {
+ memdelete(material->data);
+ material->data = nullptr;
+ }
+ }
+
+ shader->mode = new_mode;
+
+ if (new_mode < RS::SHADER_MAX && shader_data_request_func[new_mode]) {
+ shader->data = shader_data_request_func[new_mode]();
+ } else {
+ shader->mode = RS::SHADER_MAX; //invalid
+ }
+
+ for (Material *E : shader->owners) {
+ Material *material = E;
+ if (shader->data) {
+ material->data = material_data_request_func[new_mode](shader->data);
+ material->data->self = material->self;
+ material->data->set_next_pass(material->next_pass);
+ material->data->set_render_priority(material->priority);
+ }
+ material->shader_mode = new_mode;
+ }
+
+ if (shader->data) {
+ for (const KeyValue<StringName, HashMap<int, RID>> &E : shader->default_texture_parameter) {
+ for (const KeyValue<int, RID> &E2 : E.value) {
+ shader->data->set_default_texture_param(E.key, E2.value, E2.key);
+ }
+ }
+ }
+ }
+
+ if (shader->data) {
+ shader->data->set_code(p_code);
+ }
+
+ for (Material *E : shader->owners) {
+ Material *material = E;
+ material->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MATERIAL);
+ _material_queue_update(material, true, true);
+ }
+}
+
+void MaterialStorage::shader_set_path_hint(RID p_shader, const String &p_path) {
+ GLES3::Shader *shader = shader_owner.get_or_null(p_shader);
+ ERR_FAIL_COND(!shader);
+
+ shader->path_hint = p_path;
+}
+
+String MaterialStorage::shader_get_code(RID p_shader) const {
+ const GLES3::Shader *shader = shader_owner.get_or_null(p_shader);
+ ERR_FAIL_COND_V(!shader, String());
+ return shader->code;
+}
+
+void MaterialStorage::shader_get_shader_uniform_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
+ GLES3::Shader *shader = shader_owner.get_or_null(p_shader);
+ ERR_FAIL_COND(!shader);
+ if (shader->data) {
+ return shader->data->get_shader_uniform_list(p_param_list);
+ }
+}
+
+void MaterialStorage::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index) {
+ GLES3::Shader *shader = shader_owner.get_or_null(p_shader);
+ ERR_FAIL_COND(!shader);
+
+ if (p_texture.is_valid() && TextureStorage::get_singleton()->owns_texture(p_texture)) {
+ if (!shader->default_texture_parameter.has(p_name)) {
+ shader->default_texture_parameter[p_name] = HashMap<int, RID>();
+ }
+ shader->default_texture_parameter[p_name][p_index] = p_texture;
+ } else {
+ if (shader->default_texture_parameter.has(p_name) && shader->default_texture_parameter[p_name].has(p_index)) {
+ shader->default_texture_parameter[p_name].erase(p_index);
+
+ if (shader->default_texture_parameter[p_name].is_empty()) {
+ shader->default_texture_parameter.erase(p_name);
+ }
+ }
+ }
+ if (shader->data) {
+ shader->data->set_default_texture_param(p_name, p_texture, p_index);
+ }
+ for (Material *E : shader->owners) {
+ Material *material = E;
+ _material_queue_update(material, false, true);
+ }
+}
+
+RID MaterialStorage::shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const {
+ const GLES3::Shader *shader = shader_owner.get_or_null(p_shader);
+ ERR_FAIL_COND_V(!shader, RID());
+ if (shader->default_texture_parameter.has(p_name) && shader->default_texture_parameter[p_name].has(p_index)) {
+ return shader->default_texture_parameter[p_name][p_index];
+ }
+
+ return RID();
+}
+
+Variant MaterialStorage::shader_get_param_default(RID p_shader, const StringName &p_param) const {
+ Shader *shader = shader_owner.get_or_null(p_shader);
+ ERR_FAIL_COND_V(!shader, Variant());
+ if (shader->data) {
+ return shader->data->get_default_parameter(p_param);
+ }
+ return Variant();
+}
+
+RS::ShaderNativeSourceCode MaterialStorage::shader_get_native_source_code(RID p_shader) const {
+ Shader *shader = shader_owner.get_or_null(p_shader);
+ ERR_FAIL_COND_V(!shader, RS::ShaderNativeSourceCode());
+ if (shader->data) {
+ return shader->data->get_native_source_code();
+ }
+ return RS::ShaderNativeSourceCode();
+}
+
+/* MATERIAL API */
+
+void MaterialStorage::_material_queue_update(GLES3::Material *material, bool p_uniform, bool p_texture) {
+ material->uniform_dirty = material->uniform_dirty || p_uniform;
+ material->texture_dirty = material->texture_dirty || p_texture;
+
+ if (material->update_element.in_list()) {
+ return;
+ }
+
+ material_update_list.add(&material->update_element);
+}
+
+void MaterialStorage::_update_queued_materials() {
+ while (material_update_list.first()) {
+ Material *material = material_update_list.first()->self();
+
+ if (material->data) {
+ material->data->update_parameters(material->params, material->uniform_dirty, material->texture_dirty);
+ }
+ material->texture_dirty = false;
+ material->uniform_dirty = false;
+
+ material_update_list.remove(&material->update_element);
+ }
+}
+
+RID MaterialStorage::material_allocate() {
+ return material_owner.allocate_rid();
+}
+
+void MaterialStorage::material_initialize(RID p_rid) {
+ material_owner.initialize_rid(p_rid);
+ Material *material = material_owner.get_or_null(p_rid);
+ material->self = p_rid;
+}
+
+void MaterialStorage::material_free(RID p_rid) {
+ Material *material = material_owner.get_or_null(p_rid);
+ ERR_FAIL_COND(!material);
+
+ material_set_shader(p_rid, RID()); //clean up shader
+ material->dependency.deleted_notify(p_rid);
+
+ material_owner.free(p_rid);
+}
+
+void MaterialStorage::material_set_shader(RID p_material, RID p_shader) {
+ GLES3::Material *material = material_owner.get_or_null(p_material);
+ ERR_FAIL_COND(!material);
+
+ if (material->data) {
+ memdelete(material->data);
+ material->data = nullptr;
+ }
+
+ if (material->shader) {
+ material->shader->owners.erase(material);
+ material->shader = nullptr;
+ material->shader_mode = RS::SHADER_MAX;
+ }
+
+ if (p_shader.is_null()) {
+ material->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MATERIAL);
+ material->shader_id = 0;
+ return;
+ }
+
+ Shader *shader = get_shader(p_shader);
+ ERR_FAIL_COND(!shader);
+ material->shader = shader;
+ material->shader_mode = shader->mode;
+ material->shader_id = p_shader.get_local_index();
+ shader->owners.insert(material);
+
+ if (shader->mode == RS::SHADER_MAX) {
+ return;
+ }
+
+ ERR_FAIL_COND(shader->data == nullptr);
+
+ material->data = material_data_request_func[shader->mode](shader->data);
+ material->data->self = p_material;
+ material->data->set_next_pass(material->next_pass);
+ material->data->set_render_priority(material->priority);
+ //updating happens later
+ material->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MATERIAL);
+ _material_queue_update(material, true, true);
+}
+
+void MaterialStorage::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) {
+ GLES3::Material *material = material_owner.get_or_null(p_material);
+ ERR_FAIL_COND(!material);
+
+ if (p_value.get_type() == Variant::NIL) {
+ material->params.erase(p_param);
+ } else {
+ ERR_FAIL_COND(p_value.get_type() == Variant::OBJECT); //object not allowed
+ material->params[p_param] = p_value;
+ }
+
+ if (material->shader && material->shader->data) { //shader is valid
+ bool is_texture = material->shader->data->is_param_texture(p_param);
+ _material_queue_update(material, !is_texture, is_texture);
+ } else {
+ _material_queue_update(material, true, true);
+ }
+}
+
+Variant MaterialStorage::material_get_param(RID p_material, const StringName &p_param) const {
+ const GLES3::Material *material = material_owner.get_or_null(p_material);
+ ERR_FAIL_COND_V(!material, Variant());
+ if (material->params.has(p_param)) {
+ return material->params[p_param];
+ } else {
+ return Variant();
+ }
+}
+
+void MaterialStorage::material_set_next_pass(RID p_material, RID p_next_material) {
+ GLES3::Material *material = material_owner.get_or_null(p_material);
+ ERR_FAIL_COND(!material);
+
+ if (material->next_pass == p_next_material) {
+ return;
+ }
+
+ material->next_pass = p_next_material;
+ if (material->data) {
+ material->data->set_next_pass(p_next_material);
+ }
+
+ material->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MATERIAL);
+}
+
+void MaterialStorage::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);
+
+ GLES3::Material *material = material_owner.get_or_null(p_material);
+ ERR_FAIL_COND(!material);
+ material->priority = priority;
+ if (material->data) {
+ material->data->set_render_priority(priority);
+ }
+}
+
+bool MaterialStorage::material_is_animated(RID p_material) {
+ GLES3::Material *material = material_owner.get_or_null(p_material);
+ ERR_FAIL_COND_V(!material, false);
+ if (material->shader && material->shader->data) {
+ if (material->shader->data->is_animated()) {
+ return true;
+ } else if (material->next_pass.is_valid()) {
+ return material_is_animated(material->next_pass);
+ }
+ }
+ return false; //by default nothing is animated
+}
+
+bool MaterialStorage::material_casts_shadows(RID p_material) {
+ GLES3::Material *material = material_owner.get_or_null(p_material);
+ ERR_FAIL_COND_V(!material, true);
+ if (material->shader && material->shader->data) {
+ if (material->shader->data->casts_shadows()) {
+ return true;
+ } else if (material->next_pass.is_valid()) {
+ return material_casts_shadows(material->next_pass);
+ }
+ }
+ return true; //by default everything casts shadows
+}
+
+void MaterialStorage::material_get_instance_shader_uniforms(RID p_material, List<InstanceShaderParam> *r_parameters) {
+ GLES3::Material *material = material_owner.get_or_null(p_material);
+ ERR_FAIL_COND(!material);
+ if (material->shader && material->shader->data) {
+ material->shader->data->get_instance_param_list(r_parameters);
+
+ if (material->next_pass.is_valid()) {
+ material_get_instance_shader_uniforms(material->next_pass, r_parameters);
+ }
+ }
+}
+
+void MaterialStorage::material_update_dependency(RID p_material, DependencyTracker *p_instance) {
+ Material *material = material_owner.get_or_null(p_material);
+ ERR_FAIL_COND(!material);
+ p_instance->update_dependency(&material->dependency);
+ if (material->next_pass.is_valid()) {
+ material_update_dependency(material->next_pass, p_instance);
+ }
+}
+
+/* Canvas Shader Data */
+
+void CanvasShaderData::set_code(const String &p_code) {
+ // compile the shader
+
+ code = p_code;
+ valid = false;
+ ubo_size = 0;
+ uniforms.clear();
+ uses_screen_texture = false;
+ uses_sdf = false;
+ uses_time = false;
+
+ if (code.is_empty()) {
+ return; //just invalid, but no error
+ }
+
+ ShaderCompiler::GeneratedCode gen_code;
+
+ int blend_modei = BLEND_MODE_MIX;
+ uses_screen_texture = false;
+
+ ShaderCompiler::IdentifierActions actions;
+ actions.entry_point_stages["vertex"] = ShaderCompiler::STAGE_VERTEX;
+ actions.entry_point_stages["fragment"] = ShaderCompiler::STAGE_FRAGMENT;
+ actions.entry_point_stages["light"] = ShaderCompiler::STAGE_FRAGMENT;
+
+ actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_modei, BLEND_MODE_ADD);
+ actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_modei, BLEND_MODE_MIX);
+ actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_modei, BLEND_MODE_SUB);
+ actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_modei, BLEND_MODE_MUL);
+ actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_modei, BLEND_MODE_PMALPHA);
+ actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_modei, BLEND_MODE_DISABLED);
+
+ actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
+ actions.usage_flag_pointers["texture_sdf"] = &uses_sdf;
+ actions.usage_flag_pointers["TIME"] = &uses_time;
+
+ actions.uniforms = &uniforms;
+ Error err = MaterialStorage::get_singleton()->shaders.compiler_canvas.compile(RS::SHADER_CANVAS_ITEM, code, &actions, path, gen_code);
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
+
+ if (version.is_null()) {
+ version = MaterialStorage::get_singleton()->shaders.canvas_shader.version_create();
+ }
+
+ blend_mode = BlendMode(blend_modei);
+
+#if 0
+ print_line("**compiling shader:");
+ print_line("**defines:\n");
+ for (int i = 0; i < gen_code.defines.size(); i++) {
+ print_line(gen_code.defines[i]);
+ }
+ print_line("\n**uniforms:\n" + gen_code.uniforms);
+ print_line("\n**vertex_globals:\n" + gen_code.vertex_global);
+ print_line("\n**vertex_code:\n" + gen_code.vertex);
+ print_line("\n**fragment_globals:\n" + gen_code.fragment_global);
+ print_line("\n**fragment_code:\n" + gen_code.fragment);
+ print_line("\n**light_code:\n" + gen_code.light);
+#endif
+
+ Vector<StringName> texture_uniform_names;
+ for (int i = 0; i < gen_code.texture_uniforms.size(); i++) {
+ texture_uniform_names.push_back(gen_code.texture_uniforms[i].name);
+ }
+
+ MaterialStorage::get_singleton()->shaders.canvas_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_names);
+ ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.canvas_shader.version_is_valid(version));
+
+ ubo_size = gen_code.uniform_total_size;
+ ubo_offsets = gen_code.uniform_offsets;
+ texture_uniforms = gen_code.texture_uniforms;
+
+ valid = true;
+}
+
+void CanvasShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
+ if (!p_texture.is_valid()) {
+ if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
+ default_texture_params[p_name].erase(p_index);
+
+ if (default_texture_params[p_name].is_empty()) {
+ default_texture_params.erase(p_name);
+ }
+ }
+ } else {
+ if (!default_texture_params.has(p_name)) {
+ default_texture_params[p_name] = HashMap<int, RID>();
+ }
+ default_texture_params[p_name][p_index] = p_texture;
+ }
+}
+
+void CanvasShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
+ HashMap<int, StringName> order;
+
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ continue;
+ }
+ if (E.value.texture_order >= 0) {
+ order[E.value.texture_order + 100000] = E.key;
+ } else {
+ order[E.value.order] = E.key;
+ }
+ }
+
+ String last_group;
+ for (const KeyValue<int, StringName> &E : order) {
+ String group = uniforms[E.value].group;
+ if (!uniforms[E.value].subgroup.is_empty()) {
+ group += "::" + uniforms[E.value].subgroup;
+ }
+
+ if (group != last_group) {
+ PropertyInfo pi;
+ pi.usage = PROPERTY_USAGE_GROUP;
+ pi.name = group;
+ p_param_list->push_back(pi);
+
+ last_group = group;
+ }
+
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
+ pi.name = E.value;
+ p_param_list->push_back(pi);
+ }
+}
+
+void CanvasShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ RendererMaterialStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E.value);
+ p.info.name = E.key; //supply name
+ p.index = E.value.instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
+ p_param_list->push_back(p);
+ }
+}
+
+bool CanvasShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+bool CanvasShaderData::is_animated() const {
+ return false;
+}
+
+bool CanvasShaderData::casts_shadows() const {
+ return false;
+}
+
+Variant CanvasShaderData::get_default_parameter(const StringName &p_parameter) const {
+ if (uniforms.has(p_parameter)) {
+ ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+ Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
+ }
+ return Variant();
+}
+
+RS::ShaderNativeSourceCode CanvasShaderData::get_native_source_code() const {
+ return MaterialStorage::get_singleton()->shaders.canvas_shader.version_get_native_source_code(version);
+}
+
+CanvasShaderData::CanvasShaderData() {
+ valid = false;
+ uses_screen_texture = false;
+ uses_sdf = false;
+}
+
+CanvasShaderData::~CanvasShaderData() {
+ if (version.is_valid()) {
+ MaterialStorage::get_singleton()->shaders.canvas_shader.version_free(version);
+ }
+}
+
+GLES3::ShaderData *GLES3::_create_canvas_shader_func() {
+ CanvasShaderData *shader_data = memnew(CanvasShaderData);
+ return shader_data;
+}
+
+void CanvasMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+ return update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size);
+}
+
+void CanvasMaterialData::bind_uniforms() {
+ // Bind Material Uniforms
+ glBindBufferBase(GL_UNIFORM_BUFFER, RasterizerCanvasGLES3::MATERIAL_UNIFORM_LOCATION, uniform_buffer);
+
+ RID *textures = texture_cache.ptrw();
+ ShaderCompiler::GeneratedCode::Texture *texture_uniforms = shader_data->texture_uniforms.ptrw();
+ for (int ti = 0; ti < texture_cache.size(); ti++) {
+ Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
+ glActiveTexture(GL_TEXTURE1 + ti); // Start at GL_TEXTURE1 because texture slot 0 is used by the base texture
+ glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
+
+ // Set sampler state here as the same texture can be used in multiple places with different flags
+ // Need to convert sampler state from ShaderLanguage::Texture* to RS::CanvasItemTexture*
+ RS::CanvasItemTextureFilter filter = RS::CanvasItemTextureFilter((int(texture_uniforms[ti].filter) + 1) % RS::CANVAS_ITEM_TEXTURE_FILTER_MAX);
+ RS::CanvasItemTextureRepeat repeat = RS::CanvasItemTextureRepeat((int(texture_uniforms[ti].repeat) + 1) % RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
+ texture->gl_set_filter(filter);
+ texture->gl_set_repeat(repeat);
+ }
+}
+
+CanvasMaterialData::~CanvasMaterialData() {
+}
+
+GLES3::MaterialData *GLES3::_create_canvas_material_func(ShaderData *p_shader) {
+ CanvasMaterialData *material_data = memnew(CanvasMaterialData);
+ material_data->shader_data = static_cast<CanvasShaderData *>(p_shader);
+ //update will happen later anyway so do nothing.
+ return material_data;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// SKY SHADER
+
+void SkyShaderData::set_code(const String &p_code) {
+ //compile
+
+ code = p_code;
+ valid = false;
+ ubo_size = 0;
+ uniforms.clear();
+
+ if (code.is_empty()) {
+ return; //just invalid, but no error
+ }
+
+ ShaderCompiler::GeneratedCode gen_code;
+ ShaderCompiler::IdentifierActions actions;
+ actions.entry_point_stages["sky"] = ShaderCompiler::STAGE_FRAGMENT;
+
+ uses_time = false;
+ uses_half_res = false;
+ uses_quarter_res = false;
+ uses_position = false;
+ uses_light = false;
+
+ actions.render_mode_flags["use_half_res_pass"] = &uses_half_res;
+ actions.render_mode_flags["use_quarter_res_pass"] = &uses_quarter_res;
+
+ actions.usage_flag_pointers["TIME"] = &uses_time;
+ actions.usage_flag_pointers["POSITION"] = &uses_position;
+ actions.usage_flag_pointers["LIGHT0_ENABLED"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_ENERGY"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_DIRECTION"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_SIZE"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_ENABLED"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_ENERGY"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_DIRECTION"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_SIZE"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_ENABLED"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_ENERGY"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_DIRECTION"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_SIZE"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_ENABLED"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_ENERGY"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_DIRECTION"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_SIZE"] = &uses_light;
+
+ actions.uniforms = &uniforms;
+
+ Error err = MaterialStorage::get_singleton()->shaders.compiler_sky.compile(RS::SHADER_SKY, code, &actions, path, gen_code);
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
+
+ if (version.is_null()) {
+ version = MaterialStorage::get_singleton()->shaders.sky_shader.version_create();
+ }
+
+#if 0
+ print_line("**compiling shader:");
+ print_line("**defines:\n");
+ for (int i = 0; i < gen_code.defines.size(); i++) {
+ print_line(gen_code.defines[i]);
+ }
+ print_line("\n**uniforms:\n" + gen_code.uniforms);
+ // print_line("\n**vertex_globals:\n" + gen_code.vertex_global);
+ // print_line("\n**vertex_code:\n" + gen_code.vertex);
+ print_line("\n**fragment_globals:\n" + gen_code.fragment_global);
+ print_line("\n**fragment_code:\n" + gen_code.fragment);
+ print_line("\n**light_code:\n" + gen_code.light);
+#endif
+
+ Vector<StringName> texture_uniform_names;
+ for (int i = 0; i < gen_code.texture_uniforms.size(); i++) {
+ texture_uniform_names.push_back(gen_code.texture_uniforms[i].name);
+ }
+
+ MaterialStorage::get_singleton()->shaders.sky_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_names);
+ ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.sky_shader.version_is_valid(version));
+
+ ubo_size = gen_code.uniform_total_size;
+ ubo_offsets = gen_code.uniform_offsets;
+ texture_uniforms = gen_code.texture_uniforms;
+
+ valid = true;
+}
+
+void SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
+ if (!p_texture.is_valid()) {
+ if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
+ default_texture_params[p_name].erase(p_index);
+
+ if (default_texture_params[p_name].is_empty()) {
+ default_texture_params.erase(p_name);
+ }
+ }
+ } else {
+ if (!default_texture_params.has(p_name)) {
+ default_texture_params[p_name] = HashMap<int, RID>();
+ }
+ default_texture_params[p_name][p_index] = p_texture;
+ }
+}
+
+void SkyShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
+ RBMap<int, StringName> order;
+
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ if (E.value.texture_order >= 0) {
+ order[E.value.texture_order + 100000] = E.key;
+ } else {
+ order[E.value.order] = E.key;
+ }
+ }
+
+ String last_group;
+ for (const KeyValue<int, StringName> &E : order) {
+ String group = uniforms[E.value].group;
+ if (!uniforms[E.value].subgroup.is_empty()) {
+ group += "::" + uniforms[E.value].subgroup;
+ }
+
+ if (group != last_group) {
+ PropertyInfo pi;
+ pi.usage = PROPERTY_USAGE_GROUP;
+ pi.name = group;
+ p_param_list->push_back(pi);
+
+ last_group = group;
+ }
+
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
+ pi.name = E.value;
+ p_param_list->push_back(pi);
+ }
+}
+
+void SkyShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ RendererMaterialStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E.value);
+ p.info.name = E.key; //supply name
+ p.index = E.value.instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
+ p_param_list->push_back(p);
+ }
+}
+
+bool SkyShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+bool SkyShaderData::is_animated() const {
+ return false;
+}
+
+bool SkyShaderData::casts_shadows() const {
+ return false;
+}
+
+Variant SkyShaderData::get_default_parameter(const StringName &p_parameter) const {
+ if (uniforms.has(p_parameter)) {
+ ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+ Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
+ }
+ return Variant();
+}
+
+RS::ShaderNativeSourceCode SkyShaderData::get_native_source_code() const {
+ return MaterialStorage::get_singleton()->shaders.sky_shader.version_get_native_source_code(version);
+}
+
+SkyShaderData::SkyShaderData() {
+ valid = false;
+}
+
+SkyShaderData::~SkyShaderData() {
+ if (version.is_valid()) {
+ MaterialStorage::get_singleton()->shaders.sky_shader.version_free(version);
+ }
+}
+
+GLES3::ShaderData *GLES3::_create_sky_shader_func() {
+ SkyShaderData *shader_data = memnew(SkyShaderData);
+ return shader_data;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Sky material
+
+void SkyMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+ uniform_set_updated = true;
+ return update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size);
+}
+
+SkyMaterialData::~SkyMaterialData() {
+}
+GLES3::MaterialData *GLES3::_create_sky_material_func(ShaderData *p_shader) {
+ SkyMaterialData *material_data = memnew(SkyMaterialData);
+ material_data->shader_data = static_cast<SkyShaderData *>(p_shader);
+ //update will happen later anyway so do nothing.
+ return material_data;
+}
+
+void SkyMaterialData::bind_uniforms() {
+ // Bind Material Uniforms
+ glBindBufferBase(GL_UNIFORM_BUFFER, SKY_MATERIAL_UNIFORM_LOCATION, uniform_buffer);
+
+ RID *textures = texture_cache.ptrw();
+ ShaderCompiler::GeneratedCode::Texture *texture_uniforms = shader_data->texture_uniforms.ptrw();
+ for (int ti = 0; ti < texture_cache.size(); ti++) {
+ Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
+ glActiveTexture(GL_TEXTURE0 + ti);
+ glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
+
+ // Set sampler state here as the same texture can be used in multiple places with different flags
+ // Need to convert sampler state from ShaderLanguage::Texture* to RS::CanvasItemTexture*
+ RS::CanvasItemTextureFilter filter = RS::CanvasItemTextureFilter((int(texture_uniforms[ti].filter) + 1) % RS::CANVAS_ITEM_TEXTURE_FILTER_MAX);
+ RS::CanvasItemTextureRepeat repeat = RS::CanvasItemTextureRepeat((int(texture_uniforms[ti].repeat) + 1) % RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
+ texture->gl_set_filter(filter);
+ texture->gl_set_repeat(repeat);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Scene SHADER
+
+void SceneShaderData::set_code(const String &p_code) {
+ //compile
+
+ code = p_code;
+ valid = false;
+ ubo_size = 0;
+ uniforms.clear();
+ uses_screen_texture = false;
+
+ if (code.is_empty()) {
+ return; //just invalid, but no error
+ }
+
+ ShaderCompiler::GeneratedCode gen_code;
+
+ int blend_modei = BLEND_MODE_MIX;
+ int depth_testi = DEPTH_TEST_ENABLED;
+ int alpha_antialiasing_modei = ALPHA_ANTIALIASING_OFF;
+ int cull_modei = CULL_BACK;
+ int depth_drawi = DEPTH_DRAW_OPAQUE;
+
+ uses_point_size = false;
+ uses_alpha = false;
+ uses_alpha_clip = false;
+ uses_blend_alpha = false;
+ uses_depth_pre_pass = false;
+ uses_discard = false;
+ uses_roughness = false;
+ uses_normal = false;
+ wireframe = false;
+
+ unshaded = false;
+ uses_vertex = false;
+ uses_position = false;
+ uses_sss = false;
+ uses_transmittance = false;
+ uses_screen_texture = false;
+ uses_depth_texture = false;
+ uses_normal_texture = false;
+ uses_time = false;
+ writes_modelview_or_projection = false;
+ uses_world_coordinates = false;
+ uses_particle_trails = false;
+
+ ShaderCompiler::IdentifierActions actions;
+ actions.entry_point_stages["vertex"] = ShaderCompiler::STAGE_VERTEX;
+ actions.entry_point_stages["fragment"] = ShaderCompiler::STAGE_FRAGMENT;
+ actions.entry_point_stages["light"] = ShaderCompiler::STAGE_FRAGMENT;
+
+ actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_modei, BLEND_MODE_ADD);
+ actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_modei, BLEND_MODE_MIX);
+ actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_modei, BLEND_MODE_SUB);
+ actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_modei, BLEND_MODE_MUL);
+
+ actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_modei, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE);
+ actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_modei, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE);
+
+ actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED);
+ actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
+ actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
+
+ actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
+
+ actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_modei, CULL_DISABLED);
+ actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_modei, CULL_FRONT);
+ actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull_modei, CULL_BACK);
+
+ actions.render_mode_flags["unshaded"] = &unshaded;
+ actions.render_mode_flags["wireframe"] = &wireframe;
+ actions.render_mode_flags["particle_trails"] = &uses_particle_trails;
+
+ actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
+ actions.usage_flag_pointers["ALPHA_SCISSOR_THRESHOLD"] = &uses_alpha_clip;
+ actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass;
+
+ actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
+ actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance;
+
+ actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
+ actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture;
+ actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture;
+ actions.usage_flag_pointers["DISCARD"] = &uses_discard;
+ actions.usage_flag_pointers["TIME"] = &uses_time;
+ actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness;
+ actions.usage_flag_pointers["NORMAL"] = &uses_normal;
+ actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal;
+
+ actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size;
+ actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size;
+
+ actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection;
+ actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection;
+ actions.write_flag_pointers["VERTEX"] = &uses_vertex;
+ actions.write_flag_pointers["POSITION"] = &uses_position;
+
+ actions.usage_flag_pointers["TANGENT"] = &uses_tangent;
+ actions.usage_flag_pointers["BINORMAL"] = &uses_tangent;
+ actions.usage_flag_pointers["COLOR"] = &uses_color;
+ actions.usage_flag_pointers["UV"] = &uses_uv;
+ actions.usage_flag_pointers["UV2"] = &uses_uv2;
+ actions.usage_flag_pointers["CUSTOM0"] = &uses_custom0;
+ actions.usage_flag_pointers["CUSTOM1"] = &uses_custom1;
+ actions.usage_flag_pointers["CUSTOM2"] = &uses_custom2;
+ actions.usage_flag_pointers["CUSTOM3"] = &uses_custom3;
+ actions.usage_flag_pointers["BONE_INDICES"] = &uses_bones;
+ actions.usage_flag_pointers["BONE_WEIGHTS"] = &uses_weights;
+
+ actions.uniforms = &uniforms;
+
+ Error err = MaterialStorage::get_singleton()->shaders.compiler_scene.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
+
+ if (version.is_null()) {
+ version = MaterialStorage::get_singleton()->shaders.scene_shader.version_create();
+ }
+
+ depth_draw = DepthDraw(depth_drawi);
+ depth_test = DepthTest(depth_testi);
+ cull_mode = Cull(cull_modei);
+ blend_mode = BlendMode(blend_modei);
+ alpha_antialiasing_mode = AlphaAntiAliasing(alpha_antialiasing_modei);
+ vertex_input_mask = uint32_t(uses_normal);
+ vertex_input_mask |= uses_tangent << 1;
+ vertex_input_mask |= uses_color << 2;
+ vertex_input_mask |= uses_uv << 3;
+ vertex_input_mask |= uses_uv2 << 4;
+ vertex_input_mask |= uses_custom0 << 5;
+ vertex_input_mask |= uses_custom1 << 6;
+ vertex_input_mask |= uses_custom2 << 7;
+ vertex_input_mask |= uses_custom3 << 8;
+ vertex_input_mask |= uses_bones << 9;
+ vertex_input_mask |= uses_weights << 10;
+
+#if 0
+ print_line("**compiling shader:");
+ print_line("**defines:\n");
+ for (int i = 0; i < gen_code.defines.size(); i++) {
+ print_line(gen_code.defines[i]);
+ }
+
+ Map<String, String>::Element *el = gen_code.code.front();
+ while (el) {
+ print_line("\n**code " + el->key() + ":\n" + el->value());
+
+ el = el->next();
+ }
+
+ print_line("\n**uniforms:\n" + gen_code.uniforms);
+ print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]);
+ print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
+#endif
+
+ Vector<StringName> texture_uniform_names;
+ for (int i = 0; i < gen_code.texture_uniforms.size(); i++) {
+ texture_uniform_names.push_back(gen_code.texture_uniforms[i].name);
+ }
+
+ MaterialStorage::get_singleton()->shaders.scene_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_names);
+ ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.scene_shader.version_is_valid(version));
+
+ ubo_size = gen_code.uniform_total_size;
+ ubo_offsets = gen_code.uniform_offsets;
+ texture_uniforms = gen_code.texture_uniforms;
+
+ // if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage
+ if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) {
+ blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE;
+ }
+
+ valid = true;
+}
+
+void SceneShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
+ if (!p_texture.is_valid()) {
+ if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
+ default_texture_params[p_name].erase(p_index);
+
+ if (default_texture_params[p_name].is_empty()) {
+ default_texture_params.erase(p_name);
+ }
+ }
+ } else {
+ if (!default_texture_params.has(p_name)) {
+ default_texture_params[p_name] = HashMap<int, RID>();
+ }
+ default_texture_params[p_name][p_index] = p_texture;
+ }
+}
+
+void SceneShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
+ RBMap<int, StringName> order;
+
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ continue;
+ }
+
+ if (E.value.texture_order >= 0) {
+ order[E.value.texture_order + 100000] = E.key;
+ } else {
+ order[E.value.order] = E.key;
+ }
+ }
+
+ String last_group;
+ for (const KeyValue<int, StringName> &E : order) {
+ String group = uniforms[E.value].group;
+ if (!uniforms[E.value].subgroup.is_empty()) {
+ group += "::" + uniforms[E.value].subgroup;
+ }
+
+ if (group != last_group) {
+ PropertyInfo pi;
+ pi.usage = PROPERTY_USAGE_GROUP;
+ pi.name = group;
+ p_param_list->push_back(pi);
+
+ last_group = group;
+ }
+
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
+ pi.name = E.value;
+ p_param_list->push_back(pi);
+ }
+}
+
+void SceneShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ RendererMaterialStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E.value);
+ p.info.name = E.key; //supply name
+ p.index = E.value.instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
+ p_param_list->push_back(p);
+ }
+}
+
+bool SceneShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+bool SceneShaderData::is_animated() const {
+ return false;
+}
+
+bool SceneShaderData::casts_shadows() const {
+ return false;
+}
+
+Variant SceneShaderData::get_default_parameter(const StringName &p_parameter) const {
+ if (uniforms.has(p_parameter)) {
+ ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+ Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
+ }
+ return Variant();
+}
+
+RS::ShaderNativeSourceCode SceneShaderData::get_native_source_code() const {
+ return MaterialStorage::get_singleton()->shaders.scene_shader.version_get_native_source_code(version);
+}
+
+SceneShaderData::SceneShaderData() {
+ valid = false;
+ uses_screen_texture = false;
+}
+
+SceneShaderData::~SceneShaderData() {
+ if (version.is_valid()) {
+ MaterialStorage::get_singleton()->shaders.scene_shader.version_free(version);
+ }
+}
+
+GLES3::ShaderData *GLES3::_create_scene_shader_func() {
+ SceneShaderData *shader_data = memnew(SceneShaderData);
+ return shader_data;
+}
+
+void SceneMaterialData::set_render_priority(int p_priority) {
+ priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits
+}
+
+void SceneMaterialData::set_next_pass(RID p_pass) {
+ next_pass = p_pass;
+}
+
+void SceneMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+ return update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size);
+}
+
+SceneMaterialData::~SceneMaterialData() {
+}
+
+GLES3::MaterialData *GLES3::_create_scene_material_func(ShaderData *p_shader) {
+ SceneMaterialData *material_data = memnew(SceneMaterialData);
+ material_data->shader_data = static_cast<SceneShaderData *>(p_shader);
+ //update will happen later anyway so do nothing.
+ return material_data;
+}
+
+void SceneMaterialData::bind_uniforms() {
+ // Bind Material Uniforms
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MATERIAL_UNIFORM_LOCATION, uniform_buffer);
+
+ RID *textures = texture_cache.ptrw();
+ ShaderCompiler::GeneratedCode::Texture *texture_uniforms = shader_data->texture_uniforms.ptrw();
+ for (int ti = 0; ti < texture_cache.size(); ti++) {
+ Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
+ glActiveTexture(GL_TEXTURE0 + ti);
+ glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
+
+ // Set sampler state here as the same texture can be used in multiple places with different flags
+ // Need to convert sampler state from ShaderLanguage::Texture* to RS::CanvasItemTexture*
+ RS::CanvasItemTextureFilter filter = RS::CanvasItemTextureFilter((int(texture_uniforms[ti].filter) + 1) % RS::CANVAS_ITEM_TEXTURE_FILTER_MAX);
+ RS::CanvasItemTextureRepeat repeat = RS::CanvasItemTextureRepeat((int(texture_uniforms[ti].repeat) + 1) % RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
+ texture->gl_set_filter(filter);
+ texture->gl_set_repeat(repeat);
+ }
+}
+
+#endif // !GLES3_ENABLED
diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h
new file mode 100644
index 0000000000..2ca47351a4
--- /dev/null
+++ b/drivers/gles3/storage/material_storage.h
@@ -0,0 +1,602 @@
+/*************************************************************************/
+/* material_storage.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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 MATERIAL_STORAGE_GLES3_H
+#define MATERIAL_STORAGE_GLES3_H
+
+#ifdef GLES3_ENABLED
+
+#include "core/templates/local_vector.h"
+#include "core/templates/rid_owner.h"
+#include "core/templates/self_list.h"
+#include "servers/rendering/renderer_compositor.h"
+#include "servers/rendering/shader_compiler.h"
+#include "servers/rendering/shader_language.h"
+#include "servers/rendering/storage/material_storage.h"
+#include "servers/rendering/storage/utilities.h"
+
+#include "../shaders/canvas.glsl.gen.h"
+#include "../shaders/cubemap_filter.glsl.gen.h"
+#include "../shaders/scene.glsl.gen.h"
+#include "../shaders/sky.glsl.gen.h"
+
+namespace GLES3 {
+
+/* Shader Structs */
+
+struct ShaderData {
+ virtual void set_code(const String &p_Code) = 0;
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) = 0;
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const = 0;
+
+ virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const = 0;
+ virtual bool is_param_texture(const StringName &p_param) const = 0;
+ virtual bool is_animated() const = 0;
+ virtual bool casts_shadows() const = 0;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const = 0;
+ virtual RS::ShaderNativeSourceCode get_native_source_code() const { return RS::ShaderNativeSourceCode(); }
+
+ virtual ~ShaderData() {}
+};
+
+typedef ShaderData *(*ShaderDataRequestFunction)();
+
+struct Material;
+
+struct Shader {
+ ShaderData *data = nullptr;
+ String code;
+ String path_hint;
+ RS::ShaderMode mode;
+ HashMap<StringName, HashMap<int, RID>> default_texture_parameter;
+ HashSet<Material *> owners;
+};
+
+/* Material structs */
+
+struct MaterialData {
+ void update_uniform_buffer(const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const HashMap<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color);
+ void update_textures(const HashMap<StringName, Variant> &p_parameters, const HashMap<StringName, HashMap<int, RID>> &p_default_textures, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color);
+
+ virtual void set_render_priority(int p_priority) = 0;
+ virtual void set_next_pass(RID p_pass) = 0;
+ virtual void update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) = 0;
+ virtual void bind_uniforms() = 0;
+ virtual ~MaterialData();
+
+ // Used internally by all Materials
+ void update_parameters_internal(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size);
+
+protected:
+ Vector<uint8_t> ubo_data;
+ GLuint uniform_buffer = GLuint(0);
+ Vector<RID> texture_cache;
+
+private:
+ friend class MaterialStorage;
+ RID self;
+ List<RID>::Element *global_buffer_E = nullptr;
+ List<RID>::Element *global_texture_E = nullptr;
+ uint64_t global_textures_pass = 0;
+ HashMap<StringName, uint64_t> used_global_textures;
+
+ //internally by update_parameters_internal
+};
+
+typedef MaterialData *(*MaterialDataRequestFunction)(ShaderData *);
+
+struct Material {
+ RID self;
+ MaterialData *data = nullptr;
+ Shader *shader = nullptr;
+ //shortcut to shader data and type
+ RS::ShaderMode shader_mode = RS::SHADER_MAX;
+ uint32_t shader_id = 0;
+ bool uniform_dirty = false;
+ bool texture_dirty = false;
+ HashMap<StringName, Variant> params;
+ int32_t priority = 0;
+ RID next_pass;
+ SelfList<Material> update_element;
+
+ Dependency dependency;
+
+ Material() :
+ update_element(this) {}
+};
+
+/* CanvasItem Materials */
+
+struct CanvasShaderData : public ShaderData {
+ enum BlendMode { //used internally
+ BLEND_MODE_MIX,
+ BLEND_MODE_ADD,
+ BLEND_MODE_SUB,
+ BLEND_MODE_MUL,
+ BLEND_MODE_PMALPHA,
+ BLEND_MODE_DISABLED,
+ };
+
+ bool valid;
+ RID version;
+ String path;
+ BlendMode blend_mode = BLEND_MODE_MIX;
+
+ HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
+
+ Vector<uint32_t> ubo_offsets;
+ uint32_t ubo_size;
+
+ String code;
+ HashMap<StringName, HashMap<int, RID>> default_texture_params;
+
+ bool uses_screen_texture = false;
+ bool uses_sdf = false;
+ bool uses_time = false;
+
+ virtual void set_code(const String &p_Code);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
+
+ virtual bool is_param_texture(const StringName &p_param) const;
+ virtual bool is_animated() const;
+ virtual bool casts_shadows() const;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+
+ CanvasShaderData();
+ virtual ~CanvasShaderData();
+};
+
+ShaderData *_create_canvas_shader_func();
+
+struct CanvasMaterialData : public MaterialData {
+ CanvasShaderData *shader_data = nullptr;
+
+ virtual void set_render_priority(int p_priority) {}
+ virtual void set_next_pass(RID p_pass) {}
+ virtual void update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual void bind_uniforms();
+ virtual ~CanvasMaterialData();
+};
+
+MaterialData *_create_canvas_material_func(ShaderData *p_shader);
+
+/* Sky Materials */
+
+struct SkyShaderData : public ShaderData {
+ bool valid;
+ RID version;
+
+ HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
+
+ Vector<uint32_t> ubo_offsets;
+ uint32_t ubo_size;
+
+ String path;
+ String code;
+ HashMap<StringName, HashMap<int, RID>> default_texture_params;
+
+ bool uses_time;
+ bool uses_position;
+ bool uses_half_res;
+ bool uses_quarter_res;
+ bool uses_light;
+
+ virtual void set_code(const String &p_Code);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
+ virtual bool is_param_texture(const StringName &p_param) const;
+ virtual bool is_animated() const;
+ virtual bool casts_shadows() const;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+ SkyShaderData();
+ virtual ~SkyShaderData();
+};
+
+ShaderData *_create_sky_shader_func();
+
+struct SkyMaterialData : public MaterialData {
+ SkyShaderData *shader_data = nullptr;
+ bool uniform_set_updated = false;
+
+ virtual void set_render_priority(int p_priority) {}
+ virtual void set_next_pass(RID p_pass) {}
+ virtual void update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual void bind_uniforms();
+ virtual ~SkyMaterialData();
+};
+
+MaterialData *_create_sky_material_func(ShaderData *p_shader);
+
+/* Scene Materials */
+
+struct SceneShaderData : public ShaderData {
+ enum BlendMode { //used internally
+ BLEND_MODE_MIX,
+ BLEND_MODE_ADD,
+ BLEND_MODE_SUB,
+ BLEND_MODE_MUL,
+ BLEND_MODE_ALPHA_TO_COVERAGE
+ };
+
+ enum DepthDraw {
+ DEPTH_DRAW_DISABLED,
+ DEPTH_DRAW_OPAQUE,
+ DEPTH_DRAW_ALWAYS
+ };
+
+ enum DepthTest {
+ DEPTH_TEST_DISABLED,
+ DEPTH_TEST_ENABLED
+ };
+
+ enum Cull {
+ CULL_DISABLED,
+ CULL_FRONT,
+ CULL_BACK
+ };
+
+ enum AlphaAntiAliasing {
+ ALPHA_ANTIALIASING_OFF,
+ ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE,
+ ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
+ };
+
+ bool valid;
+ RID version;
+
+ String path;
+
+ HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
+
+ Vector<uint32_t> ubo_offsets;
+ uint32_t ubo_size;
+
+ String code;
+ HashMap<StringName, HashMap<int, RID>> default_texture_params;
+
+ BlendMode blend_mode;
+ AlphaAntiAliasing alpha_antialiasing_mode;
+ DepthDraw depth_draw;
+ DepthTest depth_test;
+ Cull cull_mode;
+
+ bool uses_point_size;
+ bool uses_alpha;
+ bool uses_blend_alpha;
+ bool uses_alpha_clip;
+ bool uses_depth_pre_pass;
+ bool uses_discard;
+ bool uses_roughness;
+ bool uses_normal;
+ bool uses_particle_trails;
+ bool wireframe;
+
+ bool unshaded;
+ bool uses_vertex;
+ bool uses_position;
+ bool uses_sss;
+ bool uses_transmittance;
+ bool uses_screen_texture;
+ bool uses_depth_texture;
+ bool uses_normal_texture;
+ bool uses_time;
+ bool writes_modelview_or_projection;
+ bool uses_world_coordinates;
+ bool uses_tangent;
+ bool uses_color;
+ bool uses_uv;
+ bool uses_uv2;
+ bool uses_custom0;
+ bool uses_custom1;
+ bool uses_custom2;
+ bool uses_custom3;
+ bool uses_bones;
+ bool uses_weights;
+
+ uint32_t vertex_input_mask = 0;
+
+ uint64_t last_pass = 0;
+ uint32_t index = 0;
+
+ virtual void set_code(const String &p_Code);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
+
+ virtual bool is_param_texture(const StringName &p_param) const;
+ virtual bool is_animated() const;
+ virtual bool casts_shadows() const;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+
+ SceneShaderData();
+ virtual ~SceneShaderData();
+};
+
+ShaderData *_create_scene_shader_func();
+
+struct SceneMaterialData : public MaterialData {
+ SceneShaderData *shader_data = nullptr;
+ uint64_t last_pass = 0;
+ uint32_t index = 0;
+ RID next_pass;
+ uint8_t priority = 0;
+ virtual void set_render_priority(int p_priority);
+ virtual void set_next_pass(RID p_pass);
+ virtual void update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual void bind_uniforms();
+ virtual ~SceneMaterialData();
+};
+
+MaterialData *_create_scene_material_func(ShaderData *p_shader);
+
+/* Global shader uniform structs */
+struct GlobalShaderUniforms {
+ enum {
+ BUFFER_DIRTY_REGION_SIZE = 1024
+ };
+ struct Variable {
+ HashSet<RID> texture_materials; // materials using this
+
+ RS::GlobalShaderUniformType type;
+ Variant value;
+ Variant override;
+ int32_t buffer_index; //for vectors
+ int32_t buffer_elements; //for vectors
+ };
+
+ HashMap<StringName, Variable> variables;
+
+ struct Value {
+ float x;
+ float y;
+ float z;
+ float w;
+ };
+
+ struct ValueInt {
+ int32_t x;
+ int32_t y;
+ int32_t z;
+ int32_t w;
+ };
+
+ struct ValueUInt {
+ uint32_t x;
+ uint32_t y;
+ uint32_t z;
+ uint32_t w;
+ };
+
+ struct ValueUsage {
+ uint32_t elements = 0;
+ };
+
+ List<RID> materials_using_buffer;
+ List<RID> materials_using_texture;
+
+ GLuint buffer = GLuint(0);
+ Value *buffer_values = nullptr;
+ ValueUsage *buffer_usage = nullptr;
+ bool *buffer_dirty_regions = nullptr;
+ uint32_t buffer_dirty_region_count = 0;
+
+ uint32_t buffer_size;
+
+ bool must_update_texture_materials = false;
+ bool must_update_buffer_materials = false;
+
+ HashMap<RID, int32_t> instance_buffer_pos;
+};
+
+class MaterialStorage : public RendererMaterialStorage {
+private:
+ friend struct MaterialData;
+ static MaterialStorage *singleton;
+
+ /* GLOBAL SHADER UNIFORM API */
+
+ GlobalShaderUniforms global_shader_uniforms;
+
+ int32_t _global_shader_uniform_allocate(uint32_t p_elements);
+ void _global_shader_uniform_store_in_buffer(int32_t p_index, RS::GlobalShaderUniformType p_type, const Variant &p_value);
+ void _global_shader_uniform_mark_buffer_dirty(int32_t p_index, int32_t p_elements);
+
+ /* SHADER API */
+
+ ShaderDataRequestFunction shader_data_request_func[RS::SHADER_MAX];
+ mutable RID_Owner<Shader, true> shader_owner;
+
+ /* MATERIAL API */
+ MaterialDataRequestFunction material_data_request_func[RS::SHADER_MAX];
+ mutable RID_Owner<Material, true> material_owner;
+
+ SelfList<Material>::List material_update_list;
+
+public:
+ static MaterialStorage *get_singleton();
+
+ MaterialStorage();
+ virtual ~MaterialStorage();
+
+ static _FORCE_INLINE_ void store_transform(const Transform3D &p_mtx, float *p_array) {
+ p_array[0] = p_mtx.basis.rows[0][0];
+ p_array[1] = p_mtx.basis.rows[1][0];
+ p_array[2] = p_mtx.basis.rows[2][0];
+ p_array[3] = 0;
+ p_array[4] = p_mtx.basis.rows[0][1];
+ p_array[5] = p_mtx.basis.rows[1][1];
+ p_array[6] = p_mtx.basis.rows[2][1];
+ p_array[7] = 0;
+ p_array[8] = p_mtx.basis.rows[0][2];
+ p_array[9] = p_mtx.basis.rows[1][2];
+ p_array[10] = p_mtx.basis.rows[2][2];
+ p_array[11] = 0;
+ p_array[12] = p_mtx.origin.x;
+ p_array[13] = p_mtx.origin.y;
+ p_array[14] = p_mtx.origin.z;
+ p_array[15] = 1;
+ }
+
+ static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_mtx, float *p_array) {
+ p_array[0] = p_mtx.rows[0][0];
+ p_array[1] = p_mtx.rows[1][0];
+ p_array[2] = p_mtx.rows[2][0];
+ p_array[3] = 0;
+ p_array[4] = p_mtx.rows[0][1];
+ p_array[5] = p_mtx.rows[1][1];
+ p_array[6] = p_mtx.rows[2][1];
+ p_array[7] = 0;
+ p_array[8] = p_mtx.rows[0][2];
+ p_array[9] = p_mtx.rows[1][2];
+ p_array[10] = p_mtx.rows[2][2];
+ p_array[11] = 0;
+ }
+
+ static _FORCE_INLINE_ void store_camera(const Projection &p_mtx, float *p_array) {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ p_array[i * 4 + j] = p_mtx.matrix[i][j];
+ }
+ }
+ }
+
+ struct Shaders {
+ CanvasShaderGLES3 canvas_shader;
+ SkyShaderGLES3 sky_shader;
+ SceneShaderGLES3 scene_shader;
+ CubemapFilterShaderGLES3 cubemap_filter_shader;
+
+ ShaderCompiler compiler_canvas;
+ ShaderCompiler compiler_scene;
+ ShaderCompiler compiler_particles;
+ ShaderCompiler compiler_sky;
+ } shaders;
+
+ /* GLOBAL SHADER UNIFORM API */
+
+ void _update_global_shader_uniforms();
+
+ virtual void global_shader_uniform_add(const StringName &p_name, RS::GlobalShaderUniformType p_type, const Variant &p_value) override;
+ virtual void global_shader_uniform_remove(const StringName &p_name) override;
+ virtual Vector<StringName> global_shader_uniform_get_list() const override;
+
+ virtual void global_shader_uniform_set(const StringName &p_name, const Variant &p_value) override;
+ virtual void global_shader_uniform_set_override(const StringName &p_name, const Variant &p_value) override;
+ virtual Variant global_shader_uniform_get(const StringName &p_name) const override;
+ virtual RS::GlobalShaderUniformType global_shader_uniform_get_type(const StringName &p_name) const override;
+ RS::GlobalShaderUniformType global_shader_uniform_get_type_internal(const StringName &p_name) const;
+
+ virtual void global_shader_uniforms_load_settings(bool p_load_textures = true) override;
+ virtual void global_shader_uniforms_clear() override;
+
+ virtual int32_t global_shader_uniforms_instance_allocate(RID p_instance) override;
+ virtual void global_shader_uniforms_instance_free(RID p_instance) override;
+ virtual void global_shader_uniforms_instance_update(RID p_instance, int p_index, const Variant &p_value) override;
+
+ GLuint global_shader_uniforms_get_uniform_buffer() const;
+
+ /* SHADER API */
+
+ Shader *get_shader(RID p_rid) { return shader_owner.get_or_null(p_rid); };
+ bool owns_shader(RID p_rid) { return shader_owner.owns(p_rid); };
+
+ void _shader_make_dirty(Shader *p_shader);
+
+ virtual RID shader_allocate() override;
+ virtual void shader_initialize(RID p_rid) override;
+ virtual void shader_free(RID p_rid) override;
+
+ virtual void shader_set_code(RID p_shader, const String &p_code) override;
+ virtual void shader_set_path_hint(RID p_shader, const String &p_path) override;
+ virtual String shader_get_code(RID p_shader) const override;
+ virtual void shader_get_shader_uniform_list(RID p_shader, List<PropertyInfo> *p_param_list) const override;
+
+ virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override;
+ virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const override;
+ virtual Variant shader_get_param_default(RID p_shader, const StringName &p_param) const override;
+
+ virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override;
+
+ /* MATERIAL API */
+
+ Material *get_material(RID p_rid) { return material_owner.get_or_null(p_rid); };
+ bool owns_material(RID p_rid) { return material_owner.owns(p_rid); };
+
+ void _material_queue_update(Material *material, bool p_uniform, bool p_texture);
+ void _update_queued_materials();
+
+ virtual RID material_allocate() override;
+ virtual void material_initialize(RID p_rid) override;
+ virtual void material_free(RID p_rid) override;
+
+ virtual void material_set_shader(RID p_material, RID p_shader) override;
+
+ virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) override;
+ virtual Variant material_get_param(RID p_material, const StringName &p_param) const override;
+
+ virtual void material_set_next_pass(RID p_material, RID p_next_material) override;
+ virtual void material_set_render_priority(RID p_material, int priority) override;
+
+ virtual bool material_is_animated(RID p_material) override;
+ virtual bool material_casts_shadows(RID p_material) override;
+
+ virtual void material_get_instance_shader_uniforms(RID p_material, List<InstanceShaderParam> *r_parameters) override;
+
+ virtual void material_update_dependency(RID p_material, DependencyTracker *p_instance) override;
+
+ _FORCE_INLINE_ uint32_t material_get_shader_id(RID p_material) {
+ Material *material = material_owner.get_or_null(p_material);
+ return material->shader_id;
+ }
+
+ _FORCE_INLINE_ MaterialData *material_get_data(RID p_material, RS::ShaderMode p_shader_mode) {
+ Material *material = material_owner.get_or_null(p_material);
+ if (!material || material->shader_mode != p_shader_mode) {
+ return nullptr;
+ } else {
+ return material->data;
+ }
+ }
+};
+
+} // namespace GLES3
+
+#endif // GLES3_ENABLED
+
+#endif // MATERIAL_STORAGE_GLES3_H
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
new file mode 100644
index 0000000000..d2c2aa0259
--- /dev/null
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -0,0 +1,1558 @@
+/*************************************************************************/
+/* mesh_storage.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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. */
+/*************************************************************************/
+
+#ifdef GLES3_ENABLED
+
+#include "mesh_storage.h"
+#include "material_storage.h"
+#include "utilities.h"
+
+using namespace GLES3;
+
+MeshStorage *MeshStorage::singleton = nullptr;
+
+MeshStorage *MeshStorage::get_singleton() {
+ return singleton;
+}
+
+MeshStorage::MeshStorage() {
+ singleton = this;
+}
+
+MeshStorage::~MeshStorage() {
+ singleton = nullptr;
+}
+
+/* MESH API */
+
+RID MeshStorage::mesh_allocate() {
+ return mesh_owner.allocate_rid();
+}
+
+void MeshStorage::mesh_initialize(RID p_rid) {
+ mesh_owner.initialize_rid(p_rid, Mesh());
+}
+
+void MeshStorage::mesh_free(RID p_rid) {
+ mesh_clear(p_rid);
+ mesh_set_shadow_mesh(p_rid, RID());
+ Mesh *mesh = mesh_owner.get_or_null(p_rid);
+ ERR_FAIL_COND(!mesh);
+
+ mesh->dependency.deleted_notify(p_rid);
+ if (mesh->instances.size()) {
+ ERR_PRINT("deleting mesh with active instances");
+ }
+ if (mesh->shadow_owners.size()) {
+ for (Mesh *E : mesh->shadow_owners) {
+ Mesh *shadow_owner = E;
+ shadow_owner->shadow_mesh = RID();
+ shadow_owner->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH);
+ }
+ }
+ mesh_owner.free(p_rid);
+}
+
+void MeshStorage::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) {
+ ERR_FAIL_COND(p_blend_shape_count < 0);
+
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+
+ ERR_FAIL_COND(mesh->surface_count > 0); //surfaces already exist
+ WARN_PRINT_ONCE("blend shapes not supported by GLES3 renderer yet");
+ mesh->blend_shape_count = p_blend_shape_count;
+}
+
+bool MeshStorage::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND_V(!mesh, false);
+
+ return mesh->blend_shape_count > 0 || (mesh->has_bone_weights && p_has_skeleton);
+}
+
+void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+
+ ERR_FAIL_COND(mesh->surface_count == RS::MAX_MESH_SURFACES);
+
+#ifdef DEBUG_ENABLED
+ //do a validation, to catch errors first
+ {
+ uint32_t stride = 0;
+ uint32_t attrib_stride = 0;
+ uint32_t skin_stride = 0;
+
+ // TODO: I think this should be <=, but it is copied from RendererRD, will have to verify later
+ for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) {
+ if ((p_surface.format & (1 << i))) {
+ switch (i) {
+ case RS::ARRAY_VERTEX: {
+ if (p_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
+ stride += sizeof(float) * 2;
+ } else {
+ stride += sizeof(float) * 3;
+ }
+
+ } break;
+ case RS::ARRAY_NORMAL: {
+ stride += sizeof(int32_t);
+
+ } break;
+ case RS::ARRAY_TANGENT: {
+ stride += sizeof(int32_t);
+
+ } break;
+ case RS::ARRAY_COLOR: {
+ attrib_stride += sizeof(uint32_t);
+ } break;
+ case RS::ARRAY_TEX_UV: {
+ attrib_stride += sizeof(float) * 2;
+
+ } break;
+ case RS::ARRAY_TEX_UV2: {
+ attrib_stride += sizeof(float) * 2;
+
+ } break;
+ case RS::ARRAY_CUSTOM0:
+ case RS::ARRAY_CUSTOM1:
+ case RS::ARRAY_CUSTOM2:
+ case RS::ARRAY_CUSTOM3: {
+ int idx = i - RS::ARRAY_CUSTOM0;
+ uint32_t fmt_shift[RS::ARRAY_CUSTOM_COUNT] = { RS::ARRAY_FORMAT_CUSTOM0_SHIFT, RS::ARRAY_FORMAT_CUSTOM1_SHIFT, RS::ARRAY_FORMAT_CUSTOM2_SHIFT, RS::ARRAY_FORMAT_CUSTOM3_SHIFT };
+ uint32_t fmt = (p_surface.format >> fmt_shift[idx]) & RS::ARRAY_FORMAT_CUSTOM_MASK;
+ uint32_t fmtsize[RS::ARRAY_CUSTOM_MAX] = { 4, 4, 4, 8, 4, 8, 12, 16 };
+ attrib_stride += fmtsize[fmt];
+
+ } break;
+ case RS::ARRAY_WEIGHTS:
+ case RS::ARRAY_BONES: {
+ //uses a separate array
+ bool use_8 = p_surface.format & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
+ skin_stride += sizeof(int16_t) * (use_8 ? 16 : 8);
+ } break;
+ }
+ }
+ }
+
+ int expected_size = stride * p_surface.vertex_count;
+ ERR_FAIL_COND_MSG(expected_size != p_surface.vertex_data.size(), "Size of vertex data provided (" + itos(p_surface.vertex_data.size()) + ") does not match expected (" + itos(expected_size) + ")");
+
+ int bs_expected_size = expected_size * mesh->blend_shape_count;
+
+ ERR_FAIL_COND_MSG(bs_expected_size != p_surface.blend_shape_data.size(), "Size of blend shape data provided (" + itos(p_surface.blend_shape_data.size()) + ") does not match expected (" + itos(bs_expected_size) + ")");
+
+ int expected_attrib_size = attrib_stride * p_surface.vertex_count;
+ ERR_FAIL_COND_MSG(expected_attrib_size != p_surface.attribute_data.size(), "Size of attribute data provided (" + itos(p_surface.attribute_data.size()) + ") does not match expected (" + itos(expected_attrib_size) + ")");
+
+ if ((p_surface.format & RS::ARRAY_FORMAT_WEIGHTS) && (p_surface.format & RS::ARRAY_FORMAT_BONES)) {
+ expected_size = skin_stride * p_surface.vertex_count;
+ ERR_FAIL_COND_MSG(expected_size != p_surface.skin_data.size(), "Size of skin data provided (" + itos(p_surface.skin_data.size()) + ") does not match expected (" + itos(expected_size) + ")");
+ }
+ }
+
+#endif
+
+ Mesh::Surface *s = memnew(Mesh::Surface);
+
+ s->format = p_surface.format;
+ s->primitive = p_surface.primitive;
+
+ glGenBuffers(1, &s->vertex_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer);
+ glBufferData(GL_ARRAY_BUFFER, p_surface.vertex_data.size(), p_surface.vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ s->vertex_buffer_size = p_surface.vertex_data.size();
+
+ if (p_surface.attribute_data.size()) {
+ glGenBuffers(1, &s->attribute_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, s->attribute_buffer);
+ glBufferData(GL_ARRAY_BUFFER, p_surface.attribute_data.size(), p_surface.attribute_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ s->attribute_buffer_size = p_surface.attribute_data.size();
+ }
+ if (p_surface.skin_data.size()) {
+ glGenBuffers(1, &s->skin_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, s->skin_buffer);
+ glBufferData(GL_ARRAY_BUFFER, p_surface.skin_data.size(), p_surface.skin_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ s->skin_buffer_size = p_surface.skin_data.size();
+ }
+
+ s->vertex_count = p_surface.vertex_count;
+
+ if (p_surface.format & RS::ARRAY_FORMAT_BONES) {
+ mesh->has_bone_weights = true;
+ }
+
+ if (p_surface.index_count) {
+ bool is_index_16 = p_surface.vertex_count <= 65536;
+ glGenBuffers(1, &s->index_buffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_buffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, p_surface.index_data.size(), p_surface.index_data.ptr(), GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind
+ s->index_count = p_surface.index_count;
+ s->index_buffer_size = p_surface.index_data.size();
+
+ if (p_surface.lods.size()) {
+ s->lods = memnew_arr(Mesh::Surface::LOD, p_surface.lods.size());
+ s->lod_count = p_surface.lods.size();
+
+ for (int i = 0; i < p_surface.lods.size(); i++) {
+ glGenBuffers(1, &s->lods[i].index_buffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->lods[i].index_buffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, p_surface.lods[i].index_data.size(), p_surface.lods[i].index_data.ptr(), GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind
+ s->lods[i].edge_length = p_surface.lods[i].edge_length;
+ s->lods[i].index_count = p_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4);
+ s->lods[i].index_buffer_size = p_surface.lods[i].index_data.size();
+ }
+ }
+ }
+
+ s->aabb = p_surface.aabb;
+ s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them.
+
+ if (mesh->blend_shape_count > 0) {
+ //s->blend_shape_buffer = RD::get_singleton()->storage_buffer_create(p_surface.blend_shape_data.size(), p_surface.blend_shape_data);
+ }
+
+ if (mesh->surface_count == 0) {
+ mesh->bone_aabbs = p_surface.bone_aabbs;
+ mesh->aabb = p_surface.aabb;
+ } else {
+ if (mesh->bone_aabbs.size() < p_surface.bone_aabbs.size()) {
+ // ArrayMesh::_surface_set_data only allocates bone_aabbs up to max_bone
+ // Each surface may affect different numbers of bones.
+ mesh->bone_aabbs.resize(p_surface.bone_aabbs.size());
+ }
+ for (int i = 0; i < p_surface.bone_aabbs.size(); i++) {
+ AABB bone = p_surface.bone_aabbs[i];
+ if (!bone.has_no_volume()) {
+ mesh->bone_aabbs.write[i].merge_with(p_surface.bone_aabbs[i]);
+ }
+ }
+ mesh->aabb.merge_with(p_surface.aabb);
+ }
+
+ s->material = p_surface.material;
+
+ mesh->surfaces = (Mesh::Surface **)memrealloc(mesh->surfaces, sizeof(Mesh::Surface *) * (mesh->surface_count + 1));
+ mesh->surfaces[mesh->surface_count] = s;
+ mesh->surface_count++;
+
+ for (MeshInstance *mi : mesh->instances) {
+ _mesh_instance_add_surface(mi, mesh, mesh->surface_count - 1);
+ }
+
+ mesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH);
+
+ for (Mesh *E : mesh->shadow_owners) {
+ Mesh *shadow_owner = E;
+ shadow_owner->shadow_mesh = RID();
+ shadow_owner->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH);
+ }
+
+ mesh->material_cache.clear();
+}
+
+int MeshStorage::mesh_get_blend_shape_count(RID p_mesh) const {
+ const Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND_V(!mesh, -1);
+ return mesh->blend_shape_count;
+}
+
+void MeshStorage::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_INDEX((int)p_mode, 2);
+
+ mesh->blend_shape_mode = p_mode;
+}
+
+RS::BlendShapeMode MeshStorage::mesh_get_blend_shape_mode(RID p_mesh) const {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND_V(!mesh, RS::BLEND_SHAPE_MODE_NORMALIZED);
+ return mesh->blend_shape_mode;
+}
+
+void MeshStorage::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+}
+
+void MeshStorage::mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+}
+
+void MeshStorage::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+}
+
+void MeshStorage::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+ mesh->surfaces[p_surface]->material = p_material;
+
+ mesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MATERIAL);
+ mesh->material_cache.clear();
+}
+
+RID MeshStorage::mesh_surface_get_material(RID p_mesh, int p_surface) const {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND_V(!mesh, RID());
+ ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RID());
+
+ return mesh->surfaces[p_surface]->material;
+}
+
+RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND_V(!mesh, RS::SurfaceData());
+ ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RS::SurfaceData());
+
+ Mesh::Surface &s = *mesh->surfaces[p_surface];
+
+ RS::SurfaceData sd;
+ sd.format = s.format;
+ sd.vertex_data = Utilities::buffer_get_data(GL_ARRAY_BUFFER, s.vertex_buffer, s.vertex_buffer_size);
+
+ if (s.attribute_buffer != 0) {
+ sd.attribute_data = Utilities::buffer_get_data(GL_ARRAY_BUFFER, s.attribute_buffer, s.attribute_buffer_size);
+ }
+
+ sd.vertex_count = s.vertex_count;
+ sd.index_count = s.index_count;
+ sd.primitive = s.primitive;
+
+ if (sd.index_count) {
+ sd.index_data = Utilities::buffer_get_data(GL_ELEMENT_ARRAY_BUFFER, s.index_buffer, s.index_buffer_size);
+ }
+
+ sd.aabb = s.aabb;
+ for (uint32_t i = 0; i < s.lod_count; i++) {
+ RS::SurfaceData::LOD lod;
+ lod.edge_length = s.lods[i].edge_length;
+ lod.index_data = Utilities::buffer_get_data(GL_ELEMENT_ARRAY_BUFFER, s.lods[i].index_buffer, s.lods[i].index_buffer_size);
+ sd.lods.push_back(lod);
+ }
+
+ sd.bone_aabbs = s.bone_aabbs;
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ return sd;
+}
+
+int MeshStorage::mesh_get_surface_count(RID p_mesh) const {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND_V(!mesh, 0);
+ return mesh->surface_count;
+}
+
+void MeshStorage::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ mesh->custom_aabb = p_aabb;
+}
+
+AABB MeshStorage::mesh_get_custom_aabb(RID p_mesh) const {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND_V(!mesh, AABB());
+ return mesh->custom_aabb;
+}
+
+AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND_V(!mesh, AABB());
+
+ if (mesh->custom_aabb != AABB()) {
+ return mesh->custom_aabb;
+ }
+
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+
+ if (!skeleton || skeleton->size == 0) {
+ return mesh->aabb;
+ }
+
+ // Calculate AABB based on Skeleton
+
+ AABB aabb;
+
+ for (uint32_t i = 0; i < mesh->surface_count; i++) {
+ AABB laabb;
+ if ((mesh->surfaces[i]->format & RS::ARRAY_FORMAT_BONES) && mesh->surfaces[i]->bone_aabbs.size()) {
+ int bs = mesh->surfaces[i]->bone_aabbs.size();
+ const AABB *skbones = mesh->surfaces[i]->bone_aabbs.ptr();
+
+ int sbs = skeleton->size;
+ ERR_CONTINUE(bs > sbs);
+ const float *baseptr = skeleton->data.ptr();
+
+ bool first = true;
+
+ if (skeleton->use_2d) {
+ for (int j = 0; j < bs; j++) {
+ if (skbones[0].size == Vector3()) {
+ continue; //bone is unused
+ }
+
+ const float *dataptr = baseptr + j * 8;
+
+ Transform3D mtx;
+
+ mtx.basis.rows[0].x = dataptr[0];
+ mtx.basis.rows[1].x = dataptr[1];
+ mtx.origin.x = dataptr[3];
+
+ mtx.basis.rows[0].y = dataptr[4];
+ mtx.basis.rows[1].y = dataptr[5];
+ mtx.origin.y = dataptr[7];
+
+ 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 (skbones[0].size == Vector3()) {
+ continue; //bone is unused
+ }
+
+ const float *dataptr = baseptr + j * 12;
+
+ Transform3D mtx;
+
+ mtx.basis.rows[0][0] = dataptr[0];
+ mtx.basis.rows[0][1] = dataptr[1];
+ mtx.basis.rows[0][2] = dataptr[2];
+ mtx.origin.x = dataptr[3];
+ mtx.basis.rows[1][0] = dataptr[4];
+ mtx.basis.rows[1][1] = dataptr[5];
+ mtx.basis.rows[1][2] = dataptr[6];
+ mtx.origin.y = dataptr[7];
+ mtx.basis.rows[2][0] = dataptr[8];
+ mtx.basis.rows[2][1] = dataptr[9];
+ mtx.basis.rows[2][2] = dataptr[10];
+ mtx.origin.z = dataptr[11];
+
+ AABB baabb = mtx.xform(skbones[j]);
+ if (first) {
+ laabb = baabb;
+ first = false;
+ } else {
+ laabb.merge_with(baabb);
+ }
+ }
+ }
+
+ if (laabb.size == Vector3()) {
+ laabb = mesh->surfaces[i]->aabb;
+ }
+ } else {
+ laabb = mesh->surfaces[i]->aabb;
+ }
+
+ if (i == 0) {
+ aabb = laabb;
+ } else {
+ aabb.merge_with(laabb);
+ }
+ }
+
+ return aabb;
+}
+
+void MeshStorage::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+
+ Mesh *shadow_mesh = mesh_owner.get_or_null(mesh->shadow_mesh);
+ if (shadow_mesh) {
+ shadow_mesh->shadow_owners.erase(mesh);
+ }
+ mesh->shadow_mesh = p_shadow_mesh;
+
+ shadow_mesh = mesh_owner.get_or_null(mesh->shadow_mesh);
+
+ if (shadow_mesh) {
+ shadow_mesh->shadow_owners.insert(mesh);
+ }
+
+ mesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH);
+}
+
+void MeshStorage::mesh_clear(RID p_mesh) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ for (uint32_t i = 0; i < mesh->surface_count; i++) {
+ Mesh::Surface &s = *mesh->surfaces[i];
+
+ if (s.vertex_buffer != 0) {
+ glDeleteBuffers(1, &s.vertex_buffer);
+ s.vertex_buffer = 0;
+ }
+
+ if (s.version_count != 0) {
+ for (uint32_t j = 0; j < s.version_count; j++) {
+ glDeleteVertexArrays(1, &s.versions[j].vertex_array);
+ s.versions[j].vertex_array = 0;
+ }
+ }
+
+ if (s.attribute_buffer != 0) {
+ glDeleteBuffers(1, &s.attribute_buffer);
+ s.attribute_buffer = 0;
+ }
+
+ if (s.skin_buffer != 0) {
+ glDeleteBuffers(1, &s.skin_buffer);
+ s.skin_buffer = 0;
+ }
+
+ if (s.index_buffer != 0) {
+ glDeleteBuffers(1, &s.index_buffer);
+ s.index_buffer = 0;
+ }
+ memdelete(mesh->surfaces[i]);
+ }
+ if (mesh->surfaces) {
+ memfree(mesh->surfaces);
+ }
+
+ mesh->surfaces = nullptr;
+ mesh->surface_count = 0;
+ mesh->material_cache.clear();
+ //clear instance data
+ for (MeshInstance *mi : mesh->instances) {
+ _mesh_instance_clear(mi);
+ }
+ mesh->has_bone_weights = false;
+ mesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH);
+
+ for (Mesh *E : mesh->shadow_owners) {
+ Mesh *shadow_owner = E;
+ shadow_owner->shadow_mesh = RID();
+ shadow_owner->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH);
+ }
+}
+
+void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis) {
+ Mesh::Surface::Attrib attribs[RS::ARRAY_MAX];
+
+ int attributes_stride = 0;
+ int vertex_stride = 0;
+ int skin_stride = 0;
+
+ for (int i = 0; i < RS::ARRAY_INDEX; i++) {
+ if (!(s->format & (1 << i))) {
+ attribs[i].enabled = false;
+ attribs[i].integer = false;
+ continue;
+ }
+
+ attribs[i].enabled = true;
+ attribs[i].integer = false;
+
+ switch (i) {
+ case RS::ARRAY_VERTEX: {
+ attribs[i].offset = vertex_stride;
+ if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
+ attribs[i].size = 2;
+ } else {
+ attribs[i].size = 3;
+ }
+ attribs[i].type = GL_FLOAT;
+ vertex_stride += attribs[i].size * sizeof(float);
+ attribs[i].normalized = GL_FALSE;
+ } break;
+ case RS::ARRAY_NORMAL: {
+ attribs[i].offset = vertex_stride;
+ // Will need to change to accommodate octahedral compression
+ attribs[i].size = 4;
+ attribs[i].type = GL_UNSIGNED_INT_2_10_10_10_REV;
+ vertex_stride += sizeof(float);
+ attribs[i].normalized = GL_TRUE;
+ } break;
+ case RS::ARRAY_TANGENT: {
+ attribs[i].offset = vertex_stride;
+ attribs[i].size = 4;
+ attribs[i].type = GL_UNSIGNED_INT_2_10_10_10_REV;
+ vertex_stride += sizeof(float);
+ attribs[i].normalized = GL_TRUE;
+ } break;
+ case RS::ARRAY_COLOR: {
+ attribs[i].offset = attributes_stride;
+ attribs[i].size = 4;
+ attribs[i].type = GL_UNSIGNED_BYTE;
+ attributes_stride += 4;
+ attribs[i].normalized = GL_TRUE;
+ } break;
+ case RS::ARRAY_TEX_UV: {
+ attribs[i].offset = attributes_stride;
+ attribs[i].size = 2;
+ attribs[i].type = GL_FLOAT;
+ attributes_stride += 2 * sizeof(float);
+ attribs[i].normalized = GL_FALSE;
+ } break;
+ case RS::ARRAY_TEX_UV2: {
+ attribs[i].offset = attributes_stride;
+ attribs[i].size = 2;
+ attribs[i].type = GL_FLOAT;
+ attributes_stride += 2 * sizeof(float);
+ attribs[i].normalized = GL_FALSE;
+ } break;
+ case RS::ARRAY_CUSTOM0:
+ case RS::ARRAY_CUSTOM1:
+ case RS::ARRAY_CUSTOM2:
+ case RS::ARRAY_CUSTOM3: {
+ attribs[i].offset = attributes_stride;
+
+ int idx = i - RS::ARRAY_CUSTOM0;
+ uint32_t fmt_shift[RS::ARRAY_CUSTOM_COUNT] = { RS::ARRAY_FORMAT_CUSTOM0_SHIFT, RS::ARRAY_FORMAT_CUSTOM1_SHIFT, RS::ARRAY_FORMAT_CUSTOM2_SHIFT, RS::ARRAY_FORMAT_CUSTOM3_SHIFT };
+ uint32_t fmt = (s->format >> fmt_shift[idx]) & RS::ARRAY_FORMAT_CUSTOM_MASK;
+ uint32_t fmtsize[RS::ARRAY_CUSTOM_MAX] = { 4, 4, 4, 8, 4, 8, 12, 16 };
+ GLenum gl_type[RS::ARRAY_CUSTOM_MAX] = { GL_UNSIGNED_BYTE, GL_BYTE, GL_HALF_FLOAT, GL_HALF_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT };
+ GLboolean norm[RS::ARRAY_CUSTOM_MAX] = { GL_TRUE, GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE };
+ attribs[i].type = gl_type[fmt];
+ attributes_stride += fmtsize[fmt];
+ attribs[i].size = fmtsize[fmt] / sizeof(float);
+ attribs[i].normalized = norm[fmt];
+ } break;
+ case RS::ARRAY_BONES: {
+ attribs[i].offset = skin_stride;
+ attribs[i].size = 4;
+ attribs[i].type = GL_UNSIGNED_SHORT;
+ attributes_stride += 4 * sizeof(uint16_t);
+ attribs[i].normalized = GL_FALSE;
+ attribs[i].integer = true;
+ } break;
+ case RS::ARRAY_WEIGHTS: {
+ attribs[i].offset = skin_stride;
+ attribs[i].size = 4;
+ attribs[i].type = GL_UNSIGNED_SHORT;
+ attributes_stride += 4 * sizeof(uint16_t);
+ attribs[i].normalized = GL_TRUE;
+ } break;
+ }
+ }
+
+ glGenVertexArrays(1, &v.vertex_array);
+ glBindVertexArray(v.vertex_array);
+
+ for (int i = 0; i < RS::ARRAY_INDEX; i++) {
+ if (!attribs[i].enabled) {
+ glDisableVertexAttribArray(i);
+ continue;
+ }
+ if (i <= RS::ARRAY_TANGENT) {
+ attribs[i].stride = vertex_stride;
+ if (mis) {
+ glBindBuffer(GL_ARRAY_BUFFER, mis->vertex_buffer);
+ } else {
+ glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer);
+ }
+ } else if (i <= RS::ARRAY_CUSTOM3) {
+ attribs[i].stride = attributes_stride;
+ glBindBuffer(GL_ARRAY_BUFFER, s->attribute_buffer);
+ } else {
+ attribs[i].stride = skin_stride;
+ glBindBuffer(GL_ARRAY_BUFFER, s->skin_buffer);
+ }
+
+ if (attribs[i].integer) {
+ glVertexAttribIPointer(i, attribs[i].size, attribs[i].type, attribs[i].stride, CAST_INT_TO_UCHAR_PTR(attribs[i].offset));
+ } else {
+ glVertexAttribPointer(i, attribs[i].size, attribs[i].type, attribs[i].normalized, attribs[i].stride, CAST_INT_TO_UCHAR_PTR(attribs[i].offset));
+ }
+ glEnableVertexAttribArray(i);
+ }
+
+ // Do not bind index here as we want to switch between index buffers for LOD
+
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ v.input_mask = p_input_mask;
+}
+
+/* MESH INSTANCE API */
+
+RID MeshStorage::mesh_instance_create(RID p_base) {
+ Mesh *mesh = mesh_owner.get_or_null(p_base);
+ ERR_FAIL_COND_V(!mesh, RID());
+
+ RID rid = mesh_instance_owner.make_rid();
+ MeshInstance *mi = mesh_instance_owner.get_or_null(rid);
+
+ mi->mesh = mesh;
+
+ for (uint32_t i = 0; i < mesh->surface_count; i++) {
+ _mesh_instance_add_surface(mi, mesh, i);
+ }
+
+ mi->I = mesh->instances.push_back(mi);
+
+ mi->dirty = true;
+
+ return rid;
+}
+
+void MeshStorage::mesh_instance_free(RID p_rid) {
+ MeshInstance *mi = mesh_instance_owner.get_or_null(p_rid);
+ _mesh_instance_clear(mi);
+ mi->mesh->instances.erase(mi->I);
+ mi->I = nullptr;
+
+ mesh_instance_owner.free(p_rid);
+}
+
+void MeshStorage::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) {
+ MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
+ if (mi->skeleton == p_skeleton) {
+ return;
+ }
+ mi->skeleton = p_skeleton;
+ mi->skeleton_version = 0;
+ mi->dirty = true;
+}
+
+void MeshStorage::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) {
+ MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
+ ERR_FAIL_COND(!mi);
+ ERR_FAIL_INDEX(p_shape, (int)mi->blend_weights.size());
+ mi->blend_weights[p_shape] = p_weight;
+ mi->weights_dirty = true;
+}
+
+void MeshStorage::_mesh_instance_clear(MeshInstance *mi) {
+ for (uint32_t i = 0; i < mi->surfaces.size(); i++) {
+ if (mi->surfaces[i].version_count != 0) {
+ for (uint32_t j = 0; j < mi->surfaces[i].version_count; j++) {
+ glDeleteVertexArrays(1, &mi->surfaces[i].versions[j].vertex_array);
+ mi->surfaces[i].versions[j].vertex_array = 0;
+ }
+ memfree(mi->surfaces[i].versions);
+ }
+ if (mi->surfaces[i].vertex_buffer != 0) {
+ glDeleteBuffers(1, &mi->surfaces[i].vertex_buffer);
+ mi->surfaces[i].vertex_buffer = 0;
+ }
+ }
+ mi->surfaces.clear();
+
+ if (mi->blend_weights_buffer != 0) {
+ glDeleteBuffers(1, &mi->blend_weights_buffer);
+ mi->blend_weights_buffer = 0;
+ }
+ mi->blend_weights.clear();
+ mi->weights_dirty = false;
+ mi->skeleton_version = 0;
+}
+
+void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface) {
+ if (mesh->blend_shape_count > 0 && mi->blend_weights_buffer == 0) {
+ mi->blend_weights.resize(mesh->blend_shape_count);
+ for (uint32_t i = 0; i < mi->blend_weights.size(); i++) {
+ mi->blend_weights[i] = 0;
+ }
+ // Todo allocate buffer for blend_weights and copy data to it
+ //mi->blend_weights_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * mi->blend_weights.size(), mi->blend_weights.to_byte_array());
+
+ mi->weights_dirty = true;
+ }
+
+ MeshInstance::Surface s;
+ if (mesh->blend_shape_count > 0 || (mesh->surfaces[p_surface]->format & RS::ARRAY_FORMAT_BONES)) {
+ //surface warrants transform
+ //s.vertex_buffer = RD::get_singleton()->vertex_buffer_create(mesh->surfaces[p_surface]->vertex_buffer_size, Vector<uint8_t>(), true);
+ }
+
+ mi->surfaces.push_back(s);
+ mi->dirty = true;
+}
+
+void MeshStorage::mesh_instance_check_for_update(RID p_mesh_instance) {
+ MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
+
+ bool needs_update = mi->dirty;
+
+ if (mi->weights_dirty && !mi->weight_update_list.in_list()) {
+ dirty_mesh_instance_weights.add(&mi->weight_update_list);
+ needs_update = true;
+ }
+
+ if (mi->array_update_list.in_list()) {
+ return;
+ }
+
+ if (!needs_update && mi->skeleton.is_valid()) {
+ Skeleton *sk = skeleton_owner.get_or_null(mi->skeleton);
+ if (sk && sk->version != mi->skeleton_version) {
+ needs_update = true;
+ }
+ }
+
+ if (needs_update) {
+ dirty_mesh_instance_arrays.add(&mi->array_update_list);
+ }
+}
+
+void MeshStorage::update_mesh_instances() {
+ while (dirty_mesh_instance_weights.first()) {
+ MeshInstance *mi = dirty_mesh_instance_weights.first()->self();
+
+ if (mi->blend_weights_buffer != 0) {
+ //RD::get_singleton()->buffer_update(mi->blend_weights_buffer, 0, mi->blend_weights.size() * sizeof(float), mi->blend_weights.ptr());
+ }
+ dirty_mesh_instance_weights.remove(&mi->weight_update_list);
+ mi->weights_dirty = false;
+ }
+ if (dirty_mesh_instance_arrays.first() == nullptr) {
+ return; //nothing to do
+ }
+
+ // Process skeletons and blend shapes using transform feedback
+ // TODO: Implement when working on skeletons and blend shapes
+}
+
+/* MULTIMESH API */
+
+RID MeshStorage::multimesh_allocate() {
+ return multimesh_owner.allocate_rid();
+}
+
+void MeshStorage::multimesh_initialize(RID p_rid) {
+ multimesh_owner.initialize_rid(p_rid, MultiMesh());
+}
+
+void MeshStorage::multimesh_free(RID p_rid) {
+ _update_dirty_multimeshes();
+ multimesh_allocate_data(p_rid, 0, RS::MULTIMESH_TRANSFORM_2D);
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_rid);
+ multimesh->dependency.deleted_notify(p_rid);
+ multimesh_owner.free(p_rid);
+}
+
+void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+
+ if (multimesh->instances == p_instances && multimesh->xform_format == p_transform_format && multimesh->uses_colors == p_use_colors && multimesh->uses_custom_data == p_use_custom_data) {
+ return;
+ }
+
+ if (multimesh->buffer) {
+ glDeleteBuffers(1, &multimesh->buffer);
+ multimesh->buffer = 0;
+ }
+
+ if (multimesh->data_cache_dirty_regions) {
+ memdelete_arr(multimesh->data_cache_dirty_regions);
+ multimesh->data_cache_dirty_regions = nullptr;
+ multimesh->data_cache_used_dirty_regions = 0;
+ }
+
+ multimesh->instances = p_instances;
+ multimesh->xform_format = p_transform_format;
+ multimesh->uses_colors = p_use_colors;
+ multimesh->color_offset_cache = p_transform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12;
+ multimesh->uses_custom_data = p_use_custom_data;
+ multimesh->custom_data_offset_cache = multimesh->color_offset_cache + (p_use_colors ? 2 : 0);
+ multimesh->stride_cache = multimesh->custom_data_offset_cache + (p_use_custom_data ? 2 : 0);
+ multimesh->buffer_set = false;
+
+ multimesh->data_cache = Vector<float>();
+ multimesh->aabb = AABB();
+ multimesh->aabb_dirty = false;
+ multimesh->visible_instances = MIN(multimesh->visible_instances, multimesh->instances);
+
+ if (multimesh->instances) {
+ glGenBuffers(1, &multimesh->buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer);
+ glBufferData(GL_ARRAY_BUFFER, multimesh->instances * multimesh->stride_cache * sizeof(float), nullptr, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+
+ multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MULTIMESH);
+}
+
+int MeshStorage::multimesh_get_instance_count(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, 0);
+ return multimesh->instances;
+}
+
+void MeshStorage::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ if (multimesh->mesh == p_mesh || p_mesh.is_null()) {
+ return;
+ }
+ multimesh->mesh = p_mesh;
+
+ if (multimesh->instances == 0) {
+ return;
+ }
+
+ if (multimesh->data_cache.size()) {
+ //we have a data cache, just mark it dirty
+ _multimesh_mark_all_dirty(multimesh, false, true);
+ } else if (multimesh->instances) {
+ // Need to re-create AABB. Unfortunately, calling this has a penalty.
+ if (multimesh->buffer_set) {
+ Vector<uint8_t> buffer = Utilities::buffer_get_data(GL_ARRAY_BUFFER, multimesh->buffer, multimesh->instances * multimesh->stride_cache * sizeof(float));
+ const uint8_t *r = buffer.ptr();
+ const float *data = (const float *)r;
+ _multimesh_re_create_aabb(multimesh, data, multimesh->instances);
+ }
+ }
+
+ multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH);
+}
+
+#define MULTIMESH_DIRTY_REGION_SIZE 512
+
+void MeshStorage::_multimesh_make_local(MultiMesh *multimesh) const {
+ if (multimesh->data_cache.size() > 0) {
+ return; //already local
+ }
+ ERR_FAIL_COND(multimesh->data_cache.size() > 0);
+ // this means that the user wants to load/save individual elements,
+ // for this, the data must reside on CPU, so just copy it there.
+ multimesh->data_cache.resize(multimesh->instances * multimesh->stride_cache);
+ {
+ float *w = multimesh->data_cache.ptrw();
+
+ if (multimesh->buffer_set) {
+ Vector<uint8_t> buffer = Utilities::buffer_get_data(GL_ARRAY_BUFFER, multimesh->buffer, multimesh->instances * multimesh->stride_cache * sizeof(float));
+
+ {
+ const uint8_t *r = buffer.ptr();
+ memcpy(w, r, buffer.size());
+ }
+ } else {
+ memset(w, 0, (size_t)multimesh->instances * multimesh->stride_cache * sizeof(float));
+ }
+ }
+ uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+ multimesh->data_cache_dirty_regions = memnew_arr(bool, data_cache_dirty_region_count);
+ for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
+ multimesh->data_cache_dirty_regions[i] = false;
+ }
+ multimesh->data_cache_used_dirty_regions = 0;
+}
+
+void MeshStorage::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb) {
+ uint32_t region_index = p_index / MULTIMESH_DIRTY_REGION_SIZE;
+#ifdef DEBUG_ENABLED
+ uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+ ERR_FAIL_UNSIGNED_INDEX(region_index, data_cache_dirty_region_count); //bug
+#endif
+ if (!multimesh->data_cache_dirty_regions[region_index]) {
+ multimesh->data_cache_dirty_regions[region_index] = true;
+ multimesh->data_cache_used_dirty_regions++;
+ }
+
+ if (p_aabb) {
+ multimesh->aabb_dirty = true;
+ }
+
+ if (!multimesh->dirty) {
+ multimesh->dirty_list = multimesh_dirty_list;
+ multimesh_dirty_list = multimesh;
+ multimesh->dirty = true;
+ }
+}
+
+void MeshStorage::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb) {
+ if (p_data) {
+ uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+
+ for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
+ if (!multimesh->data_cache_dirty_regions[i]) {
+ multimesh->data_cache_dirty_regions[i] = true;
+ multimesh->data_cache_used_dirty_regions++;
+ }
+ }
+ }
+
+ if (p_aabb) {
+ multimesh->aabb_dirty = true;
+ }
+
+ if (!multimesh->dirty) {
+ multimesh->dirty_list = multimesh_dirty_list;
+ multimesh_dirty_list = multimesh;
+ multimesh->dirty = true;
+ }
+}
+
+void MeshStorage::_multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances) {
+ ERR_FAIL_COND(multimesh->mesh.is_null());
+ AABB aabb;
+ AABB mesh_aabb = mesh_get_aabb(multimesh->mesh);
+ for (int i = 0; i < p_instances; i++) {
+ const float *data = p_data + multimesh->stride_cache * i;
+ Transform3D t;
+
+ if (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_3D) {
+ t.basis.rows[0][0] = data[0];
+ t.basis.rows[0][1] = data[1];
+ t.basis.rows[0][2] = data[2];
+ t.origin.x = data[3];
+ t.basis.rows[1][0] = data[4];
+ t.basis.rows[1][1] = data[5];
+ t.basis.rows[1][2] = data[6];
+ t.origin.y = data[7];
+ t.basis.rows[2][0] = data[8];
+ t.basis.rows[2][1] = data[9];
+ t.basis.rows[2][2] = data[10];
+ t.origin.z = data[11];
+
+ } else {
+ t.basis.rows[0].x = data[0];
+ t.basis.rows[1].x = data[1];
+ t.origin.x = data[3];
+
+ t.basis.rows[0].y = data[4];
+ t.basis.rows[1].y = data[5];
+ t.origin.y = data[7];
+ }
+
+ if (i == 0) {
+ aabb = t.xform(mesh_aabb);
+ } else {
+ aabb.merge_with(t.xform(mesh_aabb));
+ }
+ }
+
+ multimesh->aabb = aabb;
+}
+
+void MeshStorage::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_INDEX(p_index, multimesh->instances);
+ ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D);
+
+ _multimesh_make_local(multimesh);
+
+ {
+ float *w = multimesh->data_cache.ptrw();
+
+ float *dataptr = w + p_index * multimesh->stride_cache;
+
+ dataptr[0] = p_transform.basis.rows[0][0];
+ dataptr[1] = p_transform.basis.rows[0][1];
+ dataptr[2] = p_transform.basis.rows[0][2];
+ dataptr[3] = p_transform.origin.x;
+ dataptr[4] = p_transform.basis.rows[1][0];
+ dataptr[5] = p_transform.basis.rows[1][1];
+ dataptr[6] = p_transform.basis.rows[1][2];
+ dataptr[7] = p_transform.origin.y;
+ dataptr[8] = p_transform.basis.rows[2][0];
+ dataptr[9] = p_transform.basis.rows[2][1];
+ dataptr[10] = p_transform.basis.rows[2][2];
+ dataptr[11] = p_transform.origin.z;
+ }
+
+ _multimesh_mark_dirty(multimesh, p_index, true);
+}
+
+void MeshStorage::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_INDEX(p_index, multimesh->instances);
+ ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_2D);
+
+ _multimesh_make_local(multimesh);
+
+ {
+ float *w = multimesh->data_cache.ptrw();
+
+ float *dataptr = w + p_index * multimesh->stride_cache;
+
+ dataptr[0] = p_transform.columns[0][0];
+ dataptr[1] = p_transform.columns[1][0];
+ dataptr[2] = 0;
+ dataptr[3] = p_transform.columns[2][0];
+ dataptr[4] = p_transform.columns[0][1];
+ dataptr[5] = p_transform.columns[1][1];
+ dataptr[6] = 0;
+ dataptr[7] = p_transform.columns[2][1];
+ }
+
+ _multimesh_mark_dirty(multimesh, p_index, true);
+}
+
+void MeshStorage::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_INDEX(p_index, multimesh->instances);
+ ERR_FAIL_COND(!multimesh->uses_colors);
+
+ _multimesh_make_local(multimesh);
+
+ {
+ // Colors are packed into 2 floats.
+ float *w = multimesh->data_cache.ptrw();
+
+ float *dataptr = w + p_index * multimesh->stride_cache + multimesh->color_offset_cache;
+ uint16_t val[4] = { Math::make_half_float(p_color.r), Math::make_half_float(p_color.g), Math::make_half_float(p_color.b), Math::make_half_float(p_color.a) };
+ memcpy(dataptr, val, 2 * 4);
+ }
+
+ _multimesh_mark_dirty(multimesh, p_index, false);
+}
+
+void MeshStorage::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_INDEX(p_index, multimesh->instances);
+ ERR_FAIL_COND(!multimesh->uses_custom_data);
+
+ _multimesh_make_local(multimesh);
+
+ {
+ float *w = multimesh->data_cache.ptrw();
+
+ float *dataptr = w + p_index * multimesh->stride_cache + multimesh->custom_data_offset_cache;
+ uint16_t val[4] = { Math::make_half_float(p_color.r), Math::make_half_float(p_color.g), Math::make_half_float(p_color.b), Math::make_half_float(p_color.a) };
+ memcpy(dataptr, val, 2 * 4);
+ }
+
+ _multimesh_mark_dirty(multimesh, p_index, false);
+}
+
+RID MeshStorage::multimesh_get_mesh(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, RID());
+
+ return multimesh->mesh;
+}
+
+AABB MeshStorage::multimesh_get_aabb(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, AABB());
+ if (multimesh->aabb_dirty) {
+ const_cast<MeshStorage *>(this)->_update_dirty_multimeshes();
+ }
+ return multimesh->aabb;
+}
+
+Transform3D MeshStorage::multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, Transform3D());
+ ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform3D());
+ ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D, Transform3D());
+
+ _multimesh_make_local(multimesh);
+
+ Transform3D t;
+ {
+ const float *r = multimesh->data_cache.ptr();
+
+ const float *dataptr = r + p_index * multimesh->stride_cache;
+
+ t.basis.rows[0][0] = dataptr[0];
+ t.basis.rows[0][1] = dataptr[1];
+ t.basis.rows[0][2] = dataptr[2];
+ t.origin.x = dataptr[3];
+ t.basis.rows[1][0] = dataptr[4];
+ t.basis.rows[1][1] = dataptr[5];
+ t.basis.rows[1][2] = dataptr[6];
+ t.origin.y = dataptr[7];
+ t.basis.rows[2][0] = dataptr[8];
+ t.basis.rows[2][1] = dataptr[9];
+ t.basis.rows[2][2] = dataptr[10];
+ t.origin.z = dataptr[11];
+ }
+
+ return t;
+}
+
+Transform2D MeshStorage::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, Transform2D());
+ ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform2D());
+ ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_2D, Transform2D());
+
+ _multimesh_make_local(multimesh);
+
+ Transform2D t;
+ {
+ const float *r = multimesh->data_cache.ptr();
+
+ const float *dataptr = r + p_index * multimesh->stride_cache;
+
+ t.columns[0][0] = dataptr[0];
+ t.columns[1][0] = dataptr[1];
+ t.columns[2][0] = dataptr[3];
+ t.columns[0][1] = dataptr[4];
+ t.columns[1][1] = dataptr[5];
+ t.columns[2][1] = dataptr[7];
+ }
+
+ return t;
+}
+
+Color MeshStorage::multimesh_instance_get_color(RID p_multimesh, int p_index) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, Color());
+ ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color());
+ ERR_FAIL_COND_V(!multimesh->uses_colors, Color());
+
+ _multimesh_make_local(multimesh);
+
+ Color c;
+ {
+ const float *r = multimesh->data_cache.ptr();
+
+ const float *dataptr = r + p_index * multimesh->stride_cache + multimesh->color_offset_cache;
+ uint16_t raw_data[4];
+ memcpy(raw_data, dataptr, 2 * 4);
+ c.r = Math::half_to_float(raw_data[0]);
+ c.g = Math::half_to_float(raw_data[1]);
+ c.b = Math::half_to_float(raw_data[2]);
+ c.a = Math::half_to_float(raw_data[3]);
+ }
+
+ return c;
+}
+
+Color MeshStorage::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, Color());
+ ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color());
+ ERR_FAIL_COND_V(!multimesh->uses_custom_data, Color());
+
+ _multimesh_make_local(multimesh);
+
+ Color c;
+ {
+ const float *r = multimesh->data_cache.ptr();
+
+ const float *dataptr = r + p_index * multimesh->stride_cache + multimesh->custom_data_offset_cache;
+ uint16_t raw_data[4];
+ memcpy(raw_data, dataptr, 2 * 4);
+ c.r = Math::half_to_float(raw_data[0]);
+ c.g = Math::half_to_float(raw_data[1]);
+ c.b = Math::half_to_float(raw_data[2]);
+ c.a = Math::half_to_float(raw_data[3]);
+ }
+
+ return c;
+}
+
+void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+
+ if (multimesh->uses_colors || multimesh->uses_custom_data) {
+ // Color and custom need to be packed so copy buffer to data_cache and pack.
+
+ _multimesh_make_local(multimesh);
+ multimesh->data_cache = p_buffer;
+
+ float *w = multimesh->data_cache.ptrw();
+ uint32_t old_stride = multimesh->xform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12;
+ old_stride += multimesh->uses_colors ? 4 : 0;
+ old_stride += multimesh->uses_custom_data ? 4 : 0;
+ for (int i = 0; i < multimesh->instances; i++) {
+ {
+ float *dataptr = w + i * old_stride;
+ float *newptr = w + i * multimesh->stride_cache;
+ float vals[8] = { dataptr[0], dataptr[1], dataptr[2], dataptr[3], dataptr[4], dataptr[5], dataptr[6], dataptr[7] };
+ memcpy(newptr, vals, 8 * 4);
+ }
+
+ if (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_3D) {
+ float *dataptr = w + i * old_stride + 8;
+ float *newptr = w + i * multimesh->stride_cache + 8;
+ float vals[8] = { dataptr[0], dataptr[1], dataptr[2], dataptr[3] };
+ memcpy(newptr, vals, 4 * 4);
+ }
+
+ if (multimesh->uses_colors) {
+ float *dataptr = w + i * old_stride + (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12);
+ float *newptr = w + i * multimesh->stride_cache + multimesh->color_offset_cache;
+ uint16_t val[4] = { Math::make_half_float(dataptr[0]), Math::make_half_float(dataptr[1]), Math::make_half_float(dataptr[2]), Math::make_half_float(dataptr[3]) };
+ memcpy(newptr, val, 2 * 4);
+ }
+ if (multimesh->uses_custom_data) {
+ float *dataptr = w + i * old_stride + (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12) + (multimesh->uses_colors ? 4 : 0);
+ float *newptr = w + i * multimesh->stride_cache + multimesh->custom_data_offset_cache;
+ uint16_t val[4] = { Math::make_half_float(dataptr[0]), Math::make_half_float(dataptr[1]), Math::make_half_float(dataptr[2]), Math::make_half_float(dataptr[3]) };
+ memcpy(newptr, val, 2 * 4);
+ }
+ }
+
+ multimesh->data_cache.resize(multimesh->instances * (int)multimesh->stride_cache);
+ const float *r = multimesh->data_cache.ptr();
+ glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer);
+ glBufferData(GL_ARRAY_BUFFER, multimesh->data_cache.size() * sizeof(float), r, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ } else {
+ // Only Transform is being used, so we can upload directly.
+ ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache));
+ const float *r = p_buffer.ptr();
+ glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer);
+ glBufferData(GL_ARRAY_BUFFER, p_buffer.size() * sizeof(float), r, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+
+ multimesh->buffer_set = true;
+
+ if (multimesh->data_cache.size() || multimesh->uses_colors || multimesh->uses_custom_data) {
+ //if we have a data cache, just update it
+ multimesh->data_cache = multimesh->data_cache;
+ {
+ //clear dirty since nothing will be dirty anymore
+ uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+ for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
+ multimesh->data_cache_dirty_regions[i] = false;
+ }
+ multimesh->data_cache_used_dirty_regions = 0;
+ }
+
+ _multimesh_mark_all_dirty(multimesh, false, true); //update AABB
+ } else if (multimesh->mesh.is_valid()) {
+ //if we have a mesh set, we need to re-generate the AABB from the new data
+ const float *data = p_buffer.ptr();
+
+ _multimesh_re_create_aabb(multimesh, data, multimesh->instances);
+ multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
+ }
+}
+
+Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, Vector<float>());
+ Vector<float> ret;
+ if (multimesh->buffer == 0) {
+ return Vector<float>();
+ } else if (multimesh->data_cache.size()) {
+ ret = multimesh->data_cache;
+ } else {
+ // Buffer not cached, so fetch from GPU memory. This can be a stalling operation, avoid whenever possible.
+
+ Vector<uint8_t> buffer = Utilities::buffer_get_data(GL_ARRAY_BUFFER, multimesh->buffer, multimesh->instances * multimesh->stride_cache * sizeof(float));
+ ret.resize(multimesh->instances * multimesh->stride_cache);
+ {
+ float *w = ret.ptrw();
+ const uint8_t *r = buffer.ptr();
+ memcpy(w, r, buffer.size());
+ }
+ }
+ if (multimesh->uses_colors || multimesh->uses_custom_data) {
+ // Need to decompress buffer.
+ uint32_t new_stride = multimesh->xform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12;
+ new_stride += multimesh->uses_colors ? 4 : 0;
+ new_stride += multimesh->uses_custom_data ? 4 : 0;
+
+ Vector<float> decompressed;
+ decompressed.resize(multimesh->instances * (int)new_stride);
+ float *w = decompressed.ptrw();
+ const float *r = ret.ptr();
+
+ for (int i = 0; i < multimesh->instances; i++) {
+ {
+ float *newptr = w + i * new_stride;
+ const float *oldptr = r + i * multimesh->stride_cache;
+ float vals[8] = { oldptr[0], oldptr[1], oldptr[2], oldptr[3], oldptr[4], oldptr[5], oldptr[6], oldptr[7] };
+ memcpy(newptr, vals, 8 * 4);
+ }
+
+ if (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_3D) {
+ float *newptr = w + i * new_stride + 8;
+ const float *oldptr = r + i * multimesh->stride_cache + 8;
+ float vals[8] = { oldptr[0], oldptr[1], oldptr[2], oldptr[3] };
+ memcpy(newptr, vals, 4 * 4);
+ }
+
+ if (multimesh->uses_colors) {
+ float *newptr = w + i * new_stride + (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12);
+ const float *oldptr = r + i * multimesh->stride_cache + multimesh->color_offset_cache;
+ uint16_t raw_data[4];
+ memcpy(raw_data, oldptr, 2 * 4);
+ newptr[0] = Math::half_to_float(raw_data[0]);
+ newptr[1] = Math::half_to_float(raw_data[1]);
+ newptr[2] = Math::half_to_float(raw_data[2]);
+ newptr[3] = Math::half_to_float(raw_data[3]);
+ }
+ if (multimesh->uses_custom_data) {
+ float *newptr = w + i * new_stride + (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12) + (multimesh->uses_colors ? 4 : 0);
+ const float *oldptr = r + i * multimesh->stride_cache + multimesh->custom_data_offset_cache;
+ uint16_t raw_data[4];
+ memcpy(raw_data, oldptr, 2 * 4);
+ newptr[0] = Math::half_to_float(raw_data[0]);
+ newptr[1] = Math::half_to_float(raw_data[1]);
+ newptr[2] = Math::half_to_float(raw_data[2]);
+ newptr[3] = Math::half_to_float(raw_data[3]);
+ }
+ }
+ return decompressed;
+ } else {
+ return ret;
+ }
+}
+
+void MeshStorage::multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_COND(p_visible < -1 || p_visible > multimesh->instances);
+ if (multimesh->visible_instances == p_visible) {
+ return;
+ }
+
+ if (multimesh->data_cache.size()) {
+ //there is a data cache..
+ _multimesh_mark_all_dirty(multimesh, false, true);
+ }
+
+ multimesh->visible_instances = p_visible;
+
+ multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES);
+}
+
+int MeshStorage::multimesh_get_visible_instances(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, 0);
+ return multimesh->visible_instances;
+}
+
+void MeshStorage::_update_dirty_multimeshes() {
+ while (multimesh_dirty_list) {
+ MultiMesh *multimesh = multimesh_dirty_list;
+
+ if (multimesh->data_cache.size()) { //may have been cleared, so only process if it exists
+ const float *data = multimesh->data_cache.ptr();
+
+ uint32_t visible_instances = multimesh->visible_instances >= 0 ? multimesh->visible_instances : multimesh->instances;
+
+ if (multimesh->data_cache_used_dirty_regions) {
+ uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+ uint32_t visible_region_count = visible_instances == 0 ? 0 : (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+
+ GLint region_size = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float);
+
+ if (multimesh->data_cache_used_dirty_regions > 32 || multimesh->data_cache_used_dirty_regions > visible_region_count / 2) {
+ // If there too many dirty regions, or represent the majority of regions, just copy all, else transfer cost piles up too much
+ glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer);
+ glBufferData(GL_ARRAY_BUFFER, MIN(visible_region_count * region_size, multimesh->instances * multimesh->stride_cache * sizeof(float)), data, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ } else {
+ // Not that many regions? update them all
+ // TODO: profile the performance cost on low end
+ glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer);
+ for (uint32_t i = 0; i < visible_region_count; i++) {
+ if (multimesh->data_cache_dirty_regions[i]) {
+ GLint offset = i * region_size;
+ GLint size = multimesh->stride_cache * (uint32_t)multimesh->instances * (uint32_t)sizeof(float);
+ uint32_t region_start_index = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * i;
+ glBufferSubData(GL_ARRAY_BUFFER, offset, MIN(region_size, size - offset), &data[region_start_index]);
+ }
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+
+ for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
+ multimesh->data_cache_dirty_regions[i] = false;
+ }
+
+ multimesh->data_cache_used_dirty_regions = 0;
+ }
+
+ if (multimesh->aabb_dirty && multimesh->mesh.is_valid()) {
+ _multimesh_re_create_aabb(multimesh, data, visible_instances);
+ multimesh->aabb_dirty = false;
+ multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
+ }
+ }
+
+ multimesh_dirty_list = multimesh->dirty_list;
+
+ multimesh->dirty_list = nullptr;
+ multimesh->dirty = false;
+ }
+
+ multimesh_dirty_list = nullptr;
+}
+
+/* SKELETON API */
+
+RID MeshStorage::skeleton_allocate() {
+ return RID();
+}
+
+void MeshStorage::skeleton_initialize(RID p_rid) {
+}
+
+void MeshStorage::skeleton_free(RID p_rid) {
+}
+
+void MeshStorage::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton) {
+}
+
+void MeshStorage::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) {
+}
+
+int MeshStorage::skeleton_get_bone_count(RID p_skeleton) const {
+ return 0;
+}
+
+void MeshStorage::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) {
+}
+
+Transform3D MeshStorage::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const {
+ return Transform3D();
+}
+
+void MeshStorage::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) {
+}
+
+Transform2D MeshStorage::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const {
+ return Transform2D();
+}
+
+void MeshStorage::skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) {
+}
+
+/* OCCLUDER */
+
+void MeshStorage::occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) {
+}
+
+#endif // GLES3_ENABLED
diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h
new file mode 100644
index 0000000000..339380b3b0
--- /dev/null
+++ b/drivers/gles3/storage/mesh_storage.h
@@ -0,0 +1,546 @@
+/*************************************************************************/
+/* mesh_storage.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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 MESH_STORAGE_GLES3_H
+#define MESH_STORAGE_GLES3_H
+
+#ifdef GLES3_ENABLED
+
+#include "core/templates/local_vector.h"
+#include "core/templates/rid_owner.h"
+#include "core/templates/self_list.h"
+#include "servers/rendering/storage/mesh_storage.h"
+#include "servers/rendering/storage/utilities.h"
+
+#include "platform_config.h"
+#ifndef OPENGL_INCLUDE_H
+#include <GLES3/gl3.h>
+#else
+#include OPENGL_INCLUDE_H
+#endif
+
+namespace GLES3 {
+
+struct MeshInstance;
+
+struct Mesh {
+ struct Surface {
+ struct Attrib {
+ bool enabled;
+ bool integer;
+ GLint size;
+ GLenum type;
+ GLboolean normalized;
+ GLsizei stride;
+ uint32_t offset;
+ };
+ RS::PrimitiveType primitive = RS::PRIMITIVE_POINTS;
+ uint32_t format = 0;
+
+ GLuint vertex_buffer = 0;
+ GLuint attribute_buffer = 0;
+ GLuint skin_buffer = 0;
+ uint32_t vertex_count = 0;
+ uint32_t vertex_buffer_size = 0;
+ uint32_t attribute_buffer_size = 0;
+ uint32_t skin_buffer_size = 0;
+
+ // Cache vertex arrays so they can be created
+ struct Version {
+ uint32_t input_mask = 0;
+ GLuint vertex_array;
+
+ Attrib attribs[RS::ARRAY_MAX];
+ };
+
+ SpinLock version_lock; //needed to access versions
+ Version *versions = nullptr; //allocated on demand
+ uint32_t version_count = 0;
+
+ GLuint index_buffer = 0;
+ uint32_t index_count = 0;
+ uint32_t index_buffer_size = 0;
+
+ struct LOD {
+ float edge_length = 0.0;
+ uint32_t index_count = 0;
+ uint32_t index_buffer_size = 0;
+ GLuint index_buffer;
+ };
+
+ LOD *lods = nullptr;
+ uint32_t lod_count = 0;
+
+ AABB aabb;
+
+ Vector<AABB> bone_aabbs;
+
+ GLuint blend_shape_buffer = 0;
+
+ RID material;
+ };
+
+ uint32_t blend_shape_count = 0;
+ RS::BlendShapeMode blend_shape_mode = RS::BLEND_SHAPE_MODE_NORMALIZED;
+
+ Surface **surfaces = nullptr;
+ uint32_t surface_count = 0;
+
+ Vector<AABB> bone_aabbs;
+
+ bool has_bone_weights = false;
+
+ AABB aabb;
+ AABB custom_aabb;
+
+ Vector<RID> material_cache;
+
+ List<MeshInstance *> instances;
+
+ RID shadow_mesh;
+ HashSet<Mesh *> shadow_owners;
+
+ Dependency dependency;
+};
+
+/* Mesh Instance */
+
+struct MeshInstance {
+ Mesh *mesh = nullptr;
+ RID skeleton;
+ struct Surface {
+ GLuint vertex_buffer = 0;
+
+ Mesh::Surface::Version *versions = nullptr; //allocated on demand
+ uint32_t version_count = 0;
+ };
+ LocalVector<Surface> surfaces;
+ LocalVector<float> blend_weights;
+
+ GLuint blend_weights_buffer = 0;
+ List<MeshInstance *>::Element *I = nullptr; //used to erase itself
+ uint64_t skeleton_version = 0;
+ bool dirty = false;
+ bool weights_dirty = false;
+ SelfList<MeshInstance> weight_update_list;
+ SelfList<MeshInstance> array_update_list;
+ MeshInstance() :
+ weight_update_list(this), array_update_list(this) {}
+};
+
+/* MultiMesh */
+
+struct MultiMesh {
+ RID mesh;
+ int instances = 0;
+ RS::MultimeshTransformFormat xform_format = RS::MULTIMESH_TRANSFORM_3D;
+ bool uses_colors = false;
+ bool uses_custom_data = false;
+ int visible_instances = -1;
+ AABB aabb;
+ bool aabb_dirty = false;
+ bool buffer_set = false;
+ uint32_t stride_cache = 0;
+ uint32_t color_offset_cache = 0;
+ uint32_t custom_data_offset_cache = 0;
+
+ Vector<float> data_cache; //used if individual setting is used
+ bool *data_cache_dirty_regions = nullptr;
+ uint32_t data_cache_used_dirty_regions = 0;
+
+ GLuint buffer;
+
+ bool dirty = false;
+ MultiMesh *dirty_list = nullptr;
+
+ Dependency dependency;
+};
+
+struct Skeleton {
+ bool use_2d = false;
+ int size = 0;
+ Vector<float> data;
+ GLuint buffer = 0;
+
+ bool dirty = false;
+ Skeleton *dirty_list = nullptr;
+ Transform2D base_transform_2d;
+
+ uint64_t version = 1;
+
+ Dependency dependency;
+};
+
+class MeshStorage : public RendererMeshStorage {
+private:
+ static MeshStorage *singleton;
+
+ /* Mesh */
+
+ mutable RID_Owner<Mesh, true> mesh_owner;
+
+ void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis = nullptr);
+
+ /* Mesh Instance API */
+
+ mutable RID_Owner<MeshInstance> mesh_instance_owner;
+
+ void _mesh_instance_clear(MeshInstance *mi);
+ void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface);
+ SelfList<MeshInstance>::List dirty_mesh_instance_weights;
+ SelfList<MeshInstance>::List dirty_mesh_instance_arrays;
+
+ /* MultiMesh */
+
+ mutable RID_Owner<MultiMesh, true> multimesh_owner;
+
+ MultiMesh *multimesh_dirty_list = nullptr;
+
+ _FORCE_INLINE_ void _multimesh_make_local(MultiMesh *multimesh) const;
+ _FORCE_INLINE_ void _multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb);
+ _FORCE_INLINE_ void _multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb);
+ _FORCE_INLINE_ void _multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances);
+
+ /* Skeleton */
+
+ mutable RID_Owner<Skeleton, true> skeleton_owner;
+
+ Skeleton *skeleton_dirty_list = nullptr;
+
+ _FORCE_INLINE_ void _skeleton_make_dirty(Skeleton *skeleton);
+
+public:
+ static MeshStorage *get_singleton();
+
+ MeshStorage();
+ virtual ~MeshStorage();
+
+ /* MESH API */
+
+ Mesh *get_mesh(RID p_rid) { return mesh_owner.get_or_null(p_rid); };
+ bool owns_mesh(RID p_rid) { return mesh_owner.owns(p_rid); };
+
+ virtual RID mesh_allocate() override;
+ virtual void mesh_initialize(RID p_rid) override;
+ virtual void mesh_free(RID p_rid) override;
+
+ virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override;
+ virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override;
+
+ virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override;
+
+ virtual int mesh_get_blend_shape_count(RID p_mesh) const override;
+
+ virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override;
+ virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override;
+
+ virtual void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
+ virtual void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
+ virtual void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
+
+ virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override;
+ virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const override;
+
+ virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override;
+ virtual int mesh_get_surface_count(RID p_mesh) const override;
+
+ virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override;
+ virtual AABB mesh_get_custom_aabb(RID p_mesh) const override;
+
+ virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override;
+ virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override;
+ virtual void mesh_clear(RID p_mesh) override;
+
+ _FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND_V(!mesh, nullptr);
+ r_surface_count = mesh->surface_count;
+ if (r_surface_count == 0) {
+ return nullptr;
+ }
+ if (mesh->material_cache.is_empty()) {
+ mesh->material_cache.resize(mesh->surface_count);
+ for (uint32_t i = 0; i < r_surface_count; i++) {
+ mesh->material_cache.write[i] = mesh->surfaces[i]->material;
+ }
+ }
+
+ return mesh->material_cache.ptr();
+ }
+
+ _FORCE_INLINE_ void *mesh_get_surface(RID p_mesh, uint32_t p_surface_index) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND_V(!mesh, nullptr);
+ ERR_FAIL_UNSIGNED_INDEX_V(p_surface_index, mesh->surface_count, nullptr);
+
+ return mesh->surfaces[p_surface_index];
+ }
+
+ _FORCE_INLINE_ RID mesh_get_shadow_mesh(RID p_mesh) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND_V(!mesh, RID());
+
+ return mesh->shadow_mesh;
+ }
+
+ _FORCE_INLINE_ RS::PrimitiveType mesh_surface_get_primitive(void *p_surface) {
+ Mesh::Surface *surface = reinterpret_cast<Mesh::Surface *>(p_surface);
+ return surface->primitive;
+ }
+
+ _FORCE_INLINE_ bool mesh_surface_has_lod(void *p_surface) const {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+ return s->lod_count > 0;
+ }
+
+ _FORCE_INLINE_ uint32_t mesh_surface_get_vertices_drawn_count(void *p_surface) const {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+ return s->index_count ? s->index_count : s->vertex_count;
+ }
+
+ _FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_mesh_lod_threshold, uint32_t *r_index_count = nullptr) const {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+
+ int32_t current_lod = -1;
+ if (r_index_count) {
+ *r_index_count = s->index_count;
+ }
+ for (uint32_t i = 0; i < s->lod_count; i++) {
+ float screen_size = s->lods[i].edge_length * p_model_scale / p_distance_threshold;
+ if (screen_size > p_mesh_lod_threshold) {
+ break;
+ }
+ current_lod = i;
+ }
+ if (current_lod == -1) {
+ return 0;
+ } else {
+ if (r_index_count) {
+ *r_index_count = s->lods[current_lod].index_count;
+ }
+ return current_lod + 1;
+ }
+ }
+
+ _FORCE_INLINE_ GLuint mesh_surface_get_index_buffer(void *p_surface, uint32_t p_lod) const {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+
+ if (p_lod == 0) {
+ return s->index_buffer;
+ } else {
+ return s->lods[p_lod - 1].index_buffer;
+ }
+ }
+
+ _FORCE_INLINE_ GLenum mesh_surface_get_index_type(void *p_surface) const {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+
+ return s->vertex_count <= 65536 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
+ }
+
+ // Use this to cache Vertex Array Objects so they are only generated once
+ _FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint32_t p_input_mask, GLuint &r_vertex_array_gl) {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+
+ s->version_lock.lock();
+
+ //there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
+
+ for (uint32_t i = 0; i < s->version_count; i++) {
+ if (s->versions[i].input_mask != p_input_mask) {
+ continue;
+ }
+ //we have this version, hooray
+ r_vertex_array_gl = s->versions[i].vertex_array;
+ s->version_lock.unlock();
+ return;
+ }
+
+ uint32_t version = s->version_count;
+ s->version_count++;
+ s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count);
+
+ _mesh_surface_generate_version_for_input_mask(s->versions[version], s, p_input_mask);
+
+ r_vertex_array_gl = s->versions[version].vertex_array;
+
+ s->version_lock.unlock();
+ }
+
+ /* MESH INSTANCE API */
+
+ MeshInstance *get_mesh_instance(RID p_rid) { return mesh_instance_owner.get_or_null(p_rid); };
+ bool owns_mesh_instance(RID p_rid) { return mesh_instance_owner.owns(p_rid); };
+
+ virtual RID mesh_instance_create(RID p_base) override;
+ virtual void mesh_instance_free(RID p_rid) override;
+ virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override;
+ virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) override;
+ virtual void mesh_instance_check_for_update(RID p_mesh_instance) override;
+ virtual void update_mesh_instances() override;
+
+ _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, GLuint &r_vertex_array_gl) {
+ MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
+ ERR_FAIL_COND(!mi);
+ Mesh *mesh = mi->mesh;
+ ERR_FAIL_UNSIGNED_INDEX(p_surface_index, mesh->surface_count);
+
+ MeshInstance::Surface *mis = &mi->surfaces[p_surface_index];
+ Mesh::Surface *s = mesh->surfaces[p_surface_index];
+
+ s->version_lock.lock();
+
+ //there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
+
+ for (uint32_t i = 0; i < mis->version_count; i++) {
+ if (mis->versions[i].input_mask != p_input_mask) {
+ continue;
+ }
+ //we have this version, hooray
+ r_vertex_array_gl = mis->versions[i].vertex_array;
+ s->version_lock.unlock();
+ return;
+ }
+
+ uint32_t version = mis->version_count;
+ mis->version_count++;
+ mis->versions = (Mesh::Surface::Version *)memrealloc(mis->versions, sizeof(Mesh::Surface::Version) * mis->version_count);
+
+ _mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, mis);
+
+ r_vertex_array_gl = mis->versions[version].vertex_array;
+
+ s->version_lock.unlock();
+ }
+
+ /* MULTIMESH API */
+
+ MultiMesh *get_multimesh(RID p_rid) { return multimesh_owner.get_or_null(p_rid); };
+ bool owns_multimesh(RID p_rid) { return multimesh_owner.owns(p_rid); };
+
+ virtual RID multimesh_allocate() override;
+ virtual void multimesh_initialize(RID p_rid) override;
+ virtual void multimesh_free(RID p_rid) override;
+ virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override;
+ virtual int multimesh_get_instance_count(RID p_multimesh) const override;
+
+ virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override;
+ virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override;
+ virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override;
+ virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override;
+ virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override;
+
+ virtual RID multimesh_get_mesh(RID p_multimesh) const override;
+ virtual AABB multimesh_get_aabb(RID p_multimesh) const override;
+
+ virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override;
+ virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override;
+ virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override;
+ virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override;
+ virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
+ virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const override;
+
+ virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override;
+ virtual int multimesh_get_visible_instances(RID p_multimesh) const override;
+
+ void _update_dirty_multimeshes();
+
+ _FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ return multimesh->xform_format;
+ }
+
+ _FORCE_INLINE_ bool multimesh_uses_colors(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ return multimesh->uses_colors;
+ }
+
+ _FORCE_INLINE_ bool multimesh_uses_custom_data(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ return multimesh->uses_custom_data;
+ }
+
+ _FORCE_INLINE_ uint32_t multimesh_get_instances_to_draw(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ if (multimesh->visible_instances >= 0) {
+ return multimesh->visible_instances;
+ }
+ return multimesh->instances;
+ }
+
+ _FORCE_INLINE_ GLuint multimesh_get_gl_buffer(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ return multimesh->buffer;
+ }
+
+ _FORCE_INLINE_ uint32_t multimesh_get_stride(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ return multimesh->stride_cache;
+ }
+
+ _FORCE_INLINE_ uint32_t multimesh_get_color_offset(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ return multimesh->color_offset_cache;
+ }
+
+ _FORCE_INLINE_ uint32_t multimesh_get_custom_data_offset(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ return multimesh->custom_data_offset_cache;
+ }
+
+ /* SKELETON API */
+
+ Skeleton *get_skeleton(RID p_rid) { return skeleton_owner.get_or_null(p_rid); };
+ bool owns_skeleton(RID p_rid) { return skeleton_owner.owns(p_rid); };
+
+ virtual RID skeleton_allocate() override;
+ virtual void skeleton_initialize(RID p_rid) override;
+ virtual void skeleton_free(RID p_rid) override;
+
+ virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) override;
+ virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) override;
+ virtual int skeleton_get_bone_count(RID p_skeleton) const override;
+ virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) override;
+ virtual Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override;
+ virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) override;
+ virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const override;
+
+ virtual void skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) override;
+
+ /* OCCLUDER */
+
+ void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices);
+};
+
+} // namespace GLES3
+
+#endif // GLES3_ENABLED
+
+#endif // MESH_STORAGE_GLES3_H
diff --git a/drivers/gles3/storage/particles_storage.cpp b/drivers/gles3/storage/particles_storage.cpp
new file mode 100644
index 0000000000..9ed9fedd5a
--- /dev/null
+++ b/drivers/gles3/storage/particles_storage.cpp
@@ -0,0 +1,254 @@
+/*************************************************************************/
+/* particles_storage.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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. */
+/*************************************************************************/
+
+#ifdef GLES3_ENABLED
+
+#include "particles_storage.h"
+
+using namespace GLES3;
+
+ParticlesStorage *ParticlesStorage::singleton = nullptr;
+
+ParticlesStorage *ParticlesStorage::get_singleton() {
+ return singleton;
+}
+
+ParticlesStorage::ParticlesStorage() {
+ singleton = this;
+}
+
+ParticlesStorage::~ParticlesStorage() {
+ singleton = nullptr;
+}
+
+/* PARTICLES */
+
+RID ParticlesStorage::particles_allocate() {
+ return RID();
+}
+
+void ParticlesStorage::particles_initialize(RID p_rid) {
+}
+
+void ParticlesStorage::particles_free(RID p_rid) {
+}
+
+void ParticlesStorage::particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) {
+}
+
+void ParticlesStorage::particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
+}
+
+void ParticlesStorage::particles_set_emitting(RID p_particles, bool p_emitting) {
+}
+
+void ParticlesStorage::particles_set_amount(RID p_particles, int p_amount) {
+}
+
+void ParticlesStorage::particles_set_lifetime(RID p_particles, double p_lifetime) {
+}
+
+void ParticlesStorage::particles_set_one_shot(RID p_particles, bool p_one_shot) {
+}
+
+void ParticlesStorage::particles_set_pre_process_time(RID p_particles, double p_time) {
+}
+
+void ParticlesStorage::particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) {
+}
+
+void ParticlesStorage::particles_set_randomness_ratio(RID p_particles, real_t p_ratio) {
+}
+
+void ParticlesStorage::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) {
+}
+
+void ParticlesStorage::particles_set_speed_scale(RID p_particles, double p_scale) {
+}
+
+void ParticlesStorage::particles_set_use_local_coordinates(RID p_particles, bool p_enable) {
+}
+
+void ParticlesStorage::particles_set_process_material(RID p_particles, RID p_material) {
+}
+
+RID ParticlesStorage::particles_get_process_material(RID p_particles) const {
+ return RID();
+}
+
+void ParticlesStorage::particles_set_fixed_fps(RID p_particles, int p_fps) {
+}
+
+void ParticlesStorage::particles_set_interpolate(RID p_particles, bool p_enable) {
+}
+
+void ParticlesStorage::particles_set_fractional_delta(RID p_particles, bool p_enable) {
+}
+
+void ParticlesStorage::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) {
+}
+
+void ParticlesStorage::particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) {
+}
+
+void ParticlesStorage::particles_set_collision_base_size(RID p_particles, real_t p_size) {
+}
+
+void ParticlesStorage::particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) {
+}
+
+void ParticlesStorage::particles_set_trails(RID p_particles, bool p_enable, double p_length) {
+}
+
+void ParticlesStorage::particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) {
+}
+
+void ParticlesStorage::particles_restart(RID p_particles) {
+}
+
+void ParticlesStorage::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) {
+}
+
+void ParticlesStorage::particles_set_draw_passes(RID p_particles, int p_count) {
+}
+
+void ParticlesStorage::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {
+}
+
+void ParticlesStorage::particles_request_process(RID p_particles) {
+}
+
+AABB ParticlesStorage::particles_get_current_aabb(RID p_particles) {
+ return AABB();
+}
+
+AABB ParticlesStorage::particles_get_aabb(RID p_particles) const {
+ return AABB();
+}
+
+void ParticlesStorage::particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) {
+}
+
+bool ParticlesStorage::particles_get_emitting(RID p_particles) {
+ return false;
+}
+
+int ParticlesStorage::particles_get_draw_passes(RID p_particles) const {
+ return 0;
+}
+
+RID ParticlesStorage::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const {
+ return RID();
+}
+
+void ParticlesStorage::particles_add_collision(RID p_particles, RID p_instance) {
+}
+
+void ParticlesStorage::particles_remove_collision(RID p_particles, RID p_instance) {
+}
+
+void ParticlesStorage::particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) {
+}
+
+void ParticlesStorage::update_particles() {
+}
+
+bool ParticlesStorage::particles_is_inactive(RID p_particles) const {
+ return false;
+}
+
+/* PARTICLES COLLISION */
+
+RID ParticlesStorage::particles_collision_allocate() {
+ return RID();
+}
+
+void ParticlesStorage::particles_collision_initialize(RID p_rid) {
+}
+
+void ParticlesStorage::particles_collision_free(RID p_rid) {
+}
+
+void ParticlesStorage::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) {
+}
+
+void ParticlesStorage::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) {
+}
+
+void ParticlesStorage::particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) {
+}
+
+void ParticlesStorage::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) {
+}
+
+void ParticlesStorage::particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) {
+}
+
+void ParticlesStorage::particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) {
+}
+
+void ParticlesStorage::particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) {
+}
+
+void ParticlesStorage::particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) {
+}
+
+void ParticlesStorage::particles_collision_height_field_update(RID p_particles_collision) {
+}
+
+void ParticlesStorage::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) {
+}
+
+AABB ParticlesStorage::particles_collision_get_aabb(RID p_particles_collision) const {
+ return AABB();
+}
+
+bool ParticlesStorage::particles_collision_is_heightfield(RID p_particles_collision) const {
+ return false;
+}
+
+RID ParticlesStorage::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const {
+ return RID();
+}
+
+RID ParticlesStorage::particles_collision_instance_create(RID p_collision) {
+ return RID();
+}
+
+void ParticlesStorage::particles_collision_instance_free(RID p_rid) {
+}
+
+void ParticlesStorage::particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) {
+}
+
+void ParticlesStorage::particles_collision_instance_set_active(RID p_collision_instance, bool p_active) {
+}
+
+#endif // GLES3_ENABLED
diff --git a/drivers/gles3/storage/particles_storage.h b/drivers/gles3/storage/particles_storage.h
new file mode 100644
index 0000000000..84d1f94d8c
--- /dev/null
+++ b/drivers/gles3/storage/particles_storage.h
@@ -0,0 +1,140 @@
+/*************************************************************************/
+/* particles_storage.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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 PARTICLES_STORAGE_GLES3_H
+#define PARTICLES_STORAGE_GLES3_H
+
+#ifdef GLES3_ENABLED
+
+#include "core/templates/local_vector.h"
+#include "core/templates/rid_owner.h"
+#include "core/templates/self_list.h"
+#include "servers/rendering/storage/particles_storage.h"
+
+namespace GLES3 {
+
+class ParticlesStorage : public RendererParticlesStorage {
+private:
+ static ParticlesStorage *singleton;
+
+public:
+ static ParticlesStorage *get_singleton();
+
+ ParticlesStorage();
+ virtual ~ParticlesStorage();
+
+ /* PARTICLES */
+
+ virtual RID particles_allocate() override;
+ virtual void particles_initialize(RID p_rid) override;
+ virtual void particles_free(RID p_rid) override;
+
+ virtual void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) override;
+ virtual void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) override;
+ virtual void particles_set_emitting(RID p_particles, bool p_emitting) override;
+ virtual void particles_set_amount(RID p_particles, int p_amount) override;
+ virtual void particles_set_lifetime(RID p_particles, double p_lifetime) override;
+ virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) override;
+ virtual void particles_set_pre_process_time(RID p_particles, double p_time) override;
+ virtual void particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) override;
+ virtual void particles_set_randomness_ratio(RID p_particles, real_t p_ratio) override;
+ virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) override;
+ virtual void particles_set_speed_scale(RID p_particles, double p_scale) override;
+ virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) override;
+ virtual void particles_set_process_material(RID p_particles, RID p_material) override;
+ virtual RID particles_get_process_material(RID p_particles) const override;
+ virtual void particles_set_fixed_fps(RID p_particles, int p_fps) override;
+ virtual void particles_set_interpolate(RID p_particles, bool p_enable) override;
+ virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) override;
+ virtual void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) override;
+ virtual void particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) override;
+ virtual void particles_set_collision_base_size(RID p_particles, real_t p_size) override;
+
+ virtual void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) override;
+
+ virtual void particles_set_trails(RID p_particles, bool p_enable, double p_length) override;
+ virtual void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) override;
+
+ virtual void particles_restart(RID p_particles) override;
+
+ virtual void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) override;
+
+ virtual void particles_set_draw_passes(RID p_particles, int p_count) override;
+ virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) override;
+
+ virtual void particles_request_process(RID p_particles) override;
+ virtual AABB particles_get_current_aabb(RID p_particles) override;
+ virtual AABB particles_get_aabb(RID p_particles) const override;
+
+ virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override;
+
+ virtual bool particles_get_emitting(RID p_particles) override;
+ virtual int particles_get_draw_passes(RID p_particles) const override;
+ virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const override;
+
+ virtual void particles_add_collision(RID p_particles, RID p_instance) override;
+ virtual void particles_remove_collision(RID p_particles, RID p_instance) override;
+
+ virtual void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) override;
+
+ virtual void update_particles() override;
+ virtual bool particles_is_inactive(RID p_particles) const override;
+
+ /* PARTICLES COLLISION */
+
+ virtual RID particles_collision_allocate() override;
+ virtual void particles_collision_initialize(RID p_rid) override;
+ virtual void particles_collision_free(RID p_rid) override;
+
+ virtual void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) override;
+ virtual void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) override;
+ virtual void particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) override;
+ virtual void particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) override;
+ virtual void particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) override;
+ virtual void particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) override;
+ virtual void particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) override;
+ virtual void particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) override;
+ virtual void particles_collision_height_field_update(RID p_particles_collision) override;
+ virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) override;
+ virtual AABB particles_collision_get_aabb(RID p_particles_collision) const override;
+ virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override;
+ virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const override;
+
+ virtual RID particles_collision_instance_create(RID p_collision) override;
+ virtual void particles_collision_instance_free(RID p_rid) override;
+ virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) override;
+ virtual void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override;
+};
+
+} // namespace GLES3
+
+#endif // GLES3_ENABLED
+
+#endif // PARTICLES_STORAGE_GLES3_H
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
new file mode 100644
index 0000000000..543638e8ff
--- /dev/null
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -0,0 +1,1693 @@
+/*************************************************************************/
+/* texture_storage.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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. */
+/*************************************************************************/
+
+#ifdef GLES3_ENABLED
+
+#include "texture_storage.h"
+#include "config.h"
+#include "drivers/gles3/effects/copy_effects.h"
+
+using namespace GLES3;
+
+TextureStorage *TextureStorage::singleton = nullptr;
+
+TextureStorage *TextureStorage::get_singleton() {
+ return singleton;
+}
+
+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,
+};
+
+TextureStorage::TextureStorage() {
+ singleton = this;
+
+ system_fbo = 0;
+
+ { //create default textures
+ { // White Textures
+
+ Ref<Image> image;
+ image.instantiate();
+ image->create(4, 4, true, Image::FORMAT_RGBA8);
+ image->fill(Color(1, 1, 1, 1));
+ image->generate_mipmaps();
+
+ default_gl_textures[DEFAULT_GL_TEXTURE_WHITE] = texture_allocate();
+ texture_2d_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_WHITE], image);
+
+ Vector<Ref<Image>> images;
+ images.push_back(image);
+
+ default_gl_textures[DEFAULT_GL_TEXTURE_2D_ARRAY_WHITE] = texture_allocate();
+ texture_2d_layered_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_2D_ARRAY_WHITE], images, RS::TEXTURE_LAYERED_2D_ARRAY);
+
+ for (int i = 0; i < 3; i++) {
+ images.push_back(image);
+ }
+
+ default_gl_textures[DEFAULT_GL_TEXTURE_3D_WHITE] = texture_allocate();
+ texture_3d_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_3D_WHITE], image->get_format(), 4, 4, 4, false, images);
+
+ for (int i = 0; i < 2; i++) {
+ images.push_back(image);
+ }
+
+ default_gl_textures[DEFAULT_GL_TEXTURE_CUBEMAP_WHITE] = texture_allocate();
+ texture_2d_layered_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_CUBEMAP_WHITE], images, RS::TEXTURE_LAYERED_CUBEMAP);
+ }
+
+ { // black
+ Ref<Image> image;
+ image.instantiate();
+ image->create(4, 4, true, Image::FORMAT_RGBA8);
+ image->fill(Color(0, 0, 0, 1));
+ image->generate_mipmaps();
+
+ default_gl_textures[DEFAULT_GL_TEXTURE_BLACK] = texture_allocate();
+ texture_2d_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_BLACK], image);
+
+ Vector<Ref<Image>> images;
+
+ for (int i = 0; i < 4; i++) {
+ images.push_back(image);
+ }
+
+ default_gl_textures[DEFAULT_GL_TEXTURE_3D_BLACK] = texture_allocate();
+ texture_3d_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_3D_BLACK], image->get_format(), 4, 4, 4, false, images);
+
+ for (int i = 0; i < 2; i++) {
+ images.push_back(image);
+ }
+ default_gl_textures[DEFAULT_GL_TEXTURE_CUBEMAP_BLACK] = texture_allocate();
+ texture_2d_layered_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_CUBEMAP_BLACK], images, RS::TEXTURE_LAYERED_CUBEMAP);
+ }
+
+ { // transparent black
+ Ref<Image> image;
+ image.instantiate();
+ image->create(4, 4, true, Image::FORMAT_RGBA8);
+ image->fill(Color(0, 0, 0, 0));
+ image->generate_mipmaps();
+
+ default_gl_textures[DEFAULT_GL_TEXTURE_TRANSPARENT] = texture_allocate();
+ texture_2d_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_TRANSPARENT], image);
+ }
+
+ {
+ Ref<Image> image;
+ image.instantiate();
+ image->create(4, 4, true, Image::FORMAT_RGBA8);
+ image->fill(Color(0.5, 0.5, 1, 1));
+ image->generate_mipmaps();
+
+ default_gl_textures[DEFAULT_GL_TEXTURE_NORMAL] = texture_allocate();
+ texture_2d_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_NORMAL], image);
+ }
+
+ {
+ Ref<Image> image;
+ image.instantiate();
+ image->create(4, 4, true, Image::FORMAT_RGBA8);
+ image->fill(Color(1.0, 0.5, 1, 1));
+ image->generate_mipmaps();
+
+ default_gl_textures[DEFAULT_GL_TEXTURE_ANISO] = texture_allocate();
+ texture_2d_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_ANISO], image);
+ }
+
+ {
+ unsigned char pixel_data[4 * 4 * 4];
+ for (int i = 0; i < 16; i++) {
+ pixel_data[i * 4 + 0] = 0;
+ pixel_data[i * 4 + 1] = 0;
+ pixel_data[i * 4 + 2] = 0;
+ pixel_data[i * 4 + 3] = 0;
+ }
+
+ default_gl_textures[DEFAULT_GL_TEXTURE_2D_UINT] = texture_allocate();
+ Texture texture;
+ texture.width = 4;
+ texture.height = 4;
+ texture.format = Image::FORMAT_RGBA8;
+ texture.type = Texture::TYPE_2D;
+ texture.target = GL_TEXTURE_2D;
+ texture.active = true;
+ glGenTextures(1, &texture.tex_id);
+ texture_owner.initialize_rid(default_gl_textures[DEFAULT_GL_TEXTURE_2D_UINT], texture);
+
+ glBindTexture(GL_TEXTURE_2D, texture.tex_id);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, 4, 4, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, pixel_data);
+ texture.gl_set_filter(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
+ }
+ {
+ uint16_t pixel_data[4 * 4];
+ for (int i = 0; i < 16; i++) {
+ pixel_data[i] = Math::make_half_float(1.0f);
+ }
+
+ default_gl_textures[DEFAULT_GL_TEXTURE_DEPTH] = texture_allocate();
+ Texture texture;
+ texture.width = 4;
+ texture.height = 4;
+ texture.format = Image::FORMAT_RGBA8;
+ texture.type = Texture::TYPE_2D;
+ texture.target = GL_TEXTURE_2D;
+ texture.active = true;
+ glGenTextures(1, &texture.tex_id);
+ texture_owner.initialize_rid(default_gl_textures[DEFAULT_GL_TEXTURE_DEPTH], texture);
+
+ glBindTexture(GL_TEXTURE_2D, texture.tex_id);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 4, 4, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, pixel_data);
+ texture.gl_set_filter(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
+ }
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+#ifdef GLES_OVER_GL
+ glEnable(GL_PROGRAM_POINT_SIZE);
+#endif
+}
+
+TextureStorage::~TextureStorage() {
+ singleton = nullptr;
+ for (int i = 0; i < DEFAULT_GL_TEXTURE_MAX; i++) {
+ texture_free(default_gl_textures[i]);
+ }
+}
+
+//TODO, move back to storage
+bool TextureStorage::can_create_resources_async() const {
+ return false;
+}
+
+/* Canvas Texture API */
+
+RID TextureStorage::canvas_texture_allocate() {
+ return canvas_texture_owner.allocate_rid();
+}
+
+void TextureStorage::canvas_texture_initialize(RID p_rid) {
+ canvas_texture_owner.initialize_rid(p_rid);
+}
+
+void TextureStorage::canvas_texture_free(RID p_rid) {
+ canvas_texture_owner.free(p_rid);
+}
+
+void TextureStorage::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) {
+ CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture);
+ switch (p_channel) {
+ case RS::CANVAS_TEXTURE_CHANNEL_DIFFUSE: {
+ ct->diffuse = p_texture;
+ } break;
+ case RS::CANVAS_TEXTURE_CHANNEL_NORMAL: {
+ ct->normal_map = p_texture;
+ } break;
+ case RS::CANVAS_TEXTURE_CHANNEL_SPECULAR: {
+ ct->specular = p_texture;
+ } break;
+ }
+}
+
+void TextureStorage::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess) {
+ CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture);
+ ct->specular_color.r = p_specular_color.r;
+ ct->specular_color.g = p_specular_color.g;
+ ct->specular_color.b = p_specular_color.b;
+ ct->specular_color.a = p_shininess;
+}
+
+void TextureStorage::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) {
+ CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture);
+ ct->texture_filter = p_filter;
+}
+
+void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) {
+ CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture);
+ ct->texture_repeat = p_repeat;
+}
+
+/* CANVAS SHADOW */
+
+RID TextureStorage::canvas_light_shadow_buffer_create(int p_width) {
+ Config *config = Config::get_singleton();
+ 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, GL_DEPTH_COMPONENT16, 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_RGBA8, cls->size, cls->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ } else {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, cls->size, cls->height, 0, GL_RED, GL_FLOAT, nullptr);
+ }
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cls->distance, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ //printf("errnum: %x\n",status);
+ glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::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);
+}
+
+/* Texture API */
+
+Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, 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 {
+ Config *config = Config::get_singleton();
+ 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: {
+#ifdef GLES_OVER_GL
+ r_gl_internal_format = GL_R8;
+ r_gl_format = GL_RED;
+ r_gl_type = GL_UNSIGNED_BYTE;
+#else
+ r_gl_internal_format = GL_LUMINANCE;
+ r_gl_format = GL_LUMINANCE;
+ r_gl_type = GL_UNSIGNED_BYTE;
+#endif
+ } break;
+ case Image::FORMAT_LA8: {
+#ifdef GLES_OVER_GL
+ r_gl_internal_format = GL_RG8;
+ r_gl_format = GL_RG;
+ r_gl_type = GL_UNSIGNED_BYTE;
+#else
+ r_gl_internal_format = GL_LUMINANCE_ALPHA;
+ r_gl_format = GL_LUMINANCE_ALPHA;
+ r_gl_type = GL_UNSIGNED_BYTE;
+#endif
+ } break;
+ case Image::FORMAT_R8: {
+ r_gl_internal_format = GL_R8;
+ r_gl_format = GL_RED;
+ r_gl_type = GL_UNSIGNED_BYTE;
+
+ } break;
+ case Image::FORMAT_RG8: {
+ r_gl_internal_format = GL_RG8;
+ r_gl_format = GL_RG;
+ r_gl_type = GL_UNSIGNED_BYTE;
+
+ } break;
+ case Image::FORMAT_RGB8: {
+ r_gl_internal_format = GL_RGB8;
+ 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_RGBA8;
+ r_gl_type = GL_UNSIGNED_BYTE;
+
+ } break;
+ case Image::FORMAT_RGBA4444: {
+ r_gl_internal_format = GL_RGBA4;
+ r_gl_format = GL_RGBA;
+ r_gl_type = GL_UNSIGNED_SHORT_4_4_4_4;
+
+ } break;
+ case Image::FORMAT_RF: {
+ r_gl_internal_format = GL_R32F;
+ r_gl_format = GL_RED;
+ r_gl_type = GL_FLOAT;
+
+ } break;
+ case Image::FORMAT_RGF: {
+ r_gl_internal_format = GL_RG32F;
+ r_gl_format = GL_RG;
+ r_gl_type = GL_FLOAT;
+
+ } break;
+ case Image::FORMAT_RGBF: {
+ r_gl_internal_format = GL_RGB32F;
+ r_gl_format = GL_RGB;
+ r_gl_type = GL_FLOAT;
+
+ } break;
+ case Image::FORMAT_RGBAF: {
+ r_gl_internal_format = GL_RGBA32F;
+ r_gl_format = GL_RGBA;
+ r_gl_type = GL_FLOAT;
+
+ } break;
+ case Image::FORMAT_RH: {
+ r_gl_internal_format = GL_R16F;
+ r_gl_format = GL_RED;
+ r_gl_type = GL_HALF_FLOAT;
+ } break;
+ case Image::FORMAT_RGH: {
+ r_gl_internal_format = GL_RG16F;
+ r_gl_format = GL_RG;
+ r_gl_type = GL_HALF_FLOAT;
+
+ } break;
+ case Image::FORMAT_RGBH: {
+ r_gl_internal_format = GL_RGB16F;
+ r_gl_format = GL_RGB;
+ r_gl_type = GL_HALF_FLOAT;
+
+ } break;
+ case Image::FORMAT_RGBAH: {
+ r_gl_internal_format = GL_RGBA16F;
+ r_gl_format = GL_RGBA;
+ r_gl_type = GL_HALF_FLOAT;
+
+ } break;
+ case Image::FORMAT_RGBE9995: {
+ r_gl_internal_format = GL_RGB9_E5;
+ r_gl_format = GL_RGB;
+ r_gl_type = GL_UNSIGNED_INT_5_9_9_9_REV;
+
+ } 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_ETC2_R11: {
+ if (config->etc2_supported) {
+ r_gl_internal_format = _EXT_COMPRESSED_R11_EAC;
+ r_gl_format = GL_RED;
+ r_gl_type = GL_UNSIGNED_BYTE;
+ r_compressed = true;
+
+ } else {
+ need_decompress = true;
+ }
+ } break;
+ case Image::FORMAT_ETC2_R11S: {
+ if (config->etc2_supported) {
+ r_gl_internal_format = _EXT_COMPRESSED_SIGNED_R11_EAC;
+ r_gl_format = GL_RED;
+ r_gl_type = GL_UNSIGNED_BYTE;
+ r_compressed = true;
+
+ } else {
+ need_decompress = true;
+ }
+ } break;
+ case Image::FORMAT_ETC2_RG11: {
+ if (config->etc2_supported) {
+ r_gl_internal_format = _EXT_COMPRESSED_RG11_EAC;
+ r_gl_format = GL_RG;
+ r_gl_type = GL_UNSIGNED_BYTE;
+ r_compressed = true;
+
+ } else {
+ need_decompress = true;
+ }
+ } break;
+ case Image::FORMAT_ETC2_RG11S: {
+ if (config->etc2_supported) {
+ r_gl_internal_format = _EXT_COMPRESSED_SIGNED_RG11_EAC;
+ r_gl_format = GL_RG;
+ r_gl_type = GL_UNSIGNED_BYTE;
+ r_compressed = true;
+
+ } else {
+ need_decompress = true;
+ }
+ } break;
+ case Image::FORMAT_ETC:
+ case Image::FORMAT_ETC2_RGB8: {
+ if (config->etc2_supported) {
+ r_gl_internal_format = _EXT_COMPRESSED_RGB8_ETC2;
+ r_gl_format = GL_RGB;
+ r_gl_type = GL_UNSIGNED_BYTE;
+ r_compressed = true;
+
+ } else {
+ need_decompress = true;
+ }
+ } break;
+ case Image::FORMAT_ETC2_RGBA8: {
+ if (config->etc2_supported) {
+ r_gl_internal_format = _EXT_COMPRESSED_RGBA8_ETC2_EAC;
+ r_gl_format = GL_RGBA;
+ r_gl_type = GL_UNSIGNED_BYTE;
+ r_compressed = true;
+
+ } else {
+ need_decompress = true;
+ }
+ } break;
+ case Image::FORMAT_ETC2_RGB8A1: {
+ if (config->etc2_supported) {
+ r_gl_internal_format = _EXT_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
+ r_gl_format = GL_RGBA;
+ r_gl_type = GL_UNSIGNED_BYTE;
+ r_compressed = true;
+
+ } else {
+ need_decompress = true;
+ }
+ } break;
+ default: {
+ ERR_FAIL_V_MSG(Ref<Image>(), "Image Format: " + itos(p_format) + " is not supported by the OpenGL3 Renderer");
+ }
+ }
+
+ 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;
+}
+
+RID TextureStorage::texture_allocate() {
+ return texture_owner.allocate_rid();
+}
+
+void TextureStorage::texture_free(RID p_texture) {
+ Texture *t = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND(!t);
+ ERR_FAIL_COND(t->is_render_target);
+
+ if (t->canvas_texture) {
+ memdelete(t->canvas_texture);
+ }
+
+ if (t->tex_id != 0) {
+ glDeleteTextures(1, &t->tex_id);
+ t->tex_id = 0;
+ }
+
+ if (t->is_proxy && t->proxy_to.is_valid()) {
+ Texture *proxy_to = texture_owner.get_or_null(t->proxy_to);
+ if (proxy_to) {
+ proxy_to->proxies.erase(p_texture);
+ }
+ }
+
+ //decal_atlas_remove_texture(p_texture);
+
+ for (int i = 0; i < t->proxies.size(); i++) {
+ Texture *p = texture_owner.get_or_null(t->proxies[i]);
+ ERR_CONTINUE(!p);
+ p->proxy_to = RID();
+ p->tex_id = 0;
+ }
+
+ texture_owner.free(p_texture);
+}
+
+void TextureStorage::texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) {
+ Texture texture;
+ texture.width = p_image->get_width();
+ texture.height = p_image->get_height();
+ texture.alloc_width = texture.width;
+ texture.alloc_height = texture.height;
+ texture.mipmaps = p_image->get_mipmap_count();
+ texture.format = p_image->get_format();
+ texture.type = Texture::TYPE_2D;
+ texture.target = GL_TEXTURE_2D;
+ _get_gl_image_and_format(Ref<Image>(), texture.format, texture.real_format, texture.gl_format_cache, texture.gl_internal_format_cache, texture.gl_type_cache, texture.compressed, false);
+ //texture.total_data_size = p_image->get_image_data_size(); // verify that this returns size in bytes
+ texture.active = true;
+ glGenTextures(1, &texture.tex_id);
+ texture_owner.initialize_rid(p_texture, texture);
+ texture_set_data(p_texture, p_image);
+}
+
+void TextureStorage::texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) {
+ texture_owner.initialize_rid(p_texture, Texture());
+}
+
+void TextureStorage::texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) {
+ texture_owner.initialize_rid(p_texture, Texture());
+}
+
+// Called internally when texture_proxy_create(p_base) is called.
+// Note: p_base is the root and p_texture is the proxy.
+void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) {
+ Texture *texture = texture_owner.get_or_null(p_base);
+ ERR_FAIL_COND(!texture);
+ Texture proxy_tex;
+ proxy_tex.copy_from(*texture);
+ proxy_tex.proxy_to = p_base;
+ proxy_tex.is_render_target = false;
+ proxy_tex.is_proxy = true;
+ proxy_tex.proxies.clear();
+ texture->proxies.push_back(p_texture);
+ texture_owner.initialize_rid(p_texture, proxy_tex);
+}
+
+void TextureStorage::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) {
+ // only 1 layer so far
+ texture_set_data(p_texture, p_image);
+#ifdef TOOLS_ENABLED
+ Texture *tex = texture_owner.get_or_null(p_texture);
+
+ tex->image_cache_2d.unref();
+#endif
+}
+
+void TextureStorage::texture_proxy_update(RID p_texture, RID p_proxy_to) {
+}
+
+void TextureStorage::texture_2d_placeholder_initialize(RID p_texture) {
+ //this could be better optimized to reuse an existing image , done this way
+ //for now to get it working
+ Ref<Image> image;
+ image.instantiate();
+ image->create(4, 4, false, Image::FORMAT_RGBA8);
+ image->fill(Color(1, 0, 1, 1));
+
+ texture_2d_initialize(p_texture, image);
+}
+
+void TextureStorage::texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) {
+ //this could be better optimized to reuse an existing image , done this way
+ //for now to get it working
+ Ref<Image> image;
+ image.instantiate();
+ image->create(4, 4, false, Image::FORMAT_RGBA8);
+ image->fill(Color(1, 0, 1, 1));
+
+ Vector<Ref<Image>> images;
+ if (p_layered_type == RS::TEXTURE_LAYERED_2D_ARRAY) {
+ images.push_back(image);
+ } else {
+ //cube
+ for (int i = 0; i < 6; i++) {
+ images.push_back(image);
+ }
+ }
+
+ texture_2d_layered_initialize(p_texture, images, p_layered_type);
+}
+
+void TextureStorage::texture_3d_placeholder_initialize(RID p_texture) {
+ //this could be better optimized to reuse an existing image , done this way
+ //for now to get it working
+ Ref<Image> image;
+ image.instantiate();
+ image->create(4, 4, false, Image::FORMAT_RGBA8);
+ image->fill(Color(1, 0, 1, 1));
+
+ Vector<Ref<Image>> images;
+ //cube
+ for (int i = 0; i < 4; i++) {
+ images.push_back(image);
+ }
+
+ texture_3d_initialize(p_texture, Image::FORMAT_RGBA8, 4, 4, 4, false, images);
+}
+
+Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
+ Texture *texture = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND_V(!texture, Ref<Image>());
+
+#ifdef TOOLS_ENABLED
+ if (texture->image_cache_2d.is_valid() && !texture->is_render_target) {
+ return texture->image_cache_2d;
+ }
+#endif
+
+#ifdef GLES_OVER_GL
+ // OpenGL 3.3 supports glGetTexImage which is faster and simpler than glReadPixels.
+ Vector<uint8_t> data;
+
+ int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, texture->real_format, texture->mipmaps > 1);
+
+ data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers
+ uint8_t *w = 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, texture->real_format, i);
+
+ if (texture->compressed) {
+ glPixelStorei(GL_PACK_ALIGNMENT, 4);
+ glGetCompressedTexImage(texture->target, i, &w[ofs]);
+
+ } else {
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+ glGetTexImage(texture->target, i, texture->gl_format_cache, texture->gl_type_cache, &w[ofs]);
+ }
+ }
+
+ data.resize(data_size);
+
+ ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
+ Ref<Image> image;
+ image.instantiate();
+ image->create(texture->width, texture->height, texture->mipmaps > 1, texture->real_format, data);
+ ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
+ if (texture->format != texture->real_format) {
+ image->convert(texture->format);
+ }
+#else
+ // Support for Web and Mobile will come later.
+ Ref<Image> image;
+#endif
+
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint() && !texture->is_render_target) {
+ texture->image_cache_2d = image;
+ }
+#endif
+
+ return image;
+}
+
+void TextureStorage::texture_replace(RID p_texture, RID p_by_texture) {
+ Texture *tex_to = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND(!tex_to);
+ ERR_FAIL_COND(tex_to->is_proxy); //can't replace proxy
+ Texture *tex_from = texture_owner.get_or_null(p_by_texture);
+ ERR_FAIL_COND(!tex_from);
+ ERR_FAIL_COND(tex_from->is_proxy); //can't replace proxy
+
+ if (tex_to == tex_from) {
+ return;
+ }
+
+ if (tex_to->canvas_texture) {
+ memdelete(tex_to->canvas_texture);
+ tex_to->canvas_texture = nullptr;
+ }
+
+ if (tex_to->tex_id) {
+ glDeleteTextures(1, &tex_to->tex_id);
+ tex_to->tex_id = 0;
+ }
+
+ Vector<RID> proxies_to_update = tex_to->proxies;
+ Vector<RID> proxies_to_redirect = tex_from->proxies;
+
+ tex_to->copy_from(*tex_from);
+
+ tex_to->proxies = proxies_to_update; //restore proxies, so they can be updated
+
+ if (tex_to->canvas_texture) {
+ tex_to->canvas_texture->diffuse = p_texture; //update
+ }
+
+ for (int i = 0; i < proxies_to_update.size(); i++) {
+ texture_proxy_update(proxies_to_update[i], p_texture);
+ }
+ for (int i = 0; i < proxies_to_redirect.size(); i++) {
+ texture_proxy_update(proxies_to_redirect[i], p_texture);
+ }
+ //delete last, so proxies can be updated
+ texture_owner.free(p_by_texture);
+
+ //decal_atlas_mark_dirty_on_texture(p_texture);
+}
+
+void TextureStorage::texture_set_size_override(RID p_texture, int p_width, int p_height) {
+ Texture *texture = texture_owner.get_or_null(p_texture);
+
+ ERR_FAIL_COND(!texture);
+ ERR_FAIL_COND(texture->is_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 TextureStorage::texture_set_path(RID p_texture, const String &p_path) {
+ Texture *texture = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND(!texture);
+
+ texture->path = p_path;
+}
+
+String TextureStorage::texture_get_path(RID p_texture) const {
+ Texture *texture = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND_V(!texture, "");
+
+ return texture->path;
+}
+
+void TextureStorage::texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
+ Texture *texture = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND(!texture);
+
+ texture->detect_3d_callback = p_callback;
+ texture->detect_3d_callback_ud = p_userdata;
+}
+
+void TextureStorage::texture_set_detect_srgb_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
+}
+
+void TextureStorage::texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
+ Texture *texture = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND(!texture);
+
+ texture->detect_normal_callback = p_callback;
+ texture->detect_normal_callback_ud = p_userdata;
+}
+
+void TextureStorage::texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) {
+ Texture *texture = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND(!texture);
+
+ texture->detect_roughness_callback = p_callback;
+ texture->detect_roughness_callback_ud = p_userdata;
+}
+
+void TextureStorage::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.get_or_null(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 TextureStorage::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) {
+ Texture *texture = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND(!texture);
+
+ texture->redraw_if_visible = p_enable;
+}
+
+Size2 TextureStorage::texture_size_with_proxy(RID p_texture) {
+ const Texture *texture = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND_V(!texture, Size2());
+ if (texture->is_proxy) {
+ const Texture *proxy = texture_owner.get_or_null(texture->proxy_to);
+ return Size2(proxy->width, proxy->height);
+ } else {
+ return Size2(texture->width, texture->height);
+ }
+}
+
+void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer) {
+ Texture *texture = texture_owner.get_or_null(p_texture);
+
+ ERR_FAIL_COND(!texture);
+ if (texture->target == GL_TEXTURE_3D) {
+ // Target is set to a 3D texture or array texture, exit early to avoid spamming errors
+ return;
+ }
+ ERR_FAIL_COND(!texture->active);
+ ERR_FAIL_COND(texture->is_render_target);
+ ERR_FAIL_COND(p_image.is_null());
+ ERR_FAIL_COND(texture->format != p_image->get_format());
+
+ ERR_FAIL_COND(!p_image->get_width());
+ ERR_FAIL_COND(!p_image->get_height());
+
+ // ERR_FAIL_COND(texture->type == RS::TEXTURE_TYPE_EXTERNAL);
+
+ GLenum type;
+ GLenum format;
+ GLenum internal_format;
+ bool compressed = false;
+
+ // print_line("texture_set_data width " + itos (p_image->get_width()) + " height " + itos(p_image->get_height()));
+
+ Image::Format real_format;
+ Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), real_format, format, internal_format, type, compressed, texture->resize_to_po2);
+ ERR_FAIL_COND(img.is_null());
+ 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);
+ }
+
+ GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : GL_TEXTURE_2D;
+
+ Vector<uint8_t> read = img->get_data();
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(texture->target, texture->tex_id);
+
+ // set filtering and repeat state to default
+ texture->gl_set_filter(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
+ texture->gl_set_repeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+
+ //set swizle for older format compatibility
+#ifdef GLES_OVER_GL
+ switch (texture->format) {
+ case Image::FORMAT_L8: {
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_RED);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_RED);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_ONE);
+
+ } break;
+ case Image::FORMAT_LA8: {
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_RED);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_RED);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_GREEN);
+ } break;
+ default: {
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_BLUE);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_ALPHA);
+
+ } break;
+ }
+#endif
+
+ int 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 (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);
+ glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]);
+ }
+
+ tsize += size;
+
+ w = MAX(1, w >> 1);
+ h = MAX(1, h >> 1);
+ }
+
+ // info.texture_mem -= texture->total_data_size; // TODO make this work again!!
+ texture->total_data_size = tsize;
+ // info.texture_mem += texture->total_data_size; // TODO make this work again!!
+
+ // 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);
+
+ texture->mipmaps = mipmaps;
+}
+
+void TextureStorage::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) {
+ ERR_PRINT("Not implemented yet, sorry :(");
+}
+
+Image::Format TextureStorage::texture_get_format(RID p_texture) const {
+ Texture *texture = texture_owner.get_or_null(p_texture);
+
+ ERR_FAIL_COND_V(!texture, Image::FORMAT_L8);
+
+ return texture->format;
+}
+
+uint32_t TextureStorage::texture_get_texid(RID p_texture) const {
+ Texture *texture = texture_owner.get_or_null(p_texture);
+
+ ERR_FAIL_COND_V(!texture, 0);
+
+ return texture->tex_id;
+}
+
+uint32_t TextureStorage::texture_get_width(RID p_texture) const {
+ Texture *texture = texture_owner.get_or_null(p_texture);
+
+ ERR_FAIL_COND_V(!texture, 0);
+
+ return texture->width;
+}
+
+uint32_t TextureStorage::texture_get_height(RID p_texture) const {
+ Texture *texture = texture_owner.get_or_null(p_texture);
+
+ ERR_FAIL_COND_V(!texture, 0);
+
+ return texture->height;
+}
+
+uint32_t TextureStorage::texture_get_depth(RID p_texture) const {
+ Texture *texture = texture_owner.get_or_null(p_texture);
+
+ ERR_FAIL_COND_V(!texture, 0);
+
+ return texture->depth;
+}
+
+void TextureStorage::texture_bind(RID p_texture, uint32_t p_texture_no) {
+ Texture *texture = texture_owner.get_or_null(p_texture);
+
+ ERR_FAIL_COND(!texture);
+
+ glActiveTexture(GL_TEXTURE0 + p_texture_no);
+ glBindTexture(texture->target, texture->tex_id);
+}
+
+RID TextureStorage::texture_create_radiance_cubemap(RID p_source, int p_resolution) const {
+ return RID();
+}
+
+/* DECAL API */
+
+RID TextureStorage::decal_allocate() {
+ return RID();
+}
+
+void TextureStorage::decal_initialize(RID p_rid) {
+}
+
+void TextureStorage::decal_set_extents(RID p_decal, const Vector3 &p_extents) {
+}
+
+void TextureStorage::decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) {
+}
+
+void TextureStorage::decal_set_emission_energy(RID p_decal, float p_energy) {
+}
+
+void TextureStorage::decal_set_albedo_mix(RID p_decal, float p_mix) {
+}
+
+void TextureStorage::decal_set_modulate(RID p_decal, const Color &p_modulate) {
+}
+
+void TextureStorage::decal_set_cull_mask(RID p_decal, uint32_t p_layers) {
+}
+
+void TextureStorage::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) {
+}
+
+void TextureStorage::decal_set_fade(RID p_decal, float p_above, float p_below) {
+}
+
+void TextureStorage::decal_set_normal_fade(RID p_decal, float p_fade) {
+}
+
+AABB TextureStorage::decal_get_aabb(RID p_decal) const {
+ return AABB();
+}
+
+/* RENDER TARGET API */
+
+GLuint TextureStorage::system_fbo = 0;
+
+void TextureStorage::_update_render_target(RenderTarget *rt) {
+ // do not allocate a render target with no size
+ if (rt->size.x <= 0 || rt->size.y <= 0) {
+ return;
+ }
+
+ // do not allocate a render target that is attached to the screen
+ if (rt->direct_to_screen) {
+ rt->fbo = system_fbo;
+ return;
+ }
+
+ rt->color_internal_format = rt->is_transparent ? GL_RGBA8 : GL_RGB10_A2;
+ rt->color_format = GL_RGBA;
+ rt->color_type = rt->is_transparent ? GL_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
+ rt->image_format = Image::FORMAT_RGBA8;
+
+ glDisable(GL_SCISSOR_TEST);
+ glColorMask(1, 1, 1, 1);
+ glDepthMask(GL_FALSE);
+
+ {
+ /* Front FBO */
+
+ Texture *texture = get_texture(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, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ glDeleteFramebuffers(1, &rt->fbo);
+ glDeleteTextures(1, &rt->color);
+ rt->fbo = 0;
+ rt->size.x = 0;
+ rt->size.y = 0;
+ rt->color = 0;
+ texture->tex_id = 0;
+ texture->active = false;
+ WARN_PRINT("Could not create render target, status: " + get_framebuffer_error(status));
+ return;
+ }
+
+ texture->format = rt->image_format;
+ texture->real_format = rt->image_format;
+ texture->type = Texture::TYPE_2D;
+ texture->target = GL_TEXTURE_2D;
+ texture->gl_format_cache = rt->color_format;
+ texture->gl_type_cache = GL_UNSIGNED_BYTE;
+ texture->gl_internal_format_cache = rt->color_internal_format;
+ texture->tex_id = rt->color;
+ texture->width = rt->size.x;
+ texture->alloc_width = rt->size.x;
+ texture->height = rt->size.y;
+ texture->alloc_height = rt->size.y;
+ texture->active = true;
+ }
+
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glBindFramebuffer(GL_FRAMEBUFFER, system_fbo);
+}
+
+void TextureStorage::_create_render_target_backbuffer(RenderTarget *rt) {
+ ERR_FAIL_COND_MSG(rt->backbuffer_fbo != 0, "Cannot allocate RenderTarget backbuffer: already initialized.");
+ ERR_FAIL_COND(rt->direct_to_screen);
+ // Allocate mipmap chains for full screen blur
+ // Limit mipmaps so smallest is 32x32 to avoid unnecessary framebuffer switches
+ int count = MAX(1, Image::get_image_required_mipmaps(rt->size.x, rt->size.y, Image::FORMAT_RGBA8) - 4);
+ if (rt->size.x > 40 && rt->size.y > 40) {
+ GLsizei width = rt->size.x;
+ GLsizei height = rt->size.y;
+
+ rt->mipmap_count = count;
+
+ glGenTextures(1, &rt->backbuffer);
+ glBindTexture(GL_TEXTURE_2D, rt->backbuffer);
+
+ for (int l = 0; l < count; l++) {
+ glTexImage2D(GL_TEXTURE_2D, l, rt->color_internal_format, width, height, 0, rt->color_format, rt->color_type, nullptr);
+ width = MAX(1, (width / 2));
+ height = MAX(1, (height / 2));
+ }
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, count - 1);
+
+ glGenFramebuffers(1, &rt->backbuffer_fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->backbuffer, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ WARN_PRINT_ONCE("Cannot allocate mipmaps for canvas screen blur. Status: " + get_framebuffer_error(status));
+ glBindFramebuffer(GL_FRAMEBUFFER, system_fbo);
+ return;
+ }
+
+ // Initialize all levels to opaque Magenta.
+ for (int j = 0; j < count; j++) {
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->backbuffer, j);
+ glClearColor(1.0, 0.0, 1.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->backbuffer, 0);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+}
+
+void TextureStorage::_clear_render_target(RenderTarget *rt) {
+ // there is nothing to clear when DIRECT_TO_SCREEN is used
+ if (rt->direct_to_screen) {
+ return;
+ }
+
+ if (rt->fbo) {
+ glDeleteFramebuffers(1, &rt->fbo);
+ glDeleteTextures(1, &rt->color);
+ rt->fbo = 0;
+ rt->color = 0;
+ }
+ /*
+ if (rt->external.fbo != 0) {
+ // free this
+ glDeleteFramebuffers(1, &rt->external.fbo);
+
+ // clean up our texture
+ Texture *t = get_texture(rt->external.texture);
+ t->alloc_height = 0;
+ t->alloc_width = 0;
+ t->width = 0;
+ t->height = 0;
+ t->active = false;
+ texture_free(rt->external.texture);
+ memdelete(t);
+
+ rt->external.fbo = 0;
+ }
+ */
+
+ Texture *tex = get_texture(rt->texture);
+ tex->alloc_height = 0;
+ tex->alloc_width = 0;
+ tex->width = 0;
+ tex->height = 0;
+ tex->active = false;
+
+ if (rt->backbuffer_fbo != 0) {
+ glDeleteFramebuffers(1, &rt->backbuffer_fbo);
+ glDeleteTextures(1, &rt->backbuffer);
+ rt->backbuffer = 0;
+ rt->backbuffer_fbo = 0;
+ }
+}
+
+RID TextureStorage::render_target_create() {
+ RenderTarget render_target;
+ //render_target.was_used = false;
+ render_target.clear_requested = false;
+
+ Texture t;
+ t.active = true;
+ t.render_target = &render_target;
+ t.is_render_target = true;
+
+ render_target.texture = texture_owner.make_rid(t);
+ _update_render_target(&render_target);
+ return render_target_owner.make_rid(render_target);
+}
+
+void TextureStorage::render_target_free(RID p_rid) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_rid);
+ _clear_render_target(rt);
+
+ Texture *t = get_texture(rt->texture);
+ if (t) {
+ t->is_render_target = false;
+ texture_free(rt->texture);
+ //memdelete(t);
+ }
+ render_target_owner.free(p_rid);
+}
+
+void TextureStorage::render_target_set_position(RID p_render_target, int p_x, int p_y) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ rt->position = Point2i(p_x, p_y);
+}
+
+void TextureStorage::render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ if (p_width == rt->size.x && p_height == rt->size.y) {
+ return;
+ }
+
+ _clear_render_target(rt);
+
+ rt->size = Size2i(p_width, p_height);
+
+ _update_render_target(rt);
+}
+
+// TODO: convert to Size2i internally
+Size2i TextureStorage::render_target_get_size(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, Size2());
+
+ return rt->size;
+}
+
+RID TextureStorage::render_target_get_texture(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
+
+ if (rt->external.fbo == 0) {
+ return rt->texture;
+ } else {
+ return rt->external.texture;
+ }
+}
+
+void TextureStorage::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {
+ RenderTarget *rt = render_target_owner.get_or_null(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 = get_texture(rt->external.texture);
+ t->alloc_height = 0;
+ t->alloc_width = 0;
+ t->width = 0;
+ t->height = 0;
+ t->active = false;
+ texture_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 = Texture::TYPE_2D;
+ 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->total_data_size = 0;
+ t->mipmaps = 1;
+ t->active = true;
+ t->tex_id = 0;
+ t->render_target = rt;
+ t->is_render_target = true;
+
+ //rt->external.texture = make_rid(t);
+
+ } else {
+ // bind our frame buffer
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo);
+
+ // find our texture
+ t = get_texture(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->size.x;
+ t->height = rt->size.y;
+ t->alloc_height = rt->size.x;
+ t->alloc_width = rt->size.y;
+
+ // Switch our texture on our frame buffer
+ {
+ // set our texture as the destination for our framebuffer
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture_id, 0);
+ }
+
+ // check status and unbind
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ WARN_PRINT("framebuffer fail, status: " + get_framebuffer_error(status));
+ }
+
+ ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
+ }
+}
+
+void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_transparent) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ rt->is_transparent = p_transparent;
+
+ _clear_render_target(rt);
+ _update_render_target(rt);
+}
+
+void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ if (p_direct_to_screen == rt->direct_to_screen) {
+ return;
+ }
+ // 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
+ _clear_render_target(rt);
+ rt->direct_to_screen = p_direct_to_screen;
+ _update_render_target(rt);
+}
+
+bool TextureStorage::render_target_was_used(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, false);
+
+ return rt->used_in_frame;
+}
+
+void TextureStorage::render_target_clear_used(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ rt->used_in_frame = false;
+}
+
+void TextureStorage::render_target_request_clear(RID p_render_target, const Color &p_clear_color) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+ rt->clear_requested = true;
+ rt->clear_color = p_clear_color;
+}
+
+bool TextureStorage::render_target_is_clear_requested(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, false);
+ return rt->clear_requested;
+}
+Color TextureStorage::render_target_get_clear_request_color(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, Color());
+ return rt->clear_color;
+}
+
+void TextureStorage::render_target_disable_clear_request(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+ rt->clear_requested = false;
+}
+
+void TextureStorage::render_target_do_clear_request(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+ if (!rt->clear_requested) {
+ return;
+ }
+
+ glClearBufferfv(GL_COLOR, 0, rt->clear_color.components);
+ rt->clear_requested = false;
+}
+
+void TextureStorage::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) {
+}
+
+Rect2i TextureStorage::render_target_get_sdf_rect(RID p_render_target) const {
+ return Rect2i();
+}
+
+void TextureStorage::render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) {
+}
+
+void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+ ERR_FAIL_COND(rt->direct_to_screen);
+
+ if (rt->backbuffer_fbo == 0) {
+ _create_render_target_backbuffer(rt);
+ }
+
+ Rect2i region;
+ if (p_region == Rect2i()) {
+ region.size = rt->size;
+ } else {
+ region = Rect2i(Size2i(), rt->size).intersection(p_region);
+ if (region.size == Size2i()) {
+ return; //nothing to do
+ }
+ }
+
+ glDisable(GL_BLEND);
+ //single texture copy for backbuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, rt->color);
+ GLES3::CopyEffects::get_singleton()->copy_screen();
+
+ if (p_gen_mipmaps) {
+ GLES3::CopyEffects::get_singleton()->bilinear_blur(rt->backbuffer, rt->mipmap_count, region);
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
+ }
+
+ glEnable(GL_BLEND); // 2D almost always uses blend.
+}
+
+void TextureStorage::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+ ERR_FAIL_COND(rt->direct_to_screen);
+
+ if (rt->backbuffer_fbo == 0) {
+ _create_render_target_backbuffer(rt);
+ }
+
+ Rect2i region;
+ if (p_region == Rect2i()) {
+ // Just do a full screen clear;
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
+ glClearColor(p_color.r, p_color.g, p_color.b, p_color.a);
+ glClear(GL_COLOR_BUFFER_BIT);
+ } else {
+ region = Rect2i(Size2i(), rt->size).intersection(p_region);
+ if (region.size == Size2i()) {
+ return; //nothing to do
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
+ GLES3::CopyEffects::get_singleton()->set_color(p_color, region);
+ }
+}
+
+void TextureStorage::render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ if (rt->backbuffer_fbo == 0) {
+ _create_render_target_backbuffer(rt);
+ }
+
+ Rect2i region;
+ if (p_region == Rect2i()) {
+ region.size = rt->size;
+ } else {
+ region = Rect2i(Size2i(), rt->size).intersection(p_region);
+ if (region.size == Size2i()) {
+ return; //nothing to do
+ }
+ }
+
+ GLES3::CopyEffects::get_singleton()->bilinear_blur(rt->backbuffer, rt->mipmap_count, region);
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
+}
+
+#endif // GLES3_ENABLED
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
new file mode 100644
index 0000000000..71f713bc9f
--- /dev/null
+++ b/drivers/gles3/storage/texture_storage.h
@@ -0,0 +1,583 @@
+/*************************************************************************/
+/* texture_storage.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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 TEXTURE_STORAGE_GLES3_H
+#define TEXTURE_STORAGE_GLES3_H
+
+#ifdef GLES3_ENABLED
+
+#include "config.h"
+#include "core/os/os.h"
+#include "core/templates/rid_owner.h"
+#include "servers/rendering/renderer_compositor.h"
+#include "servers/rendering/storage/texture_storage.h"
+
+// This must come first to avoid windows.h mess
+#include "platform_config.h"
+#ifndef OPENGL_INCLUDE_H
+#include <GLES3/gl3.h>
+#else
+#include OPENGL_INCLUDE_H
+#endif
+
+namespace GLES3 {
+
+#define _GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#define _GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+
+#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_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
+
+#define _EXT_COMPRESSED_R11_EAC 0x9270
+#define _EXT_COMPRESSED_SIGNED_R11_EAC 0x9271
+#define _EXT_COMPRESSED_RG11_EAC 0x9272
+#define _EXT_COMPRESSED_SIGNED_RG11_EAC 0x9273
+#define _EXT_COMPRESSED_RGB8_ETC2 0x9274
+#define _EXT_COMPRESSED_SRGB8_ETC2 0x9275
+#define _EXT_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
+#define _EXT_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
+#define _EXT_COMPRESSED_RGBA8_ETC2_EAC 0x9278
+#define _EXT_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
+
+#define _GL_TEXTURE_EXTERNAL_OES 0x8D65
+
+#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
+#endif //!GLES_OVER_GL
+
+enum DefaultGLTexture {
+ DEFAULT_GL_TEXTURE_WHITE,
+ DEFAULT_GL_TEXTURE_BLACK,
+ DEFAULT_GL_TEXTURE_TRANSPARENT,
+ DEFAULT_GL_TEXTURE_NORMAL,
+ DEFAULT_GL_TEXTURE_ANISO,
+ DEFAULT_GL_TEXTURE_DEPTH,
+ DEFAULT_GL_TEXTURE_CUBEMAP_BLACK,
+ //DEFAULT_GL_TEXTURE_CUBEMAP_ARRAY_BLACK, // Cubemap Arrays not supported in GL 3.3 or GL ES 3.0
+ DEFAULT_GL_TEXTURE_CUBEMAP_WHITE,
+ DEFAULT_GL_TEXTURE_3D_WHITE,
+ DEFAULT_GL_TEXTURE_3D_BLACK,
+ DEFAULT_GL_TEXTURE_2D_ARRAY_WHITE,
+ DEFAULT_GL_TEXTURE_2D_UINT,
+ DEFAULT_GL_TEXTURE_MAX
+};
+
+struct CanvasTexture {
+ RID diffuse;
+ RID normal_map;
+ RID specular;
+ Color specular_color = Color(1, 1, 1, 1);
+ float shininess = 1.0;
+
+ RS::CanvasItemTextureFilter texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
+ RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
+
+ Size2i size_cache = Size2i(1, 1);
+ bool use_normal_cache = false;
+ bool use_specular_cache = false;
+ bool cleared_cache = true;
+};
+
+/* CANVAS SHADOW */
+
+struct CanvasLightShadow {
+ RID self;
+ int size;
+ int height;
+ GLuint fbo;
+ GLuint depth;
+ GLuint distance; //for older devices
+};
+
+struct RenderTarget;
+
+struct Texture {
+ RID self;
+
+ bool is_proxy = false;
+ bool is_render_target = false;
+
+ RID proxy_to = RID();
+ Vector<RID> proxies;
+
+ String path;
+ int width = 0;
+ int height = 0;
+ int depth = 0;
+ int mipmaps = 1;
+ int layers = 1;
+ int alloc_width = 0;
+ int alloc_height = 0;
+ Image::Format format = Image::FORMAT_R8;
+ Image::Format real_format = Image::FORMAT_R8;
+
+ enum Type {
+ TYPE_2D,
+ TYPE_LAYERED,
+ TYPE_3D
+ };
+
+ Type type;
+ RS::TextureLayeredType layered_type = RS::TEXTURE_LAYERED_2D_ARRAY;
+
+ GLenum target = GL_TEXTURE_2D;
+ GLenum gl_format_cache = 0;
+ GLenum gl_internal_format_cache = 0;
+ GLenum gl_type_cache = 0;
+
+ int total_data_size = 0;
+
+ bool compressed = false;
+
+ bool resize_to_po2 = false;
+
+ bool active = false;
+ GLuint tex_id = 0;
+
+ uint16_t stored_cube_sides = 0;
+
+ RenderTarget *render_target = nullptr;
+
+ Ref<Image> image_cache_2d;
+
+ bool redraw_if_visible = false;
+
+ RS::TextureDetectCallback detect_3d_callback = nullptr;
+ void *detect_3d_callback_ud = nullptr;
+
+ RS::TextureDetectCallback detect_normal_callback = nullptr;
+ void *detect_normal_callback_ud = nullptr;
+
+ RS::TextureDetectRoughnessCallback detect_roughness_callback = nullptr;
+ void *detect_roughness_callback_ud = nullptr;
+
+ CanvasTexture *canvas_texture = nullptr;
+
+ void copy_from(const Texture &o) {
+ proxy_to = o.proxy_to;
+ is_proxy = o.is_proxy;
+ width = o.width;
+ height = o.height;
+ alloc_width = o.alloc_width;
+ alloc_height = o.alloc_height;
+ format = o.format;
+ type = o.type;
+ layered_type = o.layered_type;
+ target = o.target;
+ total_data_size = o.total_data_size;
+ compressed = o.compressed;
+ mipmaps = o.mipmaps;
+ resize_to_po2 = o.resize_to_po2;
+ active = o.active;
+ tex_id = o.tex_id;
+ stored_cube_sides = o.stored_cube_sides;
+ render_target = o.render_target;
+ is_render_target = o.is_render_target;
+ redraw_if_visible = o.redraw_if_visible;
+ detect_3d_callback = o.detect_3d_callback;
+ detect_3d_callback_ud = o.detect_3d_callback_ud;
+ detect_normal_callback = o.detect_normal_callback;
+ detect_normal_callback_ud = o.detect_normal_callback_ud;
+ detect_roughness_callback = o.detect_roughness_callback;
+ detect_roughness_callback_ud = o.detect_roughness_callback_ud;
+ }
+
+ // texture state
+ void gl_set_filter(RS::CanvasItemTextureFilter p_filter) {
+ if (p_filter == state_filter) {
+ return;
+ }
+ Config *config = Config::get_singleton();
+ state_filter = p_filter;
+ GLenum pmin = GL_NEAREST; // param min
+ GLenum pmag = GL_NEAREST; // param mag
+ GLint max_lod = 1000;
+ bool use_anisotropy = false;
+ switch (state_filter) {
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: {
+ pmin = GL_NEAREST;
+ pmag = GL_NEAREST;
+ max_lod = 0;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: {
+ pmin = GL_LINEAR;
+ pmag = GL_LINEAR;
+ max_lod = 0;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: {
+ use_anisotropy = true;
+ };
+ [[fallthrough]];
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: {
+ pmag = GL_NEAREST;
+ if (mipmaps <= 1) {
+ pmin = GL_NEAREST;
+ max_lod = 0;
+ } else if (config->use_nearest_mip_filter) {
+ pmin = GL_NEAREST_MIPMAP_NEAREST;
+ } else {
+ pmin = GL_NEAREST_MIPMAP_LINEAR;
+ }
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: {
+ use_anisotropy = true;
+ };
+ [[fallthrough]];
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
+ pmag = GL_LINEAR;
+ if (mipmaps <= 1) {
+ pmin = GL_LINEAR;
+ max_lod = 0;
+ } else if (config->use_nearest_mip_filter) {
+ pmin = GL_LINEAR_MIPMAP_NEAREST;
+ } else {
+ pmin = GL_LINEAR_MIPMAP_LINEAR;
+ }
+ } break;
+ default: {
+ } break;
+ }
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, pmin);
+ glTexParameteri(target, GL_TEXTURE_MAG_FILTER, pmag);
+ glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, max_lod);
+ if (config->support_anisotropic_filter && use_anisotropy) {
+ glTexParameterf(target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, config->anisotropic_level);
+ }
+ }
+ void gl_set_repeat(RS::CanvasItemTextureRepeat p_repeat) {
+ if (p_repeat == state_repeat) {
+ return;
+ }
+ state_repeat = p_repeat;
+ GLenum prep = GL_CLAMP_TO_EDGE; // parameter repeat
+ switch (state_repeat) {
+ case RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {
+ prep = GL_REPEAT;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: {
+ prep = GL_MIRRORED_REPEAT;
+ } break;
+ default: {
+ } break;
+ }
+ glTexParameteri(target, GL_TEXTURE_WRAP_T, prep);
+ glTexParameteri(target, GL_TEXTURE_WRAP_R, prep);
+ glTexParameteri(target, GL_TEXTURE_WRAP_S, prep);
+ }
+
+private:
+ RS::CanvasItemTextureFilter state_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
+ RS::CanvasItemTextureRepeat state_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
+};
+
+struct RenderTarget {
+ struct External {
+ GLuint fbo = 0;
+ GLuint color = 0;
+ GLuint depth = 0;
+ RID texture;
+
+ External() {
+ }
+ } external;
+
+ Point2i position = Point2i(0, 0);
+ Size2i size = Size2i(0, 0);
+ int mipmap_count = 1;
+ RID self;
+ GLuint fbo = 0;
+ GLuint color = 0;
+ GLuint backbuffer_fbo = 0;
+ GLuint backbuffer = 0;
+
+ GLuint color_internal_format = GL_RGBA8;
+ GLuint color_format = GL_RGBA;
+ GLuint color_type = GL_UNSIGNED_BYTE;
+ Image::Format image_format = Image::FORMAT_RGBA8;
+
+ bool is_transparent = false;
+ bool direct_to_screen = false;
+
+ bool used_in_frame = false;
+ RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
+
+ RID texture;
+
+ Color clear_color = Color(1, 1, 1, 1);
+ bool clear_requested = false;
+
+ RenderTarget() {
+ }
+};
+
+class TextureStorage : public RendererTextureStorage {
+private:
+ static TextureStorage *singleton;
+
+ RID default_gl_textures[DEFAULT_GL_TEXTURE_MAX];
+
+ /* Canvas Texture API */
+
+ RID_Owner<CanvasTexture, true> canvas_texture_owner;
+
+ /* CANVAS SHADOW */
+
+ RID_PtrOwner<CanvasLightShadow> canvas_light_shadow_owner;
+
+ /* Texture API */
+
+ mutable RID_Owner<Texture> texture_owner;
+
+ Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, 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;
+
+ /* Render Target API */
+
+ mutable RID_Owner<RenderTarget> render_target_owner;
+
+ void _clear_render_target(RenderTarget *rt);
+ void _update_render_target(RenderTarget *rt);
+ void _create_render_target_backbuffer(RenderTarget *rt);
+
+public:
+ static TextureStorage *get_singleton();
+
+ TextureStorage();
+ virtual ~TextureStorage();
+
+ _FORCE_INLINE_ RID texture_gl_get_default(DefaultGLTexture p_texture) {
+ return default_gl_textures[p_texture];
+ }
+
+ /* Canvas Texture API */
+
+ CanvasTexture *get_canvas_texture(RID p_rid) { return canvas_texture_owner.get_or_null(p_rid); };
+ bool owns_canvas_texture(RID p_rid) { return canvas_texture_owner.owns(p_rid); };
+
+ virtual RID canvas_texture_allocate() override;
+ virtual void canvas_texture_initialize(RID p_rid) override;
+ virtual void canvas_texture_free(RID p_rid) override;
+
+ virtual void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) override;
+ virtual void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) override;
+
+ virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override;
+ virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override;
+
+ /* CANVAS SHADOW */
+
+ RID canvas_light_shadow_buffer_create(int p_width);
+
+ /* Texture API */
+
+ Texture *get_texture(RID p_rid) {
+ Texture *texture = texture_owner.get_or_null(p_rid);
+ if (texture && texture->is_proxy) {
+ return texture_owner.get_or_null(texture->proxy_to);
+ }
+ return texture;
+ };
+ bool owns_texture(RID p_rid) { return texture_owner.owns(p_rid); };
+
+ virtual bool can_create_resources_async() const override;
+
+ RID texture_create();
+
+ virtual RID texture_allocate() override;
+ virtual void texture_free(RID p_rid) override;
+
+ virtual void texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) override;
+ virtual void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) override;
+ virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) override;
+ virtual void texture_proxy_initialize(RID p_texture, RID p_base) override; //all slices, then all the mipmaps, must be coherent
+
+ virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override;
+ virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override{};
+ virtual void texture_proxy_update(RID p_proxy, RID p_base) override;
+
+ //these two APIs can be used together or in combination with the others.
+ virtual void texture_2d_placeholder_initialize(RID p_texture) override;
+ virtual void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) override;
+ virtual void texture_3d_placeholder_initialize(RID p_texture) override;
+
+ virtual Ref<Image> texture_2d_get(RID p_texture) const override;
+ virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const override { return Ref<Image>(); };
+ virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const override { return Vector<Ref<Image>>(); };
+
+ virtual void texture_replace(RID p_texture, RID p_by_texture) override;
+ virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) override;
+
+ virtual void texture_set_path(RID p_texture, const String &p_path) override;
+ virtual String texture_get_path(RID p_texture) const override;
+
+ virtual void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override;
+ void texture_set_detect_srgb_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) override;
+ virtual 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) override;
+
+ virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) override;
+
+ virtual Size2 texture_size_with_proxy(RID p_proxy) override;
+
+ void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0);
+ 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);
+ //Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const;
+ void texture_set_sampler(RID p_texture, RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat);
+ Image::Format texture_get_format(RID p_texture) const;
+ uint32_t texture_get_texid(RID p_texture) const;
+ uint32_t texture_get_width(RID p_texture) const;
+ uint32_t texture_get_height(RID p_texture) const;
+ uint32_t texture_get_depth(RID p_texture) const;
+ void texture_bind(RID p_texture, uint32_t p_texture_no);
+ RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const;
+
+ /* DECAL API */
+
+ virtual RID decal_allocate() override;
+ virtual void decal_initialize(RID p_rid) override;
+ virtual void decal_free(RID p_rid) override{};
+
+ virtual void decal_set_extents(RID p_decal, const Vector3 &p_extents) override;
+ virtual void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) override;
+ virtual void decal_set_emission_energy(RID p_decal, float p_energy) override;
+ virtual void decal_set_albedo_mix(RID p_decal, float p_mix) override;
+ virtual void decal_set_modulate(RID p_decal, const Color &p_modulate) override;
+ virtual void decal_set_cull_mask(RID p_decal, uint32_t p_layers) override;
+ virtual void decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) override;
+ virtual void decal_set_fade(RID p_decal, float p_above, float p_below) override;
+ virtual void decal_set_normal_fade(RID p_decal, float p_fade) override;
+
+ virtual AABB decal_get_aabb(RID p_decal) const override;
+
+ virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {}
+ virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {}
+
+ /* RENDER TARGET API */
+
+ static GLuint system_fbo;
+
+ RenderTarget *get_render_target(RID p_rid) { return render_target_owner.get_or_null(p_rid); };
+ bool owns_render_target(RID p_rid) { return render_target_owner.owns(p_rid); };
+
+ virtual RID render_target_create() override;
+ virtual void render_target_free(RID p_rid) override;
+ virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) override;
+ virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override;
+ Size2i render_target_get_size(RID p_render_target);
+ virtual RID render_target_get_texture(RID p_render_target) override;
+ virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override;
+
+ virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override;
+ virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override;
+ virtual bool render_target_was_used(RID p_render_target) override;
+ void render_target_clear_used(RID p_render_target);
+
+ // new
+ void render_target_set_as_unused(RID p_render_target) override {
+ render_target_clear_used(p_render_target);
+ }
+
+ 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;
+ Color render_target_get_clear_request_color(RID p_render_target) override;
+ 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;
+ void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override;
+
+ void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps);
+ void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color);
+ void render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region);
+ virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override{};
+ virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override{};
+
+ void bind_framebuffer(GLuint framebuffer) {
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ }
+
+ void bind_framebuffer_system() {
+ glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
+ }
+
+ String get_framebuffer_error(GLenum p_status);
+};
+
+inline String TextureStorage::get_framebuffer_error(GLenum p_status) {
+#if defined(DEBUG_ENABLED) && defined(GLES_OVER_GL)
+ if (p_status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) {
+ return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
+ } else if (p_status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) {
+ return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
+ } else if (p_status == GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER) {
+ return "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER";
+ } else if (p_status == GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER) {
+ return "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER";
+ }
+#endif
+ return itos(p_status);
+}
+
+} // namespace GLES3
+
+#endif // GLES3_ENABLED
+
+#endif // TEXTURE_STORAGE_GLES3_H
diff --git a/drivers/gles3/storage/utilities.cpp b/drivers/gles3/storage/utilities.cpp
new file mode 100644
index 0000000000..654104722b
--- /dev/null
+++ b/drivers/gles3/storage/utilities.cpp
@@ -0,0 +1,353 @@
+/*************************************************************************/
+/* utilities.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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. */
+/*************************************************************************/
+
+#ifdef GLES3_ENABLED
+
+#include "utilities.h"
+#include "config.h"
+#include "light_storage.h"
+#include "material_storage.h"
+#include "mesh_storage.h"
+#include "particles_storage.h"
+#include "texture_storage.h"
+
+using namespace GLES3;
+
+Utilities *Utilities::singleton = nullptr;
+
+Utilities::Utilities() {
+ singleton = this;
+}
+
+Utilities::~Utilities() {
+ singleton = nullptr;
+}
+
+Vector<uint8_t> Utilities::buffer_get_data(GLenum p_target, GLuint p_buffer, uint32_t p_buffer_size) {
+ Vector<uint8_t> ret;
+ ret.resize(p_buffer_size);
+ glBindBuffer(p_target, p_buffer);
+
+#if defined(__EMSCRIPTEN__)
+ {
+ uint8_t *w = ret.ptrw();
+ glGetBufferSubData(p_target, 0, p_buffer_size, w);
+ }
+#else
+ void *data = glMapBufferRange(p_target, 0, p_buffer_size, GL_MAP_READ_BIT);
+ ERR_FAIL_NULL_V(data, Vector<uint8_t>());
+ {
+ uint8_t *w = ret.ptrw();
+ memcpy(w, data, p_buffer_size);
+ }
+ glUnmapBuffer(p_target);
+#endif
+ glBindBuffer(p_target, 0);
+ return ret;
+}
+
+/* INSTANCES */
+
+RS::InstanceType Utilities::get_base_type(RID p_rid) const {
+ if (GLES3::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
+ return RS::INSTANCE_MESH;
+ } else if (GLES3::MeshStorage::get_singleton()->owns_multimesh(p_rid)) {
+ return RS::INSTANCE_MULTIMESH;
+ } else if (GLES3::LightStorage::get_singleton()->owns_light(p_rid)) {
+ return RS::INSTANCE_LIGHT;
+ }
+ return RS::INSTANCE_NONE;
+}
+
+bool Utilities::free(RID p_rid) {
+ if (GLES3::TextureStorage::get_singleton()->owns_render_target(p_rid)) {
+ GLES3::TextureStorage::get_singleton()->render_target_free(p_rid);
+ return true;
+ } else if (GLES3::TextureStorage::get_singleton()->owns_texture(p_rid)) {
+ GLES3::TextureStorage::get_singleton()->texture_free(p_rid);
+ return true;
+ } else if (GLES3::TextureStorage::get_singleton()->owns_canvas_texture(p_rid)) {
+ GLES3::TextureStorage::get_singleton()->canvas_texture_free(p_rid);
+ return true;
+ } else if (GLES3::MaterialStorage::get_singleton()->owns_shader(p_rid)) {
+ GLES3::MaterialStorage::get_singleton()->shader_free(p_rid);
+ return true;
+ } else if (GLES3::MaterialStorage::get_singleton()->owns_material(p_rid)) {
+ GLES3::MaterialStorage::get_singleton()->material_free(p_rid);
+ return true;
+ } else if (GLES3::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
+ GLES3::MeshStorage::get_singleton()->mesh_free(p_rid);
+ return true;
+ } else if (GLES3::MeshStorage::get_singleton()->owns_multimesh(p_rid)) {
+ GLES3::MeshStorage::get_singleton()->multimesh_free(p_rid);
+ return true;
+ } else if (GLES3::MeshStorage::get_singleton()->owns_mesh_instance(p_rid)) {
+ GLES3::MeshStorage::get_singleton()->mesh_instance_free(p_rid);
+ return true;
+ } else if (GLES3::LightStorage::get_singleton()->owns_light(p_rid)) {
+ GLES3::LightStorage::get_singleton()->light_free(p_rid);
+ return true;
+ } else {
+ return false;
+ }
+ /*
+ else if (reflection_probe_owner.owns(p_rid)) {
+ // delete the texture
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(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.get_or_null(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.get_or_null(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.get_or_null(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;
+ }
+ */
+}
+
+/* DEPENDENCIES */
+
+void Utilities::base_update_dependency(RID p_base, DependencyTracker *p_instance) {
+ if (MeshStorage::get_singleton()->owns_mesh(p_base)) {
+ Mesh *mesh = MeshStorage::get_singleton()->get_mesh(p_base);
+ p_instance->update_dependency(&mesh->dependency);
+ } else if (MeshStorage::get_singleton()->owns_multimesh(p_base)) {
+ MultiMesh *multimesh = MeshStorage::get_singleton()->get_multimesh(p_base);
+ p_instance->update_dependency(&multimesh->dependency);
+ if (multimesh->mesh.is_valid()) {
+ base_update_dependency(multimesh->mesh, p_instance);
+ }
+ } else if (LightStorage::get_singleton()->owns_light(p_base)) {
+ Light *l = LightStorage::get_singleton()->get_light(p_base);
+ p_instance->update_dependency(&l->dependency);
+ }
+}
+
+/* VISIBILITY NOTIFIER */
+
+RID Utilities::visibility_notifier_allocate() {
+ return RID();
+}
+
+void Utilities::visibility_notifier_initialize(RID p_notifier) {
+}
+
+void Utilities::visibility_notifier_free(RID p_notifier) {
+}
+
+void Utilities::visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) {
+}
+
+void Utilities::visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) {
+}
+
+AABB Utilities::visibility_notifier_get_aabb(RID p_notifier) const {
+ return AABB();
+}
+
+void Utilities::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) {
+}
+
+/* TIMING */
+
+//void Utilities::render_info_begin_capture() {
+// info.snap = info.render;
+//}
+
+//void Utilities::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;
+// info.snap._2d_item_count = info.render._2d_item_count - info.snap._2d_item_count;
+// info.snap._2d_draw_call_count = info.render._2d_draw_call_count - info.snap._2d_draw_call_count;
+//}
+
+//int Utilities::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;
+// /*
+// case RS::INFO_2D_ITEMS_IN_FRAME: {
+// return info.snap._2d_item_count;
+// } break;
+// case RS::INFO_2D_DRAW_CALLS_IN_FRAME: {
+// return info.snap._2d_draw_call_count;
+// } break;
+// */
+// default: {
+// return get_render_info(p_info);
+// }
+// }
+//}
+
+//int Utilities::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_2D_ITEMS_IN_FRAME:
+// return info.render_final._2d_item_count;
+// case RS::INFO_2D_DRAW_CALLS_IN_FRAME:
+// return info.render_final._2d_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
+// }
+//}
+
+/* MISC */
+
+void Utilities::update_dirty_resources() {
+ MaterialStorage::get_singleton()->_update_global_shader_uniforms();
+ MaterialStorage::get_singleton()->_update_queued_materials();
+ //MeshStorage::get_singleton()->_update_dirty_skeletons();
+ MeshStorage::get_singleton()->_update_dirty_multimeshes();
+}
+
+void Utilities::set_debug_generate_wireframes(bool p_generate) {
+}
+
+bool Utilities::has_os_feature(const String &p_feature) const {
+ Config *config = Config::get_singleton();
+ if (!config) {
+ return false;
+ }
+
+ if (p_feature == "rgtc") {
+ return config->rgtc_supported;
+ }
+
+ if (p_feature == "s3tc") {
+ return config->s3tc_supported;
+ }
+
+ if (p_feature == "bptc") {
+ return config->bptc_supported;
+ }
+
+ if (p_feature == "etc" || p_feature == "etc2") {
+ return config->etc2_supported;
+ }
+
+ return false;
+}
+
+void Utilities::update_memory_info() {
+}
+
+uint64_t Utilities::get_rendering_info(RS::RenderingInfo p_info) {
+ return 0;
+}
+
+String Utilities::get_video_adapter_name() const {
+ return (const char *)glGetString(GL_RENDERER);
+}
+
+String Utilities::get_video_adapter_vendor() const {
+ return (const char *)glGetString(GL_VENDOR);
+}
+
+RenderingDevice::DeviceType Utilities::get_video_adapter_type() const {
+ return RenderingDevice::DeviceType::DEVICE_TYPE_OTHER;
+}
+
+String Utilities::get_video_adapter_api_version() const {
+ return (const char *)glGetString(GL_VERSION);
+}
+
+#endif // GLES3_ENABLED
diff --git a/drivers/gles3/storage/utilities.h b/drivers/gles3/storage/utilities.h
new file mode 100644
index 0000000000..e054f2f816
--- /dev/null
+++ b/drivers/gles3/storage/utilities.h
@@ -0,0 +1,159 @@
+/*************************************************************************/
+/* utilities.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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 UTILITIES_GLES3_H
+#define UTILITIES_GLES3_H
+
+#ifdef GLES3_ENABLED
+
+#include "servers/rendering/storage/utilities.h"
+
+#include "platform_config.h"
+#ifndef OPENGL_INCLUDE_H
+#include <GLES3/gl3.h>
+#else
+#include OPENGL_INCLUDE_H
+#endif
+
+namespace GLES3 {
+
+class Utilities : public RendererUtilities {
+private:
+ static Utilities *singleton;
+
+public:
+ static Utilities *get_singleton() { return singleton; }
+
+ Utilities();
+ ~Utilities();
+
+ // Buffer size is specified in bytes
+ static Vector<uint8_t> buffer_get_data(GLenum p_target, GLuint p_buffer, uint32_t p_buffer_size);
+
+ /* INSTANCES */
+
+ virtual RS::InstanceType get_base_type(RID p_rid) const override;
+ virtual bool free(RID p_rid) override;
+
+ /* DEPENDENCIES */
+
+ virtual void base_update_dependency(RID p_base, DependencyTracker *p_instance) override;
+
+ /* VISIBILITY NOTIFIER */
+ virtual RID visibility_notifier_allocate() override;
+ virtual void visibility_notifier_initialize(RID p_notifier) override;
+ virtual void visibility_notifier_free(RID p_notifier) override;
+
+ virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) override;
+ virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) override;
+
+ virtual AABB visibility_notifier_get_aabb(RID p_notifier) const override;
+ virtual void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) override;
+
+ /* TIMING */
+
+ struct Info {
+ uint64_t texture_mem = 0;
+ uint64_t vertex_mem = 0;
+
+ 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;
+ uint32_t _2d_item_count;
+ uint32_t _2d_draw_call_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;
+ _2d_item_count = 0;
+ _2d_draw_call_count = 0;
+ }
+ } render, render_final, snap;
+
+ Info() {
+ render.reset();
+ render_final.reset();
+ }
+
+ } info;
+
+ virtual void capture_timestamps_begin() override {}
+ virtual void capture_timestamp(const String &p_name) override {}
+ virtual uint32_t get_captured_timestamps_count() const override {
+ return 0;
+ }
+ virtual uint64_t get_captured_timestamps_frame() const override {
+ return 0;
+ }
+ virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const override {
+ return 0;
+ }
+ virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const override {
+ return 0;
+ }
+ virtual String get_captured_timestamp_name(uint32_t p_index) const override {
+ return String();
+ }
+
+ // void render_info_begin_capture() override;
+ // void render_info_end_capture() override;
+ // int get_captured_render_info(RS::RenderInfo p_info) override;
+
+ // int get_render_info(RS::RenderInfo p_info) override;
+
+ /* MISC */
+
+ virtual void update_dirty_resources() override;
+ virtual void set_debug_generate_wireframes(bool p_generate) override;
+
+ virtual bool has_os_feature(const String &p_feature) const override;
+
+ virtual void update_memory_info() override;
+
+ virtual uint64_t get_rendering_info(RS::RenderingInfo p_info) override;
+ virtual String get_video_adapter_name() const override;
+ virtual String get_video_adapter_vendor() const override;
+ virtual RenderingDevice::DeviceType get_video_adapter_type() const override;
+ virtual String get_video_adapter_api_version() const override;
+};
+
+} // namespace GLES3
+
+#endif // GLES3_ENABLED
+
+#endif // UTILITIES_GLES3_H
diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp
index 46e271f9c9..917bfec574 100644
--- a/drivers/png/image_loader_png.cpp
+++ b/drivers/png/image_loader_png.cpp
@@ -36,18 +36,16 @@
#include <string.h>
-Error ImageLoaderPNG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
+Error ImageLoaderPNG::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
const uint64_t buffer_size = f->get_length();
Vector<uint8_t> file_buffer;
Error err = file_buffer.resize(buffer_size);
if (err) {
- f->close();
return err;
}
{
uint8_t *writer = file_buffer.ptrw();
f->get_buffer(writer, buffer_size);
- f->close();
}
const uint8_t *reader = file_buffer.ptr();
return PNGDriverCommon::png_to_image(reader, buffer_size, p_force_linear, p_image);
diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h
index af3bcd5b66..9bcfb720d3 100644
--- a/drivers/png/image_loader_png.h
+++ b/drivers/png/image_loader_png.h
@@ -40,9 +40,9 @@ private:
static Ref<Image> load_mem_png(const uint8_t *p_png, int p_size);
public:
- virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderPNG();
};
-#endif
+#endif // IMAGE_LOADER_PNG_H
diff --git a/drivers/png/png_driver_common.h b/drivers/png/png_driver_common.h
index 62302bbdbb..24546d4402 100644
--- a/drivers/png/png_driver_common.h
+++ b/drivers/png/png_driver_common.h
@@ -43,4 +43,4 @@ Error png_to_image(const uint8_t *p_source, size_t p_size, bool p_force_linear,
Error image_to_png(const Ref<Image> &p_image, Vector<uint8_t> &p_buffer);
} // namespace PNGDriverCommon
-#endif
+#endif // PNG_DRIVER_COMMON_H
diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp
index 77390a5915..275f3240d7 100644
--- a/drivers/png/resource_saver_png.cpp
+++ b/drivers/png/resource_saver_png.cpp
@@ -35,7 +35,7 @@
#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) {
+Error ResourceSaverPNG::save(const Ref<Resource> &p_resource, const String &p_path, 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.");
@@ -46,26 +46,22 @@ Error ResourceSaverPNG::save(const String &p_path, const RES &p_resource, uint32
Error err = save_image(p_path, img);
return err;
-};
+}
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.");
- FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
ERR_FAIL_COND_V_MSG(err, err, vformat("Can't save PNG at path: '%s'.", p_path));
const uint8_t *reader = buffer.ptr();
file->store_buffer(reader, buffer.size());
if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
- memdelete(file);
return ERR_CANT_CREATE;
}
- file->close();
- memdelete(file);
-
return OK;
}
@@ -76,11 +72,11 @@ Vector<uint8_t> ResourceSaverPNG::save_image_to_buffer(const Ref<Image> &p_img)
return buffer;
}
-bool ResourceSaverPNG::recognize(const RES &p_resource) const {
+bool ResourceSaverPNG::recognize(const Ref<Resource> &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 {
+void ResourceSaverPNG::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
if (Object::cast_to<ImageTexture>(*p_resource)) {
p_extensions->push_back("png");
}
@@ -89,4 +85,4 @@ void ResourceSaverPNG::get_recognized_extensions(const RES &p_resource, List<Str
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 f39e52c7ec..260a643a1b 100644
--- a/drivers/png/resource_saver_png.h
+++ b/drivers/png/resource_saver_png.h
@@ -39,9 +39,9 @@ public:
static Error save_image(const String &p_path, const Ref<Image> &p_img);
static Vector<uint8_t> save_image_to_buffer(const Ref<Image> &p_img);
- virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
- virtual bool recognize(const RES &p_resource) const;
- virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const;
+ virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0);
+ virtual bool recognize(const Ref<Resource> &p_resource) const;
+ virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
ResourceSaverPNG();
};
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index ef9bbc3483..a6c35b6837 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -41,7 +41,7 @@
#endif
void AudioDriverPulseAudio::pa_state_cb(pa_context *c, void *userdata) {
- AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata;
+ AudioDriverPulseAudio *ad = static_cast<AudioDriverPulseAudio *>(userdata);
switch (pa_context_get_state(c)) {
case PA_CONTEXT_TERMINATED:
@@ -65,7 +65,7 @@ void AudioDriverPulseAudio::pa_state_cb(pa_context *c, void *userdata) {
}
void AudioDriverPulseAudio::pa_sink_info_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata) {
- AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata;
+ AudioDriverPulseAudio *ad = static_cast<AudioDriverPulseAudio *>(userdata);
// If eol is set to a positive number, you're at the end of the list
if (eol > 0) {
@@ -84,7 +84,7 @@ void AudioDriverPulseAudio::pa_sink_info_cb(pa_context *c, const pa_sink_info *l
}
void AudioDriverPulseAudio::pa_source_info_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata) {
- AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata;
+ AudioDriverPulseAudio *ad = static_cast<AudioDriverPulseAudio *>(userdata);
// If eol is set to a positive number, you're at the end of the list
if (eol > 0) {
@@ -104,7 +104,7 @@ 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;
+ AudioDriverPulseAudio *ad = static_cast<AudioDriverPulseAudio *>(userdata);
ad->capture_default_device = i->default_source_name;
ad->default_device = i->default_sink_name;
@@ -379,7 +379,7 @@ float AudioDriverPulseAudio::get_latency() {
}
void AudioDriverPulseAudio::thread_func(void *p_udata) {
- AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)p_udata;
+ AudioDriverPulseAudio *ad = static_cast<AudioDriverPulseAudio *>(p_udata);
unsigned int write_ofs = 0;
size_t avail_bytes = 0;
uint64_t default_device_msec = OS::get_singleton()->get_ticks_msec();
@@ -588,7 +588,7 @@ AudioDriver::SpeakerMode AudioDriverPulseAudio::get_speaker_mode() const {
}
void AudioDriverPulseAudio::pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata) {
- AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata;
+ AudioDriverPulseAudio *ad = static_cast<AudioDriverPulseAudio *>(userdata);
// If eol is set to a positive number, you're at the end of the list
if (eol > 0) {
@@ -771,7 +771,7 @@ void AudioDriverPulseAudio::capture_set_device(const String &p_name) {
}
void AudioDriverPulseAudio::pa_sourcelist_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata) {
- AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata;
+ AudioDriverPulseAudio *ad = static_cast<AudioDriverPulseAudio *>(userdata);
// If eol is set to a positive number, you're at the end of the list
if (eol > 0) {
diff --git a/drivers/register_driver_types.cpp b/drivers/register_driver_types.cpp
index 1047e89e85..504ef9843a 100644
--- a/drivers/register_driver_types.cpp
+++ b/drivers/register_driver_types.cpp
@@ -55,9 +55,7 @@ void unregister_core_driver_types() {
}
void register_driver_types() {
- NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_DRIVER);
}
void unregister_driver_types() {
- NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_DRIVER);
}
diff --git a/drivers/register_driver_types.h b/drivers/register_driver_types.h
index c008d93185..41f95b57e7 100644
--- a/drivers/register_driver_types.h
+++ b/drivers/register_driver_types.h
@@ -37,4 +37,4 @@ void unregister_core_driver_types();
void register_driver_types();
void unregister_driver_types();
-#endif
+#endif // REGISTER_DRIVER_TYPES_H
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp
index 5fdfde4913..b8b72b8d30 100644
--- a/drivers/unix/dir_access_unix.cpp
+++ b/drivers/unix/dir_access_unix.cpp
@@ -33,6 +33,7 @@
#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)
#include "core/os/memory.h"
+#include "core/os/os.h"
#include "core/string/print_string.h"
#include "core/templates/list.h"
@@ -49,10 +50,6 @@
#include <mntent.h>
#endif
-DirAccess *DirAccessUnix::create_fs() {
- return memnew(DirAccessUnix);
-}
-
Error DirAccessUnix::list_dir_begin() {
list_dir_end(); //close any previous dir opening!
@@ -138,9 +135,9 @@ uint64_t DirAccessUnix::get_modified_time(String p_file) {
return flags.st_mtime;
} else {
ERR_FAIL_V(0);
- };
+ }
return 0;
-};
+}
String DirAccessUnix::get_next() {
if (!dir_stream) {
@@ -216,10 +213,11 @@ static bool _filter_drive(struct mntent *mnt) {
#endif
static void _get_drives(List<String> *list) {
+ // Add root.
list->push_back("/");
#if defined(HAVE_MNTENT) && defined(X11_ENABLED)
- // Check /etc/mtab for the list of mounted partitions
+ // Check /etc/mtab for the list of mounted partitions.
FILE *mtab = setmntent("/etc/mtab", "r");
if (mtab) {
struct mntent mnt;
@@ -239,7 +237,7 @@ static void _get_drives(List<String> *list) {
}
#endif
- // Add $HOME
+ // Add $HOME.
const char *home = getenv("HOME");
if (home) {
// Only add if it's not a duplicate
@@ -248,7 +246,8 @@ static void _get_drives(List<String> *list) {
list->push_back(home_name);
}
- // Check $HOME/.config/gtk-3.0/bookmarks
+ // Check GTK+3 bookmarks for both XDG locations (Documents, Downloads, etc.)
+ // and potential user-defined bookmarks.
char path[1024];
snprintf(path, 1024, "%s/.config/gtk-3.0/bookmarks", home);
FILE *fd = fopen(path, "r");
@@ -257,7 +256,7 @@ static void _get_drives(List<String> *list) {
while (fgets(string, 1024, fd)) {
// Parse only file:// links
if (strncmp(string, "file://", 7) == 0) {
- // Strip any unwanted edges on the strings and push_back if it's not a duplicate
+ // Strip any unwanted edges on the strings and push_back if it's not a duplicate.
String fpath = String::utf8(string + 7).strip_edges().split_spaces()[0].uri_decode();
if (!list->find(fpath)) {
list->push_back(fpath);
@@ -267,6 +266,12 @@ static void _get_drives(List<String> *list) {
fclose(fd);
}
+
+ // Add Desktop dir.
+ String dpath = OS::get_singleton()->get_system_dir(OS::SystemDir::SYSTEM_DIR_DESKTOP);
+ if (dpath.length() > 0 && !list->find(dpath)) {
+ list->push_back(dpath);
+ }
}
list->sort();
@@ -320,11 +325,11 @@ Error DirAccessUnix::make_dir(String p_dir) {
if (success) {
return OK;
- };
+ }
if (err == EEXIST) {
return ERR_ALREADY_EXISTS;
- };
+ }
return ERR_CANT_CREATE;
}
@@ -338,7 +343,7 @@ 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) != OK) {
prev_dir = real_current_dir_name; //no utf8, maybe latin?
}
@@ -374,7 +379,7 @@ Error DirAccessUnix::change_dir(String p_dir) {
return OK;
}
-String DirAccessUnix::get_current_dir(bool p_include_drive) {
+String DirAccessUnix::get_current_dir(bool p_include_drive) const {
String base = _get_root_path();
if (!base.is_empty()) {
String bd = current_dir.replace_first(base, "");
@@ -474,14 +479,14 @@ uint64_t DirAccessUnix::get_space_left() {
struct statvfs vfs;
if (statvfs(current_dir.utf8().get_data(), &vfs) != 0) {
return 0;
- };
+ }
return (uint64_t)vfs.f_bavail * (uint64_t)vfs.f_frsize;
#else
// FIXME: Implement this.
return 0;
#endif
-};
+}
String DirAccessUnix::get_filesystem_type() const {
return ""; //TODO this should be implemented
@@ -500,7 +505,7 @@ 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) != OK) {
current_dir = real_current_dir_name;
}
@@ -511,4 +516,4 @@ DirAccessUnix::~DirAccessUnix() {
list_dir_end();
}
-#endif //posix_enabled
+#endif // UNIX_ENABLED || LIBC_FILEIO_ENABLED
diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h
index f90f55605c..f5dca7c282 100644
--- a/drivers/unix/dir_access_unix.h
+++ b/drivers/unix/dir_access_unix.h
@@ -41,56 +41,55 @@
#include <unistd.h>
class DirAccessUnix : public DirAccess {
- DIR *dir_stream;
+ DIR *dir_stream = nullptr;
- static DirAccess *create_fs();
-
- String current_dir;
- bool _cisdir;
- bool _cishidden;
+ bool _cisdir = false;
+ bool _cishidden = false;
protected:
+ String current_dir;
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
- virtual String get_next();
- virtual bool current_is_dir() const;
- virtual bool current_is_hidden() const;
+ virtual Error list_dir_begin() override; ///< This starts dir listing
+ virtual String get_next() override;
+ virtual bool current_is_dir() const override;
+ virtual bool current_is_hidden() const override;
- virtual void list_dir_end(); ///<
+ virtual void list_dir_end() override; ///<
- virtual int get_drive_count();
- virtual String get_drive(int p_drive);
- virtual int get_current_drive();
- virtual bool drives_are_shortcuts();
+ virtual int get_drive_count() override;
+ virtual String get_drive(int p_drive) override;
+ virtual int get_current_drive() override;
+ virtual bool drives_are_shortcuts() override;
- virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
- virtual String get_current_dir(bool p_include_drive = true); ///< return current dir location
- virtual Error make_dir(String p_dir);
+ virtual Error change_dir(String p_dir) override; ///< can be relative or absolute, return false on success
+ virtual String get_current_dir(bool p_include_drive = true) const override; ///< return current dir location
+ virtual Error make_dir(String p_dir) override;
- virtual bool file_exists(String p_file);
- virtual bool dir_exists(String p_dir);
- virtual bool is_readable(String p_dir);
- virtual bool is_writable(String p_dir);
+ virtual bool file_exists(String p_file) override;
+ virtual bool dir_exists(String p_dir) override;
+ virtual bool is_readable(String p_dir) override;
+ virtual bool is_writable(String p_dir) override;
virtual uint64_t get_modified_time(String p_file);
- virtual Error rename(String p_path, String p_new_path);
- virtual Error remove(String p_path);
+ virtual Error rename(String p_path, String p_new_path) override;
+ virtual Error remove(String p_path) override;
- virtual bool is_link(String p_file);
- virtual String read_link(String p_file);
- virtual Error create_link(String p_source, String p_target);
+ virtual bool is_link(String p_file) override;
+ virtual String read_link(String p_file) override;
+ virtual Error create_link(String p_source, String p_target) override;
- virtual uint64_t get_space_left();
+ virtual uint64_t get_space_left() override;
- virtual String get_filesystem_type() const;
+ virtual String get_filesystem_type() const override;
DirAccessUnix();
~DirAccessUnix();
};
-#endif //UNIX ENABLED
-#endif
+#endif // UNIX_ENABLED || LIBC_FILEIO_ENABLED
+
+#endif // DIR_ACCESS_UNIX_H
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index 80ae999ac9..388ad479b9 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -71,10 +71,7 @@ void FileAccessUnix::check_errors() const {
}
Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) {
- if (f) {
- fclose(f);
- }
- f = nullptr;
+ _close();
path_src = p_path;
path = fix_path(p_path);
@@ -148,7 +145,7 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) {
return OK;
}
-void FileAccessUnix::close() {
+void FileAccessUnix::_close() {
if (!f) {
return;
}
@@ -246,7 +243,7 @@ uint64_t FileAccessUnix::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
uint64_t read = fread(p_dst, 1, p_length, f);
check_errors();
return read;
-};
+}
Error FileAccessUnix::get_error() const {
return last_error;
@@ -285,8 +282,9 @@ bool FileAccessUnix::file_exists(const String &p_path) {
return false;
}
#else
- if (_access(filename.utf8().get_data(), 4) == -1)
+ if (_access(filename.utf8().get_data(), 4) == -1) {
return false;
+ }
#endif
// See if this is a regular file
@@ -309,7 +307,7 @@ uint64_t FileAccessUnix::_get_modified_time(const String &p_file) {
} else {
print_verbose("Failed to get modified time for: " + p_file + "");
return 0;
- };
+ }
}
uint32_t FileAccessUnix::_get_unix_permissions(const String &p_file) {
@@ -321,7 +319,7 @@ uint32_t FileAccessUnix::_get_unix_permissions(const String &p_file) {
return flags.st_mode & 0x7FF; //only permissions
} else {
ERR_FAIL_V_MSG(0, "Failed to get unix permissions for: " + p_file + ".");
- };
+ }
}
Error FileAccessUnix::_set_unix_permissions(const String &p_file, uint32_t p_permissions) {
@@ -335,14 +333,10 @@ Error FileAccessUnix::_set_unix_permissions(const String &p_file, uint32_t p_per
return FAILED;
}
-FileAccess *FileAccessUnix::create_libc() {
- return memnew(FileAccessUnix);
-}
-
CloseNotificationFunc FileAccessUnix::close_notification_func = nullptr;
FileAccessUnix::~FileAccessUnix() {
- close();
+ _close();
}
-#endif
+#endif // UNIX_ENABLED || LIBC_FILEIO_ENABLED
diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h
index 8ebdcd2a2d..297c34e454 100644
--- a/drivers/unix/file_access_unix.h
+++ b/drivers/unix/file_access_unix.h
@@ -49,43 +49,43 @@ class FileAccessUnix : public FileAccess {
String path;
String path_src;
- static FileAccess *create_libc();
+ void _close();
public:
static CloseNotificationFunc close_notification_func;
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual void close(); ///< close a file
- virtual bool is_open() const; ///< true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
- virtual String get_path() const; /// returns the path for the current open file
- virtual String get_path_absolute() const; /// returns the absolute path for the current open file
+ virtual String get_path() const override; /// returns the path for the current open file
+ virtual String get_path_absolute() const override; /// returns the absolute path for the current open file
- virtual void seek(uint64_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual uint64_t get_position() const; ///< get position in the file
- virtual uint64_t get_length() const; ///< get size of the file
+ virtual void seek(uint64_t p_position) override; ///< seek to a given position
+ virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file
+ virtual uint64_t get_position() const override; ///< get position in the file
+ virtual uint64_t get_length() const override; ///< get size of the file
- virtual bool eof_reached() const; ///< reading passed EOF
+ virtual bool eof_reached() const override; ///< reading passed EOF
- virtual uint8_t get_8() const; ///< get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint8_t get_8() const override; ///< get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual Error get_error() const; ///< get last error
+ virtual Error get_error() const override; ///< get last error
- virtual void flush();
- virtual void store_8(uint8_t p_dest); ///< store a byte
- virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override; ///< store a byte
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
- virtual bool file_exists(const String &p_path); ///< return true if a file exists
+ virtual bool file_exists(const String &p_path) override; ///< return true if a file exists
- virtual uint64_t _get_modified_time(const String &p_file);
- virtual uint32_t _get_unix_permissions(const String &p_file);
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
+ virtual uint64_t _get_modified_time(const String &p_file) override;
+ virtual uint32_t _get_unix_permissions(const String &p_file) override;
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override;
FileAccessUnix() {}
virtual ~FileAccessUnix();
};
-#endif
-#endif
+#endif // UNIX_ENABLED || LIBC_FILEIO_ENABLED
+
+#endif // FILE_ACCESS_UNIX_H
diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp
index d82dcb8a8d..0dc2efedc1 100644
--- a/drivers/unix/ip_unix.cpp
+++ b/drivers/unix/ip_unix.cpp
@@ -72,10 +72,10 @@ static IPAddress _sockaddr2ip(struct sockaddr *p_addr) {
} else if (p_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
ip.set_ipv6(addr6->sin6_addr.s6_addr);
- };
+ }
return ip;
-};
+}
void IPUnix::_resolve_hostname(List<IPAddress> &r_addresses, const String &p_hostname, Type p_type) const {
struct addrinfo hints;
@@ -90,22 +90,22 @@ void IPUnix::_resolve_hostname(List<IPAddress> &r_addresses, const String &p_hos
} else {
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_ADDRCONFIG;
- };
+ }
hints.ai_flags &= ~AI_NUMERICHOST;
int s = getaddrinfo(p_hostname.utf8().get_data(), nullptr, &hints, &result);
if (s != 0) {
- ERR_PRINT("getaddrinfo failed! Cannot resolve hostname.");
+ print_verbose("getaddrinfo failed! Cannot resolve hostname.");
return;
- };
+ }
if (result == nullptr || result->ai_addr == nullptr) {
- ERR_PRINT("Invalid response from getaddrinfo");
+ print_verbose("Invalid response from getaddrinfo");
if (result) {
freeaddrinfo(result);
}
return;
- };
+ }
struct addrinfo *next = result;
@@ -128,7 +128,7 @@ void IPUnix::_resolve_hostname(List<IPAddress> &r_addresses, const String &p_hos
#if defined(UWP_ENABLED)
-void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
+void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const {
using namespace Windows::Networking;
using namespace Windows::Networking::Connectivity;
@@ -138,11 +138,12 @@ void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) con
for (int i = 0; i < hostnames->Size; i++) {
auto hostname = hostnames->GetAt(i);
- if (hostname->Type != HostNameType::Ipv4 && hostname->Type != HostNameType::Ipv6)
+ if (hostname->Type != HostNameType::Ipv4 && hostname->Type != HostNameType::Ipv6) {
continue;
+ }
String name = hostname->RawName->Data();
- Map<String, Interface_Info>::Element *E = r_interfaces->find(name);
+ HashMap<String, Interface_Info>::Element *E = r_interfaces->find(name);
if (!E) {
Interface_Info info;
info.name = name;
@@ -161,7 +162,7 @@ void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) con
#else
-void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
+void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const {
ULONG buf_size = 1024;
IP_ADAPTER_ADDRESSES *addrs;
@@ -171,14 +172,14 @@ void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) con
nullptr, addrs, &buf_size);
if (err == NO_ERROR) {
break;
- };
+ }
memfree(addrs);
if (err == ERROR_BUFFER_OVERFLOW) {
continue; // will go back and alloc the right size
- };
+ }
ERR_FAIL_MSG("Call to GetAdaptersAddresses failed with error " + itos(err) + ".");
- };
+ }
IP_ADAPTER_ADDRESSES *adapter = addrs;
@@ -191,25 +192,27 @@ void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) con
IP_ADAPTER_UNICAST_ADDRESS *address = adapter->FirstUnicastAddress;
while (address != nullptr) {
int family = address->Address.lpSockaddr->sa_family;
- if (family != AF_INET && family != AF_INET6)
+ if (family != AF_INET && family != AF_INET6) {
continue;
+ }
info.ip_addresses.push_front(_sockaddr2ip(address->Address.lpSockaddr));
address = address->Next;
}
adapter = adapter->Next;
// Only add interface if it has at least one IP
- if (info.ip_addresses.size() > 0)
+ if (info.ip_addresses.size() > 0) {
r_interfaces->insert(info.name, info);
- };
+ }
+ }
memfree(addrs);
-};
+}
#endif
#else // UNIX
-void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
+void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const {
struct ifaddrs *ifAddrStruct = nullptr;
struct ifaddrs *ifa = nullptr;
int family;
@@ -227,7 +230,7 @@ void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) con
continue;
}
- Map<String, Interface_Info>::Element *E = r_interfaces->find(ifa->ifa_name);
+ HashMap<String, Interface_Info>::Iterator E = r_interfaces->find(ifa->ifa_name);
if (!E) {
Interface_Info info;
info.name = ifa->ifa_name;
@@ -237,7 +240,7 @@ void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) con
ERR_CONTINUE(!E);
}
- Interface_Info &info = E->get();
+ Interface_Info &info = E->value;
info.ip_addresses.push_front(_sockaddr2ip(ifa->ifa_addr));
}
diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h
index f0ad01d248..798d02095c 100644
--- a/drivers/unix/ip_unix.h
+++ b/drivers/unix/ip_unix.h
@@ -43,11 +43,12 @@ class IPUnix : public IP {
static IP *_create_unix();
public:
- virtual void get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const override;
+ virtual void get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const override;
static void make_default();
IPUnix();
};
#endif
+
#endif // IP_UNIX_H
diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp
index bdfd264a0c..f172f31b24 100644
--- a/drivers/unix/net_socket_posix.cpp
+++ b/drivers/unix/net_socket_posix.cpp
@@ -147,7 +147,7 @@ void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_
if (r_port) {
*r_port = ntohs(addr6->sin6_port);
}
- };
+ }
}
NetSocket *NetSocketPosix::_create_func() {
@@ -256,7 +256,7 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IPAddress p_ip, Str
IPAddress if_ip;
uint32_t if_v6id = 0;
- Map<String, IP::Interface_Info> if_info;
+ HashMap<String, IP::Interface_Info> if_info;
IP::get_singleton()->get_local_interfaces(&if_info);
for (KeyValue<String, IP::Interface_Info> &E : if_info) {
IP::Interface_Info &c = E.value;
@@ -325,8 +325,9 @@ Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) {
#if defined(__OpenBSD__)
// OpenBSD does not support dual stacking, fallback to IPv4 only.
- if (ip_type == IP::TYPE_ANY)
+ if (ip_type == IP::TYPE_ANY) {
ip_type = IP::TYPE_IPV4;
+ }
#endif
int family = ip_type == IP::TYPE_IPV4 ? AF_INET : AF_INET6;
@@ -420,7 +421,7 @@ Error NetSocketPosix::listen(int p_max_pending) {
print_verbose("Failed to listen from socket.");
close();
return FAILED;
- };
+ }
return OK;
}
@@ -494,8 +495,9 @@ Error NetSocketPosix::poll(PollType p_type, int p_timeout) const {
return FAILED;
}
- if (ret == 0)
+ if (ret == 0) {
return ERR_BUSY;
+ }
if (FD_ISSET(_sock, &ex)) {
_get_socket_error();
@@ -503,10 +505,12 @@ Error NetSocketPosix::poll(PollType p_type, int p_timeout) const {
return FAILED;
}
- if (rdp && FD_ISSET(_sock, rdp))
+ if (rdp && FD_ISSET(_sock, rdp)) {
ready = true;
- if (wrp && FD_ISSET(_sock, wrp))
+ }
+ if (wrp && FD_ISSET(_sock, wrp)) {
ready = true;
+ }
return ready ? OK : ERR_BUSY;
#else
diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h
index 867513099a..5558114cb1 100644
--- a/drivers/unix/net_socket_posix.h
+++ b/drivers/unix/net_socket_posix.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef NET_SOCKET_UNIX_H
-#define NET_SOCKET_UNIX_H
+#ifndef NET_SOCKET_POSIX_H
+#define NET_SOCKET_POSIX_H
#include "core/io/net_socket.h"
@@ -104,4 +104,4 @@ public:
~NetSocketPosix();
};
-#endif
+#endif // NET_SOCKET_POSIX_H
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index 00f84eba8c..5bf14056ab 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -65,6 +65,21 @@
#include <time.h>
#include <unistd.h>
+#if defined(MACOS_ENABLED) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28)
+// Random location for getentropy. Fitting.
+#include <sys/random.h>
+#define UNIX_GET_ENTROPY
+#elif defined(__FreeBSD__) || defined(__OpenBSD__) || (defined(__GLIBC_MINOR__) && (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 26))
+// In <unistd.h>.
+// One day... (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 700)
+// https://publications.opengroup.org/standards/unix/c211
+#define UNIX_GET_ENTROPY
+#endif
+
+#if !defined(UNIX_GET_ENTROPY) && !defined(NO_URANDOM)
+#include <fcntl.h>
+#endif
+
/// Clock Setup function (used by get_ticks_usec)
static uint64_t _clock_start = 0;
#if defined(__APPLE__)
@@ -91,7 +106,7 @@ static void _setup_clock() {
void OS_Unix::debug_break() {
assert(false);
-};
+}
static void handle_interrupt(int sig) {
if (!EngineDebugger::is_active()) {
@@ -150,6 +165,31 @@ String OS_Unix::get_stdin_string(bool p_block) {
return "";
}
+Error OS_Unix::get_entropy(uint8_t *r_buffer, int p_bytes) {
+#if defined(UNIX_GET_ENTROPY)
+ int left = p_bytes;
+ int ofs = 0;
+ do {
+ int chunk = MIN(left, 256);
+ ERR_FAIL_COND_V(getentropy(r_buffer + ofs, chunk), FAILED);
+ left -= chunk;
+ ofs += chunk;
+ } while (left > 0);
+#elif !defined(NO_URANDOM)
+ int r = open("/dev/urandom", O_RDONLY);
+ ERR_FAIL_COND_V(r < 0, FAILED);
+ int left = p_bytes;
+ do {
+ ssize_t ret = read(r, r_buffer, p_bytes);
+ ERR_FAIL_COND_V(ret <= 0, FAILED);
+ left -= ret;
+ } while (left > 0);
+#else
+ return ERR_UNAVAILABLE;
+#endif
+ return OK;
+}
+
String OS_Unix::get_name() const {
return "Unix";
}
@@ -158,7 +198,7 @@ double OS_Unix::get_unix_time() const {
struct timeval tv_now;
gettimeofday(&tv_now, nullptr);
return (double)tv_now.tv_sec + double(tv_now.tv_usec) / 1000000;
-};
+}
OS::Date OS_Unix::get_date(bool p_utc) const {
time_t t = time(nullptr);
@@ -273,7 +313,12 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, St
if (p_pipe_mutex) {
p_pipe_mutex->lock();
}
- (*r_pipe) += String::utf8(buf);
+ String pipe_out;
+ if (pipe_out.parse_utf8(buf) == OK) {
+ (*r_pipe) += pipe_out;
+ } else {
+ (*r_pipe) += String(buf); // If not valid UTF-8 try decode as Latin-1
+ }
if (p_pipe_mutex) {
p_pipe_mutex->unlock();
}
@@ -370,7 +415,16 @@ Error OS_Unix::kill(const ProcessID &p_pid) {
int OS_Unix::get_process_id() const {
return getpid();
-};
+}
+
+bool OS_Unix::is_process_running(const ProcessID &p_pid) const {
+ int status = 0;
+ if (waitpid(p_pid, &status, WNOHANG) != 0) {
+ return false;
+ }
+
+ return true;
+}
bool OS_Unix::has_environment(const String &p_var) const {
return getenv(p_var.utf8().get_data()) != nullptr;
@@ -389,7 +443,7 @@ String OS_Unix::get_locale() const {
return locale;
}
-Error OS_Unix::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
+Error OS_Unix::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
String path = p_path;
if (FileAccess::exists(path) && path.is_relative_path()) {
@@ -399,17 +453,22 @@ Error OS_Unix::open_dynamic_library(const String p_path, void *&p_library_handle
}
if (!FileAccess::exists(path)) {
- //this code exists so gdnative can load .so files from within the executable path
+ // This code exists so GDExtension can load .so files from within the executable path.
path = get_executable_path().get_base_dir().plus_file(p_path.get_file());
}
if (!FileAccess::exists(path)) {
- //this code exists so gdnative can load .so files from a standard unix location
+ // This code exists so GDExtension can load .so files from a standard unix location.
path = get_executable_path().get_base_dir().plus_file("../lib").plus_file(p_path.get_file());
}
p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ". Error: " + dlerror());
+
+ if (r_resolved_path != nullptr) {
+ *r_resolved_path = path;
+ }
+
return OK;
}
@@ -515,8 +574,9 @@ String OS_Unix::get_executable_path() const {
char *resolved_path = new char[buff_size + 1];
- if (_NSGetExecutablePath(resolved_path, &buff_size) == 1)
+ if (_NSGetExecutablePath(resolved_path, &buff_size) == 1) {
WARN_PRINT("MAXPATHLEN is too small");
+ }
String path(resolved_path);
delete[] resolved_path;
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index 3f0e8a171c..f4609a565b 100644
--- a/drivers/unix/os_unix.h
+++ b/drivers/unix/os_unix.h
@@ -43,7 +43,6 @@ protected:
virtual void initialize_core();
virtual int unix_initialize_audio(int p_audio_driver);
- //virtual Error initialize(int p_video_driver,int p_audio_driver);
virtual void finalize_core() override;
@@ -54,17 +53,9 @@ public:
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);
- //virtual bool is_mouse_grab_enabled() const = 0;
- //virtual void get_mouse_position(int &x, int &y) const;
- //virtual void set_window_title(const String& p_title);
+ virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) override; // Should return cryptographycally-safe random bytes.
- //virtual void set_video_mode(const VideoMode& p_video_mode);
- //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) override;
+ virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) 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;
@@ -85,6 +76,7 @@ public:
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override;
virtual Error kill(const ProcessID &p_pid) override;
virtual int get_process_id() const override;
+ virtual bool is_process_running(const ProcessID &p_pid) const override;
virtual bool has_environment(const String &p_var) const override;
virtual String get_environment(const String &p_var) const override;
@@ -106,6 +98,6 @@ public:
virtual ~UnixTerminalLogger();
};
-#endif
+#endif // UNIX_ENABLED
-#endif
+#endif // OS_UNIX_H
diff --git a/drivers/unix/syslog_logger.cpp b/drivers/unix/syslog_logger.cpp
index 0e1a1a89a3..6189d645c6 100644
--- a/drivers/unix/syslog_logger.cpp
+++ b/drivers/unix/syslog_logger.cpp
@@ -31,7 +31,9 @@
#ifdef UNIX_ENABLED
#include "syslog_logger.h"
+
#include "core/string/print_string.h"
+
#include <syslog.h>
void SyslogLogger::logv(const char *p_format, va_list p_list, bool p_err) {
diff --git a/drivers/unix/syslog_logger.h b/drivers/unix/syslog_logger.h
index 697a96a6f9..cc6617eb25 100644
--- a/drivers/unix/syslog_logger.h
+++ b/drivers/unix/syslog_logger.h
@@ -43,6 +43,6 @@ public:
virtual ~SyslogLogger();
};
-#endif
+#endif // UNIX_ENABLED
-#endif
+#endif // SYSLOG_LOGGER_H
diff --git a/drivers/unix/thread_posix.h b/drivers/unix/thread_posix.h
index 9cd3ecbe90..672adcba72 100644
--- a/drivers/unix/thread_posix.h
+++ b/drivers/unix/thread_posix.h
@@ -35,4 +35,4 @@
void init_thread_posix();
#endif
-#endif
+#endif // THREAD_POSIX_H
diff --git a/drivers/vulkan/SCsub b/drivers/vulkan/SCsub
index 8fe75367a8..a076c0ac54 100644
--- a/drivers/vulkan/SCsub
+++ b/drivers/vulkan/SCsub
@@ -15,11 +15,11 @@ if env["use_volk"]:
if env["platform"] == "android":
env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_ANDROID_KHR"])
-elif env["platform"] == "iphone":
+elif env["platform"] == "ios":
env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_IOS_MVK"])
-elif env["platform"] == "linuxbsd":
+elif env["platform"] == "linuxbsd" and env["x11"]:
env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_XLIB_KHR"])
-elif env["platform"] == "osx":
+elif env["platform"] == "macos":
env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_MACOS_MVK"])
elif env["platform"] == "windows":
env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_WIN32_KHR"])
@@ -40,6 +40,9 @@ elif env["platform"] == "android":
# Our current NDK version only provides old Vulkan headers,
# so we have to limit VMA.
env_thirdparty_vma.AppendUnique(CPPDEFINES=["VMA_VULKAN_VERSION=1000000"])
+elif env["platform"] == "macos" or env["platform"] == "ios":
+ # MoltenVK supports only Vulkan 1.1 API, limit VMA to the same version.
+ env_thirdparty_vma.AppendUnique(CPPDEFINES=["VMA_VULKAN_VERSION=1001000"])
env_thirdparty_vma.add_source_files(thirdparty_obj, thirdparty_sources_vma)
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index ba623eb298..bcb6092d87 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -36,6 +36,7 @@
#include "core/io/marshalls.h"
#include "core/os/os.h"
#include "core/templates/hashfuncs.h"
+#include "core/version.h"
#include "drivers/vulkan/vulkan_context.h"
#include "thirdparty/misc/smolv.h"
@@ -43,7 +44,9 @@
//#define FORCE_FULL_BARRIER
-// Get the Vulkan object information and possible stage access types (bitwise OR'd with incoming values)
+static const uint32_t SMALL_ALLOCATION_MAX_SIZE = 4096;
+
+// 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 &r_stage_mask, VkAccessFlags &r_access_mask, uint32_t p_post_barrier) {
Buffer *buffer = nullptr;
if (vertex_buffer_owner.owns(p_buffer)) {
@@ -104,9 +107,9 @@ RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID
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
+static void update_external_dependency_for_store(VkSubpassDependency2KHR &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;
@@ -122,7 +125,7 @@ static void update_external_dependency_for_store(VkSubpassDependency &dependency
}
if (is_depth) {
- // Depth resources have additional stages that may be interested in them
+ // Depth resources have additional 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;
}
@@ -130,41 +133,41 @@ static void update_external_dependency_for_store(VkSubpassDependency &dependency
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>();
+ dependency_map[p_depends_on] = HashSet<RID>();
}
dependency_map[p_depends_on].insert(p_id);
if (!reverse_dependency_map.has(p_id)) {
- reverse_dependency_map[p_id] = Set<RID>();
+ reverse_dependency_map[p_id] = HashSet<RID>();
}
reverse_dependency_map[p_id].insert(p_depends_on);
}
void RenderingDeviceVulkan::_free_dependencies(RID p_id) {
- //direct dependencies must be freed
+ // Direct dependencies must be freed.
- Map<RID, Set<RID>>::Element *E = dependency_map.find(p_id);
+ HashMap<RID, HashSet<RID>>::Iterator E = dependency_map.find(p_id);
if (E) {
- while (E->get().size()) {
- free(E->get().front()->get());
+ while (E->value.size()) {
+ free(*E->value.begin());
}
- dependency_map.erase(E);
+ dependency_map.remove(E);
}
- //reverse dependencies 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());
+ for (const RID &F : E->value) {
+ HashMap<RID, HashSet<RID>>::Iterator G = dependency_map.find(F);
ERR_CONTINUE(!G);
- ERR_CONTINUE(!G->get().has(p_id));
- G->get().erase(p_id);
+ ERR_CONTINUE(!G->value.has(p_id));
+ G->value.erase(p_id);
}
- reverse_dependency_map.erase(E);
+ reverse_dependency_map.remove(E);
}
}
@@ -857,7 +860,7 @@ uint32_t RenderingDeviceVulkan::get_image_format_pixel_size(DataFormat p_format)
case DATA_FORMAT_D24_UNORM_S8_UINT:
return 4;
case DATA_FORMAT_D32_SFLOAT_S8_UINT:
- return 5; //?
+ return 5; // ?
case DATA_FORMAT_BC1_RGB_UNORM_BLOCK:
case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:
case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK:
@@ -992,7 +995,7 @@ void RenderingDeviceVulkan::get_compressed_image_format_block_dimensions(DataFor
case DATA_FORMAT_EAC_R11_SNORM_BLOCK:
case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK:
case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK:
- case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: //again, not sure about astc
+ 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:
case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK:
@@ -1070,7 +1073,7 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_block_byte_size(Data
case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK:
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_UNORM_BLOCK: // Again, not sure about astc.
case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK:
case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK:
case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK:
@@ -1098,7 +1101,7 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_block_byte_size(Data
case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK:
case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK:
case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK:
- return 8; //wrong
+ return 8; // Wrong.
default: {
}
}
@@ -1107,7 +1110,7 @@ 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_UNORM_BLOCK: // These formats are half byte size, so rshift is 1.
case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:
case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK:
case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK:
@@ -1174,31 +1177,31 @@ uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_form
}
w = MAX(blockw, w >> 1);
h = MAX(blockh, h >> 1);
- d = MAX(1, d >> 1);
+ d = MAX(1u, d >> 1);
}
return size;
}
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;
- int d = p_depth;
+ // Formats and block size don't really matter here since they can all go down to 1px (even if block is larger).
+ uint32_t w = p_width;
+ uint32_t h = p_height;
+ uint32_t d = p_depth;
- int mipmaps = 1;
+ uint32_t mipmaps = 1;
while (true) {
if (w == 1 && h == 1 && d == 1) {
break;
}
- w = MAX(1, w >> 1);
- h = MAX(1, h >> 1);
- d = MAX(1, d >> 1);
+ w = MAX(1u, w >> 1);
+ h = MAX(1u, h >> 1);
+ d = MAX(1u, d >> 1);
mipmaps++;
- };
+ }
return mipmaps;
}
@@ -1316,7 +1319,7 @@ const VkImageType RenderingDeviceVulkan::vulkan_image_type[RenderingDevice::TEXT
/**** BUFFER MANAGEMENT ****/
/***************************/
-Error RenderingDeviceVulkan::_buffer_allocate(Buffer *p_buffer, uint32_t p_size, uint32_t p_usage, VmaMemoryUsage p_mapping) {
+Error RenderingDeviceVulkan::_buffer_allocate(Buffer *p_buffer, uint32_t p_size, uint32_t p_usage, VmaMemoryUsage p_mem_usage, VmaAllocationCreateFlags p_mem_flags) {
VkBufferCreateInfo bufferInfo;
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.pNext = nullptr;
@@ -1328,13 +1331,18 @@ Error RenderingDeviceVulkan::_buffer_allocate(Buffer *p_buffer, uint32_t p_size,
bufferInfo.pQueueFamilyIndices = nullptr;
VmaAllocationCreateInfo allocInfo;
- allocInfo.flags = 0;
- allocInfo.usage = p_mapping;
+ allocInfo.flags = p_mem_flags;
+ allocInfo.usage = p_mem_usage;
allocInfo.requiredFlags = 0;
allocInfo.preferredFlags = 0;
allocInfo.memoryTypeBits = 0;
allocInfo.pool = nullptr;
allocInfo.pUserData = nullptr;
+ if (p_size <= SMALL_ALLOCATION_MAX_SIZE) {
+ uint32_t mem_type_index = 0;
+ vmaFindMemoryTypeIndexForBufferInfo(allocator, &bufferInfo, &allocInfo, &mem_type_index);
+ allocInfo.pool = _find_or_create_small_allocs_pool(mem_type_index);
+ }
VkResult err = vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &p_buffer->buffer, &p_buffer->allocation, nullptr);
ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Can't create buffer of size: " + itos(p_size) + ", error " + itos(err) + ".");
@@ -1373,8 +1381,8 @@ Error RenderingDeviceVulkan::_insert_staging_block() {
bufferInfo.pQueueFamilyIndices = nullptr;
VmaAllocationCreateInfo allocInfo;
- allocInfo.flags = 0;
- allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
+ allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
+ allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
allocInfo.requiredFlags = 0;
allocInfo.preferredFlags = 0;
allocInfo.memoryTypeBits = 0;
@@ -1393,17 +1401,17 @@ Error RenderingDeviceVulkan::_insert_staging_block() {
return OK;
}
-Error RenderingDeviceVulkan::_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, bool p_on_draw_command_buffer) {
- //determine a block to use
+Error RenderingDeviceVulkan::_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) {
+ // Determine a block to use.
r_alloc_size = p_amount;
while (true) {
r_alloc_offset = 0;
- //see if we can use current block
+ // See if we can use current block.
if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) {
- //we used this block this frame, let's see if there is still room
+ // We used this block this frame, let's see if there is still room.
uint32_t write_from = staging_buffer_blocks[staging_buffer_current].fill_amount;
@@ -1417,107 +1425,107 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_
int32_t available_bytes = int32_t(staging_buffer_block_size) - int32_t(write_from);
if ((int32_t)p_amount < available_bytes) {
- //all is good, we should be ok, all will fit
+ // All is good, we should be ok, all will fit.
r_alloc_offset = write_from;
} else if (p_can_segment && available_bytes >= (int32_t)p_required_align) {
- //ok all won't fit but at least we can fit a chunkie
- //all is good, update what needs to be written to
+ // Ok all won't fit but at least we can fit a chunkie.
+ // All is good, update what needs to be written to.
r_alloc_offset = write_from;
r_alloc_size = available_bytes - (available_bytes % p_required_align);
} else {
- //can't fit it into this buffer.
- //will need to try next buffer
+ // Can't fit it into this buffer.
+ // Will need to try next buffer.
staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size();
- // before doing anything, though, let's check that we didn't manage to fill all blocks
- // possible in a single frame
+ // Before doing anything, though, let's check that we didn't manage to fill all blocks.
+ // Possible in a single frame.
if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) {
- //guess we did.. ok, let's see if we can insert a new block..
+ // Guess we did.. ok, let's see if we can insert a new block.
if ((uint64_t)staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
- //we can, so we are safe
+ // We can, so we are safe.
Error err = _insert_staging_block();
if (err) {
return err;
}
- //claim for this frame
+ // Claim for this frame.
staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
} else {
// Ok, worst case scenario, all the staging buffers belong to this frame
// and this frame is not even done.
- // If this is the main thread, it means the user is likely loading a lot of resources at once,
- // otherwise, the thread should just be blocked until the next frame (currently unimplemented)
+ // If this is the main thread, it means the user is likely loading a lot of resources at once,.
+ // Otherwise, the thread should just be blocked until the next frame (currently unimplemented).
- if (false) { //separate thread from render
+ if (false) { // Separate thread from render.
//block_until_next_frame()
continue;
} else {
- //flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands
+ // Flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands.
_flush(true);
- //clear the whole staging buffer
+ // Clear the whole staging buffer.
for (int i = 0; i < staging_buffer_blocks.size(); i++) {
staging_buffer_blocks.write[i].frame_used = 0;
staging_buffer_blocks.write[i].fill_amount = 0;
}
- //claim current
+ // Claim current.
staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
}
}
} else {
- //not from current frame, so continue and try again
+ // Not from current frame, so continue and try again.
continue;
}
}
} else if (staging_buffer_blocks[staging_buffer_current].frame_used <= frames_drawn - frame_count) {
- //this is an old block, which was already processed, let's reuse
+ // This is an old block, which was already processed, let's reuse.
staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
staging_buffer_blocks.write[staging_buffer_current].fill_amount = 0;
- } else if (staging_buffer_blocks[staging_buffer_current].frame_used > frames_drawn - frame_count) {
- //this block may still be in use, let's not touch it unless we have to, so.. can we create a new one?
+ } else {
+ // This block may still be in use, let's not touch it unless we have to, so.. can we create a new one?
if ((uint64_t)staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
- //we are still allowed to create a new block, so let's do that and insert it for current pos
+ // We are still allowed to create a new block, so let's do that and insert it for current pos.
Error err = _insert_staging_block();
if (err) {
return err;
}
- //claim for this frame
+ // Claim for this frame.
staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
} else {
- // oops, we are out of room and we can't create more.
- // let's flush older frames.
+ // Oops, we are out of room and we can't create more.
+ // Let's flush older frames.
// The logic here is that if a game is loading a lot of data from the main thread, it will need to be stalled anyway.
// If loading from a separate thread, we can block that thread until next frame when more room is made (not currently implemented, though).
if (false) {
- //separate thread from render
+ // Separate thread from render.
//block_until_next_frame()
- continue; //and try again
+ continue; // And try again.
} else {
_flush(false);
for (int i = 0; i < staging_buffer_blocks.size(); i++) {
- //clear all blocks but the ones from this frame
+ // Clear all blocks but the ones from this frame.
int block_idx = (i + staging_buffer_current) % staging_buffer_blocks.size();
if (staging_buffer_blocks[block_idx].frame_used == frames_drawn) {
- break; //ok, we reached something from this frame, abort
+ break; // Ok, we reached something from this frame, abort.
}
staging_buffer_blocks.write[block_idx].frame_used = 0;
staging_buffer_blocks.write[block_idx].fill_amount = 0;
}
- //claim for current frame
+ // Claim for current frame.
staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
}
}
}
- //all was good, break
+ // All was good, break.
break;
}
@@ -1527,7 +1535,7 @@ 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
+ // 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;
@@ -1535,12 +1543,12 @@ Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, c
uint32_t block_write_offset;
uint32_t block_write_amount;
- Error err = _staging_buffer_allocate(MIN(to_submit, staging_buffer_block_size), p_required_align, block_write_offset, block_write_amount, p_use_draw_command_buffer);
+ Error err = _staging_buffer_allocate(MIN(to_submit, staging_buffer_block_size), p_required_align, block_write_offset, block_write_amount);
if (err) {
return err;
}
- //map staging buffer (It's CPU and coherent)
+ // Map staging buffer (It's CPU and coherent).
void *data_ptr = nullptr;
{
@@ -1548,12 +1556,12 @@ Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, c
ERR_FAIL_COND_V_MSG(vkerr, ERR_CANT_CREATE, "vmaMapMemory failed with error " + itos(vkerr) + ".");
}
- //copy to staging buffer
+ // Copy to staging buffer.
memcpy(((uint8_t *)data_ptr) + block_write_offset, p_data + submit_from, block_write_amount);
- //unmap
+ // Unmap.
vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation);
- //insert a command to copy this
+ // Insert a command to copy this.
VkBufferCopy region;
region.srcOffset = block_write_offset;
@@ -1579,13 +1587,13 @@ void RenderingDeviceVulkan::_memory_barrier(VkPipelineStageFlags p_src_stage_mas
mem_barrier.dstAccessMask = p_dst_sccess;
if (p_src_stage_mask == 0 || p_dst_stage_mask == 0) {
- return; //no barrier, since this is invalid
+ return; // No barrier, since this is invalid.
}
vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 1, &mem_barrier, 0, nullptr, 0, nullptr);
}
void RenderingDeviceVulkan::_full_barrier(bool p_sync_with_draw) {
- //used for debug
+ // Used for debug.
_memory_barrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_ACCESS_INDIRECT_COMMAND_READ_BIT |
VK_ACCESS_INDEX_READ_BIT |
@@ -1654,8 +1662,8 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
#ifndef ANDROID_ENABLED
// vkCreateImage fails with format list on Android (VK_ERROR_OUT_OF_HOST_MEMORY)
- VkImageFormatListCreateInfoKHR format_list_create_info; //keep out of the if, needed for creation
- Vector<VkFormat> allowed_formats; //keep out of the if, needed for creation
+ VkImageFormatListCreateInfoKHR format_list_create_info; // Keep out of the if, needed for creation.
+ Vector<VkFormat> allowed_formats; // Keep out of the if, needed for creation.
#endif
if (p_format.shareable_formats.size()) {
image_create_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
@@ -1728,7 +1736,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
image_create_info.samples = rasterization_sample_count[p_format.samples];
image_create_info.tiling = (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
- //usage
+ // Usage.
image_create_info.usage = 0;
if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) {
@@ -1751,6 +1759,10 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
image_create_info.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
}
+ if (p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {
+ image_create_info.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
+ }
+
if (p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT) {
image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
@@ -1788,7 +1800,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
}
{
- //validate that this image is supported for the intended use
+ // Validate that this image is supported for the intended use.
VkFormatProperties properties;
vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), image_create_info.format, &properties);
VkFormatFeatureFlags flags;
@@ -1822,9 +1834,14 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_ATOMIC_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)) {
ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as atomic storage image.");
}
+
+ // Validation via VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR fails if VRS attachment is not supported.
+ if (p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT && p_format.format != DATA_FORMAT_R8_UINT) {
+ ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as VRS attachment.");
+ }
}
- //some view validation
+ // Some view validation.
if (p_view.format_override != DATA_FORMAT_MAX) {
ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());
@@ -1834,16 +1851,24 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
ERR_FAIL_INDEX_V(p_view.swizzle_b, TEXTURE_SWIZZLE_MAX, RID());
ERR_FAIL_INDEX_V(p_view.swizzle_a, TEXTURE_SWIZZLE_MAX, RID());
- //allocate memory
+ // Allocate memory.
+
+ uint32_t width, height;
+ uint32_t image_size = get_image_format_required_size(p_format.format, p_format.width, p_format.height, p_format.depth, p_format.mipmaps, &width, &height);
VmaAllocationCreateInfo allocInfo;
- allocInfo.flags = 0;
- allocInfo.usage = p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT ? VMA_MEMORY_USAGE_CPU_ONLY : VMA_MEMORY_USAGE_GPU_ONLY;
+ allocInfo.flags = (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) ? VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT : 0;
+ allocInfo.pool = nullptr;
+ allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
allocInfo.requiredFlags = 0;
allocInfo.preferredFlags = 0;
allocInfo.memoryTypeBits = 0;
- allocInfo.pool = nullptr;
allocInfo.pUserData = nullptr;
+ if (image_size <= SMALL_ALLOCATION_MAX_SIZE) {
+ uint32_t mem_type_index = 0;
+ vmaFindMemoryTypeIndexForImageInfo(allocator, &image_create_info, &allocInfo, &mem_type_index);
+ allocInfo.pool = _find_or_create_small_allocs_pool(mem_type_index);
+ }
Texture texture;
@@ -1863,19 +1888,19 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
texture.samples = p_format.samples;
texture.allowed_shared_formats = p_format.shareable_formats;
- //set base layout based on usage priority
+ // Set base layout based on usage priority.
if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) {
- //first priority, readable
+ // First priority, readable.
texture.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
} else if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT) {
- //second priority, storage
+ // Second priority, storage.
texture.layout = VK_IMAGE_LAYOUT_GENERAL;
} else if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
- //third priority, color or depth
+ // Third priority, color or depth.
texture.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
@@ -1900,7 +1925,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
texture.bound = false;
- //create view
+ // Create view.
VkImageViewCreateInfo image_view_create_info;
image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
@@ -1957,7 +1982,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
ERR_FAIL_V_MSG(RID(), "vkCreateImageView failed with error " + itos(err) + ".");
}
- //barrier to set layout
+ // Barrier to set layout.
{
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
@@ -1979,6 +2004,9 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
}
RID id = texture_owner.make_rid(texture);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
if (p_data.size()) {
for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) {
@@ -1994,13 +2022,13 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID
Texture *src_texture = texture_owner.get_or_null(p_with_texture);
ERR_FAIL_COND_V(!src_texture, RID());
- if (src_texture->owner.is_valid()) { //ahh this is a share
+ if (src_texture->owner.is_valid()) { // Ahh this is a share.
p_with_texture = src_texture->owner;
src_texture = texture_owner.get_or_null(src_texture->owner);
- ERR_FAIL_COND_V(!src_texture, RID()); //this is a bug
+ ERR_FAIL_COND_V(!src_texture, RID()); // This is a bug.
}
- //create view
+ // Create view.
Texture texture = *src_texture;
@@ -2061,7 +2089,7 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID
usage_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
usage_info.pNext = nullptr;
if (p_view.format_override != DATA_FORMAT_MAX) {
- //need to validate usage with vulkan
+ // Need to validate usage with vulkan.
usage_info.usage = 0;
@@ -2108,21 +2136,145 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID
texture.owner = p_with_texture;
RID id = texture_owner.make_rid(texture);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
_add_dependency(id, p_with_texture);
return id;
}
+RID RenderingDeviceVulkan::texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, uint64_t p_flags, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers) {
+ _THREAD_SAFE_METHOD_
+ // This method creates a texture object using a VkImage created by an extension, module or other external source (OpenXR uses this).
+ VkImage image = (VkImage)p_image;
+
+ Texture texture;
+ texture.image = image;
+ // If we leave texture.allocation as a nullptr, would that be enough to detect we don't "own" the image?
+ // Also leave texture.allocation_info alone.
+ // We'll set texture.view later on.
+ texture.type = p_type;
+ texture.format = p_format;
+ texture.samples = p_samples;
+ texture.width = p_width;
+ texture.height = p_height;
+ texture.depth = p_depth;
+ texture.layers = p_layers;
+ texture.mipmaps = 0; // Maybe make this settable too?
+ texture.usage_flags = p_flags;
+ texture.base_mipmap = 0;
+ texture.base_layer = 0;
+ texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM);
+ texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB);
+
+ // Do we need to do something with texture.layout?
+
+ if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
+ texture.read_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT;
+ texture.barrier_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT;
+
+ // if (format_has_stencil(p_format.format)) {
+ // texture.barrier_aspect_mask |= VK_IMAGE_ASPECT_STENCIL_BIT;
+ // }
+ } else {
+ texture.read_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT;
+ texture.barrier_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT;
+ }
+
+ // Create a view for us to use.
+
+ VkImageViewCreateInfo image_view_create_info;
+ image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ image_view_create_info.pNext = nullptr;
+ image_view_create_info.flags = 0;
+ image_view_create_info.image = texture.image;
+
+ static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = {
+ VK_IMAGE_VIEW_TYPE_1D,
+ VK_IMAGE_VIEW_TYPE_2D,
+ VK_IMAGE_VIEW_TYPE_3D,
+ VK_IMAGE_VIEW_TYPE_CUBE,
+ VK_IMAGE_VIEW_TYPE_1D_ARRAY,
+ VK_IMAGE_VIEW_TYPE_2D_ARRAY,
+ VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,
+ };
+
+ image_view_create_info.viewType = view_types[texture.type];
+ image_view_create_info.format = vulkan_formats[texture.format];
+
+ static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = {
+ VK_COMPONENT_SWIZZLE_IDENTITY,
+ VK_COMPONENT_SWIZZLE_ZERO,
+ VK_COMPONENT_SWIZZLE_ONE,
+ VK_COMPONENT_SWIZZLE_R,
+ VK_COMPONENT_SWIZZLE_G,
+ VK_COMPONENT_SWIZZLE_B,
+ VK_COMPONENT_SWIZZLE_A
+ };
+
+ // Hardcode for now, maybe make this settable from outside.
+ image_view_create_info.components.r = component_swizzles[TEXTURE_SWIZZLE_R];
+ image_view_create_info.components.g = component_swizzles[TEXTURE_SWIZZLE_G];
+ image_view_create_info.components.b = component_swizzles[TEXTURE_SWIZZLE_B];
+ image_view_create_info.components.a = component_swizzles[TEXTURE_SWIZZLE_A];
+
+ image_view_create_info.subresourceRange.baseMipLevel = 0;
+ image_view_create_info.subresourceRange.levelCount = texture.mipmaps;
+ image_view_create_info.subresourceRange.baseArrayLayer = 0;
+ image_view_create_info.subresourceRange.layerCount = texture.layers;
+ if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
+ image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
+ } else {
+ image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ }
+
+ VkResult err = vkCreateImageView(device, &image_view_create_info, nullptr, &texture.view);
+
+ if (err) {
+ // vmaDestroyImage(allocator, texture.image, texture.allocation);
+ ERR_FAIL_V_MSG(RID(), "vkCreateImageView failed with error " + itos(err) + ".");
+ }
+
+ // Barrier to set layout.
+ {
+ 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.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ image_memory_barrier.newLayout = texture.layout;
+ 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.barrier_aspect_mask;
+ image_memory_barrier.subresourceRange.baseMipLevel = 0;
+ image_memory_barrier.subresourceRange.levelCount = texture.mipmaps;
+ image_memory_barrier.subresourceRange.baseArrayLayer = 0;
+ image_memory_barrier.subresourceRange.layerCount = texture.layers;
+
+ 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);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+
+ return id;
+}
+
RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps, TextureSliceType p_slice_type) {
_THREAD_SAFE_METHOD_
Texture *src_texture = texture_owner.get_or_null(p_with_texture);
ERR_FAIL_COND_V(!src_texture, RID());
- if (src_texture->owner.is_valid()) { //ahh this is a share
+ if (src_texture->owner.is_valid()) { // Ahh this is a share.
p_with_texture = src_texture->owner;
src_texture = texture_owner.get_or_null(src_texture->owner);
- ERR_FAIL_COND_V(!src_texture, RID()); //this is a bug
+ ERR_FAIL_COND_V(!src_texture, RID()); // This is a bug.
}
ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_CUBEMAP && (src_texture->type != TEXTURE_TYPE_CUBE && src_texture->type != TEXTURE_TYPE_CUBE_ARRAY), RID(),
@@ -2134,7 +2286,7 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p
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
+ // Create view.
ERR_FAIL_UNSIGNED_INDEX_V(p_mipmap, src_texture->mipmaps, RID());
ERR_FAIL_COND_V(p_mipmap + p_mipmaps > src_texture->mipmaps, RID());
@@ -2181,6 +2333,12 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p
image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
}
+ if (p_slice_type == TEXTURE_SLICE_2D) {
+ texture.type = TEXTURE_TYPE_2D;
+ } else if (p_slice_type == TEXTURE_SLICE_3D) {
+ texture.type = TEXTURE_TYPE_3D;
+ }
+
if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) {
image_view_create_info.format = vulkan_formats[texture.format];
} else {
@@ -2228,6 +2386,9 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p
texture.owner = p_with_texture;
RID id = texture_owner.make_rid(texture);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
_add_dependency(id, p_with_texture);
return id;
@@ -2237,6 +2398,22 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con
return _texture_update(p_texture, p_layer, p_data, p_post_barrier, false);
}
+static _ALWAYS_INLINE_ void _copy_region(uint8_t const *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_x, uint32_t p_src_y, uint32_t p_src_w, uint32_t p_src_h, uint32_t p_src_full_w, uint32_t p_unit_size) {
+ uint32_t src_offset = (p_src_y * p_src_full_w + p_src_x) * p_unit_size;
+ uint32_t dst_offset = 0;
+ for (uint32_t y = p_src_h; y > 0; y--) {
+ uint8_t const *__restrict src = p_src + src_offset;
+ uint8_t *__restrict dst = p_dst + dst_offset;
+ for (uint32_t x = p_src_w * p_unit_size; x > 0; x--) {
+ *dst = *src;
+ src++;
+ dst++;
+ }
+ src_offset += p_src_full_w * p_unit_size;
+ dst_offset += p_src_w * p_unit_size;
+ }
+}
+
Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier, bool p_use_setup_queue) {
_THREAD_SAFE_METHOD_
@@ -2249,7 +2426,7 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
if (texture->owner != RID()) {
p_texture = texture->owner;
texture = texture_owner.get_or_null(texture->owner);
- ERR_FAIL_COND_V(!texture, ERR_BUG); //this is a bug
+ ERR_FAIL_COND_V(!texture, ERR_BUG); // This is a bug.
}
ERR_FAIL_COND_V_MSG(texture->bound, ERR_CANT_ACQUIRE_RESOURCE,
@@ -2271,7 +2448,7 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
if (required_align == 1) {
required_align = get_image_format_pixel_size(texture->format);
}
- if ((required_align % 4) != 0) { //alignment rules are really strange
+ if ((required_align % 4) != 0) { // Alignment rules are really strange.
required_align *= 4;
}
@@ -2284,7 +2461,7 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
VkCommandBuffer command_buffer = p_use_setup_queue ? frames[frame].setup_command_buffer : frames[frame].draw_command_buffer;
- //barrier to transfer
+ // Barrier to transfer.
{
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
@@ -2318,12 +2495,12 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
const uint8_t *read_ptr_mipmap = r + mipmap_offset;
image_size = image_total - mipmap_offset;
- for (uint32_t z = 0; z < depth; z++) { //for 3D textures, depth may be > 0
+ for (uint32_t z = 0; z < depth; z++) { // For 3D textures, depth may be > 0.
const uint8_t *read_ptr = read_ptr_mipmap + image_size * z / depth;
- for (uint32_t x = 0; x < width; x += region_size) {
- for (uint32_t y = 0; y < height; y += region_size) {
+ for (uint32_t y = 0; y < height; y += region_size) {
+ for (uint32_t x = 0; x < width; x += region_size) {
uint32_t region_w = MIN(region_size, width - x);
uint32_t region_h = MIN(region_size, height - y);
@@ -2335,12 +2512,12 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
to_allocate >>= get_compressed_image_format_pixel_rshift(texture->format);
uint32_t alloc_offset, alloc_size;
- Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, false, !p_use_setup_queue);
+ Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, false);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
uint8_t *write_ptr;
- { //map
+ { // Map.
void *data_ptr = nullptr;
VkResult vkerr = vmaMapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation, &data_ptr);
ERR_FAIL_COND_V_MSG(vkerr, ERR_CANT_CREATE, "vmaMapMemory failed with error " + itos(vkerr) + ".");
@@ -2355,52 +2532,32 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
ERR_FAIL_COND_V(region_h % block_h, ERR_BUG);
if (block_w != 1 || block_h != 1) {
- //compressed image (blocks)
- //must copy a block region
+ // Compressed image (blocks).
+ // Must copy a block region.
uint32_t block_size = get_compressed_image_format_block_byte_size(texture->format);
- //re-create current variables in blocky format
+ // Re-create current variables in blocky format.
uint32_t xb = x / block_w;
uint32_t yb = y / block_h;
uint32_t wb = width / block_w;
//uint32_t hb = height / block_h;
uint32_t region_wb = region_w / block_w;
uint32_t region_hb = region_h / block_h;
- for (uint32_t xr = 0; xr < region_wb; xr++) {
- for (uint32_t yr = 0; yr < region_hb; yr++) {
- uint32_t src_offset = ((yr + yb) * wb + xr + xb) * block_size;
- uint32_t dst_offset = (yr * region_wb + xr) * block_size;
- //copy block
- for (uint32_t i = 0; i < block_size; i++) {
- write_ptr[dst_offset + i] = read_ptr[src_offset + i];
- }
- }
- }
-
+ _copy_region(read_ptr, write_ptr, xb, yb, region_wb, region_hb, wb, block_size);
} else {
- //regular image (pixels)
- //must copy a pixel region
-
- for (uint32_t xr = 0; xr < region_w; xr++) {
- for (uint32_t yr = 0; yr < region_h; yr++) {
- uint32_t src_offset = ((yr + y) * width + xr + x) * pixel_size;
- 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];
- }
- }
- }
+ // Regular image (pixels).
+ // Must copy a pixel region.
+ _copy_region(read_ptr, write_ptr, x, y, region_w, region_h, width, pixel_size);
}
- { //unmap
+ { // Unmap.
vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation);
}
VkBufferImageCopy buffer_image_copy;
buffer_image_copy.bufferOffset = alloc_offset;
- buffer_image_copy.bufferRowLength = 0; //tightly packed
- buffer_image_copy.bufferImageHeight = 0; //tightly 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;
@@ -2423,21 +2580,21 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
}
mipmap_offset = image_total;
- logic_width = MAX(1, logic_width >> 1);
- logic_height = MAX(1, logic_height >> 1);
+ logic_width = MAX(1u, logic_width >> 1);
+ logic_height = MAX(1u, logic_height >> 1);
}
- //barrier to restore layout
+ // Barrier to restore layout.
{
uint32_t barrier_flags = 0;
uint32_t access_flags = 0;
if (p_post_barrier & BARRIER_MASK_COMPUTE) {
barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
- access_flags |= VK_ACCESS_SHADER_READ_BIT;
+ access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
if (p_post_barrier & BARRIER_MASK_RASTER) {
barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- access_flags |= VK_ACCESS_SHADER_READ_BIT;
+ access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
if (p_post_barrier & BARRIER_MASK_TRANSFER) {
barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
@@ -2514,7 +2671,7 @@ Vector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex
const uint8_t *slice_read_ptr = ((uint8_t *)img_mem) + layout.offset + z * layout.depthPitch;
if (block_size > 1) {
- //compressed
+ // Compressed.
uint32_t line_width = (block_size * (width / blockw));
for (uint32_t y = 0; y < height / blockh; y++) {
const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch;
@@ -2524,7 +2681,7 @@ Vector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex
}
} else {
- //uncompressed
+ // Uncompressed.
for (uint32_t y = 0; y < height; y++) {
const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch;
uint8_t *wptr = write_ptr + y * pixel_size * width;
@@ -2560,19 +2717,19 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t
ERR_FAIL_COND_V(p_layer >= layer_count, Vector<uint8_t>());
if (tex->usage_flags & TEXTURE_USAGE_CPU_READ_BIT) {
- //does not need anything fancy, map and read.
+ // 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
+ // 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].draw_command_buffer; //makes more sense to retrieve
+ // Allocate 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);
+ _buffer_allocate(&tmp_buffer, buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST, VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT);
- { //Source image barrier
+ { // Source image barrier.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -2622,13 +2779,13 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t
vkCmdCopyImageToBuffer(command_buffer, tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, tmp_buffer.buffer, 1, &buffer_image_copy);
- computed_w = MAX(1, computed_w >> 1);
- computed_h = MAX(1, computed_h >> 1);
- computed_d = MAX(1, computed_d >> 1);
+ computed_w = MAX(1u, computed_w >> 1);
+ computed_h = MAX(1u, computed_h >> 1);
+ computed_d = MAX(1u, computed_d >> 1);
offset += size;
}
- { //restore src
+ { // Restore src.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -2743,9 +2900,9 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
VkCommandBuffer command_buffer = frames[frame].draw_command_buffer;
{
- //PRE Copy the image
+ // PRE Copy the image.
- { //Source
+ { // Source.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -2765,7 +2922,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
- { //Dest
+ { // Dest.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -2786,7 +2943,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
- //COPY
+ // COPY.
{
VkImageCopy image_copy_region;
@@ -2813,7 +2970,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
vkCmdCopyImage(command_buffer, src_tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_tex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region);
}
- // RESTORE LAYOUT for SRC and DST
+ // RESTORE LAYOUT for SRC and DST.
uint32_t barrier_flags = 0;
uint32_t access_flags = 0;
@@ -2834,7 +2991,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
}
- { //restore src
+ { // Restore src.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -2851,10 +3008,10 @@ 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, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
+ vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
- { //make dst readable
+ { // Make dst readable.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
@@ -2877,6 +3034,13 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
}
}
+ if (dst_tex->used_in_frame != frames_drawn) {
+ dst_tex->used_in_raster = false;
+ dst_tex->used_in_compute = false;
+ dst_tex->used_in_frame = frames_drawn;
+ }
+ dst_tex->used_in_transfer = true;
+
return OK;
}
@@ -2914,9 +3078,9 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
VkCommandBuffer command_buffer = frames[frame].draw_command_buffer;
{
- //PRE Copy the image
+ // PRE Copy the image.
- { //Source
+ { // Source.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -2936,7 +3100,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
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
+ { // Dest.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -2957,7 +3121,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
- //COPY
+ // COPY.
{
VkImageResolve image_copy_region;
@@ -2984,7 +3148,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
vkCmdResolveImage(command_buffer, src_tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_tex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region);
}
- // RESTORE LAYOUT for SRC and DST
+ // RESTORE LAYOUT for SRC and DST.
uint32_t barrier_flags = 0;
uint32_t access_flags = 0;
@@ -3005,7 +3169,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
}
- { //restore src
+ { // Restore src.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -3025,7 +3189,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
- { //make dst readable
+ { // Make dst readable.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
@@ -3078,13 +3242,13 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,
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 owner should be a property of the owner. (Here and places like _get_buffer_from_owner)
+ // NOTE: Perhaps the valid stages/accesses for a given owner 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;
- { // Barrier from previous access with optional layout change (see clear_layout logic above)
+ { // 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;
@@ -3120,7 +3284,7 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,
vkCmdClearColorImage(command_buffer, src_tex->image, clear_layout, &clear_color, 1, &range);
- { // Barrier to post clear accesses (changing back the layout if needed)
+ { // Barrier to post clear accesses (changing back the layout if needed).
uint32_t barrier_flags = 0;
uint32_t access_flags = 0;
@@ -3176,7 +3340,7 @@ bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_f
_THREAD_SAFE_METHOD_
- //validate that this image is supported for the intended use
+ // Validate that this image is supported for the intended use.
VkFormatProperties properties;
vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), vulkan_formats[p_format], &properties);
VkFormatFeatureFlags flags;
@@ -3207,6 +3371,11 @@ bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_f
return false;
}
+ // Validation via VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR fails if VRS attachment is not supported.
+ if (p_usage & TEXTURE_USAGE_VRS_ATTACHMENT_BIT && p_format != DATA_FORMAT_R8_UINT) {
+ return false;
+ }
+
return true;
}
@@ -3215,30 +3384,45 @@ bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_f
/********************/
VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, uint32_t p_view_count, Vector<TextureSamples> *r_samples) {
- // Set up dependencies from/to external equivalent to the default (implicit) one, and then amend them
+ // Set up 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
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | // From Section 7.1 of Vulkan API Spec v1.1.148.
+ VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR;
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];
+ VkSubpassDependency2KHR dependencies[2] = {
+ { VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR, nullptr, VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, default_access_mask, 0, 0 },
+ { VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR, nullptr, 0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, default_access_mask, 0, 0, 0 }
+ };
+ VkSubpassDependency2KHR &dependency_from_external = dependencies[0];
+ VkSubpassDependency2KHR &dependency_to_external = dependencies[1];
LocalVector<int32_t> attachment_last_pass;
attachment_last_pass.resize(p_attachments.size());
- Vector<VkAttachmentDescription> attachments;
+ // These are only used if we use multiview but we need to define them in scope.
+ const uint32_t view_mask = (1 << p_view_count) - 1;
+ const uint32_t correlation_mask = (1 << p_view_count) - 1;
+
+ Vector<VkAttachmentDescription2KHR> attachments;
+ Vector<int> attachment_remap;
for (int i = 0; i < p_attachments.size(); i++) {
+ if (p_attachments[i].usage_flags == AttachmentFormat::UNUSED_ATTACHMENT) {
+ attachment_remap.push_back(VK_ATTACHMENT_UNUSED);
+ continue;
+ }
+
ERR_FAIL_INDEX_V(p_attachments[i].format, DATA_FORMAT_MAX, VK_NULL_HANDLE);
ERR_FAIL_INDEX_V(p_attachments[i].samples, TEXTURE_SAMPLES_MAX, VK_NULL_HANDLE);
- ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)),
- VK_NULL_HANDLE, "Texture format for index (" + itos(i) + ") requires an attachment (color, depth, input or stencil) bit set.");
+ ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT | TEXTURE_USAGE_VRS_ATTACHMENT_BIT)),
+ VK_NULL_HANDLE, "Texture format for index (" + itos(i) + ") requires an attachment (color, depth-stencil, input or VRS) bit set.");
- VkAttachmentDescription description = {};
+ VkAttachmentDescription2KHR description = {};
+ description.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR;
+ description.pNext = nullptr;
description.flags = 0;
description.format = vulkan_formats[p_attachments[i].format];
description.samples = rasterization_sample_count[p_attachments[i].samples];
@@ -3247,83 +3431,95 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
bool is_storage = p_attachments[i].usage_flags & TEXTURE_USAGE_STORAGE_BIT;
bool is_depth = p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_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 synchronization 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 ? p_initial_depth_action : p_initial_action) {
- case INITIAL_ACTION_CLEAR_REGION:
- case INITIAL_ACTION_CLEAR: {
- if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
- description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
- description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
- description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
- 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_KEEP: {
- if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
- description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
- description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
- description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
- description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
- description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
- description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
- 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: {
- if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
- description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
- description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
- 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_CLEAR_REGION_CONTINUE:
- case INITIAL_ACTION_CONTINUE: {
- if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
- description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
- description.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
- description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
- description.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
- } 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;
+ // We can setup a framebuffer where we write to our VRS texture to set it up.
+ // We make the assumption here that if our texture is actually used as our VRS attachment.
+ // It is used as such for each subpass. This is fairly certain seeing the restrictions on subpasses.
+ bool is_vrs = p_attachments[i].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT && i == p_passes[0].vrs_attachment;
+
+ if (is_vrs) {
+ // For VRS we only read, there is no writing to this texture.
+ description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ description.initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ } else {
+ // 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 synchronization 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 ? p_initial_depth_action : p_initial_action) {
+ case INITIAL_ACTION_CLEAR_REGION:
+ case INITIAL_ACTION_CLEAR: {
+ if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
+ description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
+ description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+ 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_KEEP: {
+ if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
+ description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
+ description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+ description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ 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: {
+ if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
+ description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
+ 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_CLEAR_REGION_CONTINUE:
+ case INITIAL_ACTION_CONTINUE: {
+ if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
+ description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ description.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
+ description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ description.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ } 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;
+ default: {
+ ERR_FAIL_V(VK_NULL_HANDLE); // Should never reach here.
}
- } break;
- default: {
- ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here
}
}
@@ -3333,13 +3529,17 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
int last_pass = p_passes.size() - 1;
if (is_depth) {
- //likely missing depth resolve?
+ // Likely missing depth resolve?
if (p_passes[last_pass].depth_attachment == i) {
used_last = true;
}
+ } else if (is_vrs) {
+ if (p_passes[last_pass].vrs_attachment == i) {
+ used_last = true;
+ }
} else {
if (p_passes[last_pass].resolve_attachments.size()) {
- //if using resolve attachments, check resolve attachments
+ // If using resolve attachments, check resolve attachments.
for (int j = 0; j < p_passes[last_pass].resolve_attachments.size(); j++) {
if (p_passes[last_pass].resolve_attachments[j] == i) {
used_last = true;
@@ -3378,72 +3578,85 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
}
}
- switch (is_depth ? final_depth_action : final_action) {
- case FINAL_ACTION_READ: {
- if (p_attachments[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_attachments[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: {
- if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_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_COLOR_ATTACHMENT_OPTIMAL);
- } else if (p_attachments[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);
- } 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
- }
- } break;
- case FINAL_ACTION_CONTINUE: {
- if (p_attachments[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 = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- } else if (p_attachments[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;
- } 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
- }
+ if (is_vrs) {
+ // We don't change our VRS texture during this process.
- } break;
- default: {
- ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here
+ description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ description.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+ // TODO: Do we need to update our external dependency?
+ // update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, false);
+ } else {
+ switch (is_depth ? final_depth_action : final_action) {
+ case FINAL_ACTION_READ: {
+ if (p_attachments[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_attachments[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: {
+ if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_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_COLOR_ATTACHMENT_OPTIMAL);
+ } else if (p_attachments[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);
+ } else {
+ description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ description.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
+ }
+ } break;
+ case FINAL_ACTION_CONTINUE: {
+ if (p_attachments[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 = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ } else if (p_attachments[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;
+ } else {
+ description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ description.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
+ }
+
+ } break;
+ default: {
+ ERR_FAIL_V(VK_NULL_HANDLE); // Should never reach here.
+ }
}
}
attachment_last_pass[i] = -1;
-
+ attachment_remap.push_back(attachments.size());
attachments.push_back(description);
}
- LocalVector<VkSubpassDescription> subpasses;
- LocalVector<LocalVector<VkAttachmentReference>> color_reference_array;
- LocalVector<LocalVector<VkAttachmentReference>> input_reference_array;
- LocalVector<LocalVector<VkAttachmentReference>> resolve_reference_array;
+ LocalVector<VkSubpassDescription2KHR> subpasses;
+ LocalVector<LocalVector<VkAttachmentReference2KHR>> color_reference_array;
+ LocalVector<LocalVector<VkAttachmentReference2KHR>> input_reference_array;
+ LocalVector<LocalVector<VkAttachmentReference2KHR>> resolve_reference_array;
LocalVector<LocalVector<uint32_t>> preserve_reference_array;
- LocalVector<VkAttachmentReference> depth_reference_array;
+ LocalVector<VkAttachmentReference2KHR> depth_reference_array;
+ LocalVector<VkAttachmentReference2KHR> vrs_reference_array;
+ LocalVector<VkFragmentShadingRateAttachmentInfoKHR> vrs_attachment_info_array;
subpasses.resize(p_passes.size());
color_reference_array.resize(p_passes.size());
@@ -3451,20 +3664,25 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
resolve_reference_array.resize(p_passes.size());
preserve_reference_array.resize(p_passes.size());
depth_reference_array.resize(p_passes.size());
+ vrs_reference_array.resize(p_passes.size());
+ vrs_attachment_info_array.resize(p_passes.size());
- LocalVector<VkSubpassDependency> subpass_dependencies;
+ LocalVector<VkSubpassDependency2KHR> subpass_dependencies;
for (int i = 0; i < p_passes.size(); i++) {
const FramebufferPass *pass = &p_passes[i];
- LocalVector<VkAttachmentReference> &color_references = color_reference_array[i];
+ LocalVector<VkAttachmentReference2KHR> &color_references = color_reference_array[i];
TextureSamples texture_samples = TEXTURE_SAMPLES_1;
bool is_multisample_first = true;
+ void *subpass_nextptr = nullptr;
for (int j = 0; j < pass->color_attachments.size(); j++) {
int32_t attachment = pass->color_attachments[j];
- VkAttachmentReference reference;
+ VkAttachmentReference2KHR reference;
+ reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
+ reference.pNext = nullptr;
if (attachment == FramebufferPass::ATTACHMENT_UNUSED) {
reference.attachment = VK_ATTACHMENT_UNUSED;
reference.layout = VK_IMAGE_LAYOUT_UNDEFINED;
@@ -3479,18 +3697,21 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
} else {
ERR_FAIL_COND_V_MSG(texture_samples != p_attachments[attachment].samples, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), if an attachment is marked as multisample, all of them should be multisample and use the same number of samples.");
}
- reference.attachment = attachment;
+ reference.attachment = attachment_remap[attachment];
reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachment_last_pass[attachment] = i;
}
+ reference.aspectMask = 0;
color_references.push_back(reference);
}
- LocalVector<VkAttachmentReference> &input_references = input_reference_array[i];
+ LocalVector<VkAttachmentReference2KHR> &input_references = input_reference_array[i];
for (int j = 0; j < pass->input_attachments.size(); j++) {
int32_t attachment = pass->input_attachments[j];
- VkAttachmentReference reference;
+ VkAttachmentReference2KHR reference;
+ reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
+ reference.pNext = nullptr;
if (attachment == FramebufferPass::ATTACHMENT_UNUSED) {
reference.attachment = VK_ATTACHMENT_UNUSED;
reference.layout = VK_IMAGE_LAYOUT_UNDEFINED;
@@ -3498,14 +3719,15 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), input attachment (" + itos(j) + ").");
ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it isn't marked as an input texture.");
ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
- reference.attachment = attachment;
+ reference.attachment = attachment_remap[attachment];
reference.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
attachment_last_pass[attachment] = i;
}
+ reference.aspectMask = 0; // TODO: We need to set this here, possibly VK_IMAGE_ASPECT_COLOR_BIT?
input_references.push_back(reference);
}
- LocalVector<VkAttachmentReference> &resolve_references = resolve_reference_array[i];
+ LocalVector<VkAttachmentReference2KHR> &resolve_references = resolve_reference_array[i];
if (pass->resolve_attachments.size() > 0) {
ERR_FAIL_COND_V_MSG(pass->resolve_attachments.size() != pass->color_attachments.size(), VK_NULL_HANDLE, "The amount of resolve attachments (" + itos(pass->resolve_attachments.size()) + ") must match the number of color attachments (" + itos(pass->color_attachments.size()) + ").");
@@ -3513,7 +3735,9 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
}
for (int j = 0; j < pass->resolve_attachments.size(); j++) {
int32_t attachment = pass->resolve_attachments[j];
- VkAttachmentReference reference;
+ VkAttachmentReference2KHR reference;
+ reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
+ reference.pNext = nullptr;
if (attachment == FramebufferPass::ATTACHMENT_UNUSED) {
reference.attachment = VK_ATTACHMENT_UNUSED;
reference.layout = VK_IMAGE_LAYOUT_UNDEFINED;
@@ -3524,22 +3748,26 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
bool multisample = p_attachments[attachment].samples > TEXTURE_SAMPLES_1;
ERR_FAIL_COND_V_MSG(multisample, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachments can't be multisample.");
- reference.attachment = attachment;
- reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ reference.attachment = attachment_remap[attachment];
+ reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
attachment_last_pass[attachment] = i;
}
+ reference.aspectMask = 0;
resolve_references.push_back(reference);
}
- VkAttachmentReference &depth_stencil_reference = depth_reference_array[i];
+ VkAttachmentReference2KHR &depth_stencil_reference = depth_reference_array[i];
+ depth_stencil_reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
+ depth_stencil_reference.pNext = nullptr;
if (pass->depth_attachment != FramebufferPass::ATTACHMENT_UNUSED) {
int32_t attachment = pass->depth_attachment;
ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), depth attachment.");
ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not a depth attachment.");
ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
- depth_stencil_reference.attachment = attachment;
+ depth_stencil_reference.attachment = attachment_remap[attachment];
depth_stencil_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ depth_stencil_reference.aspectMask = 0;
attachment_last_pass[attachment] = i;
if (is_multisample_first) {
@@ -3554,6 +3782,32 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
depth_stencil_reference.layout = VK_IMAGE_LAYOUT_UNDEFINED;
}
+ if (context->get_vrs_capabilities().attachment_vrs_supported && pass->vrs_attachment != FramebufferPass::ATTACHMENT_UNUSED) {
+ int32_t attachment = pass->vrs_attachment;
+ ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer VRS format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), VRS attachment.");
+ ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer VRS format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as VRS, but it's not a VRS attachment.");
+ ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer VRS attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass.");
+
+ VkAttachmentReference2KHR &vrs_reference = vrs_reference_array[i];
+ vrs_reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
+ vrs_reference.pNext = nullptr;
+ vrs_reference.attachment = attachment_remap[attachment];
+ vrs_reference.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
+ vrs_reference.aspectMask = 0;
+
+ Size2i texel_size = context->get_vrs_capabilities().max_texel_size;
+
+ VkFragmentShadingRateAttachmentInfoKHR &vrs_attachment_info = vrs_attachment_info_array[i];
+ vrs_attachment_info.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
+ vrs_attachment_info.pNext = nullptr;
+ vrs_attachment_info.pFragmentShadingRateAttachment = &vrs_reference;
+ vrs_attachment_info.shadingRateAttachmentTexelSize = { uint32_t(texel_size.x), uint32_t(texel_size.y) };
+
+ attachment_last_pass[attachment] = i;
+
+ subpass_nextptr = &vrs_attachment_info;
+ }
+
LocalVector<uint32_t> &preserve_references = preserve_reference_array[i];
for (int j = 0; j < pass->preserve_attachments.size(); j++) {
@@ -3564,15 +3818,23 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), preserve attachment (" + itos(j) + ").");
if (attachment_last_pass[attachment] != i) {
- //preserve can still be used to keep depth or color from being discarded after use
+ // Preserve can still be used to keep depth or color from being discarded after use.
attachment_last_pass[attachment] = i;
preserve_references.push_back(attachment);
}
}
- VkSubpassDescription &subpass = subpasses[i];
+ VkSubpassDescription2KHR &subpass = subpasses[i];
+ subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
+ subpass.pNext = subpass_nextptr;
subpass.flags = 0;
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ if (p_view_count == 1) {
+ // VUID-VkSubpassDescription2-multiview-06558: If the multiview feature is not enabled, viewMask must be 0.
+ subpass.viewMask = 0;
+ } else {
+ subpass.viewMask = view_mask;
+ }
subpass.inputAttachmentCount = input_references.size();
if (input_references.size()) {
subpass.pInputAttachments = input_references.ptr();
@@ -3609,7 +3871,9 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
}
if (i > 0) {
- VkSubpassDependency dependency;
+ VkSubpassDependency2KHR dependency;
+ dependency.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR;
+ dependency.pNext = nullptr;
dependency.srcSubpass = i - 1;
dependency.dstSubpass = i;
dependency.srcStageMask = 0;
@@ -3619,27 +3883,29 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
dependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
+ dependency.viewOffset = 0;
subpass_dependencies.push_back(dependency);
}
/*
- // NOTE: Big Mallet Approach -- any layout transition causes a full barrier
+ // NOTE: Big Mallet Approach -- any layout transition causes a full barrier.
if (reference.layout != description.initialLayout) {
- // NOTE: this should be smarter based on the texture's knowledge of its previous role
+ // NOTE: This should be smarter based on the texture's knowledge of its 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 texture's knowledge of its subsequent role
+ // NOTE: This should be smarter based on the texture's knowledge of its 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;
}
*/
}
- VkRenderPassCreateInfo render_pass_create_info;
- render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ VkRenderPassCreateInfo2KHR render_pass_create_info;
+ render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
render_pass_create_info.pNext = nullptr;
render_pass_create_info.flags = 0;
+
render_pass_create_info.attachmentCount = attachments.size();
render_pass_create_info.pAttachments = attachments.ptr();
render_pass_create_info.subpassCount = subpasses.size();
@@ -3656,13 +3922,21 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
render_pass_create_info.pDependencies = nullptr;
}
- // These are only used if we use multiview but we need to define them in scope.
- const uint32_t view_mask = (1 << p_view_count) - 1;
- const uint32_t correlation_mask = (1 << p_view_count) - 1;
+ if (p_view_count == 1) {
+ // VUID-VkRenderPassCreateInfo2-viewMask-03057: If the VkSubpassDescription2::viewMask member of all elements of pSubpasses is 0, correlatedViewMaskCount must be 0.
+ render_pass_create_info.correlatedViewMaskCount = 0;
+ render_pass_create_info.pCorrelatedViewMasks = nullptr;
+ } else {
+ render_pass_create_info.correlatedViewMaskCount = 1;
+ render_pass_create_info.pCorrelatedViewMasks = &correlation_mask;
+ }
+
Vector<uint32_t> view_masks;
VkRenderPassMultiviewCreateInfo render_pass_multiview_create_info;
if (p_view_count > 1) {
+ // This may no longer be needed with the new settings already including this.
+
const VulkanContext::MultiviewCapabilities capabilities = context->get_multiview_capabilities();
// For now this only works with multiview!
@@ -3671,10 +3945,10 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
// Make sure we limit this to the number of views we support.
ERR_FAIL_COND_V_MSG(p_view_count > capabilities.max_view_count, VK_NULL_HANDLE, "Hardware does not support requested number of views for Multiview render pass");
- // Set view masks for each subpass
+ // Set view masks for each subpass.
for (uint32_t i = 0; i < subpasses.size(); i++) {
view_masks.push_back(view_mask);
- };
+ }
render_pass_multiview_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
render_pass_multiview_create_info.pNext = nullptr;
@@ -3689,8 +3963,8 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
}
VkRenderPass render_pass;
- VkResult res = vkCreateRenderPass(device, &render_pass_create_info, nullptr, &render_pass);
- ERR_FAIL_COND_V_MSG(res, VK_NULL_HANDLE, "vkCreateRenderPass failed with error " + itos(res) + ".");
+ VkResult res = context->vkCreateRenderPass2KHR(device, &render_pass_create_info, nullptr, &render_pass);
+ ERR_FAIL_COND_V_MSG(res, VK_NULL_HANDLE, "vkCreateRenderPass2KHR failed with error " + itos(res) + ".");
return render_pass;
}
@@ -3709,7 +3983,7 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
passes.push_back(pass);
return framebuffer_format_create_multipass(p_format, passes, p_view_count);
}
-RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, Vector<FramebufferPass> &p_passes, uint32_t p_view_count) {
+RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, uint32_t p_view_count) {
_THREAD_SAFE_METHOD_
FramebufferFormatKey key;
@@ -3717,16 +3991,16 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
key.passes = p_passes;
key.view_count = p_view_count;
- const Map<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key);
+ const RBMap<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key);
if (E) {
- //exists, return
+ // Exists, return.
return E->get();
}
Vector<TextureSamples> samples;
- VkRenderPass render_pass = _render_pass_create(p_attachments, p_passes, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, p_view_count, &samples); //actions don't matter for this use case
+ VkRenderPass render_pass = _render_pass_create(p_attachments, p_passes, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, p_view_count, &samples); // Actions don't matter for this use case.
- if (render_pass == VK_NULL_HANDLE) { //was likely invalid
+ 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));
@@ -3745,16 +4019,19 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
FramebufferFormatKey key;
key.passes.push_back(FramebufferPass());
- const Map<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key);
+ const RBMap<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key);
if (E) {
- //exists, return
+ // Exists, return.
return E->get();
}
- VkSubpassDescription subpass;
+ VkSubpassDescription2KHR subpass;
+ subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
+ subpass.pNext = nullptr;
subpass.flags = 0;
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
- subpass.inputAttachmentCount = 0; //unsupported for now
+ subpass.viewMask = 0;
+ subpass.inputAttachmentCount = 0; // Unsupported for now.
subpass.pInputAttachments = nullptr;
subpass.colorAttachmentCount = 0;
subpass.pColorAttachments = nullptr;
@@ -3763,8 +4040,8 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
subpass.preserveAttachmentCount = 0;
subpass.pPreserveAttachments = nullptr;
- VkRenderPassCreateInfo render_pass_create_info;
- render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ VkRenderPassCreateInfo2KHR render_pass_create_info;
+ render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
render_pass_create_info.pNext = nullptr;
render_pass_create_info.flags = 0;
render_pass_create_info.attachmentCount = 0;
@@ -3773,13 +4050,15 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
render_pass_create_info.pSubpasses = &subpass;
render_pass_create_info.dependencyCount = 0;
render_pass_create_info.pDependencies = nullptr;
+ render_pass_create_info.correlatedViewMaskCount = 0;
+ render_pass_create_info.pCorrelatedViewMasks = nullptr;
VkRenderPass render_pass;
- VkResult res = vkCreateRenderPass(device, &render_pass_create_info, nullptr, &render_pass);
+ VkResult res = context->vkCreateRenderPass2KHR(device, &render_pass_create_info, nullptr, &render_pass);
- ERR_FAIL_COND_V_MSG(res, 0, "vkCreateRenderPass for empty fb failed with error " + itos(res) + ".");
+ ERR_FAIL_COND_V_MSG(res, 0, "vkCreateRenderPass2KHR for empty fb failed with error " + itos(res) + ".");
- if (render_pass == VK_NULL_HANDLE) { //was likely invalid
+ if (render_pass == VK_NULL_HANDLE) { // Was likely invalid.
return INVALID_ID;
}
@@ -3796,11 +4075,11 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
}
RenderingDevice::TextureSamples RenderingDeviceVulkan::framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass) {
- Map<FramebufferFormatID, FramebufferFormat>::Element *E = framebuffer_formats.find(p_format);
+ HashMap<FramebufferFormatID, FramebufferFormat>::Iterator E = framebuffer_formats.find(p_format);
ERR_FAIL_COND_V(!E, TEXTURE_SAMPLES_1);
- ERR_FAIL_COND_V(p_pass >= uint32_t(E->get().pass_samples.size()), TEXTURE_SAMPLES_1);
+ ERR_FAIL_COND_V(p_pass >= uint32_t(E->value.pass_samples.size()), TEXTURE_SAMPLES_1);
- return E->get().pass_samples[p_pass];
+ return E->value.pass_samples[p_pass];
}
/***********************/
@@ -3815,7 +4094,11 @@ RID RenderingDeviceVulkan::framebuffer_create_empty(const Size2i &p_size, Textur
framebuffer.size = p_size;
framebuffer.view_count = 1;
- return framebuffer_owner.make_rid(framebuffer);
+ RID id = framebuffer_owner.make_rid(framebuffer);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check, uint32_t p_view_count) {
@@ -3825,14 +4108,15 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac
for (int i = 0; i < p_texture_attachments.size(); i++) {
Texture *texture = texture_owner.get_or_null(p_texture_attachments[i]);
- ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture index supplied for framebuffer (" + itos(i) + ") is not a valid texture.");
- ERR_FAIL_COND_V_MSG(texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");
+ ERR_FAIL_COND_V_MSG(texture && texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");
- if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
+ if (texture && texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
pass.depth_attachment = i;
+ } else if (texture && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {
+ pass.vrs_attachment = i;
} else {
- pass.color_attachments.push_back(i);
+ pass.color_attachments.push_back(texture ? i : FramebufferPass::ATTACHMENT_UNUSED);
}
}
@@ -3842,33 +4126,43 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac
return framebuffer_create_multipass(p_texture_attachments, passes, p_format_check, p_view_count);
}
-RID RenderingDeviceVulkan::framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) {
+RID RenderingDeviceVulkan::framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, const Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) {
_THREAD_SAFE_METHOD_
Vector<AttachmentFormat> attachments;
+ attachments.resize(p_texture_attachments.size());
Size2i size;
-
+ bool size_set = false;
for (int i = 0; i < p_texture_attachments.size(); i++) {
+ AttachmentFormat af;
Texture *texture = texture_owner.get_or_null(p_texture_attachments[i]);
- ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture index supplied for framebuffer (" + itos(i) + ") is not a valid texture.");
-
- ERR_FAIL_COND_V_MSG(texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");
-
- if (i == 0) {
- size.width = texture->width;
- size.height = texture->height;
+ if (!texture) {
+ af.usage_flags = AttachmentFormat::UNUSED_ATTACHMENT;
} else {
- ERR_FAIL_COND_V_MSG((uint32_t)size.width != texture->width || (uint32_t)size.height != texture->height, RID(),
- "All textures in a framebuffer should be the same size.");
- }
+ ERR_FAIL_COND_V_MSG(texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");
+
+ if (!size_set) {
+ size.width = texture->width;
+ size.height = texture->height;
+ size_set = true;
+ } else if (texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {
+ // If this is not the first attachement we assume this is used as the VRS attachment.
+ // In this case this texture will be 1/16th the size of the color attachement.
+ // So we skip the size check.
+ } else {
+ ERR_FAIL_COND_V_MSG((uint32_t)size.width != texture->width || (uint32_t)size.height != texture->height, RID(),
+ "All textures in a framebuffer should be the same size.");
+ }
- AttachmentFormat af;
- af.format = texture->format;
- af.samples = texture->samples;
- af.usage_flags = texture->usage_flags;
- attachments.push_back(af);
+ af.format = texture->format;
+ af.samples = texture->samples;
+ af.usage_flags = texture->usage_flags;
+ }
+ attachments.write[i] = af;
}
+ ERR_FAIL_COND_V_MSG(!size_set, RID(), "All attachments unused.");
+
FramebufferFormatID format_id = framebuffer_format_create_multipass(attachments, p_passes, p_view_count);
if (format_id == INVALID_ID) {
return RID();
@@ -3884,9 +4178,14 @@ RID RenderingDeviceVulkan::framebuffer_create_multipass(const Vector<RID> &p_tex
framebuffer.view_count = p_view_count;
RID id = framebuffer_owner.make_rid(framebuffer);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
for (int i = 0; i < p_texture_attachments.size(); i++) {
- _add_dependency(id, p_texture_attachments[i]);
+ if (p_texture_attachments[i].is_valid()) {
+ _add_dependency(id, p_texture_attachments[i]);
+ }
}
return id;
@@ -3901,6 +4200,22 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_get_form
return framebuffer->format_id;
}
+bool RenderingDeviceVulkan::framebuffer_is_valid(RID p_framebuffer) const {
+ _THREAD_SAFE_METHOD_
+
+ return framebuffer_owner.owns(p_framebuffer);
+}
+
+void RenderingDeviceVulkan::framebuffer_set_invalidation_callback(RID p_framebuffer, InvalidationCallback p_callback, void *p_userdata) {
+ _THREAD_SAFE_METHOD_
+
+ Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
+ ERR_FAIL_COND(!framebuffer);
+
+ framebuffer->invalidated_callback = p_callback;
+ framebuffer->invalidated_callback_userdata = p_userdata;
+}
+
/*****************/
/**** SAMPLER ****/
/*****************/
@@ -3943,7 +4258,11 @@ RID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) {
VkResult res = vkCreateSampler(device, &sampler_create_info, nullptr, &sampler);
ERR_FAIL_COND_V_MSG(res, RID(), "vkCreateSampler failed with error " + itos(res) + ".");
- return sampler_owner.make_rid(sampler);
+ RID id = sampler_owner.make_rid(sampler);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
/**********************/
@@ -3964,7 +4283,7 @@ RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Vec
usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
}
Buffer buffer;
- _buffer_allocate(&buffer, p_size_bytes, usage, VMA_MEMORY_USAGE_GPU_ONLY);
+ _buffer_allocate(&buffer, p_size_bytes, usage, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0);
if (p_data.size()) {
uint64_t data_size = p_data.size();
const uint8_t *r = p_data.ptr();
@@ -3972,10 +4291,14 @@ RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Vec
_buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, false);
}
- return vertex_buffer_owner.make_rid(buffer);
+ RID id = vertex_buffer_owner.make_rid(buffer);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
-// 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
+// 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_
@@ -3987,12 +4310,12 @@ RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(cons
return *idptr;
}
- //does not exist, create one and cache it
+ // Does not exist, create one and cache it.
VertexDescriptionCache vdcache;
vdcache.bindings = memnew_arr(VkVertexInputBindingDescription, p_vertex_formats.size());
vdcache.attributes = memnew_arr(VkVertexInputAttributeDescription, p_vertex_formats.size());
- Set<int> used_locations;
+ HashSet<int> used_locations;
for (int i = 0; i < p_vertex_formats.size(); i++) {
ERR_CONTINUE(p_vertex_formats[i].format >= DATA_FORMAT_MAX);
ERR_FAIL_COND_V(used_locations.has(p_vertex_formats[i].location), INVALID_ID);
@@ -4043,25 +4366,25 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo
vertex_array.vertex_count = p_vertex_count;
vertex_array.description = p_vertex_format;
- vertex_array.max_instances_allowed = 0xFFFFFFFF; //by default as many as you want
+ vertex_array.max_instances_allowed = 0xFFFFFFFF; // By default as many as you want.
for (int i = 0; i < p_src_buffers.size(); i++) {
Buffer *buffer = vertex_buffer_owner.get_or_null(p_src_buffers[i]);
- //validate with buffer
+ // Validate with buffer.
{
const VertexAttribute &atf = vd.vertex_formats[i];
uint32_t element_size = get_format_vertex_size(atf.format);
- ERR_FAIL_COND_V(element_size == 0, RID()); //should never happens since this was prevalidated
+ ERR_FAIL_COND_V(element_size == 0, RID()); // Should never happens since this was prevalidated.
if (atf.frequency == VERTEX_FREQUENCY_VERTEX) {
- //validate size for regular drawing
+ // Validate size for regular drawing.
uint64_t total_size = uint64_t(atf.stride) * (p_vertex_count - 1) + atf.offset + element_size;
ERR_FAIL_COND_V_MSG(total_size > buffer->size, RID(),
"Attachment (" + itos(i) + ") will read past the end of the buffer.");
} else {
- //validate size for instances drawing
+ // Validate size for instances drawing.
uint64_t available = buffer->size - atf.offset;
ERR_FAIL_COND_V_MSG(available < element_size, RID(),
"Attachment (" + itos(i) + ") uses instancing, but it's just too small.");
@@ -4072,7 +4395,7 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo
}
vertex_array.buffers.push_back(buffer->buffer);
- vertex_array.offsets.push_back(0); //offset unused, but passing anyway
+ vertex_array.offsets.push_back(0); // Offset unused, but passing anyway.
}
RID id = vertex_array_owner.make_rid(vertex_array);
@@ -4107,7 +4430,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, ignore
+ continue; // Restart index, ignore.
}
index_buffer.max_index = MAX(index16[i], index_buffer.max_index);
}
@@ -4115,7 +4438,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, ignore
+ continue; // Restart index, ignore.
}
index_buffer.max_index = MAX(index32[i], index_buffer.max_index);
}
@@ -4126,14 +4449,18 @@ RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBuff
#else
index_buffer.max_index = 0xFFFFFFFF;
#endif
- _buffer_allocate(&index_buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY);
+ _buffer_allocate(&index_buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0);
if (p_data.size()) {
uint64_t data_size = p_data.size();
const uint8_t *r = p_data.ptr();
_buffer_update(&index_buffer, 0, r, data_size);
_buffer_memory_barrier(index_buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, false);
}
- return index_buffer_owner.make_rid(index_buffer);
+ RID id = index_buffer_owner.make_rid(index_buffer);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
RID RenderingDeviceVulkan::index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count) {
@@ -4196,7 +4523,7 @@ String RenderingDeviceVulkan::_shader_uniform_debug(RID p_shader, int p_set) {
if (!ret.is_empty()) {
ret += "\n";
}
- ret += "Set: " + itos(i) + " Binding: " + itos(ui.binding) + " Type: " + shader_uniform_names[ui.type] + " Length: " + itos(ui.length);
+ ret += "Set: " + itos(i) + " Binding: " + itos(ui.binding) + " Type: " + shader_uniform_names[ui.type] + " Writable: " + (ui.writable ? "Y" : "N") + " Length: " + itos(ui.length);
}
}
return ret;
@@ -4210,7 +4537,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
case glslang::EbtSampler: {
//print_line("DEBUG: IsSampler");
if (reflection.getType()->getSampler().dim == glslang::EsdBuffer) {
- //texture buffers
+ // Texture buffers.
if (reflection.getType()->getSampler().isCombined()) {
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER;
@@ -4310,7 +4637,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
} break;*/
default: {
if (reflection.getType()->getQualifier().hasOffset() || reflection.name.find(".") != std::string::npos) {
- //member of uniform block?
+ // Member of uniform block?
return true;
}
@@ -4347,10 +4674,10 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
uint32_t binding = reflection.getType()->getQualifier().layoutBinding;
if (set < (uint32_t)bindings.size()) {
- //check if this already exists
+ // Check if this already exists.
for (int i = 0; i < bindings[set].size(); i++) {
if (bindings[set][i].binding == binding) {
- //already exists, verify that it's the same type
+ // 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 + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform type.";
@@ -4358,7 +4685,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
return false;
}
- //also, verify that it's the same size
+ // 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 + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform size.";
@@ -4366,7 +4693,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
return false;
}
- //just append stage mask and return
+ // Just append stage mask and return.
bindings.write[set].write[i].stageFlags |= shader_stage_masks[p_stage];
uniform_infos.write[set].write[i].stages |= 1 << p_stage;
return true;
@@ -4375,7 +4702,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
}
layout_binding.binding = binding;
layout_binding.stageFlags = shader_stage_masks[p_stage];
- layout_binding.pImmutableSamplers = nullptr; //no support for this yet
+ layout_binding.pImmutableSamplers = nullptr; // No support for this yet.
info.stages = 1 << p_stage;
info.binding = binding;
@@ -4394,20 +4721,22 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
}
#endif
-//version 1: initial
-//version 2: Added shader name
+// Version 1: initial.
+// Version 2: Added shader name.
+// Version 3: Added writable.
-#define SHADER_BINARY_VERSION 2
+#define SHADER_BINARY_VERSION 3
String RenderingDeviceVulkan::shader_get_binary_cache_key() const {
- return "Vulkan-SV" + itos(SHADER_BINARY_VERSION);
+ return "Vulkan-SV" + itos(SHADER_BINARY_VERSION) + "-" + String(VERSION_NUMBER) + "-" + String(VERSION_HASH);
}
struct RenderingDeviceVulkanShaderBinaryDataBinding {
uint32_t type;
uint32_t binding;
uint32_t stages;
- uint32_t length; //size of arrays (in total elements), or ubos (in bytes * total elements)
+ uint32_t length; // Size of arrays (in total elements), or ubos (in bytes * total elements).
+ uint32_t writable;
};
struct RenderingDeviceVulkanShaderBinarySpecializationConstant {
@@ -4447,7 +4776,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
binary_data.push_constant_size = 0;
binary_data.push_constants_vk_stage = 0;
- Vector<Vector<RenderingDeviceVulkanShaderBinaryDataBinding>> uniform_info; //set bindings
+ Vector<Vector<RenderingDeviceVulkanShaderBinaryDataBinding>> uniform_info; // Set bindings.
Vector<RenderingDeviceVulkanShaderBinarySpecializationConstant> specialization_constants;
uint32_t stages_processed = 0;
@@ -4481,7 +4810,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
uint32_t stage = p_spirv[i].shader_stage;
if (binding_count > 0) {
- //Parse bindings
+ // Parse bindings.
Vector<SpvReflectDescriptorBinding *> bindings;
bindings.resize(binding_count);
@@ -4497,6 +4826,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
bool need_array_dimensions = false;
bool need_block_size = false;
+ bool may_be_writable = false;
switch (binding.descriptor_type) {
case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER: {
@@ -4514,6 +4844,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
info.type = UNIFORM_TYPE_IMAGE;
need_array_dimensions = true;
+ may_be_writable = true;
} break;
case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: {
info.type = UNIFORM_TYPE_TEXTURE_BUFFER;
@@ -4522,6 +4853,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
info.type = UNIFORM_TYPE_IMAGE_BUFFER;
need_array_dimensions = true;
+ may_be_writable = true;
} break;
case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
info.type = UNIFORM_TYPE_UNIFORM_BUFFER;
@@ -4530,6 +4862,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
info.type = UNIFORM_TYPE_STORAGE_BUFFER;
need_block_size = true;
+ may_be_writable = true;
} break;
case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: {
ERR_PRINT("Dynamic uniform buffer not supported.");
@@ -4568,6 +4901,12 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
info.length = 0;
}
+ if (may_be_writable) {
+ info.writable = !(binding.type_description->decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE) && !(binding.block.decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE);
+ } else {
+ info.writable = false;
+ }
+
info.binding = binding.binding;
uint32_t set = binding.set;
@@ -4578,26 +4917,31 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
"On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ").");
if (set < (uint32_t)uniform_info.size()) {
- //check if this already exists
+ // Check if this already exists.
bool exists = false;
for (int k = 0; k < uniform_info[set].size(); k++) {
if (uniform_info[set][k].binding == (uint32_t)info.binding) {
- //already exists, verify that it's the same type
+ // Already exists, verify that it's the same type.
ERR_FAIL_COND_V_MSG(uniform_info[set][k].type != info.type, Vector<uint8_t>(),
"On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform type.");
- //also, verify that it's the same size
+ // Also, verify that it's the same size.
ERR_FAIL_COND_V_MSG(uniform_info[set][k].length != info.length, Vector<uint8_t>(),
"On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform size.");
- //just append stage mask and return
+ // Also, verify that it has the same writability.
+ ERR_FAIL_COND_V_MSG(uniform_info[set][k].writable != info.writable, Vector<uint8_t>(),
+ "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different writability.");
+
+ // Just append stage mask and return.
uniform_info.write[set].write[k].stages |= 1 << stage;
exists = true;
+ break;
}
}
if (exists) {
- continue; //merged
+ continue; // Merged.
}
}
@@ -4612,7 +4956,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
}
{
- //specialization constants
+ // Specialization constants.
uint32_t sc_count = 0;
result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, nullptr);
@@ -4630,19 +4974,22 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
for (uint32_t j = 0; j < sc_count; j++) {
int32_t existing = -1;
RenderingDeviceVulkanShaderBinarySpecializationConstant sconst;
- sconst.constant_id = spec_constants[j]->constant_id;
- switch (spec_constants[j]->constant_type) {
+ SpvReflectSpecializationConstant *spc = spec_constants[j];
+
+ sconst.constant_id = spc->constant_id;
+ sconst.int_value = 0.0; // Clear previous value JIC.
+ switch (spc->constant_type) {
case SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL: {
sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
- sconst.bool_value = spec_constants[j]->default_value.int_bool_value != 0;
+ sconst.bool_value = spc->default_value.int_bool_value != 0;
} break;
case SPV_REFLECT_SPECIALIZATION_CONSTANT_INT: {
sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
- sconst.int_value = spec_constants[j]->default_value.int_bool_value;
+ sconst.int_value = spc->default_value.int_bool_value;
} break;
case SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT: {
sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT;
- sconst.float_value = spec_constants[j]->default_value.float_value;
+ sconst.float_value = spc->default_value.float_value;
} break;
}
sconst.stage_flags = 1 << p_spirv[i].shader_stage;
@@ -4680,7 +5027,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining input variables.");
for (uint32_t j = 0; j < iv_count; j++) {
- if (input_vars[j] && input_vars[j]->decoration_flags == 0) { //regular input
+ if (input_vars[j] && input_vars[j]->decoration_flags == 0) { // Regular input.
binary_data.vertex_input_mask |= (1 << uint32_t(input_vars[j]->location));
}
}
@@ -4726,9 +5073,8 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining push constants.");
#if 0
if (pconstants[0] == nullptr) {
- FileAccess *f = FileAccess::open("res://popo.spv", FileAccess::WRITE);
+ Ref<FileAccess> f = FileAccess::open("res://popo.spv", FileAccess::WRITE);
f->store_buffer((const uint8_t *)&SpirV[0], SpirV.size() * sizeof(uint32_t));
- memdelete(f);
}
#endif
@@ -4750,7 +5096,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
Vector<Vector<uint8_t>> compressed_stages;
Vector<uint32_t> smolv_size;
- Vector<uint32_t> zstd_size; //if 0, stdno t used
+ Vector<uint32_t> zstd_size; // If 0, zstd not used.
uint32_t stages_binary_size = 0;
@@ -4762,7 +5108,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
ERR_FAIL_V_MSG(Vector<uint8_t>(), "Error compressing shader stage :" + String(shader_stage_names[p_spirv[i].shader_stage]));
} else {
smolv_size.push_back(smolv.size());
- { //zstd
+ { // zstd.
Vector<uint8_t> zstd;
zstd.resize(Compression::get_max_compressed_buffer_size(smolv.size(), Compression::MODE_ZSTD));
int dst_size = Compression::compress(zstd.ptrw(), &smolv[0], smolv.size(), Compression::MODE_ZSTD);
@@ -4775,7 +5121,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
Vector<uint8_t> smv;
smv.resize(smolv.size());
memcpy(smv.ptrw(), &smolv[0], smolv.size());
- zstd_size.push_back(0); //not using zstd
+ zstd_size.push_back(0); // Not using zstd.
compressed_stages.push_back(smv);
}
}
@@ -4795,12 +5141,12 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
binary_data.shader_name_len = shader_name_utf.length();
- uint32_t total_size = sizeof(uint32_t) * 3; //header + version + main datasize;
+ uint32_t total_size = sizeof(uint32_t) * 3; // Header + version + main datasize;.
total_size += sizeof(RenderingDeviceVulkanShaderBinaryData);
total_size += binary_data.shader_name_len;
- if ((binary_data.shader_name_len % 4) != 0) { //alignment rules are really strange
+ if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
total_size += 4 - (binary_data.shader_name_len % 4);
}
@@ -4811,18 +5157,18 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
total_size += sizeof(RenderingDeviceVulkanShaderBinarySpecializationConstant) * specialization_constants.size();
- total_size += compressed_stages.size() * sizeof(uint32_t) * 3; //sizes
+ total_size += compressed_stages.size() * sizeof(uint32_t) * 3; // Sizes.
total_size += stages_binary_size;
Vector<uint8_t> ret;
ret.resize(total_size);
- uint32_t offset = 0;
{
+ uint32_t offset = 0;
uint8_t *binptr = ret.ptrw();
binptr[0] = 'G';
binptr[1] = 'V';
binptr[2] = 'B';
- binptr[3] = 'D'; //godot vulkan binary data
+ binptr[3] = 'D'; // Godot vulkan binary data.
offset += 4;
encode_uint32(SHADER_BINARY_VERSION, binptr + offset);
offset += sizeof(uint32_t);
@@ -4833,7 +5179,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
memcpy(binptr + offset, shader_name_utf.ptr(), binary_data.shader_name_len);
offset += binary_data.shader_name_len;
- if ((binary_data.shader_name_len % 4) != 0) { //alignment rules are really strange
+ if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
offset += 4 - (binary_data.shader_name_len % 4);
}
@@ -4881,16 +5227,16 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
uint32_t binsize = p_shader_binary.size();
uint32_t read_offset = 0;
- //consistency check
+ // Consistency check.
ERR_FAIL_COND_V(binsize < sizeof(uint32_t) * 3 + sizeof(RenderingDeviceVulkanShaderBinaryData), RID());
ERR_FAIL_COND_V(binptr[0] != 'G' || binptr[1] != 'V' || binptr[2] != 'B' || binptr[3] != 'D', RID());
uint32_t bin_version = decode_uint32(binptr + 4);
- ERR_FAIL_COND_V(bin_version > SHADER_BINARY_VERSION, RID());
+ ERR_FAIL_COND_V(bin_version != SHADER_BINARY_VERSION, RID());
uint32_t bin_data_size = decode_uint32(binptr + 8);
- const RenderingDeviceVulkanShaderBinaryData &binary_data = *(const RenderingDeviceVulkanShaderBinaryData *)(binptr + 12);
+ const RenderingDeviceVulkanShaderBinaryData &binary_data = *(reinterpret_cast<const RenderingDeviceVulkanShaderBinaryData *>(binptr + 12));
Shader::PushConstant push_constant;
push_constant.push_constant_size = binary_data.push_constant_size;
@@ -4902,7 +5248,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
bool is_compute = binary_data.is_compute;
- uint32_t compute_local_size[3] = { binary_data.compute_local_size[0], binary_data.compute_local_size[1], binary_data.compute_local_size[2] };
+ const uint32_t compute_local_size[3] = { binary_data.compute_local_size[0], binary_data.compute_local_size[1], binary_data.compute_local_size[2] };
read_offset += sizeof(uint32_t) * 3 + bin_data_size;
@@ -4911,7 +5257,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
if (binary_data.shader_name_len) {
name.parse_utf8((const char *)(binptr + read_offset), binary_data.shader_name_len);
read_offset += binary_data.shader_name_len;
- if ((binary_data.shader_name_len % 4) != 0) { //alignment rules are really strange
+ if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
read_offset += 4 - (binary_data.shader_name_len % 4);
}
}
@@ -4926,13 +5272,14 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
ERR_FAIL_COND_V(read_offset + sizeof(uint32_t) >= binsize, RID());
uint32_t set_count = decode_uint32(binptr + read_offset);
read_offset += sizeof(uint32_t);
- const RenderingDeviceVulkanShaderBinaryDataBinding *set_ptr = (const RenderingDeviceVulkanShaderBinaryDataBinding *)(binptr + read_offset);
+ const RenderingDeviceVulkanShaderBinaryDataBinding *set_ptr = reinterpret_cast<const RenderingDeviceVulkanShaderBinaryDataBinding *>(binptr + read_offset);
uint32_t set_size = set_count * sizeof(RenderingDeviceVulkanShaderBinaryDataBinding);
ERR_FAIL_COND_V(read_offset + set_size >= binsize, RID());
for (uint32_t j = 0; j < set_count; j++) {
UniformInfo info;
info.type = UniformType(set_ptr[j].type);
+ info.writable = set_ptr[j].writable;
info.length = set_ptr[j].length;
info.binding = set_ptr[j].binding;
info.stages = set_ptr[j].stages;
@@ -4998,7 +5345,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
Vector<Shader::SpecializationConstant> specialization_constants;
for (uint32_t i = 0; i < binary_data.specialization_constant_count; i++) {
- const RenderingDeviceVulkanShaderBinarySpecializationConstant &src_sc = *(const RenderingDeviceVulkanShaderBinarySpecializationConstant *)(binptr + read_offset);
+ const RenderingDeviceVulkanShaderBinarySpecializationConstant &src_sc = *(reinterpret_cast<const RenderingDeviceVulkanShaderBinarySpecializationConstant *>(binptr + read_offset));
Shader::SpecializationConstant sc;
sc.constant.int_value = src_sc.int_value;
sc.constant.type = PipelineSpecializationConstantType(src_sc.type);
@@ -5027,7 +5374,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
const uint8_t *src_smolv = nullptr;
if (zstd_size > 0) {
- //decompress to smolv
+ // Decompress to smolv.
smolv.resize(smolv_size);
int dec_smolv_size = Compression::decompress(smolv.ptrw(), smolv.size(), binptr + read_offset, zstd_size, Compression::MODE_ZSTD);
ERR_FAIL_COND_V(dec_smolv_size != (int32_t)smolv_size, RID());
@@ -5056,7 +5403,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
ERR_FAIL_COND_V(read_offset != binsize, RID());
- //all good, let's create modules
+ // All good, let's create modules.
_THREAD_SAFE_METHOD_
@@ -5112,11 +5459,11 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
shader.pipeline_stages.push_back(shader_stage);
}
- //proceed to create descriptor sets
+ // 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)
+ // 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;
layout_create_info.pNext = nullptr;
@@ -5135,16 +5482,16 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
Shader::Set set;
set.descriptor_set_layout = layout;
set.uniform_info = uniform_info[i];
- //sort and hash
+ // Sort and hash.
set.uniform_info.sort();
- uint32_t format = 0; //no format, default
+ uint32_t format = 0; // No format, default.
if (set.uniform_info.size()) {
- //has data, needs an actual format;
+ // Has data, needs an actual format.
UniformSetFormat usformat;
usformat.uniform_info = set.uniform_info;
- Map<UniformSetFormat, uint32_t>::Element *E = uniform_set_format_cache.find(usformat);
+ RBMap<UniformSetFormat, uint32_t>::Element *E = uniform_set_format_cache.find(usformat);
if (E) {
format = E->get();
} else {
@@ -5159,7 +5506,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
}
if (success) {
- //create pipeline layout
+ // Create pipeline layout.
VkPipelineLayoutCreateInfo pipeline_layout_create_info;
pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipeline_layout_create_info.pNext = nullptr;
@@ -5198,7 +5545,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
}
if (!success) {
- //clean up if failed
+ // Clean up if failed.
for (int i = 0; i < shader.pipeline_stages.size(); i++) {
vkDestroyShaderModule(device, shader.pipeline_stages[i].module, nullptr);
}
@@ -5210,7 +5557,11 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
ERR_FAIL_V_MSG(RID(), error_text);
}
- return shader_owner.make_rid(shader);
+ RID id = shader_owner.make_rid(shader);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
uint32_t RenderingDeviceVulkan::shader_get_vertex_input_attribute_mask(RID p_shader) {
@@ -5235,7 +5586,7 @@ RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Ve
"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);
+ Error err = _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0);
ERR_FAIL_COND_V(err != OK, RID());
if (p_data.size()) {
uint64_t data_size = p_data.size();
@@ -5243,7 +5594,11 @@ RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Ve
_buffer_update(&buffer, 0, r, data_size);
_buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT, false);
}
- return uniform_buffer_owner.make_rid(buffer);
+ RID id = uniform_buffer_owner.make_rid(buffer);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data, uint32_t p_usage) {
@@ -5256,12 +5611,11 @@ RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Ve
ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());
Buffer buffer;
- 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);
+ Error err = _buffer_allocate(&buffer, p_size_bytes, flags, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0);
ERR_FAIL_COND_V(err != OK, RID());
if (p_data.size()) {
@@ -5287,7 +5641,7 @@ RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataF
ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != size_bytes, RID());
TextureBuffer texture_buffer;
- Error err = _buffer_allocate(&texture_buffer.buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY);
+ Error err = _buffer_allocate(&texture_buffer.buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0);
ERR_FAIL_COND_V(err != OK, RID());
if (p_data.size()) {
@@ -5314,36 +5668,40 @@ RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataF
ERR_FAIL_V_MSG(RID(), "Unable to create buffer view, error " + itos(res) + ".");
}
- //allocate the view
- return texture_buffer_owner.make_rid(texture_buffer);
+ // Allocate the view.
+ RID id = texture_buffer_owner.make_rid(texture_buffer);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
RenderingDeviceVulkan::DescriptorPool *RenderingDeviceVulkan::_descriptor_pool_allocate(const DescriptorPoolKey &p_key) {
if (!descriptor_pools.has(p_key)) {
- descriptor_pools[p_key] = Set<DescriptorPool *>();
+ descriptor_pools[p_key] = HashSet<DescriptorPool *>();
}
DescriptorPool *pool = nullptr;
- for (Set<DescriptorPool *>::Element *E = descriptor_pools[p_key].front(); E; E = E->next()) {
- if (E->get()->usage < max_descriptors_per_pool) {
- pool = E->get();
+ for (DescriptorPool *E : descriptor_pools[p_key]) {
+ if (E->usage < max_descriptors_per_pool) {
+ pool = E;
break;
}
}
if (!pool) {
- //create a new one
+ // Create a new one.
pool = memnew(DescriptorPool);
pool->usage = 0;
VkDescriptorPoolCreateInfo descriptor_pool_create_info;
descriptor_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
descriptor_pool_create_info.pNext = nullptr;
- descriptor_pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; // can't think how somebody may NOT need this flag..
+ descriptor_pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; // Can't think how somebody may NOT need this flag.
descriptor_pool_create_info.maxSets = max_descriptors_per_pool;
Vector<VkDescriptorPoolSize> sizes;
- //here comes more vulkan API strangeness
+ // Here comes more vulkan API strangeness.
if (p_key.uniform_type[UNIFORM_TYPE_SAMPLER]) {
VkDescriptorPoolSize s;
@@ -5443,7 +5801,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
ERR_FAIL_COND_V_MSG(p_shader_set >= (uint32_t)shader->sets.size() || shader->sets[p_shader_set].uniform_info.size() == 0, RID(),
"Desired set (" + itos(p_shader_set) + ") not used by shader.");
- //see that all sets in shader are satisfied
+ // See that all sets in shader are satisfied.
const Shader::Set &set = shader->sets[p_shader_set];
@@ -5456,11 +5814,11 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
Vector<VkWriteDescriptorSet> writes;
DescriptorPoolKey pool_key;
- //to keep them alive until update call
+ // To keep them alive until update call.
List<Vector<VkDescriptorBufferInfo>> buffer_infos;
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
+ // Used for verification to make sure a uniform set does not use a framebuffer bound texture.
LocalVector<UniformSet::AttachableTexture> attachable_textures;
Vector<Texture *> mutable_sampled_textures;
Vector<Texture *> mutable_storage_textures;
@@ -5481,14 +5839,14 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
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
+ 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.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.descriptorType = VK_DESCRIPTOR_TYPE_MAX_ENUM; // Invalid value.
write.pImageInfo = nullptr;
write.pBufferInfo = nullptr;
write.pTexelBufferView = nullptr;
@@ -5496,18 +5854,18 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
switch (uniform.uniform_type) {
case UNIFORM_TYPE_SAMPLER: {
- if (uniform.ids.size() != set_uniform.length) {
+ if (uniform.get_id_count() != (uint32_t)set_uniform.length) {
if (set_uniform.length > 1) {
- ERR_FAIL_V_MSG(RID(), "Sampler (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler elements, so it should be provided equal number of sampler IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ").");
+ ERR_FAIL_V_MSG(RID(), "Sampler (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler elements, so it should be provided equal number of sampler IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ").");
} else {
- ERR_FAIL_V_MSG(RID(), "Sampler (binding: " + itos(uniform.binding) + ") should provide one ID referencing a sampler (IDs provided: " + itos(uniform.ids.size()) + ").");
+ ERR_FAIL_V_MSG(RID(), "Sampler (binding: " + itos(uniform.binding) + ") should provide one ID referencing a sampler (IDs provided: " + itos(uniform.get_id_count()) + ").");
}
}
Vector<VkDescriptorImageInfo> image_info;
- for (int j = 0; j < uniform.ids.size(); j++) {
- VkSampler *sampler = sampler_owner.get_or_null(uniform.ids[j]);
+ for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
+ VkSampler *sampler = sampler_owner.get_or_null(uniform.get_id(j));
ERR_FAIL_COND_V_MSG(!sampler, RID(), "Sampler (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid sampler.");
VkDescriptorImageInfo img_info;
@@ -5519,31 +5877,31 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
}
write.dstArrayElement = 0;
- write.descriptorCount = uniform.ids.size();
+ write.descriptorCount = uniform.get_id_count();
write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
write.pImageInfo = image_infos.push_back(image_info)->get().ptr();
write.pBufferInfo = nullptr;
write.pTexelBufferView = nullptr;
- type_size = uniform.ids.size();
+ type_size = uniform.get_id_count();
} break;
case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: {
- if (uniform.ids.size() != set_uniform.length * 2) {
+ if (uniform.get_id_count() != (uint32_t)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()) + ").");
+ 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.get_id_count()) + ").");
} else {
- ERR_FAIL_V_MSG(RID(), "SamplerTexture (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture (IDs provided: " + itos(uniform.ids.size()) + ").");
+ ERR_FAIL_V_MSG(RID(), "SamplerTexture (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");
}
}
Vector<VkDescriptorImageInfo> image_info;
- for (int j = 0; j < uniform.ids.size(); j += 2) {
- VkSampler *sampler = sampler_owner.get_or_null(uniform.ids[j + 0]);
+ for (uint32_t j = 0; j < uniform.get_id_count(); j += 2) {
+ VkSampler *sampler = sampler_owner.get_or_null(uniform.get_id(j + 0));
ERR_FAIL_COND_V_MSG(!sampler, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler.");
- Texture *texture = texture_owner.get_or_null(uniform.ids[j + 1]);
+ Texture *texture = texture_owner.get_or_null(uniform.get_id(j + 1));
ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),
@@ -5556,17 +5914,17 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)) {
UniformSet::AttachableTexture attachable_texture;
attachable_texture.bind = set_uniform.binding;
- attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.ids[j + 1];
+ attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.get_id(j + 1);
attachable_textures.push_back(attachable_texture);
}
if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
- //can also be used as storage, add to mutable sampled
+ // Can also be used as storage, add to mutable sampled.
mutable_sampled_textures.push_back(texture);
}
if (texture->owner.is_valid()) {
texture = texture_owner.get_or_null(texture->owner);
- ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen
+ ERR_FAIL_COND_V(!texture, RID()); // Bug, should never happen.
}
img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@@ -5575,28 +5933,28 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
}
write.dstArrayElement = 0;
- write.descriptorCount = uniform.ids.size() / 2;
+ write.descriptorCount = uniform.get_id_count() / 2;
write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write.pImageInfo = image_infos.push_back(image_info)->get().ptr();
write.pBufferInfo = nullptr;
write.pTexelBufferView = nullptr;
- type_size = uniform.ids.size() / 2;
+ type_size = uniform.get_id_count() / 2;
} break;
case UNIFORM_TYPE_TEXTURE: {
- if (uniform.ids.size() != set_uniform.length) {
+ if (uniform.get_id_count() != (uint32_t)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()) + ").");
+ 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.get_id_count()) + ").");
} else {
- ERR_FAIL_V_MSG(RID(), "Texture (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.ids.size()) + ").");
+ ERR_FAIL_V_MSG(RID(), "Texture (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");
}
}
Vector<VkDescriptorImageInfo> image_info;
- for (int j = 0; j < uniform.ids.size(); j++) {
- Texture *texture = texture_owner.get_or_null(uniform.ids[j]);
+ for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
+ Texture *texture = texture_owner.get_or_null(uniform.get_id(j));
ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),
@@ -5609,18 +5967,18 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)) {
UniformSet::AttachableTexture attachable_texture;
attachable_texture.bind = set_uniform.binding;
- attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.ids[j];
+ attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.get_id(j);
attachable_textures.push_back(attachable_texture);
}
if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
- //can also be used as storage, add to mutable sampled
+ // Can also be used as storage, add to mutable sampled.
mutable_sampled_textures.push_back(texture);
}
if (texture->owner.is_valid()) {
texture = texture_owner.get_or_null(texture->owner);
- ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen
+ ERR_FAIL_COND_V(!texture, RID()); // Bug, should never happen.
}
img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@@ -5629,27 +5987,27 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
}
write.dstArrayElement = 0;
- write.descriptorCount = uniform.ids.size();
+ write.descriptorCount = uniform.get_id_count();
write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
write.pImageInfo = image_infos.push_back(image_info)->get().ptr();
write.pBufferInfo = nullptr;
write.pTexelBufferView = nullptr;
- type_size = uniform.ids.size();
+ type_size = uniform.get_id_count();
} break;
case UNIFORM_TYPE_IMAGE: {
- if (uniform.ids.size() != set_uniform.length) {
+ if (uniform.get_id_count() != (uint32_t)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()) + ").");
+ 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.get_id_count()) + ").");
} else {
- ERR_FAIL_V_MSG(RID(), "Image (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.ids.size()) + ").");
+ ERR_FAIL_V_MSG(RID(), "Image (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");
}
}
Vector<VkDescriptorImageInfo> image_info;
- for (int j = 0; j < uniform.ids.size(); j++) {
- Texture *texture = texture_owner.get_or_null(uniform.ids[j]);
+ for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
+ Texture *texture = texture_owner.get_or_null(uniform.get_id(j));
ERR_FAIL_COND_V_MSG(!texture, RID(),
"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
@@ -5662,13 +6020,13 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
img_info.imageView = texture->view;
if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) {
- //can also be used as storage, add to mutable sampled
+ // Can also be used as storage, add to mutable sampled.
mutable_storage_textures.push_back(texture);
}
if (texture->owner.is_valid()) {
texture = texture_owner.get_or_null(texture->owner);
- ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen
+ ERR_FAIL_COND_V(!texture, RID()); // Bug, should never happen.
}
img_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
@@ -5677,29 +6035,29 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
}
write.dstArrayElement = 0;
- write.descriptorCount = uniform.ids.size();
+ write.descriptorCount = uniform.get_id_count();
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
write.pImageInfo = image_infos.push_back(image_info)->get().ptr();
write.pBufferInfo = nullptr;
write.pTexelBufferView = nullptr;
- type_size = uniform.ids.size();
+ type_size = uniform.get_id_count();
} break;
case UNIFORM_TYPE_TEXTURE_BUFFER: {
- if (uniform.ids.size() != set_uniform.length) {
+ if (uniform.get_id_count() != (uint32_t)set_uniform.length) {
if (set_uniform.length > 1) {
- ERR_FAIL_V_MSG(RID(), "Buffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") texture buffer elements, so it should be provided equal number of texture buffer IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ").");
+ ERR_FAIL_V_MSG(RID(), "Buffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") texture buffer elements, so it should be provided equal number of texture buffer IDs to satisfy it (IDs provided: " + itos(uniform.get_id_count()) + ").");
} else {
- ERR_FAIL_V_MSG(RID(), "Buffer (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture buffer (IDs provided: " + itos(uniform.ids.size()) + ").");
+ ERR_FAIL_V_MSG(RID(), "Buffer (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture buffer (IDs provided: " + itos(uniform.get_id_count()) + ").");
}
}
Vector<VkDescriptorBufferInfo> buffer_info;
Vector<VkBufferView> buffer_view;
- for (int j = 0; j < uniform.ids.size(); j++) {
- TextureBuffer *buffer = texture_buffer_owner.get_or_null(uniform.ids[j]);
+ for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
+ TextureBuffer *buffer = texture_buffer_owner.get_or_null(uniform.get_id(j));
ERR_FAIL_COND_V_MSG(!buffer, RID(), "Texture Buffer (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture buffer.");
buffer_info.push_back(buffer->buffer.buffer_info);
@@ -5707,21 +6065,21 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
}
write.dstArrayElement = 0;
- write.descriptorCount = uniform.ids.size();
+ write.descriptorCount = uniform.get_id_count();
write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
write.pImageInfo = nullptr;
write.pBufferInfo = buffer_infos.push_back(buffer_info)->get().ptr();
write.pTexelBufferView = buffer_views.push_back(buffer_view)->get().ptr();
- type_size = uniform.ids.size();
+ type_size = uniform.get_id_count();
} break;
case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER: {
- if (uniform.ids.size() != set_uniform.length * 2) {
+ if (uniform.get_id_count() != (uint32_t)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()) + ").");
+ 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.get_id_count()) + ").");
} else {
- ERR_FAIL_V_MSG(RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture buffer (IDs provided: " + itos(uniform.ids.size()) + ").");
+ ERR_FAIL_V_MSG(RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture buffer (IDs provided: " + itos(uniform.get_id_count()) + ").");
}
}
@@ -5729,11 +6087,11 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
Vector<VkDescriptorBufferInfo> buffer_info;
Vector<VkBufferView> buffer_view;
- for (int j = 0; j < uniform.ids.size(); j += 2) {
- VkSampler *sampler = sampler_owner.get_or_null(uniform.ids[j + 0]);
+ for (uint32_t j = 0; j < uniform.get_id_count(); j += 2) {
+ VkSampler *sampler = sampler_owner.get_or_null(uniform.get_id(j + 0));
ERR_FAIL_COND_V_MSG(!sampler, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler.");
- TextureBuffer *buffer = texture_buffer_owner.get_or_null(uniform.ids[j + 1]);
+ TextureBuffer *buffer = texture_buffer_owner.get_or_null(uniform.get_id(j + 1));
VkDescriptorImageInfo img_info;
img_info.sampler = *sampler;
@@ -5749,23 +6107,23 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
}
write.dstArrayElement = 0;
- write.descriptorCount = uniform.ids.size() / 2;
+ write.descriptorCount = uniform.get_id_count() / 2;
write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
write.pImageInfo = image_infos.push_back(image_info)->get().ptr();
write.pBufferInfo = buffer_infos.push_back(buffer_info)->get().ptr();
write.pTexelBufferView = buffer_views.push_back(buffer_view)->get().ptr();
- type_size = uniform.ids.size() / 2;
+ type_size = uniform.get_id_count() / 2;
} break;
case UNIFORM_TYPE_IMAGE_BUFFER: {
- //todo
+ // Todo.
} break;
case UNIFORM_TYPE_UNIFORM_BUFFER: {
- ERR_FAIL_COND_V_MSG(uniform.ids.size() != 1, RID(),
- "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.ids.size()) + " provided).");
+ ERR_FAIL_COND_V_MSG(uniform.get_id_count() != 1, RID(),
+ "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.get_id_count()) + " provided).");
- Buffer *buffer = uniform_buffer_owner.get_or_null(uniform.ids[0]);
+ Buffer *buffer = uniform_buffer_owner.get_or_null(uniform.get_id(0));
ERR_FAIL_COND_V_MSG(!buffer, RID(), "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
ERR_FAIL_COND_V_MSG(buffer->size != (uint32_t)set_uniform.length, RID(),
@@ -5780,21 +6138,21 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
} break;
case UNIFORM_TYPE_STORAGE_BUFFER: {
- 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).");
+ ERR_FAIL_COND_V_MSG(uniform.get_id_count() != 1, RID(),
+ "Storage buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.get_id_count()) + " provided).");
Buffer *buffer = nullptr;
- if (storage_buffer_owner.owns(uniform.ids[0])) {
- buffer = storage_buffer_owner.get_or_null(uniform.ids[0]);
- } else if (vertex_buffer_owner.owns(uniform.ids[0])) {
- buffer = vertex_buffer_owner.get_or_null(uniform.ids[0]);
+ if (storage_buffer_owner.owns(uniform.get_id(0))) {
+ buffer = storage_buffer_owner.get_or_null(uniform.get_id(0));
+ } else if (vertex_buffer_owner.owns(uniform.get_id(0))) {
+ buffer = vertex_buffer_owner.get_or_null(uniform.get_id(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 it's sized on link time
+ // If 0, then it's sized on link time.
ERR_FAIL_COND_V_MSG(set_uniform.length > 0 && buffer->size != (uint32_t)set_uniform.length, RID(),
"Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ").");
@@ -5808,18 +6166,18 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
case UNIFORM_TYPE_INPUT_ATTACHMENT: {
ERR_FAIL_COND_V_MSG(shader->is_compute, RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") supplied for compute shader (this is not allowed).");
- if (uniform.ids.size() != set_uniform.length) {
+ if (uniform.get_id_count() != (uint32_t)set_uniform.length) {
if (set_uniform.length > 1) {
- ERR_FAIL_V_MSG(RID(), "InputAttachment (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()) + ").");
+ ERR_FAIL_V_MSG(RID(), "InputAttachment (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.get_id_count()) + ").");
} else {
- ERR_FAIL_V_MSG(RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.ids.size()) + ").");
+ ERR_FAIL_V_MSG(RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.get_id_count()) + ").");
}
}
Vector<VkDescriptorImageInfo> image_info;
- for (int j = 0; j < uniform.ids.size(); j++) {
- Texture *texture = texture_owner.get_or_null(uniform.ids[j]);
+ for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
+ Texture *texture = texture_owner.get_or_null(uniform.get_id(j));
ERR_FAIL_COND_V_MSG(!texture, RID(),
"InputAttachment (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
@@ -5833,7 +6191,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
if (texture->owner.is_valid()) {
texture = texture_owner.get_or_null(texture->owner);
- ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen
+ ERR_FAIL_COND_V(!texture, RID()); // Bug, should never happen.
}
img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@@ -5842,13 +6200,13 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
}
write.dstArrayElement = 0;
- write.descriptorCount = uniform.ids.size();
+ write.descriptorCount = uniform.get_id_count();
write.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
write.pImageInfo = image_infos.push_back(image_info)->get().ptr();
write.pBufferInfo = nullptr;
write.pTexelBufferView = nullptr;
- type_size = uniform.ids.size();
+ type_size = uniform.get_id_count();
} break;
default: {
}
@@ -5861,7 +6219,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
pool_key.uniform_type[set_uniform.type] += type_size;
}
- //need a descriptor pool
+ // Need a descriptor pool.
DescriptorPool *pool = _descriptor_pool_allocate(pool_key);
ERR_FAIL_COND_V(!pool, RID());
@@ -5878,7 +6236,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
VkResult res = vkAllocateDescriptorSets(device, &descriptor_set_allocate_info, &descriptor_set);
if (res) {
- _descriptor_pool_free(pool_key, pool); // meh
+ _descriptor_pool_free(pool_key, pool); // Meh.
ERR_FAIL_V_MSG(RID(), "Cannot allocate descriptor sets, error " + itos(res) + ".");
}
@@ -5894,18 +6252,20 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
uniform_set.shader_id = p_shader;
RID id = uniform_set_owner.make_rid(uniform_set);
- //add dependencies
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ // Add dependencies.
_add_dependency(id, p_shader);
for (uint32_t i = 0; i < uniform_count; i++) {
const Uniform &uniform = uniforms[i];
- int id_count = uniform.ids.size();
- const RID *ids = uniform.ids.ptr();
+ int id_count = uniform.get_id_count();
for (int j = 0; j < id_count; j++) {
- _add_dependency(id, ids[j]);
+ _add_dependency(id, uniform.get_id(j));
}
}
- //write the contents
+ // Write the contents.
if (writes.size()) {
for (int i = 0; i < writes.size(); i++) {
writes.write[i].dstSet = descriptor_set;
@@ -5920,7 +6280,7 @@ bool RenderingDeviceVulkan::uniform_set_is_valid(RID p_uniform_set) {
return uniform_set_owner.owns(p_uniform_set);
}
-void RenderingDeviceVulkan::uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata) {
+void RenderingDeviceVulkan::uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata) {
UniformSet *us = uniform_set_owner.get_or_null(p_uniform_set);
ERR_FAIL_COND(!us);
us->invalidated_callback = p_callback;
@@ -5938,7 +6298,7 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint
VkPipelineStageFlags dst_stage_mask = 0;
VkAccessFlags dst_access = 0;
if (p_post_barrier & BARRIER_MASK_TRANSFER) {
- // Protect subsequent updates...
+ // Protect subsequent updates.
dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
dst_access = VK_ACCESS_TRANSFER_WRITE_BIT;
}
@@ -5950,7 +6310,7 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint
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.");
- // no barrier should be needed here
+ // No barrier should be needed here.
// _buffer_memory_barrier(buffer->buffer, p_offset, p_size, dst_stage_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_access, VK_ACCESS_TRANSFER_WRITE_BIT, true);
Error err = _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, p_post_barrier);
@@ -5986,7 +6346,7 @@ Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint3
VkPipelineStageFlags dst_stage_mask = 0;
VkAccessFlags dst_access = 0;
if (p_post_barrier & BARRIER_MASK_TRANSFER) {
- // Protect subsequent updates...
+ // Protect subsequent updates.
dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
dst_access = VK_ACCESS_TRANSFER_WRITE_BIT;
}
@@ -5999,7 +6359,7 @@ Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint3
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.");
- // should not be needed
+ // Should not be needed.
// _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_post_barrier);
vkCmdFillBuffer(frames[frame].draw_command_buffer, buffer->buffer, p_offset, p_size, 0);
@@ -6020,10 +6380,10 @@ Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint3
Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) {
_THREAD_SAFE_METHOD_
- // It could be this buffer was just created
+ // 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
+ // Get the vulkan buffer and the potential stage/access possible.
Buffer *buffer = _get_buffer_from_owner(p_buffer, src_stage_mask, src_access_mask, BARRIER_MASK_ALL);
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.");
@@ -6035,13 +6395,13 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) {
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);
+ _buffer_allocate(&tmp_buffer, buffer->size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST, VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT);
VkBufferCopy region;
region.srcOffset = 0;
region.dstOffset = 0;
region.size = buffer->size;
- vkCmdCopyBuffer(command_buffer, buffer->buffer, tmp_buffer.buffer, 1, &region); //dst buffer is in CPU, but I wonder if src buffer needs a barrier for this..
- //flush everything so memory can be safely mapped
+ vkCmdCopyBuffer(command_buffer, buffer->buffer, tmp_buffer.buffer, 1, &region); // Dst buffer is in CPU, but I wonder if src buffer needs a barrier for this.
+ // Flush everything so memory can be safely mapped.
_flush(true);
void *buffer_mem;
@@ -6069,7 +6429,7 @@ 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, uint32_t p_for_render_pass, const Vector<PipelineSpecializationConstant> &p_specialization_constants) {
_THREAD_SAFE_METHOD_
- //needs a shader
+ // Needs a shader.
Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND_V(!shader, RID());
@@ -6077,13 +6437,13 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
"Compute shaders can't be used in render pipelines");
if (p_framebuffer_format == INVALID_ID) {
- //if nothing provided, use an empty one (no attachments)
+ // If nothing provided, use an empty one (no attachments).
p_framebuffer_format = framebuffer_format_create(Vector<AttachmentFormat>());
}
ERR_FAIL_COND_V(!framebuffer_formats.has(p_framebuffer_format), RID());
const FramebufferFormat &fb_format = framebuffer_formats[p_framebuffer_format];
- { //validate shader vs framebuffer
+ { // Validate shader vs framebuffer.
ERR_FAIL_COND_V_MSG(p_for_render_pass >= uint32_t(fb_format.E->key().passes.size()), RID(), "Render pass requested for pipeline creation (" + itos(p_for_render_pass) + ") is out of bounds");
const FramebufferPass &pass = fb_format.E->key().passes[p_for_render_pass];
@@ -6096,19 +6456,19 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
ERR_FAIL_COND_V_MSG(shader->fragment_output_mask != output_mask, RID(),
"Mismatch fragment shader output mask (" + itos(shader->fragment_output_mask) + ") and framebuffer color output mask (" + itos(output_mask) + ") when binding both in render pipeline.");
}
- //vertex
+ // Vertex.
VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_state_create_info;
if (p_vertex_format != INVALID_ID) {
- //uses vertices, else it does not
+ // Uses vertices, else it does not.
ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID());
const VertexDescriptionCache &vd = vertex_formats[p_vertex_format];
pipeline_vertex_input_state_create_info = vd.create_info;
- //validate with inputs
+ // Validate with inputs.
for (uint32_t i = 0; i < 32; i++) {
- if (!(shader->vertex_input_mask & (1 << i))) {
+ if (!(shader->vertex_input_mask & (1UL << i))) {
continue;
}
bool found = false;
@@ -6123,7 +6483,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
}
} else {
- //does not use vertices
+ // Does not use vertices.
pipeline_vertex_input_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
pipeline_vertex_input_state_create_info.pNext = nullptr;
pipeline_vertex_input_state_create_info.flags = 0;
@@ -6135,7 +6495,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
ERR_FAIL_COND_V_MSG(shader->vertex_input_mask != 0, RID(),
"Shader contains vertex inputs, but no vertex input description was provided for pipeline creation.");
}
- //input assembly
+ // Input assembly.
ERR_FAIL_INDEX_V(p_render_primitive, RENDER_PRIMITIVE_MAX, RID());
@@ -6161,7 +6521,7 @@ 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);
- //tessellation
+ // Tessellation.
VkPipelineTessellationStateCreateInfo tessellation_create_info;
tessellation_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
tessellation_create_info.pNext = nullptr;
@@ -6173,12 +6533,12 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
viewport_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewport_state_create_info.pNext = nullptr;
viewport_state_create_info.flags = 0;
- viewport_state_create_info.viewportCount = 1; //if VR extensions are supported at some point, this will have to be customizable in the framebuffer format
+ viewport_state_create_info.viewportCount = 1; // If VR extensions are supported at some point, this will have to be customizable in the framebuffer format.
viewport_state_create_info.pViewports = nullptr;
viewport_state_create_info.scissorCount = 1;
viewport_state_create_info.pScissors = nullptr;
- //rasterization
+ // Rasterization.
VkPipelineRasterizationStateCreateInfo rasterization_state_create_info;
rasterization_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterization_state_create_info.pNext = nullptr;
@@ -6186,7 +6546,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
rasterization_state_create_info.depthClampEnable = p_rasterization_state.enable_depth_clamp;
rasterization_state_create_info.rasterizerDiscardEnable = p_rasterization_state.discard_primitives;
rasterization_state_create_info.polygonMode = (p_rasterization_state.wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL);
- static VkCullModeFlags cull_mode[3] = {
+ static const VkCullModeFlags cull_mode[3] = {
VK_CULL_MODE_NONE,
VK_CULL_MODE_FRONT_BIT,
VK_CULL_MODE_BACK_BIT
@@ -6201,7 +6561,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
rasterization_state_create_info.depthBiasSlopeFactor = p_rasterization_state.depth_bias_slope_factor;
rasterization_state_create_info.lineWidth = p_rasterization_state.line_width;
- //multisample
+ // Multisample.
VkPipelineMultisampleStateCreateInfo multisample_state_create_info;
multisample_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisample_state_create_info.pNext = nullptr;
@@ -6212,8 +6572,8 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
multisample_state_create_info.minSampleShading = p_multisample_state.min_sample_shading;
Vector<VkSampleMask> sample_mask;
if (p_multisample_state.sample_mask.size()) {
- //use sample mask
- int rasterization_sample_mask_expected_size[TEXTURE_SAMPLES_MAX] = {
+ // Use sample mask.
+ const int rasterization_sample_mask_expected_size[TEXTURE_SAMPLES_MAX] = {
1, 2, 4, 8, 16, 32, 64
};
ERR_FAIL_COND_V(rasterization_sample_mask_expected_size[p_multisample_state.sample_count] != p_multisample_state.sample_mask.size(), RID());
@@ -6230,7 +6590,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
multisample_state_create_info.alphaToCoverageEnable = p_multisample_state.enable_alpha_to_coverage;
multisample_state_create_info.alphaToOneEnable = p_multisample_state.enable_alpha_to_one;
- //depth stencil
+ // Depth stencil.
VkPipelineDepthStencilStateCreateInfo depth_stencil_state_create_info;
depth_stencil_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
@@ -6270,7 +6630,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
depth_stencil_state_create_info.minDepthBounds = p_depth_stencil_state.depth_range_min;
depth_stencil_state_create_info.maxDepthBounds = p_depth_stencil_state.depth_range_max;
- //blend state
+ // Blend state.
VkPipelineColorBlendStateCreateInfo color_blend_state_create_info;
color_blend_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
color_blend_state_create_info.pNext = nullptr;
@@ -6282,49 +6642,55 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
Vector<VkPipelineColorBlendAttachmentState> attachment_states;
{
const FramebufferPass &pass = fb_format.E->key().passes[p_for_render_pass];
-
+ attachment_states.resize(pass.color_attachments.size());
+ ERR_FAIL_COND_V(p_blend_state.attachments.size() < pass.color_attachments.size(), RID());
for (int i = 0; i < pass.color_attachments.size(); i++) {
- if (pass.color_attachments[i] != FramebufferPass::ATTACHMENT_UNUSED) {
- int idx = attachment_states.size();
-
- ERR_FAIL_INDEX_V(idx, p_blend_state.attachments.size(), RID());
- VkPipelineColorBlendAttachmentState state;
- state.blendEnable = p_blend_state.attachments[idx].enable_blend;
-
- ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].src_color_blend_factor, BLEND_FACTOR_MAX, RID());
- state.srcColorBlendFactor = blend_factors[p_blend_state.attachments[idx].src_color_blend_factor];
- ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].dst_color_blend_factor, BLEND_FACTOR_MAX, RID());
- state.dstColorBlendFactor = blend_factors[p_blend_state.attachments[idx].dst_color_blend_factor];
- ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].color_blend_op, BLEND_OP_MAX, RID());
- state.colorBlendOp = blend_operations[p_blend_state.attachments[idx].color_blend_op];
-
- ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].src_alpha_blend_factor, BLEND_FACTOR_MAX, RID());
- state.srcAlphaBlendFactor = blend_factors[p_blend_state.attachments[idx].src_alpha_blend_factor];
- ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].dst_alpha_blend_factor, BLEND_FACTOR_MAX, RID());
- state.dstAlphaBlendFactor = blend_factors[p_blend_state.attachments[idx].dst_alpha_blend_factor];
- ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].alpha_blend_op, BLEND_OP_MAX, RID());
- state.alphaBlendOp = blend_operations[p_blend_state.attachments[idx].alpha_blend_op];
+ VkPipelineColorBlendAttachmentState state;
+ if (pass.color_attachments[i] == FramebufferPass::ATTACHMENT_UNUSED) {
+ state.blendEnable = false;
+
+ state.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO;
+ state.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
+ state.colorBlendOp = VK_BLEND_OP_ADD;
+
+ state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
+ state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
+ state.alphaBlendOp = VK_BLEND_OP_ADD;
+
+ state.colorWriteMask = 0;
+ } else {
+ state.blendEnable = p_blend_state.attachments[i].enable_blend;
+
+ ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_color_blend_factor, BLEND_FACTOR_MAX, RID());
+ state.srcColorBlendFactor = blend_factors[p_blend_state.attachments[i].src_color_blend_factor];
+ ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_color_blend_factor, BLEND_FACTOR_MAX, RID());
+ state.dstColorBlendFactor = blend_factors[p_blend_state.attachments[i].dst_color_blend_factor];
+ ERR_FAIL_INDEX_V(p_blend_state.attachments[i].color_blend_op, BLEND_OP_MAX, RID());
+ state.colorBlendOp = blend_operations[p_blend_state.attachments[i].color_blend_op];
+
+ ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_alpha_blend_factor, BLEND_FACTOR_MAX, RID());
+ state.srcAlphaBlendFactor = blend_factors[p_blend_state.attachments[i].src_alpha_blend_factor];
+ ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_alpha_blend_factor, BLEND_FACTOR_MAX, RID());
+ state.dstAlphaBlendFactor = blend_factors[p_blend_state.attachments[i].dst_alpha_blend_factor];
+ ERR_FAIL_INDEX_V(p_blend_state.attachments[i].alpha_blend_op, BLEND_OP_MAX, RID());
+ state.alphaBlendOp = blend_operations[p_blend_state.attachments[i].alpha_blend_op];
state.colorWriteMask = 0;
- if (p_blend_state.attachments[idx].write_r) {
+ if (p_blend_state.attachments[i].write_r) {
state.colorWriteMask |= VK_COLOR_COMPONENT_R_BIT;
}
- if (p_blend_state.attachments[idx].write_g) {
+ if (p_blend_state.attachments[i].write_g) {
state.colorWriteMask |= VK_COLOR_COMPONENT_G_BIT;
}
- if (p_blend_state.attachments[idx].write_b) {
+ if (p_blend_state.attachments[i].write_b) {
state.colorWriteMask |= VK_COLOR_COMPONENT_B_BIT;
}
- if (p_blend_state.attachments[idx].write_a) {
+ if (p_blend_state.attachments[i].write_a) {
state.colorWriteMask |= VK_COLOR_COMPONENT_A_BIT;
}
-
- attachment_states.push_back(state);
- idx++;
- };
+ }
+ attachment_states.write[i] = state;
}
-
- ERR_FAIL_COND_V(attachment_states.size() != p_blend_state.attachments.size(), RID());
}
color_blend_state_create_info.attachmentCount = attachment_states.size();
@@ -6335,15 +6701,15 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
color_blend_state_create_info.blendConstants[2] = p_blend_state.blend_constant.b;
color_blend_state_create_info.blendConstants[3] = p_blend_state.blend_constant.a;
- //dynamic state
+ // Dynamic state.
VkPipelineDynamicStateCreateInfo dynamic_state_create_info;
dynamic_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamic_state_create_info.pNext = nullptr;
dynamic_state_create_info.flags = 0;
- Vector<VkDynamicState> dynamic_states; //vulkan is weird..
+ Vector<VkDynamicState> dynamic_states; // Vulkan is weird.
- dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT); //viewport and scissor are always dynamic
+ dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT); // Viewport and scissor are always dynamic.
dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR);
if (p_dynamic_state_flags & DYNAMIC_STATE_LINE_WIDTH) {
@@ -6377,11 +6743,28 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
dynamic_state_create_info.dynamicStateCount = dynamic_states.size();
dynamic_state_create_info.pDynamicStates = dynamic_states.ptr();
- //finally, pipeline create info
+ void *graphics_pipeline_nextptr = nullptr;
+
+ VkPipelineFragmentShadingRateStateCreateInfoKHR vrs_create_info;
+ if (context->get_vrs_capabilities().attachment_vrs_supported) {
+ // If VRS is used, this defines how the different VRS types are combined.
+ // combinerOps[0] decides how we use the output of pipeline and primitive (drawcall) VRS.
+ // combinerOps[1] decides how we use the output of combinerOps[0] and our attachment VRS.
+
+ vrs_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR;
+ vrs_create_info.pNext = nullptr;
+ vrs_create_info.fragmentSize = { 4, 4 };
+ vrs_create_info.combinerOps[0] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; // We don't use pipeline/primitive VRS so this really doesn't matter.
+ vrs_create_info.combinerOps[1] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; // Always use the outcome of attachment VRS if enabled.
+
+ graphics_pipeline_nextptr = &vrs_create_info;
+ }
+
+ // Finally, pipeline create info.
VkGraphicsPipelineCreateInfo graphics_pipeline_create_info;
graphics_pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
- graphics_pipeline_create_info.pNext = nullptr;
+ graphics_pipeline_create_info.pNext = graphics_pipeline_nextptr;
graphics_pipeline_create_info.flags = 0;
Vector<VkPipelineShaderStageCreateInfo> pipeline_stages = shader->pipeline_stages;
@@ -6395,9 +6778,9 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
specialization_info.resize(pipeline_stages.size());
specialization_map_entries.resize(pipeline_stages.size());
for (int i = 0; i < shader->specialization_constants.size(); i++) {
- //see if overridden
+ // See if overridden.
const Shader::SpecializationConstant &sc = shader->specialization_constants[i];
- data_ptr[i] = sc.constant.int_value; //just copy the 32 bits
+ data_ptr[i] = sc.constant.int_value; // Just copy the 32 bits.
for (int j = 0; j < p_specialization_constants.size(); j++) {
const PipelineSpecializationConstant &psc = p_specialization_constants[j];
@@ -6492,9 +6875,12 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
};
pipeline.validation.primitive_minimum = primitive_minimum[p_render_primitive];
#endif
- //create ID to associate with this pipeline
+ // Create ID to associate with this pipeline.
RID id = render_pipeline_owner.make_rid(pipeline);
- //now add all the dependencies
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ // Now add all the dependencies.
_add_dependency(id, p_shader);
return id;
}
@@ -6511,14 +6897,14 @@ bool RenderingDeviceVulkan::render_pipeline_is_valid(RID p_pipeline) {
RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants) {
_THREAD_SAFE_METHOD_
- //needs a shader
+ // Needs a shader.
Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND_V(!shader, RID());
ERR_FAIL_COND_V_MSG(!shader->is_compute, RID(),
"Non-compute shaders can't be used in compute pipelines");
- //finally, pipeline create info
+ // Finally, pipeline create info.
VkComputePipelineCreateInfo compute_pipeline_create_info;
compute_pipeline_create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
@@ -6538,15 +6924,15 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<Pi
specialization_constant_data.resize(shader->specialization_constants.size());
uint32_t *data_ptr = specialization_constant_data.ptrw();
for (int i = 0; i < shader->specialization_constants.size(); i++) {
- //see if overridden
+ // See if overridden.
const Shader::SpecializationConstant &sc = shader->specialization_constants[i];
- data_ptr[i] = sc.constant.int_value; //just copy the 32 bits
+ data_ptr[i] = sc.constant.int_value; // Just copy the 32 bits.
for (int j = 0; j < p_specialization_constants.size(); j++) {
const PipelineSpecializationConstant &psc = p_specialization_constants[j];
if (psc.constant_id == sc.constant.constant_id) {
ERR_FAIL_COND_V_MSG(psc.type != sc.constant.type, RID(), "Specialization constant provided for id (" + itos(sc.constant.constant_id) + ") is of the wrong type.");
- data_ptr[i] = sc.constant.int_value;
+ data_ptr[i] = psc.int_value;
break;
}
}
@@ -6581,9 +6967,12 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<Pi
pipeline.local_group_size[1] = shader->compute_local_size[1];
pipeline.local_group_size[2] = shader->compute_local_size[2];
- //create ID to associate with this pipeline
+ // Create ID to associate with this pipeline.
RID id = compute_pipeline_owner.make_rid(pipeline);
- //now add all the dependencies
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ // Now add all the dependencies.
_add_dependency(id, p_shader);
return id;
}
@@ -6613,7 +7002,7 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::screen_get_framebuff
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V_MSG(local_device.is_valid(), INVALID_ID, "Local devices have no screen");
- //very hacky, but not used often per frame so I guess ok
+ // Very hacky, but not used often per frame so I guess ok.
VkFormat vkformat = context->get_screen_format();
DataFormat format = DATA_FORMAT_MAX;
for (int i = 0; i < DATA_FORMAT_MAX; i++) {
@@ -6647,6 +7036,10 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(Di
VkCommandBuffer command_buffer = frames[frame].draw_command_buffer;
+ if (!context->window_is_valid_swapchain(p_screen)) {
+ return INVALID_ID;
+ }
+
Size2i size = Size2i(context->window_get_width(p_screen), context->window_get_height(p_screen));
_draw_list_allocate(Rect2i(Vector2i(), size), 0, 0);
@@ -6711,7 +7104,7 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu
vk.view_count = p_framebuffer->view_count;
if (!p_framebuffer->framebuffers.has(vk)) {
- //need to create this version
+ // Need to create this version.
Framebuffer::Version version;
version.render_pass = _render_pass_create(framebuffer_formats[p_framebuffer->format_id].E->key().attachments, framebuffer_formats[p_framebuffer->format_id].E->key().passes, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_framebuffer->view_count);
@@ -6724,10 +7117,13 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu
Vector<VkImageView> attachments;
for (int i = 0; i < p_framebuffer->texture_ids.size(); i++) {
Texture *texture = texture_owner.get_or_null(p_framebuffer->texture_ids[i]);
- ERR_FAIL_COND_V(!texture, ERR_BUG);
- attachments.push_back(texture->view);
- ERR_FAIL_COND_V(texture->width != p_framebuffer->size.width, ERR_BUG);
- ERR_FAIL_COND_V(texture->height != p_framebuffer->size.height, ERR_BUG);
+ if (texture) {
+ attachments.push_back(texture->view);
+ if (!(texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT)) { // VRS attachment will be a different size.
+ ERR_FAIL_COND_V(texture->width != p_framebuffer->size.width, ERR_BUG);
+ ERR_FAIL_COND_V(texture->height != p_framebuffer->size.height, ERR_BUG);
+ }
+ }
}
framebuffer_create_info.attachmentCount = attachments.size();
framebuffer_create_info.pAttachments = attachments.ptr();
@@ -6771,15 +7167,20 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
Vector<VkClearValue> clear_values;
clear_values.resize(framebuffer->texture_ids.size());
-
+ int clear_values_count = 0;
{
int color_index = 0;
for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
- Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
VkClearValue clear_value;
+ Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
+ if (!texture) {
+ color_index++;
+ continue;
+ }
+
if (color_index < p_clear_colors.size() && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
- ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); //a bug
+ ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); // A bug.
Color clear_color = p_clear_colors[color_index];
clear_value.color.float32[0] = clear_color.r;
clear_value.color.float32[1] = clear_color.g;
@@ -6795,19 +7196,22 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
clear_value.color.float32[2] = 0;
clear_value.color.float32[3] = 0;
}
- clear_values.write[i] = clear_value;
+ clear_values.write[clear_values_count++] = clear_value;
}
}
- render_pass_begin.clearValueCount = clear_values.size();
+ render_pass_begin.clearValueCount = clear_values_count;
render_pass_begin.pClearValues = clear_values.ptr();
for (int i = 0; i < p_storage_textures.size(); i++) {
Texture *texture = texture_owner.get_or_null(p_storage_textures[i]);
+ if (!texture) {
+ continue;
+ }
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
+ // Must change layout to general.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -6835,13 +7239,16 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
vkCmdBeginRenderPass(command_buffer, &render_pass_begin, subpass_contents);
- //mark textures as bound
+ // Mark textures as bound.
draw_list_bound_textures.clear();
draw_list_unbind_color_textures = p_final_color_action != FINAL_ACTION_CONTINUE;
draw_list_unbind_depth_textures = p_final_depth_action != FINAL_ACTION_CONTINUE;
for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
+ if (!texture) {
+ continue;
+ }
texture->bound = true;
draw_list_bound_textures.push_back(framebuffer->texture_ids[i]);
}
@@ -6852,13 +7259,18 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
void RenderingDeviceVulkan::_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) {
Vector<VkClearAttachment> clear_attachments;
int color_index = 0;
+ int texture_index = 0;
for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
- VkClearAttachment clear_at = {};
+ if (!texture) {
+ texture_index++;
+ continue;
+ }
+
+ 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];
+ Color clear_color = p_clear_colors[texture_index++];
clear_at.clearValue.color.float32[0] = clear_color.r;
clear_at.clearValue.color.float32[1] = clear_color.g;
clear_at.clearValue.color.float32[2] = clear_color.b;
@@ -6904,7 +7316,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
bool needs_clear_color = false;
bool needs_clear_depth = false;
- if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { //check custom region
+ if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { // Check custom region.
Rect2i viewport(viewport_offset, viewport_size);
Rect2i regioni = p_region;
if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) &&
@@ -6933,19 +7345,18 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
}
}
- if (p_initial_color_action == INITIAL_ACTION_CLEAR) { //check clear values
-
+ if (p_initial_color_action == INITIAL_ACTION_CLEAR || needs_clear_color) { // Check clear values.
int color_count = 0;
for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
-
- if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
+ // We only check for our VRS usage bit if this is not the first texture id.
+ // If it is the first we're likely populating our VRS texture.
+ // Bit dirty but...
+ if (!texture || (!(texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !(i != 0 && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT))) {
color_count++;
}
}
-
- ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_count, INVALID_ID,
- "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer color attachments (" + itos(color_count) + ").");
+ ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_count, INVALID_ID, "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer color attachments (" + itos(color_count) + ").");
}
VkFramebuffer vkframebuffer;
@@ -6998,6 +7409,9 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
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_MSG(draw_list != nullptr, ERR_BUSY, "Only one draw list can be active at the same time.");
+ ERR_FAIL_COND_V_MSG(compute_list != nullptr && !compute_list->state.allow_draw_overlap, ERR_BUSY, "Only one draw/compute list can be active at the same time.");
+
ERR_FAIL_COND_V(p_splits < 1, ERR_INVALID_DECLARATION);
Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
@@ -7009,7 +7423,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
bool needs_clear_color = false;
bool needs_clear_depth = false;
- if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { //check custom region
+ if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { // Check custom region.
Rect2i viewport(viewport_offset, viewport_size);
Rect2i regioni = p_region;
if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) &&
@@ -7031,13 +7445,13 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
}
}
- if (p_initial_color_action == INITIAL_ACTION_CLEAR) { //check clear values
+ if (p_initial_color_action == INITIAL_ACTION_CLEAR || needs_clear_color) { // Check clear values.
int color_count = 0;
for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
- if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
+ if (!texture || !(texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
color_count++;
}
}
@@ -7117,7 +7531,7 @@ RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(DrawL
return nullptr;
}
- uint64_t index = p_id & ((DrawListID(1) << DrawListID(ID_BASE_SHIFT)) - 1); //mask
+ uint64_t index = p_id & ((DrawListID(1) << DrawListID(ID_BASE_SHIFT)) - 1); // Mask.
if (index >= draw_list_count) {
return nullptr;
@@ -7143,7 +7557,7 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI
#endif
if (p_render_pipeline == dl->state.pipeline) {
- return; //redundant state, return.
+ return; // Redundant state, return.
}
dl->state.pipeline = p_render_pipeline;
@@ -7152,17 +7566,17 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI
vkCmdBindPipeline(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline);
if (dl->state.pipeline_shader != pipeline->shader) {
- // shader changed, so descriptor sets may become incompatible.
+ // Shader changed, so descriptor sets may become incompatible.
- //go through ALL sets, and unbind them (and all those above) if the format is different
+ // Go through ALL sets, and unbind them (and all those above) if the format is different.
- uint32_t pcount = pipeline->set_formats.size(); //formats count in this pipeline
+ uint32_t pcount = pipeline->set_formats.size(); // Formats count in this pipeline.
dl->state.set_count = MAX(dl->state.set_count, pcount);
- const uint32_t *pformats = pipeline->set_formats.ptr(); //pipeline set formats
+ const uint32_t *pformats = pipeline->set_formats.ptr(); // Pipeline set formats.
- bool sets_valid = true; //once invalid, all above become invalid
+ bool sets_valid = true; // Once invalid, all above become invalid.
for (uint32_t i = 0; i < pcount; i++) {
- //if a part of the format is different, invalidate it (and the rest)
+ // If a part of the format is different, invalidate it (and the rest).
if (!sets_valid || dl->state.sets[i].pipeline_expected_format != pformats[i]) {
dl->state.sets[i].bound = false;
dl->state.sets[i].pipeline_expected_format = pformats[i];
@@ -7171,11 +7585,11 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI
}
for (uint32_t i = pcount; i < dl->state.set_count; i++) {
- //unbind the ones above (not used) if exist
+ // Unbind the ones above (not used) if exist.
dl->state.sets[i].bound = false;
}
- dl->state.set_count = pcount; //update set count
+ dl->state.set_count = pcount; // Update set count.
if (pipeline->push_constant_size) {
dl->state.pipeline_push_constant_stages = pipeline->push_constant_stages;
@@ -7188,7 +7602,7 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI
}
#ifdef DEBUG_ENABLED
- //update render pass pipeline info
+ // Update render pass pipeline info.
dl->validation.pipeline_active = true;
dl->validation.pipeline_dynamic_state = pipeline->validation.dynamic_state;
dl->validation.pipeline_vertex_format = pipeline->validation.vertex_format;
@@ -7218,8 +7632,8 @@ void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_
dl->state.set_count = p_index;
}
- dl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; //update set pointer
- dl->state.sets[p_index].bound = false; //needs rebind
+ dl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; // Update set pointer.
+ dl->state.sets[p_index].bound = false; // Needs rebind.
dl->state.sets[p_index].uniform_set_format = uniform_set->format;
dl->state.sets[p_index].uniform_set = p_uniform_set;
@@ -7237,7 +7651,7 @@ 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
+ { // Validate that textures bound are not attached as framebuffer bindings.
uint32_t attachable_count = uniform_set->attachable_textures.size();
const UniformSet::AttachableTexture *attachable_ptr = uniform_set->attachable_textures.ptr();
uint32_t bound_count = draw_list_bound_textures.size();
@@ -7263,7 +7677,7 @@ void RenderingDeviceVulkan::draw_list_bind_vertex_array(DrawListID p_list, RID p
ERR_FAIL_COND(!vertex_array);
if (dl->state.vertex_array == p_vertex_array) {
- return; //already set
+ return; // Already set.
}
dl->state.vertex_array = p_vertex_array;
@@ -7287,7 +7701,7 @@ void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_
ERR_FAIL_COND(!index_array);
if (dl->state.index_array == p_index_array) {
- return; //already set
+ return; // Already set.
}
dl->state.index_array = p_index_array;
@@ -7339,30 +7753,30 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices
ERR_FAIL_COND_MSG(!dl->validation.pipeline_active,
"No render pipeline was set before attempting to draw.");
if (dl->validation.pipeline_vertex_format != INVALID_ID) {
- //pipeline uses vertices, validate format
+ // Pipeline uses vertices, validate format.
ERR_FAIL_COND_MSG(dl->validation.vertex_format == INVALID_ID,
"No vertex array was bound, and render pipeline expects vertices.");
- //make sure format is right
+ // 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 number of instances is valid
+ // Make sure number of instances is valid.
ERR_FAIL_COND_MSG(p_instances > 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
+ // Using push constants, check that they were supplied.
ERR_FAIL_COND_MSG(!dl->validation.pipeline_push_constant_supplied,
"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
}
#endif
- //Bind descriptor sets
+ // 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
+ continue; // Nothing expected by this pipeline.
}
#ifdef DEBUG_ENABLED
if (dl->state.sets[i].pipeline_expected_format != dl->state.sets[i].uniform_set_format) {
@@ -7377,7 +7791,7 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices
}
#endif
if (!dl->state.sets[i].bound) {
- //All good, see if this requires re-binding
+ // All good, see if this requires re-binding.
vkCmdBindDescriptorSets(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, dl->state.pipeline_layout, i, 1, &dl->state.sets[i].descriptor_set, 0, nullptr);
dl->state.sets[i].bound = true;
}
@@ -7392,7 +7806,7 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices
"Draw command requested indices, but no index buffer was set.");
if (dl->validation.pipeline_vertex_format != INVALID_ID) {
- //uses vertices, do some vertex validations
+ // Uses vertices, do some vertex validations.
ERR_FAIL_COND_MSG(dl->validation.vertex_array_size < dl->validation.index_array_max_index,
"Index array references (max index: " + itos(dl->validation.index_array_max_index) + ") indices beyond the vertex array size (" + itos(dl->validation.vertex_array_size) + ").");
}
@@ -7518,7 +7932,7 @@ Error RenderingDeviceVulkan::draw_list_switch_to_next_pass_split(uint32_t p_spli
}
Error RenderingDeviceVulkan::_draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass) {
- // Lock while draw_list is active
+ // Lock while draw_list is active.
_THREAD_SAFE_LOCK_
if (p_splits == 0) {
@@ -7545,7 +7959,7 @@ Error RenderingDeviceVulkan::_draw_list_allocate(const Rect2i &p_viewport, uint3
VkCommandBuffer command_buffer;
VkCommandBufferAllocateInfo cmdbuf;
- //no command buffer exists, create it.
+ // No command buffer exists, create it.
cmdbuf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cmdbuf.pNext = nullptr;
cmdbuf.commandPool = split_draw_list_allocators[i].command_pool;
@@ -7564,7 +7978,7 @@ Error RenderingDeviceVulkan::_draw_list_allocate(const Rect2i &p_viewport, uint3
draw_list_split = true;
for (uint32_t i = 0; i < p_splits; i++) {
- //take a command buffer and initialize it
+ // Take a command buffer and initialize it.
VkCommandBuffer command_buffer = split_draw_list_allocators[i].command_buffers[frame];
VkCommandBufferInheritanceInfo inheritance_info;
@@ -7574,7 +7988,7 @@ Error RenderingDeviceVulkan::_draw_list_allocate(const Rect2i &p_viewport, uint3
inheritance_info.subpass = p_subpass;
inheritance_info.framebuffer = draw_list_vkframebuffer;
inheritance_info.occlusionQueryEnable = false;
- inheritance_info.queryFlags = 0; //?
+ inheritance_info.queryFlags = 0; // ?
inheritance_info.pipelineStatistics = 0;
VkCommandBufferBeginInfo cmdbuf_begin;
@@ -7607,7 +8021,7 @@ Error RenderingDeviceVulkan::_draw_list_allocate(const Rect2i &p_viewport, uint3
void RenderingDeviceVulkan::_draw_list_free(Rect2i *r_last_viewport) {
if (draw_list_split) {
- //send all command buffers
+ // 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[i].command_buffer);
@@ -7627,12 +8041,12 @@ void RenderingDeviceVulkan::_draw_list_free(Rect2i *r_last_viewport) {
if (r_last_viewport) {
*r_last_viewport = draw_list->viewport;
}
- //just end the list
+ // Just end the list.
memdelete(draw_list);
draw_list = nullptr;
}
- // draw_list is no longer active
+ // Draw_list is no longer active.
_THREAD_SAFE_UNLOCK_
}
@@ -7647,7 +8061,7 @@ void RenderingDeviceVulkan::draw_list_end(uint32_t p_post_barrier) {
for (int i = 0; i < draw_list_bound_textures.size(); i++) {
Texture *texture = texture_owner.get_or_null(draw_list_bound_textures[i]);
- ERR_CONTINUE(!texture); //wtf
+ ERR_CONTINUE(!texture); // Wtf.
if (draw_list_unbind_color_textures && (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
texture->bound = false;
}
@@ -7719,12 +8133,8 @@ void RenderingDeviceVulkan::draw_list_end(uint32_t p_post_barrier) {
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)
-
-#ifdef FORCE_FULL_BARRIER
- _full_barrier(true);
-#else
+ // * Some buffer is copied.
+ // * Another render pass happens (since we may be done).
VkMemoryBarrier mem_barrier;
mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
@@ -7736,6 +8146,8 @@ void RenderingDeviceVulkan::draw_list_end(uint32_t p_post_barrier) {
vkCmdPipelineBarrier(frames[frame].draw_command_buffer, src_stage, barrier_flags, 0, 1, &mem_barrier, 0, nullptr, image_barrier_count, image_barriers);
}
+#ifdef FORCE_FULL_BARRIER
+ _full_barrier(true);
#endif
}
@@ -7747,7 +8159,7 @@ RenderingDevice::ComputeListID RenderingDeviceVulkan::compute_list_begin(bool p_
ERR_FAIL_COND_V_MSG(!p_allow_draw_overlap && 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.");
- // Lock while compute_list is active
+ // Lock while compute_list is active.
_THREAD_SAFE_LOCK_
compute_list = memnew(ComputeList);
@@ -7767,7 +8179,7 @@ void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_l
ERR_FAIL_COND(!pipeline);
if (p_compute_pipeline == cl->state.pipeline) {
- return; //redundant state, return.
+ return; // Redundant state, return.
}
cl->state.pipeline = p_compute_pipeline;
@@ -7776,17 +8188,17 @@ void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_l
vkCmdBindPipeline(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->pipeline);
if (cl->state.pipeline_shader != pipeline->shader) {
- // shader changed, so descriptor sets may become incompatible.
+ // Shader changed, so descriptor sets may become incompatible.
- //go through ALL sets, and unbind them (and all those above) if the format is different
+ // Go through ALL sets, and unbind them (and all those above) if the format is different.
- uint32_t pcount = pipeline->set_formats.size(); //formats count in this pipeline
+ uint32_t pcount = pipeline->set_formats.size(); // Formats count in this pipeline.
cl->state.set_count = MAX(cl->state.set_count, pcount);
- const uint32_t *pformats = pipeline->set_formats.ptr(); //pipeline set formats
+ const uint32_t *pformats = pipeline->set_formats.ptr(); // Pipeline set formats.
- bool sets_valid = true; //once invalid, all above become invalid
+ bool sets_valid = true; // Once invalid, all above become invalid.
for (uint32_t i = 0; i < pcount; i++) {
- //if a part of the format is different, invalidate it (and the rest)
+ // If a part of the format is different, invalidate it (and the rest).
if (!sets_valid || cl->state.sets[i].pipeline_expected_format != pformats[i]) {
cl->state.sets[i].bound = false;
cl->state.sets[i].pipeline_expected_format = pformats[i];
@@ -7795,11 +8207,11 @@ void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_l
}
for (uint32_t i = pcount; i < cl->state.set_count; i++) {
- //unbind the ones above (not used) if exist
+ // Unbind the ones above (not used) if exist.
cl->state.sets[i].bound = false;
}
- cl->state.set_count = pcount; //update set count
+ cl->state.set_count = pcount; // Update set count.
if (pipeline->push_constant_size) {
cl->state.pipeline_push_constant_stages = pipeline->push_constant_stages;
@@ -7815,7 +8227,7 @@ void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_l
}
#ifdef DEBUG_ENABLED
- //update compute pass pipeline info
+ // Update compute pass pipeline info.
cl->validation.pipeline_active = true;
cl->validation.pipeline_push_constant_size = pipeline->push_constant_size;
#endif
@@ -7843,8 +8255,8 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list,
cl->state.set_count = p_index;
}
- cl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; //update set pointer
- cl->state.sets[p_index].bound = false; //needs rebind
+ cl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; // Update set pointer.
+ cl->state.sets[p_index].bound = false; // Needs rebind.
cl->state.sets[p_index].uniform_set_format = uniform_set->format;
cl->state.sets[p_index].uniform_set = p_uniform_set;
@@ -7947,7 +8359,7 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list,
textures_to_storage[i]->layout = VK_IMAGE_LAYOUT_GENERAL;
- cl->state.textures_to_sampled_layout.insert(textures_to_storage[i]); //needs to go back to sampled layout afterwards
+ cl->state.textures_to_sampled_layout.insert(textures_to_storage[i]); // Needs to go back to sampled layout afterwards.
}
}
@@ -7960,7 +8372,7 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list,
}
#if 0
- { //validate that textures bound are not attached as framebuffer bindings
+ { // 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();
uint32_t bound_count = draw_list_bound_textures.size();
@@ -8020,18 +8432,18 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t
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
+ // 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
+ // 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
+ continue; // Nothing expected by this pipeline.
}
#ifdef DEBUG_ENABLED
if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) {
@@ -8046,7 +8458,7 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t
}
#endif
if (!cl->state.sets[i].bound) {
- //All good, see if this requires re-binding
+ // 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;
}
@@ -8072,7 +8484,7 @@ void RenderingDeviceVulkan::compute_list_dispatch_threads(ComputeListID p_list,
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
+ // 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.");
}
@@ -8090,7 +8502,7 @@ void RenderingDeviceVulkan::compute_list_dispatch_indirect(ComputeListID p_list,
Buffer *buffer = storage_buffer_owner.get_or_null(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(!(buffer->usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT), "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.");
@@ -8103,18 +8515,18 @@ void RenderingDeviceVulkan::compute_list_dispatch_indirect(ComputeListID p_list,
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
+ // 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
+ // 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
+ continue; // Nothing expected by this pipeline.
}
#ifdef DEBUG_ENABLED
if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) {
@@ -8129,7 +8541,7 @@ void RenderingDeviceVulkan::compute_list_dispatch_indirect(ComputeListID p_list,
}
#endif
if (!cl->state.sets[i].bound) {
- //All good, see if this requires re-binding
+ // 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;
}
@@ -8178,37 +8590,34 @@ void RenderingDeviceVulkan::compute_list_end(uint32_t p_post_barrier) {
uint32_t barrier_idx = 0;
- for (Set<Texture *>::Element *E = compute_list->state.textures_to_sampled_layout.front(); E; E = E->next()) {
+ for (Texture *E : compute_list->state.textures_to_sampled_layout) {
VkImageMemoryBarrier &image_memory_barrier = image_barriers[barrier_idx++];
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 = access_flags;
- image_memory_barrier.oldLayout = E->get()->layout;
+ image_memory_barrier.oldLayout = E->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 = E->get()->image;
- image_memory_barrier.subresourceRange.aspectMask = E->get()->read_aspect_mask;
- image_memory_barrier.subresourceRange.baseMipLevel = E->get()->base_mipmap;
- image_memory_barrier.subresourceRange.levelCount = E->get()->mipmaps;
- image_memory_barrier.subresourceRange.baseArrayLayer = E->get()->base_layer;
- image_memory_barrier.subresourceRange.layerCount = E->get()->layers;
+ image_memory_barrier.image = E->image;
+ image_memory_barrier.subresourceRange.aspectMask = E->read_aspect_mask;
+ image_memory_barrier.subresourceRange.baseMipLevel = E->base_mipmap;
+ image_memory_barrier.subresourceRange.levelCount = E->mipmaps;
+ image_memory_barrier.subresourceRange.baseArrayLayer = E->base_layer;
+ image_memory_barrier.subresourceRange.layerCount = E->layers;
- E->get()->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ E->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- if (E->get()->used_in_frame != frames_drawn) {
- E->get()->used_in_transfer = false;
- E->get()->used_in_raster = false;
- E->get()->used_in_compute = false;
- E->get()->used_in_frame = frames_drawn;
+ if (E->used_in_frame != frames_drawn) {
+ E->used_in_transfer = false;
+ E->used_in_raster = false;
+ E->used_in_compute = false;
+ E->used_in_frame = frames_drawn;
}
}
-#ifdef FORCE_FULL_BARRIER
- _full_barrier(true);
-#else
VkMemoryBarrier mem_barrier;
mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
mem_barrier.pNext = nullptr;
@@ -8219,12 +8628,14 @@ void RenderingDeviceVulkan::compute_list_end(uint32_t p_post_barrier) {
vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, barrier_flags, 0, 1, &mem_barrier, 0, nullptr, image_barrier_count, image_barriers);
}
+#ifdef FORCE_FULL_BARRIER
+ _full_barrier(true);
#endif
memdelete(compute_list);
compute_list = nullptr;
- // compute_list is no longer active
+ // Compute_list is no longer active.
_THREAD_SAFE_UNLOCK_
}
@@ -8317,7 +8728,7 @@ void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_frame
"Draw list index (" + itos(i) + ") is created with a framebuffer format incompatible with this render pass.");
if (dl->validation.active) {
- //needs to be closed, so close it.
+ // Needs to be closed, so close it.
vkEndCommandBuffer(dl->command_buffer);
dl->validation.active = false;
}
@@ -8334,7 +8745,15 @@ void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_frame
#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)
+#ifdef DEV_ENABLED
+ String resource_name;
+ if (resource_names.has(p_id)) {
+ resource_name = resource_names[p_id];
+ resource_names.erase(p_id);
+ }
+#endif
+
+ // 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.get_or_null(p_id);
frames[frame].textures_to_dispose_of.push_back(*texture);
@@ -8342,6 +8761,11 @@ void RenderingDeviceVulkan::_free_internal(RID p_id) {
} else if (framebuffer_owner.owns(p_id)) {
Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_id);
frames[frame].framebuffers_to_dispose_of.push_back(*framebuffer);
+
+ if (framebuffer->invalidated_callback != nullptr) {
+ framebuffer->invalidated_callback(framebuffer->invalidated_callback_userdata);
+ }
+
framebuffer_owner.free(p_id);
} else if (sampler_owner.owns(p_id)) {
VkSampler *sampler = sampler_owner.get_or_null(p_id);
@@ -8398,30 +8822,34 @@ void RenderingDeviceVulkan::_free_internal(RID p_id) {
frames[frame].compute_pipelines_to_dispose_of.push_back(*pipeline);
compute_pipeline_owner.free(p_id);
} else {
+#ifdef DEV_ENABLED
+ ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()) + " " + resource_name);
+#else
ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()));
+#endif
}
}
void RenderingDeviceVulkan::free(RID p_id) {
_THREAD_SAFE_METHOD_
- _free_dependencies(p_id); //recursively erase dependencies first, to avoid potential API problems
+ _free_dependencies(p_id); // Recursively erase dependencies first, to avoid potential API problems.
_free_internal(p_id);
}
-// The full list of resources that can be named is in the VkObjectType enum
+// The full list of resources that can be named is in the VkObjectType enum.
// We just expose the resources that are owned and can be accessed easily.
void RenderingDeviceVulkan::set_resource_name(RID p_id, const String p_name) {
if (texture_owner.owns(p_id)) {
Texture *texture = texture_owner.get_or_null(p_id);
if (texture->owner.is_null()) {
- // Don't set the source texture's name when calling on a texture view
+ // Don't set the source texture's name when calling on a texture view.
context->set_object_name(VK_OBJECT_TYPE_IMAGE, uint64_t(texture->image), p_name);
}
context->set_object_name(VK_OBJECT_TYPE_IMAGE_VIEW, uint64_t(texture->view), p_name + " View");
} else if (framebuffer_owner.owns(p_id)) {
//Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_id);
- // Not implemented for now as the relationship between Framebuffer and RenderPass is very complex
+ // Not implemented for now as the relationship between Framebuffer and RenderPass is very complex.
} else if (sampler_owner.owns(p_id)) {
VkSampler *sampler = sampler_owner.get_or_null(p_id);
context->set_object_name(VK_OBJECT_TYPE_SAMPLER, uint64_t(*sampler), p_name);
@@ -8460,7 +8888,11 @@ void RenderingDeviceVulkan::set_resource_name(RID p_id, const String p_name) {
context->set_object_name(VK_OBJECT_TYPE_PIPELINE_LAYOUT, uint64_t(pipeline->pipeline_layout), p_name + " Layout");
} else {
ERR_PRINT("Attempted to name invalid ID: " + itos(p_id.get_id()));
+ return;
}
+#ifdef DEV_ENABLED
+ resource_names[p_id] = p_name;
+#endif
}
void RenderingDeviceVulkan::draw_command_begin_label(String p_label_name, const Color p_color) {
@@ -8478,6 +8910,7 @@ void RenderingDeviceVulkan::draw_command_end_label() {
String RenderingDeviceVulkan::get_device_vendor_name() const {
return context->get_device_vendor_name();
}
+
String RenderingDeviceVulkan::get_device_name() const {
return context->get_device_name();
}
@@ -8486,6 +8919,10 @@ RenderingDevice::DeviceType RenderingDeviceVulkan::get_device_type() const {
return context->get_device_type();
}
+String RenderingDeviceVulkan::get_device_api_version() const {
+ return context->get_device_api_version();
+}
+
String RenderingDeviceVulkan::get_device_pipeline_cache_uuid() const {
return context->get_device_pipeline_cache_uuid();
}
@@ -8499,17 +8936,17 @@ void RenderingDeviceVulkan::_finalize_command_bufers() {
ERR_PRINT("Found open compute list at the end of the frame, this should never happen (further compute will likely not work).");
}
- { //complete the setup buffer (that needs to be processed before anything else)
+ { // Complete the setup buffer (that needs to be processed before anything else).
vkEndCommandBuffer(frames[frame].setup_command_buffer);
vkEndCommandBuffer(frames[frame].draw_command_buffer);
}
}
void RenderingDeviceVulkan::_begin_frame() {
- //erase pending resources
+ // Erase pending resources.
_free_pending_resources(frame);
- //create setup command buffer and set as the setup buffer
+ // Create setup command buffer and set as the setup buffer.
{
VkCommandBufferBeginInfo cmdbuf_begin;
@@ -8528,20 +8965,20 @@ void RenderingDeviceVulkan::_begin_frame() {
if (local_device.is_null()) {
context->append_command_buffer(frames[frame].draw_command_buffer);
- context->set_setup_buffer(frames[frame].setup_command_buffer); //append now so it's added before everything else
+ context->set_setup_buffer(frames[frame].setup_command_buffer); // Append now so it's added before everything else.
}
}
- //advance current frame
+ // Advance current frame.
frames_drawn++;
- //advance staging buffer if used
+ // Advance staging buffer if used.
if (staging_buffer_used) {
staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size();
staging_buffer_used = false;
}
if (frames[frame].timestamp_count) {
- vkGetQueryPoolResults(device, frames[frame].timestamp_pool, 0, frames[frame].timestamp_count, sizeof(uint64_t) * max_timestamp_query_elements, frames[frame].timestamp_result_values, sizeof(uint64_t), VK_QUERY_RESULT_64_BIT);
+ vkGetQueryPoolResults(device, frames[frame].timestamp_pool, 0, frames[frame].timestamp_count, sizeof(uint64_t) * max_timestamp_query_elements, frames[frame].timestamp_result_values.ptr(), sizeof(uint64_t), VK_QUERY_RESULT_64_BIT);
vkCmdResetQueryPool(frames[frame].setup_command_buffer, frames[frame].timestamp_pool, 0, frames[frame].timestamp_count);
SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names);
SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values);
@@ -8559,7 +8996,7 @@ void RenderingDeviceVulkan::swap_buffers() {
_finalize_command_bufers();
screen_prepared = false;
- //swap buffers
+ // Swap buffers.
context->swap_buffers();
frame = (frame + 1) % frame_count;
@@ -8587,9 +9024,33 @@ void RenderingDeviceVulkan::sync() {
local_device_processing = false;
}
+VmaPool RenderingDeviceVulkan::_find_or_create_small_allocs_pool(uint32_t p_mem_type_index) {
+ if (small_allocs_pools.has(p_mem_type_index)) {
+ return small_allocs_pools[p_mem_type_index];
+ }
+
+ print_verbose("Creating VMA small objects pool for memory type index " + itos(p_mem_type_index));
+
+ VmaPoolCreateInfo pci;
+ pci.memoryTypeIndex = p_mem_type_index;
+ pci.flags = 0;
+ pci.blockSize = 0;
+ pci.minBlockCount = 0;
+ pci.maxBlockCount = SIZE_MAX;
+ pci.priority = 0.5f;
+ pci.minAllocationAlignment = 0;
+ pci.pMemoryAllocateNext = nullptr;
+ VmaPool pool = VK_NULL_HANDLE;
+ VkResult res = vmaCreatePool(allocator, &pci, &pool);
+ small_allocs_pools[p_mem_type_index] = pool; // Don't try to create it again if failed the first time.
+ ERR_FAIL_COND_V_MSG(res, pool, "vmaCreatePool failed with error " + itos(res) + ".");
+
+ return pool;
+}
+
void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
- //free in dependency usage order, so nothing weird happens
- //pipelines
+ // Free in dependency usage order, so nothing weird happens.
+ // Pipelines.
while (frames[p_frame].render_pipelines_to_dispose_of.front()) {
RenderPipeline *pipeline = &frames[p_frame].render_pipelines_to_dispose_of.front()->get();
@@ -8606,7 +9067,7 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
frames[p_frame].compute_pipelines_to_dispose_of.pop_front();
}
- //uniform sets
+ // Uniform sets.
while (frames[p_frame].uniform_sets_to_dispose_of.front()) {
UniformSet *uniform_set = &frames[p_frame].uniform_sets_to_dispose_of.front()->get();
@@ -8616,7 +9077,7 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
frames[p_frame].uniform_sets_to_dispose_of.pop_front();
}
- //buffer views
+ // Buffer views.
while (frames[p_frame].buffer_views_to_dispose_of.front()) {
VkBufferView buffer_view = frames[p_frame].buffer_views_to_dispose_of.front()->get();
@@ -8625,19 +9086,19 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
frames[p_frame].buffer_views_to_dispose_of.pop_front();
}
- //shaders
+ // Shaders.
while (frames[p_frame].shaders_to_dispose_of.front()) {
Shader *shader = &frames[p_frame].shaders_to_dispose_of.front()->get();
- //descriptor set layout for each set
+ // Descriptor set layout for each set.
for (int i = 0; i < shader->sets.size(); i++) {
vkDestroyDescriptorSetLayout(device, shader->sets[i].descriptor_set_layout, nullptr);
}
- //pipeline layout
+ // Pipeline layout.
vkDestroyPipelineLayout(device, shader->pipeline_layout, nullptr);
- //shaders themselves
+ // Shaders themselves.
for (int i = 0; i < shader->pipeline_stages.size(); i++) {
vkDestroyShaderModule(device, shader->pipeline_stages[i].module, nullptr);
}
@@ -8645,7 +9106,7 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
frames[p_frame].shaders_to_dispose_of.pop_front();
}
- //samplers
+ // Samplers.
while (frames[p_frame].samplers_to_dispose_of.front()) {
VkSampler sampler = frames[p_frame].samplers_to_dispose_of.front()->get();
@@ -8654,12 +9115,12 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
frames[p_frame].samplers_to_dispose_of.pop_front();
}
- //framebuffers
+ // Framebuffers.
while (frames[p_frame].framebuffers_to_dispose_of.front()) {
Framebuffer *framebuffer = &frames[p_frame].framebuffers_to_dispose_of.front()->get();
for (const KeyValue<Framebuffer::VersionKey, Framebuffer::Version> &E : framebuffer->framebuffers) {
- //first framebuffer, then render pass because it depends on it
+ // First framebuffer, then render pass because it depends on it.
vkDestroyFramebuffer(device, E.value.framebuffer, nullptr);
vkDestroyRenderPass(device, E.value.render_pass, nullptr);
}
@@ -8667,7 +9128,7 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
frames[p_frame].framebuffers_to_dispose_of.pop_front();
}
- //textures
+ // Textures.
while (frames[p_frame].textures_to_dispose_of.front()) {
Texture *texture = &frames[p_frame].textures_to_dispose_of.front()->get();
@@ -8676,14 +9137,14 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
}
vkDestroyImageView(device, texture->view, nullptr);
if (texture->owner.is_null()) {
- //actually owns the image and the allocation too
+ // Actually owns the image and the allocation too.
image_memory -= texture->allocation_info.size;
vmaDestroyImage(allocator, texture->image, texture->allocation);
}
frames[p_frame].textures_to_dispose_of.pop_front();
}
- //buffers
+ // Buffers.
while (frames[p_frame].buffers_to_dispose_of.front()) {
_buffer_free(&frames[p_frame].buffers_to_dispose_of.front()->get());
@@ -8707,17 +9168,17 @@ uint64_t RenderingDeviceVulkan::get_memory_usage(MemoryType p_type) const {
} else if (p_type == MEMORY_TEXTURES) {
return image_memory;
} else {
- VmaStats stats;
- vmaCalculateStats(allocator, &stats);
- return stats.total.usedBytes;
+ VmaTotalStatistics stats;
+ vmaCalculateStatistics(allocator, &stats);
+ return stats.total.statistics.allocationBytes;
}
}
void RenderingDeviceVulkan::_flush(bool p_current_frame) {
if (local_device.is_valid() && !p_current_frame) {
- return; //flushing previous frames has no effect with local device
+ return; // Flushing previous frames has no effect with local device.
}
- //not doing this crashes RADV (undefined behavior)
+ // Not doing this crashes RADV (undefined behavior).
if (p_current_frame) {
vkEndCommandBuffer(frames[frame].setup_command_buffer);
vkEndCommandBuffer(frames[frame].draw_command_buffer);
@@ -8741,7 +9202,7 @@ void RenderingDeviceVulkan::_flush(bool p_current_frame) {
} else {
context->flush(p_current_frame, p_current_frame);
- //re-create the setup command
+ // Re-create the setup command.
if (p_current_frame) {
VkCommandBufferBeginInfo cmdbuf_begin;
cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
@@ -8751,7 +9212,7 @@ void RenderingDeviceVulkan::_flush(bool p_current_frame) {
VkResult err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin);
ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
- context->set_setup_buffer(frames[frame].setup_command_buffer); //append now so it's added before everything else
+ context->set_setup_buffer(frames[frame].setup_command_buffer); // Append now so it's added before everything else.
}
if (p_current_frame) {
@@ -8769,21 +9230,10 @@ void RenderingDeviceVulkan::_flush(bool p_current_frame) {
}
void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_device) {
- // get our device capabilities
+ // Get our device capabilities.
{
device_capabilities.version_major = p_context->get_vulkan_major();
device_capabilities.version_minor = p_context->get_vulkan_minor();
-
- // get info about subgroups
- VulkanContext::SubgroupCapabilities subgroup_capabilities = p_context->get_subgroup_capabilities();
- device_capabilities.subgroup_size = subgroup_capabilities.size;
- device_capabilities.subgroup_in_shaders = subgroup_capabilities.supported_stages_flags_rd();
- device_capabilities.subgroup_operations = subgroup_capabilities.supported_operations_flags_rd();
-
- // get info about further features
- VulkanContext::MultiviewCapabilities multiview_capabilies = p_context->get_multiview_capabilities();
- device_capabilities.supports_multiview = multiview_capabilies.is_supported && multiview_capabilies.max_view_count > 1;
- device_capabilities.supports_fsr_half_float = p_context->get_shader_capabilities().shader_float16_is_supported && p_context->get_storage_buffer_capabilities().storage_buffer_16_bit_access_is_supported;
}
context = p_context;
@@ -8793,12 +9243,12 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
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.
+ 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.
}
limits = p_context->get_device_limits();
max_timestamp_query_elements = 256;
- { //initialize allocator
+ { // Initialize allocator.
VmaAllocatorCreateInfo allocatorInfo;
memset(&allocatorInfo, 0, sizeof(VmaAllocatorCreateInfo));
@@ -8808,13 +9258,13 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
vmaCreateAllocator(&allocatorInfo, &allocator);
}
- frames = memnew_arr(Frame, frame_count);
+ frames.resize(frame_count);
frame = 0;
- //create setup and frame buffers
+ // 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
+ { // Create command pool, one per frame is recommended.
VkCommandPoolCreateInfo cmd_pool_info;
cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cmd_pool_info.pNext = nullptr;
@@ -8825,10 +9275,10 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
ERR_FAIL_COND_MSG(res, "vkCreateCommandPool failed with error " + itos(res) + ".");
}
- { //create command buffers
+ { // Create command buffers.
VkCommandBufferAllocateInfo cmdbuf;
- //no command buffer exists, create it.
+ // No command buffer exists, create it.
cmdbuf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cmdbuf.pNext = nullptr;
cmdbuf.commandPool = frames[i].command_pool;
@@ -8843,7 +9293,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
}
{
- //create query pool
+ // Create query pool.
VkQueryPoolCreateInfo query_pool_create_info;
query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
query_pool_create_info.flags = 0;
@@ -8854,19 +9304,19 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
vkCreateQueryPool(device, &query_pool_create_info, nullptr, &frames[i].timestamp_pool);
- frames[i].timestamp_names = memnew_arr(String, max_timestamp_query_elements);
- frames[i].timestamp_cpu_values = memnew_arr(uint64_t, max_timestamp_query_elements);
+ frames[i].timestamp_names.resize(max_timestamp_query_elements);
+ frames[i].timestamp_cpu_values.resize(max_timestamp_query_elements);
frames[i].timestamp_count = 0;
- frames[i].timestamp_result_names = memnew_arr(String, max_timestamp_query_elements);
- frames[i].timestamp_cpu_result_values = memnew_arr(uint64_t, max_timestamp_query_elements);
- frames[i].timestamp_result_values = memnew_arr(uint64_t, max_timestamp_query_elements);
+ frames[i].timestamp_result_names.resize(max_timestamp_query_elements);
+ frames[i].timestamp_cpu_result_values.resize(max_timestamp_query_elements);
+ frames[i].timestamp_result_values.resize(max_timestamp_query_elements);
frames[i].timestamp_result_count = 0;
}
}
{
- //begin the first command buffer for the first frame, so
- //setting up things can be done in the meantime until swap_buffers(), which is called before advance.
+ // Begin the first command buffer for the first frame, so
+ // setting up things can be done in the meantime until swap_buffers(), which is called before advance.
VkCommandBufferBeginInfo cmdbuf_begin;
cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdbuf_begin.pNext = nullptr;
@@ -8879,42 +9329,42 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
err = vkBeginCommandBuffer(frames[0].draw_command_buffer, &cmdbuf_begin);
ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
if (local_device.is_null()) {
- context->set_setup_buffer(frames[0].setup_command_buffer); //append now so it's added before everything else
+ context->set_setup_buffer(frames[0].setup_command_buffer); // Append now so it's added before everything else.
context->append_command_buffer(frames[0].draw_command_buffer);
}
}
- // Note: If adding new project settings here, also duplicate their definition in
+ // NOTE: If adding new project settings here, also duplicate their definition in
// rendering_server.cpp for headless doctool.
staging_buffer_block_size = GLOBAL_DEF("rendering/vulkan/staging_buffer/block_size_kb", 256);
- staging_buffer_block_size = MAX(4, staging_buffer_block_size);
- staging_buffer_block_size *= 1024; //kb -> bytes
+ staging_buffer_block_size = MAX(4u, staging_buffer_block_size);
+ staging_buffer_block_size *= 1024; // Kb -> bytes.
staging_buffer_max_size = GLOBAL_DEF("rendering/vulkan/staging_buffer/max_size_mb", 128);
- staging_buffer_max_size = MAX(1, staging_buffer_max_size);
+ staging_buffer_max_size = MAX(1u, staging_buffer_max_size);
staging_buffer_max_size *= 1024 * 1024;
if (staging_buffer_max_size < staging_buffer_block_size * 4) {
- //validate enough blocks
+ // Validate enough blocks.
staging_buffer_max_size = staging_buffer_block_size * 4;
}
texture_upload_region_size_px = GLOBAL_DEF("rendering/vulkan/staging_buffer/texture_upload_region_size_px", 64);
texture_upload_region_size_px = nearest_power_of_2_templated(texture_upload_region_size_px);
- frames_drawn = frame_count; //start from frame count, so everything else is immediately old
+ frames_drawn = frame_count; // Start from frame count, so everything else is immediately old.
- //ensure current staging block is valid and at least one per frame exists
+ // Ensure current staging block is valid and at least one per frame exists.
staging_buffer_current = 0;
staging_buffer_used = false;
for (int i = 0; i < frame_count; i++) {
- //staging was never used, create a block
+ // Staging was never used, create a block.
Error err = _insert_staging_block();
ERR_CONTINUE(err != OK);
}
max_descriptors_per_pool = GLOBAL_DEF("rendering/vulkan/descriptor_pools/max_descriptors_per_pool", 64);
- //check to make sure DescriptorPoolKey is good
+ // Check to make sure DescriptorPoolKey is good.
static_assert(sizeof(uint64_t) * 3 >= UNIFORM_TYPE_MAX * sizeof(uint16_t));
draw_list = nullptr;
@@ -8935,6 +9385,11 @@ void RenderingDeviceVulkan::_free_rids(T &p_owner, const char *p_type) {
WARN_PRINT(vformat("%d RIDs of type \"%s\" were leaked.", owned.size(), p_type));
}
for (const RID &E : owned) {
+#ifdef DEV_ENABLED
+ if (resource_names.has(E)) {
+ print_line(String(" - ") + resource_names[E]);
+ }
+#endif
free(E);
}
}
@@ -8944,7 +9399,7 @@ void RenderingDeviceVulkan::capture_timestamp(const String &p_name) {
ERR_FAIL_COND_MSG(draw_list != nullptr, "Capturing timestamps during draw list creation is not allowed. Offending timestamp was: " + p_name);
ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements);
- //this should be optional for profiling, else it will slow things down
+ // This should be optional for profiling, else it will slow things down.
{
VkMemoryBarrier memoryBarrier;
@@ -8996,49 +9451,49 @@ uint64_t RenderingDeviceVulkan::get_driver_resource(DriverResource p_resource, R
switch (p_resource) {
case DRIVER_RESOURCE_VULKAN_DEVICE: {
return (uint64_t)context->get_device();
- }; break;
+ } break;
case DRIVER_RESOURCE_VULKAN_PHYSICAL_DEVICE: {
return (uint64_t)context->get_physical_device();
- }; break;
+ } break;
case DRIVER_RESOURCE_VULKAN_INSTANCE: {
return (uint64_t)context->get_instance();
- }; break;
+ } break;
case DRIVER_RESOURCE_VULKAN_QUEUE: {
return (uint64_t)context->get_graphics_queue();
- }; break;
+ } break;
case DRIVER_RESOURCE_VULKAN_QUEUE_FAMILY_INDEX: {
return context->get_graphics_queue_family_index();
- }; break;
+ } break;
case DRIVER_RESOURCE_VULKAN_IMAGE: {
Texture *tex = texture_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(tex, 0);
return (uint64_t)tex->image;
- }; break;
+ } break;
case DRIVER_RESOURCE_VULKAN_IMAGE_VIEW: {
Texture *tex = texture_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(tex, 0);
return (uint64_t)tex->view;
- }; break;
+ } break;
case DRIVER_RESOURCE_VULKAN_IMAGE_NATIVE_TEXTURE_FORMAT: {
Texture *tex = texture_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(tex, 0);
return vulkan_formats[tex->format];
- }; break;
+ } break;
case DRIVER_RESOURCE_VULKAN_SAMPLER: {
VkSampler *sampler = sampler_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(sampler, 0);
return uint64_t(*sampler);
- }; break;
+ } break;
case DRIVER_RESOURCE_VULKAN_DESCRIPTOR_SET: {
UniformSet *uniform_set = uniform_set_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(uniform_set, 0);
return uint64_t(uniform_set->descriptor_set);
- }; break;
+ } break;
case DRIVER_RESOURCE_VULKAN_BUFFER: {
Buffer *buffer = nullptr;
if (vertex_buffer_owner.owns(p_rid)) {
@@ -9056,23 +9511,23 @@ uint64_t RenderingDeviceVulkan::get_driver_resource(DriverResource p_resource, R
ERR_FAIL_NULL_V(buffer, 0);
return uint64_t(buffer->buffer);
- }; break;
+ } break;
case DRIVER_RESOURCE_VULKAN_COMPUTE_PIPELINE: {
ComputePipeline *compute_pipeline = compute_pipeline_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(compute_pipeline, 0);
return uint64_t(compute_pipeline->pipeline);
- }; break;
+ } break;
case DRIVER_RESOURCE_VULKAN_RENDER_PIPELINE: {
RenderPipeline *render_pipeline = render_pipeline_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(render_pipeline, 0);
return uint64_t(render_pipeline->pipeline);
- }; break;
+ } break;
default: {
- // not supported for this driver
+ // Not supported for this driver.
return 0;
- }; break;
+ } break;
}
}
@@ -9107,9 +9562,9 @@ static void mult64to128(uint64_t u, uint64_t v, uint64_t &h, uint64_t &l) {
uint64_t RenderingDeviceVulkan::get_captured_timestamp_gpu_time(uint32_t p_index) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
- // 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 right value
+ // 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 right value.
uint64_t shift_bits = 16;
@@ -9132,7 +9587,7 @@ String RenderingDeviceVulkan::get_captured_timestamp_name(uint32_t p_index) cons
return frames[frame].timestamp_result_names[p_index];
}
-int RenderingDeviceVulkan::limit_get(Limit p_limit) {
+uint64_t RenderingDeviceVulkan::limit_get(Limit p_limit) const {
switch (p_limit) {
case LIMIT_MAX_BOUND_UNIFORM_SETS:
return limits.maxBoundDescriptorSets;
@@ -9202,7 +9657,18 @@ int RenderingDeviceVulkan::limit_get(Limit p_limit) {
return limits.maxComputeWorkGroupSize[1];
case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z:
return limits.maxComputeWorkGroupSize[2];
-
+ case LIMIT_SUBGROUP_SIZE: {
+ VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
+ return subgroup_capabilities.size;
+ }
+ case LIMIT_SUBGROUP_IN_SHADERS: {
+ VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
+ return subgroup_capabilities.supported_stages_flags_rd();
+ }
+ case LIMIT_SUBGROUP_OPERATIONS: {
+ VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
+ return subgroup_capabilities.supported_operations_flags_rd();
+ }
default:
ERR_FAIL_V(0);
}
@@ -9211,7 +9677,7 @@ int RenderingDeviceVulkan::limit_get(Limit p_limit) {
}
void RenderingDeviceVulkan::finalize() {
- //free all resources
+ // Free all resources.
_flush(false);
@@ -9229,7 +9695,7 @@ void RenderingDeviceVulkan::finalize() {
_free_rids(framebuffer_owner, "Framebuffer");
_free_rids(sampler_owner, "Sampler");
{
- //for textures it's a bit more difficult because they may be shared
+ // For textures it's a bit more difficult because they may be shared.
List<RID> owned;
texture_owner.get_owned_list(&owned);
if (owned.size()) {
@@ -9238,59 +9704,69 @@ void RenderingDeviceVulkan::finalize() {
} else {
WARN_PRINT(vformat("%d RIDs of type \"Texture\" were leaked.", owned.size()));
}
- //free shared first
+ // Free shared first.
for (List<RID>::Element *E = owned.front(); E;) {
List<RID>::Element *N = E->next();
if (texture_is_shared(E->get())) {
+#ifdef DEV_ENABLED
+ if (resource_names.has(E->get())) {
+ print_line(String(" - ") + resource_names[E->get()]);
+ }
+#endif
free(E->get());
owned.erase(E);
}
E = N;
}
- //free non shared second, this will avoid an error trying to free unexisting textures due to dependencies.
+ // Free non shared second, this will avoid an error trying to free unexisting textures due to dependencies.
for (const RID &E : owned) {
+#ifdef DEV_ENABLED
+ if (resource_names.has(E)) {
+ print_line(String(" - ") + resource_names[E]);
+ }
+#endif
free(E);
}
}
}
- //free everything pending
+ // Free everything pending.
for (int i = 0; i < frame_count; i++) {
int f = (frame + i) % frame_count;
_free_pending_resources(f);
vkDestroyCommandPool(device, frames[i].command_pool, nullptr);
vkDestroyQueryPool(device, frames[i].timestamp_pool, nullptr);
- memdelete_arr(frames[i].timestamp_names);
- memdelete_arr(frames[i].timestamp_cpu_values);
- memdelete_arr(frames[i].timestamp_result_names);
- memdelete_arr(frames[i].timestamp_result_values);
- memdelete_arr(frames[i].timestamp_cpu_result_values);
}
for (int i = 0; i < split_draw_list_allocators.size(); i++) {
vkDestroyCommandPool(device, split_draw_list_allocators[i].command_pool, nullptr);
}
- memdelete_arr(frames);
+ frames.clear();
for (int i = 0; i < staging_buffer_blocks.size(); i++) {
vmaDestroyBuffer(allocator, staging_buffer_blocks[i].buffer, staging_buffer_blocks[i].allocation);
}
+ while (small_allocs_pools.size()) {
+ HashMap<uint32_t, VmaPool>::Iterator E = small_allocs_pools.begin();
+ vmaDestroyPool(allocator, E->value);
+ small_allocs_pools.remove(E);
+ }
vmaDestroyAllocator(allocator);
while (vertex_formats.size()) {
- Map<VertexFormatID, VertexDescriptionCache>::Element *temp = vertex_formats.front();
- memdelete_arr(temp->get().bindings);
- memdelete_arr(temp->get().attributes);
- vertex_formats.erase(temp);
+ HashMap<VertexFormatID, VertexDescriptionCache>::Iterator temp = vertex_formats.begin();
+ memdelete_arr(temp->value.bindings);
+ memdelete_arr(temp->value.attributes);
+ vertex_formats.remove(temp);
}
- for (int i = 0; i < framebuffer_formats.size(); i++) {
- vkDestroyRenderPass(device, framebuffer_formats[i].render_pass, nullptr);
+ for (KeyValue<FramebufferFormatID, FramebufferFormat> &E : framebuffer_formats) {
+ vkDestroyRenderPass(device, E.value.render_pass, nullptr);
}
framebuffer_formats.clear();
- //all these should be clear at this point
+ // All these should be clear at this point.
ERR_FAIL_COND(descriptor_pools.size());
ERR_FAIL_COND(dependency_map.size());
ERR_FAIL_COND(reverse_dependency_map.size());
@@ -9302,6 +9778,25 @@ RenderingDevice *RenderingDeviceVulkan::create_local_device() {
return rd;
}
+bool RenderingDeviceVulkan::has_feature(const Features p_feature) const {
+ switch (p_feature) {
+ case SUPPORTS_MULTIVIEW: {
+ VulkanContext::MultiviewCapabilities multiview_capabilies = context->get_multiview_capabilities();
+ return multiview_capabilies.is_supported && multiview_capabilies.max_view_count > 1;
+ } break;
+ case SUPPORTS_FSR_HALF_FLOAT: {
+ return context->get_shader_capabilities().shader_float16_is_supported && context->get_storage_buffer_capabilities().storage_buffer_16_bit_access_is_supported;
+ } break;
+ case SUPPORTS_ATTACHMENT_VRS: {
+ VulkanContext::VRSCapabilities vrs_capabilities = context->get_vrs_capabilities();
+ return vrs_capabilities.attachment_vrs_supported;
+ } break;
+ default: {
+ return false;
+ }
+ }
+}
+
RenderingDeviceVulkan::RenderingDeviceVulkan() {
device_capabilities.device_family = DEVICE_VULKAN;
}
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
index f42929ffa4..6572de7c52 100644
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ b/drivers/vulkan/rendering_device_vulkan.h
@@ -96,13 +96,13 @@ class RenderingDeviceVulkan : public RenderingDevice {
ID_TYPE_SPLIT_DRAW_LIST,
ID_TYPE_COMPUTE_LIST,
ID_TYPE_MAX,
- ID_BASE_SHIFT = 58 //5 bits for ID types
+ ID_BASE_SHIFT = 58 // 5 bits for ID types.
};
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
+ HashMap<RID, HashSet<RID>> dependency_map; // IDs to IDs that depend on it.
+ HashMap<RID, HashSet<RID>> reverse_dependency_map; // Same as above, but in reverse.
void _add_dependency(RID p_id, RID p_depends_on);
void _free_dependencies(RID p_id);
@@ -152,7 +152,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t read_aspect_mask = 0;
uint32_t barrier_aspect_mask = 0;
- bool bound = false; //bound to framebffer
+ bool bound = false; // Bound to framebffer.
RID owner;
};
@@ -206,7 +206,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
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 _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);
Error _insert_staging_block();
struct Buffer {
@@ -214,12 +214,12 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t usage = 0;
VkBuffer buffer = VK_NULL_HANDLE;
VmaAllocation allocation = nullptr;
- VkDescriptorBufferInfo buffer_info; //used for binding
+ VkDescriptorBufferInfo buffer_info; // Used for binding.
Buffer() {
}
};
- Error _buffer_allocate(Buffer *p_buffer, uint32_t p_size, uint32_t p_usage, VmaMemoryUsage p_mapping);
+ Error _buffer_allocate(Buffer *p_buffer, uint32_t p_size, uint32_t p_usage, VmaMemoryUsage p_mem_usage, VmaAllocationCreateFlags p_mem_flags);
Error _buffer_free(Buffer *p_buffer);
Error _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 = false, uint32_t p_required_align = 32);
@@ -241,6 +241,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
Vector<AttachmentFormat> attachments;
Vector<FramebufferPass> passes;
uint32_t view_count = 1;
+
bool operator<(const FramebufferFormatKey &p_key) const {
if (view_count != p_key.view_count) {
return view_count < p_key.view_count;
@@ -255,7 +256,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
const FramebufferPass *key_pass_ptr = p_key.passes.ptr();
for (uint32_t i = 0; i < pass_size; i++) {
- { //compare color attachments
+ { // Compare color attachments.
uint32_t attachment_size = pass_ptr[i].color_attachments.size();
uint32_t key_attachment_size = key_pass_ptr[i].color_attachments.size();
if (attachment_size != key_attachment_size) {
@@ -270,7 +271,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
}
}
}
- { //compare input attachments
+ { // Compare input attachments.
uint32_t attachment_size = pass_ptr[i].input_attachments.size();
uint32_t key_attachment_size = key_pass_ptr[i].input_attachments.size();
if (attachment_size != key_attachment_size) {
@@ -285,7 +286,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
}
}
}
- { //compare resolve attachments
+ { // Compare resolve attachments.
uint32_t attachment_size = pass_ptr[i].resolve_attachments.size();
uint32_t key_attachment_size = key_pass_ptr[i].resolve_attachments.size();
if (attachment_size != key_attachment_size) {
@@ -300,7 +301,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
}
}
}
- { //compare preserve attachments
+ { // Compare preserve attachments.
uint32_t attachment_size = pass_ptr[i].preserve_attachments.size();
uint32_t key_attachment_size = key_pass_ptr[i].preserve_attachments.size();
if (attachment_size != key_attachment_size) {
@@ -342,22 +343,22 @@ class RenderingDeviceVulkan : public RenderingDevice {
}
}
- return false; //equal
+ return false; // Equal.
}
};
VkRenderPass _render_pass_create(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, uint32_t p_view_count = 1, Vector<TextureSamples> *r_samples = nullptr);
// This is a cache and it's never freed, it ensures
// IDs for a given format are always unique.
- Map<FramebufferFormatKey, FramebufferFormatID> framebuffer_format_cache;
+ RBMap<FramebufferFormatKey, FramebufferFormatID> framebuffer_format_cache;
struct FramebufferFormat {
- const Map<FramebufferFormatKey, FramebufferFormatID>::Element *E;
- VkRenderPass render_pass = VK_NULL_HANDLE; //here for constructing shaders, never used, see section (7.2. Render Pass Compatibility from Vulkan spec)
+ const RBMap<FramebufferFormatKey, FramebufferFormatID>::Element *E;
+ VkRenderPass render_pass = VK_NULL_HANDLE; // Here for constructing shaders, never used, see section (7.2. Render Pass Compatibility from Vulkan spec).
Vector<TextureSamples> pass_samples;
- uint32_t view_count = 1; // number of views
+ uint32_t view_count = 1; // Number of views.
};
- Map<FramebufferFormatID, FramebufferFormat> framebuffer_formats;
+ HashMap<FramebufferFormatID, FramebufferFormat> framebuffer_formats;
struct Framebuffer {
FramebufferFormatID format_id = 0;
@@ -391,14 +392,16 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t storage_mask = 0;
Vector<RID> texture_ids;
+ InvalidationCallback invalidated_callback = nullptr;
+ void *invalidated_callback_userdata = nullptr;
struct Version {
VkFramebuffer framebuffer = VK_NULL_HANDLE;
- VkRenderPass render_pass = VK_NULL_HANDLE; //this one is owned
+ VkRenderPass render_pass = VK_NULL_HANDLE; // This one is owned.
uint32_t subpass_count = 1;
};
- Map<VersionKey, Version> framebuffers;
+ RBMap<VersionKey, Version> framebuffers;
Size2 size;
uint32_t view_count;
};
@@ -451,23 +454,23 @@ class RenderingDeviceVulkan : public RenderingDevice {
return false;
}
}
- return true; //they are equal
+ return true; // They are equal.
}
}
uint32_t hash() const {
int vdc = vertex_formats.size();
- uint32_t h = hash_djb2_one_32(vdc);
+ uint32_t h = hash_murmur3_one_32(vdc);
const VertexAttribute *ptr = vertex_formats.ptr();
for (int i = 0; i < vdc; i++) {
const VertexAttribute &vd = ptr[i];
- h = hash_djb2_one_32(vd.location, h);
- h = hash_djb2_one_32(vd.offset, h);
- h = hash_djb2_one_32(vd.format, h);
- h = hash_djb2_one_32(vd.stride, h);
- h = hash_djb2_one_32(vd.frequency, h);
+ h = hash_murmur3_one_32(vd.location, h);
+ h = hash_murmur3_one_32(vd.offset, h);
+ h = hash_murmur3_one_32(vd.format, h);
+ h = hash_murmur3_one_32(vd.stride, h);
+ h = hash_murmur3_one_32(vd.frequency, h);
}
- return h;
+ return hash_fmix32(h);
}
};
@@ -488,7 +491,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
VkPipelineVertexInputStateCreateInfo create_info;
};
- Map<VertexFormatID, VertexDescriptionCache> vertex_formats;
+ HashMap<VertexFormatID, VertexDescriptionCache> vertex_formats;
struct VertexArray {
RID buffer;
@@ -496,14 +499,14 @@ class RenderingDeviceVulkan : public RenderingDevice {
int vertex_count = 0;
uint32_t max_instances_allowed = 0;
- Vector<VkBuffer> buffers; //not owned, just referenced
+ Vector<VkBuffer> buffers; // Not owned, just referenced.
Vector<VkDeviceSize> offsets;
};
RID_Owner<VertexArray, true> vertex_array_owner;
struct IndexBuffer : public Buffer {
- uint32_t max_index = 0; //used for validation
+ 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;
@@ -512,8 +515,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
RID_Owner<IndexBuffer, true> index_buffer_owner;
struct IndexArray {
- uint32_t max_index = 0; //remember the maximum index here too, for validation
- VkBuffer buffer; //not owned, inherited from index buffer
+ uint32_t max_index = 0; // Remember the maximum index here too, for validation.
+ VkBuffer buffer; // Not owned, inherited from index buffer.
uint32_t offset = 0;
uint32_t indices = 0;
VkIndexType index_type = VK_INDEX_TYPE_NONE_NV;
@@ -544,12 +547,13 @@ class RenderingDeviceVulkan : public RenderingDevice {
struct UniformInfo {
UniformType type = UniformType::UNIFORM_TYPE_MAX;
+ bool writable = false;
int binding = 0;
uint32_t stages = 0;
- int length = 0; //size of arrays (in total elements), or ubos (in bytes * total elements)
+ 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);
+ return (binding != p_info.binding || type != p_info.type || writable != p_info.writable || stages != p_info.stages || length != p_info.length);
}
bool operator<(const UniformInfo &p_info) const {
@@ -559,6 +563,9 @@ class RenderingDeviceVulkan : public RenderingDevice {
if (type != p_info.type) {
return type < p_info.type;
}
+ if (writable != p_info.writable) {
+ return writable < p_info.writable;
+ }
if (stages != p_info.stages) {
return stages < p_info.stages;
}
@@ -592,7 +599,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
// Always grows, never shrinks, ensuring unique IDs, but we assume
// the amount of formats will never be a problem, as the amount of shaders
// in a game is limited.
- Map<UniformSetFormat, uint32_t> uniform_set_format_cache;
+ RBMap<UniformSetFormat, uint32_t> uniform_set_format_cache;
// Shaders in Vulkan are just pretty much
// precompiled blocks of SPIR-V bytecode. They
@@ -615,7 +622,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE;
};
- uint32_t vertex_input_mask = 0; //inputs used, this is mostly for validation
+ uint32_t vertex_input_mask = 0; // Inputs used, this is mostly for validation.
uint32_t fragment_output_mask = 0;
struct PushConstant {
@@ -633,13 +640,12 @@ class RenderingDeviceVulkan : public RenderingDevice {
};
bool is_compute = false;
- int max_output = 0;
Vector<Set> sets;
Vector<uint32_t> set_formats;
Vector<VkPipelineShaderStageCreateInfo> pipeline_stages;
Vector<SpecializationConstant> specialization_constants;
VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
- String name; //used for debug
+ String name; // Used for debug.
};
String _shader_uniform_debug(RID p_shader, int p_set = -1);
@@ -702,7 +708,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t usage;
};
- Map<DescriptorPoolKey, Set<DescriptorPool *>> descriptor_pools;
+ RBMap<DescriptorPoolKey, HashSet<DescriptorPool *>> descriptor_pools;
uint32_t max_descriptors_per_pool = 0;
DescriptorPool *_descriptor_pool_allocate(const DescriptorPoolKey &p_key);
@@ -711,7 +717,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
RID_Owner<Buffer, true> uniform_buffer_owner;
RID_Owner<Buffer, true> storage_buffer_owner;
- //texture buffer needs a view
+ // Texture buffer needs a view.
struct TextureBuffer {
Buffer buffer;
VkBufferView view = VK_NULL_HANDLE;
@@ -734,16 +740,16 @@ class RenderingDeviceVulkan : public RenderingDevice {
DescriptorPool *pool = nullptr;
DescriptorPoolKey pool_key;
VkDescriptorSet descriptor_set = VK_NULL_HANDLE;
- //VkPipelineLayout pipeline_layout; //not owned, inherited from shader
+ //VkPipelineLayout pipeline_layout; // Not owned, inherited from shader.
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
- UniformSetInvalidatedCallback invalidated_callback = nullptr;
+ 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.
+ InvalidationCallback invalidated_callback = nullptr;
void *invalidated_callback_userdata = nullptr;
};
@@ -765,7 +771,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
// was not supplied as intended.
struct RenderPipeline {
- //Cached values for validation
+ // Cached values for validation.
#ifdef DEBUG_ENABLED
struct Validation {
FramebufferFormatID framebuffer_format = 0;
@@ -777,10 +783,10 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t primitive_divisor = 0;
} validation;
#endif
- //Actual pipeline
+ // Actual pipeline.
RID shader;
Vector<uint32_t> set_formats;
- VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; // not owned, needed for push constants
+ 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;
@@ -791,7 +797,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
struct ComputePipeline {
RID shader;
Vector<uint32_t> set_formats;
- VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; // not owned, needed for push constants
+ 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;
@@ -817,7 +823,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
struct SplitDrawListAllocator {
VkCommandPool command_pool = VK_NULL_HANDLE;
- Vector<VkCommandBuffer> command_buffers; //one for each frame
+ Vector<VkCommandBuffer> command_buffers; // One for each frame.
};
Vector<SplitDrawListAllocator> split_draw_list_allocators;
@@ -866,11 +872,9 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t pipeline_dynamic_state = 0;
VertexFormatID pipeline_vertex_format = INVALID_ID;
RID pipeline_shader;
- 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 = 0;
bool pipeline_push_constant_supplied = false;
} validation;
@@ -886,8 +890,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
DrawList *draw_list = nullptr; // One for regular draw lists, multiple for split.
uint32_t draw_list_subpass_count = 0;
uint32_t draw_list_count = 0;
- VkRenderPass draw_list_render_pass;
- VkFramebuffer draw_list_vkframebuffer;
+ VkRenderPass draw_list_render_pass = VK_NULL_HANDLE;
+ VkFramebuffer draw_list_vkframebuffer = VK_NULL_HANDLE;
#ifdef DEBUG_ENABLED
FramebufferFormatID draw_list_framebuffer_format = INVALID_ID;
#endif
@@ -923,7 +927,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
};
struct State {
- Set<Texture *> textures_to_sampled_layout;
+ HashSet<Texture *> textures_to_sampled_layout;
SetState sets[MAX_UNIFORM_SETS];
uint32_t set_count = 0;
RID pipeline;
@@ -944,7 +948,6 @@ class RenderingDeviceVulkan : public RenderingDevice {
bool pipeline_active = false;
RID pipeline_shader;
uint32_t invalid_set_from = 0;
- Vector<uint32_t> pipeline_set_formats;
uint32_t pipeline_push_constant_size = 0;
bool pipeline_push_constant_supplied = false;
} validation;
@@ -972,7 +975,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
// when the frame is cycled.
struct Frame {
- //list in usage order, from last to free to first to free
+ // List in usage order, from last to free to first to free.
List<Buffer> buffers_to_dispose_of;
List<Texture> textures_to_dispose_of;
List<Framebuffer> framebuffers_to_dispose_of;
@@ -984,8 +987,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
List<ComputePipeline> compute_pipelines_to_dispose_of;
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
+ 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;
@@ -994,21 +997,21 @@ class RenderingDeviceVulkan : public RenderingDevice {
VkQueryPool timestamp_pool;
- String *timestamp_names = nullptr;
- uint64_t *timestamp_cpu_values = nullptr;
+ TightLocalVector<String> timestamp_names;
+ TightLocalVector<uint64_t> timestamp_cpu_values;
uint32_t timestamp_count = 0;
- String *timestamp_result_names = nullptr;
- uint64_t *timestamp_cpu_result_values = nullptr;
- uint64_t *timestamp_result_values = nullptr;
+ TightLocalVector<String> timestamp_result_names;
+ TightLocalVector<uint64_t> timestamp_cpu_result_values;
+ TightLocalVector<uint64_t> timestamp_result_values;
uint32_t timestamp_result_count = 0;
uint64_t index = 0;
};
uint32_t max_timestamp_query_elements = 0;
- 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
+ TightLocalVector<Frame> frames; // 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;
@@ -1016,6 +1019,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
void _free_pending_resources(int p_frame);
VmaAllocator allocator = nullptr;
+ HashMap<uint32_t, VmaPool> small_allocs_pools;
+ VmaPool _find_or_create_small_allocs_pool(uint32_t p_mem_type_index);
VulkanContext *context = nullptr;
@@ -1033,9 +1038,14 @@ class RenderingDeviceVulkan : public RenderingDevice {
void _finalize_command_bufers();
void _begin_frame();
+#ifdef DEV_ENABLED
+ HashMap<RID, String> resource_names;
+#endif
+
public:
virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data = Vector<Vector<uint8_t>>());
virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture);
+ virtual RID texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, uint64_t p_flags, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers);
virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D);
virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL);
@@ -1055,13 +1065,15 @@ public:
/*********************/
virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count = 1);
- virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, Vector<FramebufferPass> &p_passes, uint32_t p_view_count = 1);
+ virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, uint32_t p_view_count = 1);
virtual FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1);
virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass = 0);
virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
- virtual RID framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
+ virtual RID framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, const Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
virtual RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID);
+ virtual bool framebuffer_is_valid(RID p_framebuffer) const;
+ virtual void framebuffer_set_invalidation_callback(RID p_framebuffer, InvalidationCallback p_callback, void *p_userdata);
virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer);
@@ -1077,7 +1089,7 @@ public:
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
+ // 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);
virtual RID vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers);
@@ -1106,9 +1118,9 @@ public:
virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set);
virtual bool uniform_set_is_valid(RID p_uniform_set);
- virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata);
+ virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata);
- virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); //works for any buffer
+ virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); // Works for any buffer.
virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL);
virtual Vector<uint8_t> buffer_get_data(RID p_buffer);
@@ -1200,16 +1212,16 @@ public:
/**** Limits ****/
/****************/
- virtual int limit_get(Limit p_limit);
+ virtual uint64_t limit_get(Limit p_limit) const;
virtual void prepare_screen_for_drawing();
void initialize(VulkanContext *p_context, bool p_local_device = false);
void finalize();
- virtual void swap_buffers(); //for main device
+ virtual void swap_buffers(); // For main device.
- virtual void submit(); //for local device
- virtual void sync(); //for local device
+ virtual void submit(); // For local device.
+ virtual void sync(); // For local device.
virtual uint32_t get_frame_delay() const;
@@ -1226,10 +1238,13 @@ public:
virtual String get_device_vendor_name() const;
virtual String get_device_name() const;
virtual RenderingDevice::DeviceType get_device_type() const;
+ virtual String get_device_api_version() const;
virtual String get_device_pipeline_cache_uuid() const;
virtual uint64_t get_driver_resource(DriverResource p_resource, RID p_rid = RID(), uint64_t p_index = 0);
+ virtual bool has_feature(const Features p_feature) const;
+
RenderingDeviceVulkan();
~RenderingDeviceVulkan();
};
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index 1aa1bfddc8..afc3e78372 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -46,6 +46,20 @@
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define APP_SHORT_NAME "GodotEngine"
+VulkanHooks *VulkanContext::vulkan_hooks = nullptr;
+
+VkResult VulkanContext::vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
+ if (fpCreateRenderPass2KHR == nullptr) {
+ fpCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetInstanceProcAddr(inst, "vkCreateRenderPass2KHR");
+ }
+
+ if (fpCreateRenderPass2KHR == nullptr) {
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
+ } else {
+ return (fpCreateRenderPass2KHR)(device, pCreateInfo, pAllocator, pRenderPass);
+ }
+}
+
VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
@@ -70,20 +84,20 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(
strstr(pCallbackData->pMessage, "must be a memory object") != nullptr) {
return VK_FALSE;
}
- /*
- // This is a valid warning because its illegal in Vulkan, but in practice it should work according to VK_KHR_maintenance2
- if (strstr(pCallbackData->pMessage, "VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 with tiling VK_IMAGE_TILING_OPTIMAL does not support usage that includes VK_IMAGE_USAGE_STORAGE_BIT") != nullptr) {
- return VK_FALSE;
- }
- if (strstr(pCallbackData->pMessage, "VK_FORMAT_R4G4B4A4_UNORM_PACK16 with tiling VK_IMAGE_TILING_OPTIMAL does not support usage that includes VK_IMAGE_USAGE_STORAGE_BIT") != nullptr) {
- return VK_FALSE;
- }
-*/
// Workaround for Vulkan-Loader usability bug: https://github.com/KhronosGroup/Vulkan-Loader/issues/262.
if (strstr(pCallbackData->pMessage, "wrong ELF class: ELFCLASS32") != nullptr) {
return VK_FALSE;
}
+
+#ifdef WINDOWS_ENABLED
+ // Some software installs Vulkan overlays in Windows registry and never cleans them up on uninstall.
+ // So we get spammy error level messages from the loader about those - make them verbose instead.
+ if (strstr(pCallbackData->pMessage, "loader_get_json: Failed to open JSON file") != nullptr) {
+ messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
+ }
+#endif
+
if (pCallbackData->pMessageIdName && strstr(pCallbackData->pMessageIdName, "UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw") != nullptr) {
return VK_FALSE;
}
@@ -213,17 +227,17 @@ VkBool32 VulkanContext::_check_layers(uint32_t check_count, const char *const *c
Error VulkanContext::_get_preferred_validation_layers(uint32_t *count, const char *const **names) {
static const LocalVector<LocalVector<const char *>> instance_validation_layers_alt{
- // Preferred set of validation layers
+ // Preferred set of validation layers.
{ "VK_LAYER_KHRONOS_validation" },
- // Alternative (deprecated, removed in SDK 1.1.126.0) set of validation layers
+ // Alternative (deprecated, removed in SDK 1.1.126.0) set of validation layers.
{ "VK_LAYER_LUNARG_standard_validation" },
- // Alternative (deprecated, removed in SDK 1.1.121.1) set of validation layers
+ // Alternative (deprecated, removed in SDK 1.1.121.1) set of validation layers.
{ "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects" }
};
- // Clear out-arguments
+ // Clear out-arguments.
*count = 0;
if (names != nullptr) {
*names = nullptr;
@@ -267,7 +281,7 @@ typedef VkResult(VKAPI_PTR *_vkEnumerateInstanceVersion)(uint32_t *);
Error VulkanContext::_obtain_vulkan_version() {
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkApplicationInfo.html#_description
- // for Vulkan 1.0 vkEnumerateInstanceVersion is not available, including not in the loader we compile against on Android.
+ // For Vulkan 1.0 vkEnumerateInstanceVersion is not available, including not in the loader we compile against on Android.
_vkEnumerateInstanceVersion func = (_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion");
if (func != nullptr) {
uint32_t api_version;
@@ -277,15 +291,15 @@ Error VulkanContext::_obtain_vulkan_version() {
vulkan_minor = VK_API_VERSION_MINOR(api_version);
vulkan_patch = VK_API_VERSION_PATCH(api_version);
} else {
- // according to the documentation this shouldn't fail with anything except a memory allocation error
- // in which case we're in deep trouble anyway
+ // According to the documentation this shouldn't fail with anything except a memory allocation error
+ // in which case we're in deep trouble anyway.
ERR_FAIL_V(ERR_CANT_CREATE);
}
} else {
print_line("vkEnumerateInstanceVersion not available, assuming Vulkan 1.0.");
}
- // we don't go above 1.2
+ // We don't go above 1.2.
if ((vulkan_major > 1) || (vulkan_major == 1 && vulkan_minor > 2)) {
vulkan_major = 1;
vulkan_minor = 2;
@@ -301,7 +315,7 @@ Error VulkanContext::_initialize_extensions() {
enabled_extension_count = 0;
enabled_debug_utils = false;
enabled_debug_report = false;
- /* Look for instance extensions */
+ // Look for instance extensions.
VkBool32 surfaceExtFound = 0;
VkBool32 platformSurfaceExtFound = 0;
memset(extension_names, 0, sizeof(extension_names));
@@ -401,7 +415,7 @@ String VulkanContext::SubgroupCapabilities::supported_stages_desc() const {
res += ", STAGE_COMPUTE";
}
- /* these are not defined on Android GRMBL */
+ // These are not defined on Android GRMBL.
if (supportedStages & 0x00000100 /* VK_SHADER_STAGE_RAYGEN_BIT_KHR */) {
res += ", STAGE_RAYGEN_KHR";
}
@@ -427,7 +441,7 @@ String VulkanContext::SubgroupCapabilities::supported_stages_desc() const {
res += ", STAGE_MESH_NV";
}
- return res.substr(2); // remove first ", "
+ return res.substr(2); // Remove first ", ".
}
uint32_t VulkanContext::SubgroupCapabilities::supported_operations_flags_rd() const {
@@ -492,19 +506,22 @@ String VulkanContext::SubgroupCapabilities::supported_operations_desc() const {
res += ", FEATURE_PARTITIONED_NV";
}
- return res.substr(2); // remove first ", "
+ return res.substr(2); // Remove first ", ".
}
Error VulkanContext::_check_capabilities() {
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_multiview.html
// https://www.khronos.org/blog/vulkan-subgroup-tutorial
- // for Vulkan 1.0 vkGetPhysicalDeviceProperties2 is not available, including not in the loader we compile against on Android.
+ // For Vulkan 1.0 vkGetPhysicalDeviceProperties2 is not available, including not in the loader we compile against on Android.
- // so we check if the functions are accessible by getting their function pointers and skipping if not
- // (note that the desktop loader does a better job here but the android loader doesn't)
+ // So we check if the functions are accessible by getting their function pointers and skipping if not
+ // (note that the desktop loader does a better job here but the android loader doesn't.)
- // assume not supported until proven otherwise
+ // Assume not supported until proven otherwise.
+ vrs_capabilities.pipeline_vrs_supported = false;
+ vrs_capabilities.primitive_vrs_supported = false;
+ vrs_capabilities.attachment_vrs_supported = false;
multiview_capabilities.is_supported = false;
multiview_capabilities.geometry_shader_is_supported = false;
multiview_capabilities.tessellation_shader_is_supported = false;
@@ -514,82 +531,142 @@ Error VulkanContext::_check_capabilities() {
subgroup_capabilities.supportedStages = 0;
subgroup_capabilities.supportedOperations = 0;
subgroup_capabilities.quadOperationsInAllStages = false;
+ shader_capabilities.shader_float16_is_supported = false;
+ shader_capabilities.shader_int8_is_supported = false;
+ storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = false;
+ storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported = false;
+ storage_buffer_capabilities.storage_push_constant_16_is_supported = false;
+ storage_buffer_capabilities.storage_input_output_16 = false;
+
+ // Check for extended features.
+ PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2");
+ if (vkGetPhysicalDeviceFeatures2_func == nullptr) {
+ // In Vulkan 1.0 might be accessible under its original extension name.
+ vkGetPhysicalDeviceFeatures2_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2KHR");
+ }
+ if (vkGetPhysicalDeviceFeatures2_func != nullptr) {
+ // Check our extended features.
+ VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features = {
+ /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR,
+ /*pNext*/ nullptr,
+ /*pipelineFragmentShadingRate*/ false,
+ /*primitiveFragmentShadingRate*/ false,
+ /*attachmentFragmentShadingRate*/ false,
+ };
- // check for extended features
- PFN_vkGetPhysicalDeviceFeatures2 device_features_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2");
- if (device_features_func == nullptr) {
- // In Vulkan 1.0 might be accessible under its original extension name
- device_features_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2KHR");
- }
- if (device_features_func != nullptr) {
- // check our extended features
- VkPhysicalDeviceMultiviewFeatures multiview_features;
- multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
- multiview_features.pNext = nullptr;
+ VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features = {
+ /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR,
+ /*pNext*/ &vrs_features,
+ /*shaderFloat16*/ false,
+ /*shaderInt8*/ false,
+ };
+
+ VkPhysicalDevice16BitStorageFeaturesKHR storage_feature = {
+ /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR,
+ /*pNext*/ &shader_features,
+ /*storageBuffer16BitAccess*/ false,
+ /*uniformAndStorageBuffer16BitAccess*/ false,
+ /*storagePushConstant16*/ false,
+ /*storageInputOutput16*/ false,
+ };
+
+ VkPhysicalDeviceMultiviewFeatures multiview_features = {
+ /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES,
+ /*pNext*/ &storage_feature,
+ /*multiview*/ false,
+ /*multiviewGeometryShader*/ false,
+ /*multiviewTessellationShader*/ false,
+ };
VkPhysicalDeviceFeatures2 device_features;
device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
device_features.pNext = &multiview_features;
- device_features_func(gpu, &device_features);
+ vkGetPhysicalDeviceFeatures2_func(gpu, &device_features);
+
+ vrs_capabilities.pipeline_vrs_supported = vrs_features.pipelineFragmentShadingRate;
+ vrs_capabilities.primitive_vrs_supported = vrs_features.primitiveFragmentShadingRate;
+ vrs_capabilities.attachment_vrs_supported = vrs_features.attachmentFragmentShadingRate;
+
multiview_capabilities.is_supported = multiview_features.multiview;
multiview_capabilities.geometry_shader_is_supported = multiview_features.multiviewGeometryShader;
multiview_capabilities.tessellation_shader_is_supported = multiview_features.multiviewTessellationShader;
- VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features;
- shader_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR;
- shader_features.pNext = nullptr;
-
- device_features.pNext = &shader_features;
-
- device_features_func(gpu, &device_features);
shader_capabilities.shader_float16_is_supported = shader_features.shaderFloat16;
+ shader_capabilities.shader_int8_is_supported = shader_features.shaderInt8;
- VkPhysicalDevice16BitStorageFeaturesKHR storage_feature;
- storage_feature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR;
- storage_feature.pNext = nullptr;
-
- device_features.pNext = &storage_feature;
-
- device_features_func(gpu, &device_features);
storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = storage_feature.storageBuffer16BitAccess;
+ storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported = storage_feature.uniformAndStorageBuffer16BitAccess;
+ storage_buffer_capabilities.storage_push_constant_16_is_supported = storage_feature.storagePushConstant16;
+ storage_buffer_capabilities.storage_input_output_16 = storage_feature.storageInputOutput16;
}
- // check extended properties
+ // Check extended properties.
PFN_vkGetPhysicalDeviceProperties2 device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2");
if (device_properties_func == nullptr) {
- // In Vulkan 1.0 might be accessible under its original extension name
+ // In Vulkan 1.0 might be accessible under its original extension name.
device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2KHR");
}
if (device_properties_func != nullptr) {
+ VkPhysicalDeviceFragmentShadingRatePropertiesKHR vrsProperties;
VkPhysicalDeviceMultiviewProperties multiviewProperties;
VkPhysicalDeviceSubgroupProperties subgroupProperties;
VkPhysicalDeviceProperties2 physicalDeviceProperties;
+ void *nextptr = nullptr;
subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
- subgroupProperties.pNext = nullptr;
-
- physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+ subgroupProperties.pNext = nextptr;
+ nextptr = &subgroupProperties;
if (multiview_capabilities.is_supported) {
multiviewProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
- multiviewProperties.pNext = &subgroupProperties;
+ multiviewProperties.pNext = nextptr;
- physicalDeviceProperties.pNext = &multiviewProperties;
- } else {
- physicalDeviceProperties.pNext = &subgroupProperties;
+ nextptr = &multiviewProperties;
}
+ if (vrs_capabilities.attachment_vrs_supported) {
+ vrsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
+ vrsProperties.pNext = nextptr;
+
+ nextptr = &vrsProperties;
+ }
+
+ physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+ physicalDeviceProperties.pNext = nextptr;
+
device_properties_func(gpu, &physicalDeviceProperties);
subgroup_capabilities.size = subgroupProperties.subgroupSize;
subgroup_capabilities.supportedStages = subgroupProperties.supportedStages;
subgroup_capabilities.supportedOperations = subgroupProperties.supportedOperations;
// Note: quadOperationsInAllStages will be true if:
- // - supportedStages has VK_SHADER_STAGE_ALL_GRAPHICS + VK_SHADER_STAGE_COMPUTE_BIT
- // - supportedOperations has VK_SUBGROUP_FEATURE_QUAD_BIT
+ // - supportedStages has VK_SHADER_STAGE_ALL_GRAPHICS + VK_SHADER_STAGE_COMPUTE_BIT.
+ // - supportedOperations has VK_SUBGROUP_FEATURE_QUAD_BIT.
subgroup_capabilities.quadOperationsInAllStages = subgroupProperties.quadOperationsInAllStages;
+ if (vrs_capabilities.pipeline_vrs_supported || vrs_capabilities.primitive_vrs_supported || vrs_capabilities.attachment_vrs_supported) {
+ print_verbose("- Vulkan Variable Rate Shading supported:");
+ if (vrs_capabilities.pipeline_vrs_supported) {
+ print_verbose(" Pipeline fragment shading rate");
+ }
+ if (vrs_capabilities.primitive_vrs_supported) {
+ print_verbose(" Primitive fragment shading rate");
+ }
+ if (vrs_capabilities.attachment_vrs_supported) {
+ // TODO expose these somehow to the end user.
+ vrs_capabilities.min_texel_size.x = vrsProperties.minFragmentShadingRateAttachmentTexelSize.width;
+ vrs_capabilities.min_texel_size.y = vrsProperties.minFragmentShadingRateAttachmentTexelSize.height;
+ vrs_capabilities.max_texel_size.x = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.width;
+ vrs_capabilities.max_texel_size.y = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.height;
+
+ print_verbose(String(" Attachment fragment shading rate") + String(", min texel size: (") + itos(vrs_capabilities.min_texel_size.x) + String(", ") + itos(vrs_capabilities.min_texel_size.y) + String(")") + String(", max texel size: (") + itos(vrs_capabilities.max_texel_size.x) + String(", ") + itos(vrs_capabilities.max_texel_size.y) + String(")"));
+ }
+
+ } else {
+ print_verbose("- Vulkan Variable Rate Shading not supported");
+ }
+
if (multiview_capabilities.is_supported) {
multiview_capabilities.max_view_count = multiviewProperties.maxMultiviewViewCount;
multiview_capabilities.max_instance_count = multiviewProperties.maxMultiviewInstanceIndex;
@@ -616,10 +693,10 @@ Error VulkanContext::_check_capabilities() {
}
Error VulkanContext::_create_instance() {
- /* obtain version */
+ // Obtain Vulkan version.
_obtain_vulkan_version();
- /* initialise extensions */
+ // Initialize extensions.
{
Error err = _initialize_extensions();
if (err != OK) {
@@ -654,7 +731,7 @@ Error VulkanContext::_create_instance() {
VkDebugUtilsMessengerCreateInfoEXT dbg_messenger_create_info;
VkDebugReportCallbackCreateInfoEXT dbg_report_callback_create_info{};
if (enabled_debug_utils) {
- // VK_EXT_debug_utils style
+ // VK_EXT_debug_utils style.
dbg_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
dbg_messenger_create_info.pNext = nullptr;
dbg_messenger_create_info.flags = 0;
@@ -678,19 +755,27 @@ Error VulkanContext::_create_instance() {
inst_info.pNext = &dbg_report_callback_create_info;
}
- VkResult err = vkCreateInstance(&inst_info, nullptr, &inst);
- ERR_FAIL_COND_V_MSG(err == VK_ERROR_INCOMPATIBLE_DRIVER, ERR_CANT_CREATE,
- "Cannot find a compatible Vulkan installable client driver (ICD).\n\n"
- "vkCreateInstance Failure");
- ERR_FAIL_COND_V_MSG(err == VK_ERROR_EXTENSION_NOT_PRESENT, ERR_CANT_CREATE,
- "Cannot find a specified extension library.\n"
- "Make sure your layers path is set appropriately.\n"
- "vkCreateInstance Failure");
- ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE,
- "vkCreateInstance failed.\n\n"
- "Do you have a compatible Vulkan installable client driver (ICD) installed?\n"
- "Please look at the Getting Started guide for additional information.\n"
- "vkCreateInstance Failure");
+ VkResult err;
+
+ if (vulkan_hooks) {
+ if (!vulkan_hooks->create_vulkan_instance(&inst_info, &inst)) {
+ return ERR_CANT_CREATE;
+ }
+ } else {
+ err = vkCreateInstance(&inst_info, nullptr, &inst);
+ ERR_FAIL_COND_V_MSG(err == VK_ERROR_INCOMPATIBLE_DRIVER, ERR_CANT_CREATE,
+ "Cannot find a compatible Vulkan installable client driver (ICD).\n\n"
+ "vkCreateInstance Failure");
+ ERR_FAIL_COND_V_MSG(err == VK_ERROR_EXTENSION_NOT_PRESENT, ERR_CANT_CREATE,
+ "Cannot find a specified extension library.\n"
+ "Make sure your layers path is set appropriately.\n"
+ "vkCreateInstance Failure");
+ ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE,
+ "vkCreateInstance failed.\n\n"
+ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n"
+ "Please look at the Getting Started guide for additional information.\n"
+ "vkCreateInstance Failure");
+ }
inst_initialized = true;
@@ -699,8 +784,7 @@ Error VulkanContext::_create_instance() {
#endif
if (enabled_debug_utils) {
- // Setup VK_EXT_debug_utils function pointers always (we use them for
- // debug labels and names).
+ // Setup VK_EXT_debug_utils function pointers always (we use them for debug labels and names).
CreateDebugUtilsMessengerEXT =
(PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugUtilsMessengerEXT");
DestroyDebugUtilsMessengerEXT =
@@ -773,7 +857,7 @@ Error VulkanContext::_create_instance() {
}
Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
- /* Make initial call to query gpu_count, then second call for gpu info*/
+ // Make initial call to query gpu_count, then second call for gpu info.
uint32_t gpu_count = 0;
VkResult err = vkEnumeratePhysicalDevices(inst, &gpu_count, nullptr);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
@@ -803,116 +887,131 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
{ 0, nullptr },
};
- // TODO: At least on Linux Laptops integrated GPUs fail with Vulkan in many instances.
- // The device should really be a preference, but for now choosing a discrete GPU over the
- // integrated one is better than the default.
-
int32_t device_index = -1;
- int type_selected = -1;
- print_verbose("Vulkan devices:");
- for (uint32_t i = 0; i < gpu_count; ++i) {
- VkPhysicalDeviceProperties props;
- vkGetPhysicalDeviceProperties(physical_devices[i], &props);
-
- bool present_supported = false;
-
- uint32_t device_queue_family_count = 0;
- vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, nullptr);
- VkQueueFamilyProperties *device_queue_props = (VkQueueFamilyProperties *)malloc(device_queue_family_count * sizeof(VkQueueFamilyProperties));
- vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, device_queue_props);
- for (uint32_t j = 0; j < device_queue_family_count; j++) {
- VkBool32 supports;
- vkGetPhysicalDeviceSurfaceSupportKHR(physical_devices[i], j, p_surface, &supports);
- if (supports && ((device_queue_props[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)) {
- present_supported = true;
- } else {
- continue;
- }
- }
- String name = props.deviceName;
- String vendor = "Unknown";
- String dev_type;
- switch (props.deviceType) {
- case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: {
- dev_type = "Discrete";
- } break;
- case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: {
- dev_type = "Integrated";
- } break;
- case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: {
- dev_type = "Virtual";
- } break;
- case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_CPU: {
- dev_type = "CPU";
- } break;
- default: {
- dev_type = "Other";
- } break;
+ if (vulkan_hooks) {
+ if (!vulkan_hooks->get_physical_device(&gpu)) {
+ return ERR_CANT_CREATE;
}
- uint32_t vendor_idx = 0;
- while (vendor_names[vendor_idx].name != nullptr) {
- if (props.vendorID == vendor_names[vendor_idx].id) {
- vendor = vendor_names[vendor_idx].name;
+
+ // Not really needed but nice to print the correct entry.
+ for (uint32_t i = 0; i < gpu_count; ++i) {
+ if (physical_devices[i] == gpu) {
+ device_index = i;
break;
}
- vendor_idx++;
}
- free(device_queue_props);
- print_verbose(" #" + itos(i) + ": " + vendor + " " + name + " - " + (present_supported ? "Supported" : "Unsupported") + ", " + dev_type);
-
- if (present_supported) { // Select first supported device of preferred type: Discrete > Integrated > Virtual > CPU > Other.
+ } else {
+ // TODO: At least on Linux Laptops integrated GPUs fail with Vulkan in many instances.
+ // The device should really be a preference, but for now choosing a discrete GPU over the
+ // integrated one is better than the default.
+
+ int type_selected = -1;
+ print_verbose("Vulkan devices:");
+ for (uint32_t i = 0; i < gpu_count; ++i) {
+ VkPhysicalDeviceProperties props;
+ vkGetPhysicalDeviceProperties(physical_devices[i], &props);
+
+ bool present_supported = false;
+
+ uint32_t device_queue_family_count = 0;
+ vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, nullptr);
+ VkQueueFamilyProperties *device_queue_props = (VkQueueFamilyProperties *)malloc(device_queue_family_count * sizeof(VkQueueFamilyProperties));
+ vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, device_queue_props);
+ for (uint32_t j = 0; j < device_queue_family_count; j++) {
+ VkBool32 supports;
+ vkGetPhysicalDeviceSurfaceSupportKHR(physical_devices[i], j, p_surface, &supports);
+ if (supports && ((device_queue_props[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)) {
+ present_supported = true;
+ } else {
+ continue;
+ }
+ }
+ String name = props.deviceName;
+ String vendor = "Unknown";
+ String dev_type;
switch (props.deviceType) {
case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: {
- if (type_selected < 4) {
- type_selected = 4;
- device_index = i;
- }
+ dev_type = "Discrete";
} break;
case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: {
- if (type_selected < 3) {
- type_selected = 3;
- device_index = i;
- }
+ dev_type = "Integrated";
} break;
case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: {
- if (type_selected < 2) {
- type_selected = 2;
- device_index = i;
- }
+ dev_type = "Virtual";
} break;
case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_CPU: {
- if (type_selected < 1) {
- type_selected = 1;
- device_index = i;
- }
+ dev_type = "CPU";
} break;
default: {
- if (type_selected < 0) {
- type_selected = 0;
- device_index = i;
- }
+ dev_type = "Other";
} break;
}
+ uint32_t vendor_idx = 0;
+ while (vendor_names[vendor_idx].name != nullptr) {
+ if (props.vendorID == vendor_names[vendor_idx].id) {
+ vendor = vendor_names[vendor_idx].name;
+ break;
+ }
+ vendor_idx++;
+ }
+ free(device_queue_props);
+ print_verbose(" #" + itos(i) + ": " + vendor + " " + name + " - " + (present_supported ? "Supported" : "Unsupported") + ", " + dev_type);
+
+ if (present_supported) { // Select first supported device of preferred type: Discrete > Integrated > Virtual > CPU > Other.
+ switch (props.deviceType) {
+ case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: {
+ if (type_selected < 4) {
+ type_selected = 4;
+ device_index = i;
+ }
+ } break;
+ case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: {
+ if (type_selected < 3) {
+ type_selected = 3;
+ device_index = i;
+ }
+ } break;
+ case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: {
+ if (type_selected < 2) {
+ type_selected = 2;
+ device_index = i;
+ }
+ } break;
+ case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_CPU: {
+ if (type_selected < 1) {
+ type_selected = 1;
+ device_index = i;
+ }
+ } break;
+ default: {
+ if (type_selected < 0) {
+ type_selected = 0;
+ device_index = i;
+ }
+ } break;
+ }
+ }
}
- }
- int32_t user_device_index = Engine::get_singleton()->get_gpu_index(); // Force user selected GPU.
- if (user_device_index >= 0 && user_device_index < (int32_t)gpu_count) {
- device_index = user_device_index;
- }
+ int32_t user_device_index = Engine::get_singleton()->get_gpu_index(); // Force user selected GPU.
+ if (user_device_index >= 0 && user_device_index < (int32_t)gpu_count) {
+ device_index = user_device_index;
+ }
- ERR_FAIL_COND_V_MSG(device_index == -1, ERR_CANT_CREATE, "None of Vulkan devices supports both graphics and present queues.");
+ ERR_FAIL_COND_V_MSG(device_index == -1, ERR_CANT_CREATE, "None of Vulkan devices supports both graphics and present queues.");
+
+ gpu = physical_devices[device_index];
+ }
- gpu = physical_devices[device_index];
free(physical_devices);
- /* Look for device extensions */
+ // Look for device extensions.
uint32_t device_extension_count = 0;
VkBool32 swapchainExtFound = 0;
enabled_extension_count = 0;
memset(extension_names, 0, sizeof(extension_names));
- /* Get identifier properties */
+ // Get identifier properties.
vkGetPhysicalDeviceProperties(gpu, &gpu_props);
device_name = gpu_props.deviceName;
@@ -954,9 +1053,16 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
extension_names[enabled_extension_count++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
}
if (!strcmp(VK_KHR_MULTIVIEW_EXTENSION_NAME, device_extensions[i].extensionName)) {
- // if multiview is supported, enable it
+ // If multiview is supported, enable it.
extension_names[enabled_extension_count++] = VK_KHR_MULTIVIEW_EXTENSION_NAME;
}
+ if (!strcmp(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME, device_extensions[i].extensionName)) {
+ // if shading rate image is supported, enable it
+ extension_names[enabled_extension_count++] = VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME;
+ }
+ if (!strcmp(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, device_extensions[i].extensionName)) {
+ extension_names[enabled_extension_count++] = VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME;
+ }
if (enabled_extension_count >= MAX_EXTENSIONS) {
free(device_extensions);
ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG");
@@ -1007,19 +1113,18 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
" extension.\n\nDo you have a compatible Vulkan installable client driver (ICD) installed?\n"
"vkCreateInstance Failure");
- /* Call with nullptr data to get count */
+ // Call with nullptr data to get count.
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, nullptr);
ERR_FAIL_COND_V(queue_family_count == 0, ERR_CANT_CREATE);
queue_props = (VkQueueFamilyProperties *)malloc(queue_family_count * sizeof(VkQueueFamilyProperties));
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, queue_props);
-
// Query fine-grained feature support for this device.
// If app has specific feature requirements it should check supported
// 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
+ physical_device_features.robustBufferAccess = false; // Turn off robust buffer access, which can hamper performance on some hardware.
#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
{ \
@@ -1034,7 +1139,7 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfacePresentModesKHR);
GET_INSTANCE_PROC_ADDR(inst, GetSwapchainImagesKHR);
- // get info about what our vulkan driver is capable off
+ // Gets capability info for current Vulkan driver.
{
Error res = _check_capabilities();
if (res != OK) {
@@ -1057,9 +1162,73 @@ Error VulkanContext::_create_device() {
queues[0].pQueuePriorities = queue_priorities;
queues[0].flags = 0;
+ // Before we retrieved what is supported, here we tell Vulkan we want to enable these features using the same structs.
+ void *nextptr = nullptr;
+
+ VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features = {
+ /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR,
+ /*pNext*/ nextptr,
+ /*shaderFloat16*/ shader_capabilities.shader_float16_is_supported,
+ /*shaderInt8*/ shader_capabilities.shader_int8_is_supported,
+ };
+ nextptr = &shader_features;
+
+ VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features;
+ if (vrs_capabilities.pipeline_vrs_supported || vrs_capabilities.primitive_vrs_supported || vrs_capabilities.attachment_vrs_supported) {
+ // Insert into our chain to enable these features if they are available.
+ vrs_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
+ vrs_features.pNext = nextptr;
+ vrs_features.pipelineFragmentShadingRate = vrs_capabilities.pipeline_vrs_supported;
+ vrs_features.primitiveFragmentShadingRate = vrs_capabilities.primitive_vrs_supported;
+ vrs_features.attachmentFragmentShadingRate = vrs_capabilities.attachment_vrs_supported;
+
+ nextptr = &vrs_features;
+ }
+
+ VkPhysicalDeviceVulkan11Features vulkan11features;
+ VkPhysicalDevice16BitStorageFeaturesKHR storage_feature;
+ VkPhysicalDeviceMultiviewFeatures multiview_features;
+ if (vulkan_major > 1 || vulkan_minor >= 2) {
+ // In Vulkan 1.2 and newer we use a newer struct to enable various features.
+
+ vulkan11features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
+ vulkan11features.pNext = nextptr;
+ vulkan11features.storageBuffer16BitAccess = storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported;
+ vulkan11features.uniformAndStorageBuffer16BitAccess = storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported;
+ vulkan11features.storagePushConstant16 = storage_buffer_capabilities.storage_push_constant_16_is_supported;
+ vulkan11features.storageInputOutput16 = storage_buffer_capabilities.storage_input_output_16;
+ vulkan11features.multiview = multiview_capabilities.is_supported;
+ vulkan11features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported;
+ vulkan11features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported;
+ vulkan11features.variablePointersStorageBuffer = 0;
+ vulkan11features.variablePointers = 0;
+ vulkan11features.protectedMemory = 0;
+ vulkan11features.samplerYcbcrConversion = 0;
+ vulkan11features.shaderDrawParameters = 0;
+ nextptr = &vulkan11features;
+ } else {
+ // On Vulkan 1.0 and 1.1 we use our older structs to initialise these features.
+ storage_feature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR;
+ storage_feature.pNext = nextptr;
+ storage_feature.storageBuffer16BitAccess = storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported;
+ storage_feature.uniformAndStorageBuffer16BitAccess = storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported;
+ storage_feature.storagePushConstant16 = storage_buffer_capabilities.storage_push_constant_16_is_supported;
+ storage_feature.storageInputOutput16 = storage_buffer_capabilities.storage_input_output_16;
+ nextptr = &storage_feature;
+
+ if (vulkan_major == 1 && vulkan_minor == 1) {
+ multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
+ multiview_features.pNext = nextptr;
+ multiview_features.multiview = multiview_capabilities.is_supported;
+ multiview_features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported;
+ multiview_features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported;
+ nextptr = &multiview_features;
+ }
+ }
+
VkDeviceCreateInfo sdevice = {
/*sType*/ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
- /*pNext*/ nullptr,
+ /*pNext*/ nextptr,
/*flags*/ 0,
/*queueCreateInfoCount*/ 1,
/*pQueueCreateInfos*/ queues,
@@ -1067,8 +1236,7 @@ Error VulkanContext::_create_device() {
/*ppEnabledLayerNames*/ nullptr,
/*enabledExtensionCount*/ enabled_extension_count,
/*ppEnabledExtensionNames*/ (const char *const *)extension_names,
- /*pEnabledFeatures*/ &physical_device_features, // If specific features are required, pass them in here
-
+ /*pEnabledFeatures*/ &physical_device_features, // If specific features are required, pass them in here.
};
if (separate_present_queue) {
queues[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
@@ -1080,39 +1248,15 @@ Error VulkanContext::_create_device() {
sdevice.queueCreateInfoCount = 2;
}
- VkPhysicalDeviceVulkan11Features vulkan11features;
- VkPhysicalDeviceMultiviewFeatures multiview_features;
- if (vulkan_major > 1 || vulkan_minor >= 2) {
- vulkan11features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
- vulkan11features.pNext = nullptr;
- // !BAS! Need to figure out which ones of these we want enabled...
- vulkan11features.storageBuffer16BitAccess = 0;
- vulkan11features.uniformAndStorageBuffer16BitAccess = 0;
- vulkan11features.storagePushConstant16 = 0;
- vulkan11features.storageInputOutput16 = 0;
- vulkan11features.multiview = multiview_capabilities.is_supported;
- vulkan11features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported;
- vulkan11features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported;
- vulkan11features.variablePointersStorageBuffer = 0;
- vulkan11features.variablePointers = 0;
- vulkan11features.protectedMemory = 0;
- vulkan11features.samplerYcbcrConversion = 0;
- vulkan11features.shaderDrawParameters = 0;
-
- sdevice.pNext = &vulkan11features;
- } else if (vulkan_major == 1 && vulkan_minor == 1) {
- multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
- multiview_features.pNext = nullptr;
- multiview_features.multiview = multiview_capabilities.is_supported;
- multiview_features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported;
- multiview_features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported;
-
- sdevice.pNext = &multiview_features;
+ if (vulkan_hooks) {
+ if (!vulkan_hooks->create_vulkan_device(&sdevice, &device)) {
+ return ERR_CANT_CREATE;
+ }
+ } else {
+ err = vkCreateDevice(gpu, &sdevice, nullptr, &device);
+ ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
}
- err = vkCreateDevice(gpu, &sdevice, nullptr, &device);
- ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-
return OK;
}
@@ -1124,7 +1268,7 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) {
}
// Search for a graphics and a present queue in the array of queue
- // families, try to find one that supports both
+ // families, try to find one that supports both.
uint32_t graphicsQueueFamilyIndex = UINT32_MAX;
uint32_t presentQueueFamilyIndex = UINT32_MAX;
for (uint32_t i = 0; i < queue_family_count; i++) {
@@ -1154,7 +1298,7 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) {
free(supportsPresent);
- // Generate error if could not find both a graphics and a present queue
+ // Generate error if could not find both a graphics and a present queue.
ERR_FAIL_COND_V_MSG(graphicsQueueFamilyIndex == UINT32_MAX || presentQueueFamilyIndex == UINT32_MAX, ERR_CANT_CREATE,
"Could not find both graphics and present queues\n");
@@ -1210,7 +1354,7 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) {
color_space = surfFormats[0].colorSpace;
} else {
// These should be ordered with the ones we want to use on top and fallback modes further down
- // we want an 32bit RGBA unsigned normalised buffer or similar
+ // we want a 32bit RGBA unsigned normalised buffer or similar.
const VkFormat allowed_formats[] = {
VK_FORMAT_B8G8R8A8_UNORM,
VK_FORMAT_R8G8B8A8_UNORM
@@ -1222,7 +1366,7 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) {
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "formatCount less than 1");
}
- // Find the first format that we support
+ // Find the first format that we support.
format = VK_FORMAT_UNDEFINED;
for (uint32_t af = 0; af < allowed_formats_count && format == VK_FORMAT_UNDEFINED; af++) {
for (uint32_t sf = 0; sf < formatCount && format == VK_FORMAT_UNDEFINED; sf++) {
@@ -1254,7 +1398,7 @@ Error VulkanContext::_create_semaphores() {
VkResult err;
// Create semaphores to synchronize acquiring presentable buffers before
- // rendering and waiting for drawing to be complete before presenting
+ // rendering and waiting for drawing to be complete before presenting.
VkSemaphoreCreateInfo semaphoreCreateInfo = {
/*sType*/ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
/*pNext*/ nullptr,
@@ -1262,7 +1406,7 @@ Error VulkanContext::_create_semaphores() {
};
// Create fences that we can use to throttle if we get too far
- // ahead of the image presents
+ // ahead of the image presents.
VkFenceCreateInfo fence_ci = {
/*sType*/ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
/*pNext*/ nullptr,
@@ -1282,7 +1426,7 @@ Error VulkanContext::_create_semaphores() {
}
frame_index = 0;
- // Get Memory information and properties
+ // Get Memory information and properties.
vkGetPhysicalDeviceMemoryProperties(gpu, &memory_properties);
return OK;
@@ -1348,10 +1492,16 @@ int VulkanContext::window_get_height(DisplayServer::WindowID p_window) {
return windows[p_window].height;
}
+bool VulkanContext::window_is_valid_swapchain(DisplayServer::WindowID p_window) {
+ ERR_FAIL_COND_V(!windows.has(p_window), false);
+ Window *w = &windows[p_window];
+ return w->swapchain_image_resources != VK_NULL_HANDLE;
+}
+
VkRenderPass VulkanContext::window_get_render_pass(DisplayServer::WindowID p_window) {
ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE);
Window *w = &windows[p_window];
- //vulkan use of currentbuffer
+ // Vulkan use of currentbuffer.
return w->render_pass;
}
@@ -1359,8 +1509,12 @@ VkFramebuffer VulkanContext::window_get_framebuffer(DisplayServer::WindowID p_wi
ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE);
ERR_FAIL_COND_V(!buffers_prepared, VK_NULL_HANDLE);
Window *w = &windows[p_window];
- //vulkan use of currentbuffer
- return w->swapchain_image_resources[w->current_buffer].framebuffer;
+ // Vulkan use of currentbuffer.
+ if (w->swapchain_image_resources != VK_NULL_HANDLE) {
+ return w->swapchain_image_resources[w->current_buffer].framebuffer;
+ } else {
+ return VK_NULL_HANDLE;
+ }
}
void VulkanContext::window_destroy(DisplayServer::WindowID p_window_id) {
@@ -1380,7 +1534,7 @@ Error VulkanContext::_clean_up_swap_chain(Window *window) {
}
vkDeviceWaitIdle(device);
- //this destroys images associated it seems
+ // This destroys images associated it seems.
fpDestroySwapchainKHR(device, window->swapchain, nullptr);
window->swapchain = VK_NULL_HANDLE;
vkDestroyRenderPass(device, window->render_pass, nullptr);
@@ -1406,7 +1560,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
_clean_up_swap_chain(window);
}
- // Check the surface capabilities and formats
+ // Check the surface capabilities and formats.
VkSurfaceCapabilitiesKHR surfCapabilities;
err = fpGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu, window->surface, &surfCapabilities);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
@@ -1423,7 +1577,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
}
VkExtent2D swapchainExtent;
- // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
+ // Width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
if (surfCapabilities.currentExtent.width == 0xFFFFFFFF) {
// If the surface size is undefined, the size is set to the size
// of the images requested, which must fit within the minimum and
@@ -1443,7 +1597,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
swapchainExtent.height = surfCapabilities.maxImageExtent.height;
}
} else {
- // If the surface size is defined, the swap chain size must match
+ // If the surface size is defined, the swap chain size must match.
swapchainExtent = surfCapabilities.currentExtent;
window->width = surfCapabilities.currentExtent.width;
window->height = surfCapabilities.currentExtent.height;
@@ -1451,23 +1605,23 @@ Error VulkanContext::_update_swap_chain(Window *window) {
if (window->width == 0 || window->height == 0) {
free(presentModes);
- //likely window minimized, no swapchain created
+ // Likely window minimized, no swapchain created.
return OK;
}
// The FIFO present mode is guaranteed by the spec to be supported
// and to have no tearing. It's a great default present mode to use.
- // There are times when you may wish to use another present mode. The
- // following code shows how to select them, and the comments provide some
- // reasons you may wish to use them.
+ // There are times when you may wish to use another present mode. The
+ // following code shows how to select them, and the comments provide some
+ // reasons you may wish to use them.
//
// It should be noted that Vulkan 1.0 doesn't provide a method for
- // synchronizing rendering with the presentation engine's display. There
+ // synchronizing rendering with the presentation engine's display. There
// is a method provided for throttling rendering with the display, but
// there are some presentation engines for which this method will not work.
// If an application doesn't throttle its rendering, and if it renders much
// faster than the refresh rate of the display, this can waste power on
- // mobile devices. That is because power is being spent rendering images
+ // mobile devices. That is because power is being spent rendering images
// that may never be seen.
// VK_PRESENT_MODE_IMMEDIATE_KHR is for applications that don't care about
@@ -1512,8 +1666,23 @@ Error VulkanContext::_update_swap_chain(Window *window) {
if (present_mode_available) {
window->presentMode = requested_present_mode;
} else {
- WARN_PRINT("Requested VSync mode is not available!");
- window->vsync_mode = DisplayServer::VSYNC_ENABLED; //Set to default
+ String present_mode_string;
+ switch (window->vsync_mode) {
+ case DisplayServer::VSYNC_MAILBOX:
+ present_mode_string = "Mailbox";
+ break;
+ case DisplayServer::VSYNC_ADAPTIVE:
+ present_mode_string = "Adaptive";
+ break;
+ case DisplayServer::VSYNC_ENABLED:
+ present_mode_string = "Enabled";
+ break;
+ case DisplayServer::VSYNC_DISABLED:
+ present_mode_string = "Disabled";
+ break;
+ }
+ WARN_PRINT(vformat("The requested V-Sync mode %s is not available. Falling back to V-Sync mode Enabled.", present_mode_string));
+ window->vsync_mode = DisplayServer::VSYNC_ENABLED; // Set to default.
}
print_verbose("Using present mode: " + String(string_VkPresentModeKHR(window->presentMode)));
@@ -1522,15 +1691,15 @@ Error VulkanContext::_update_swap_chain(Window *window) {
// Determine the number of VkImages to use in the swap chain.
// Application desires to acquire 3 images at a time for triple
- // buffering
+ // buffering.
uint32_t desiredNumOfSwapchainImages = 3;
if (desiredNumOfSwapchainImages < surfCapabilities.minImageCount) {
desiredNumOfSwapchainImages = surfCapabilities.minImageCount;
}
// If maxImageCount is 0, we can ask for as many images as we want;
- // otherwise we're limited to maxImageCount
+ // otherwise we're limited to maxImageCount.
if ((surfCapabilities.maxImageCount > 0) && (desiredNumOfSwapchainImages > surfCapabilities.maxImageCount)) {
- // Application must settle for fewer images than desired:
+ // Application must settle for fewer images than desired.
desiredNumOfSwapchainImages = surfCapabilities.maxImageCount;
}
@@ -1541,7 +1710,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
preTransform = surfCapabilities.currentTransform;
}
- // Find a supported composite alpha mode - one of these is guaranteed to be set
+ // Find a supported composite alpha mode - one of these is guaranteed to be set.
VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = {
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
@@ -1588,7 +1757,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
if (swapchainImageCount == 0) {
- //assign here for the first time.
+ // Assign here for the first time.
swapchainImageCount = sp_image_count;
} else {
ERR_FAIL_COND_V(swapchainImageCount != sp_image_count, ERR_BUG);
@@ -1646,7 +1815,9 @@ Error VulkanContext::_update_swap_chain(Window *window) {
/******** FRAMEBUFFER ************/
{
- const VkAttachmentDescription attachment = {
+ const VkAttachmentDescription2KHR attachment = {
+ /*sType*/ VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR,
+ /*pNext*/ nullptr,
/*flags*/ 0,
/*format*/ format,
/*samples*/ VK_SAMPLE_COUNT_1_BIT,
@@ -1658,14 +1829,20 @@ Error VulkanContext::_update_swap_chain(Window *window) {
/*finalLayout*/ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
};
- const VkAttachmentReference color_reference = {
+ const VkAttachmentReference2KHR color_reference = {
+ /*sType*/ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR,
+ /*pNext*/ nullptr,
/*attachment*/ 0,
/*layout*/ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ /*aspectMask*/ 0,
};
- const VkSubpassDescription subpass = {
+ const VkSubpassDescription2KHR subpass = {
+ /*sType*/ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR,
+ /*pNext*/ nullptr,
/*flags*/ 0,
/*pipelineBindPoint*/ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ /*viewMask*/ 0,
/*inputAttachmentCount*/ 0,
/*pInputAttachments*/ nullptr,
/*colorAttachmentCount*/ 1,
@@ -1675,8 +1852,9 @@ Error VulkanContext::_update_swap_chain(Window *window) {
/*preserveAttachmentCount*/ 0,
/*pPreserveAttachments*/ nullptr,
};
- const VkRenderPassCreateInfo rp_info = {
- /*sTyp*/ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+
+ const VkRenderPassCreateInfo2KHR rp_info = {
+ /*sType*/ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR,
/*pNext*/ nullptr,
/*flags*/ 0,
/*attachmentCount*/ 1,
@@ -1685,9 +1863,11 @@ Error VulkanContext::_update_swap_chain(Window *window) {
/*pSubpasses*/ &subpass,
/*dependencyCount*/ 0,
/*pDependencies*/ nullptr,
+ /*correlatedViewMaskCount*/ 0,
+ /*pCorrelatedViewMasks*/ nullptr,
};
- err = vkCreateRenderPass(device, &rp_info, nullptr, &window->render_pass);
+ err = vkCreateRenderPass2KHR(device, &rp_info, nullptr, &window->render_pass);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
for (uint32_t i = 0; i < swapchainImageCount; i++) {
@@ -1760,7 +1940,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
}
}
- //reset current buffer
+ // Reset current buffer.
window->current_buffer = 0;
return OK;
@@ -1781,27 +1961,30 @@ Error VulkanContext::initialize() {
return OK;
}
-void VulkanContext::set_setup_buffer(const VkCommandBuffer &pCommandBuffer) {
- command_buffer_queue.write[0] = pCommandBuffer;
+void VulkanContext::set_setup_buffer(VkCommandBuffer p_command_buffer) {
+ command_buffer_queue.write[0] = p_command_buffer;
}
-void VulkanContext::append_command_buffer(const VkCommandBuffer &pCommandBuffer) {
+void VulkanContext::append_command_buffer(VkCommandBuffer p_command_buffer) {
if (command_buffer_queue.size() <= command_buffer_count) {
command_buffer_queue.resize(command_buffer_count + 1);
}
- command_buffer_queue.write[command_buffer_count] = pCommandBuffer;
+ command_buffer_queue.write[command_buffer_count] = p_command_buffer;
command_buffer_count++;
}
void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) {
- // ensure everything else pending is executed
+ // Ensure everything else pending is executed.
vkDeviceWaitIdle(device);
- //flush the pending setup buffer
+ // Flush the pending setup buffer.
- if (p_flush_setup && command_buffer_queue[0]) {
- //use a fence to wait for everything done
+ bool setup_flushable = p_flush_setup && command_buffer_queue[0];
+ bool pending_flushable = p_flush_pending && command_buffer_count > 1;
+
+ if (setup_flushable) {
+ // Use a fence to wait for everything done.
VkSubmitInfo submit_info;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.pNext = nullptr;
@@ -1810,33 +1993,33 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) {
submit_info.pWaitSemaphores = nullptr;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = command_buffer_queue.ptr();
- submit_info.signalSemaphoreCount = 0;
- submit_info.pSignalSemaphores = nullptr;
+ submit_info.signalSemaphoreCount = pending_flushable ? 1 : 0;
+ submit_info.pSignalSemaphores = pending_flushable ? &draw_complete_semaphores[frame_index] : nullptr;
VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
command_buffer_queue.write[0] = nullptr;
ERR_FAIL_COND(err);
- vkDeviceWaitIdle(device);
}
- if (p_flush_pending && command_buffer_count > 1) {
- //use a fence to wait for everything done
+ if (pending_flushable) {
+ // Use a fence to wait for everything to finish.
VkSubmitInfo submit_info;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.pNext = nullptr;
- submit_info.pWaitDstStageMask = nullptr;
- submit_info.waitSemaphoreCount = 0;
- submit_info.pWaitSemaphores = nullptr;
+ VkPipelineStageFlags wait_stage_mask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+ submit_info.pWaitDstStageMask = setup_flushable ? &wait_stage_mask : nullptr;
+ submit_info.waitSemaphoreCount = setup_flushable ? 1 : 0;
+ submit_info.pWaitSemaphores = setup_flushable ? &draw_complete_semaphores[frame_index] : nullptr;
submit_info.commandBufferCount = command_buffer_count - 1;
submit_info.pCommandBuffers = command_buffer_queue.ptr() + 1;
submit_info.signalSemaphoreCount = 0;
submit_info.pSignalSemaphores = nullptr;
VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
- ERR_FAIL_COND(err);
- vkDeviceWaitIdle(device);
-
command_buffer_count = 1;
+ ERR_FAIL_COND(err);
}
+
+ vkDeviceWaitIdle(device);
}
Error VulkanContext::prepare_buffers() {
@@ -1846,7 +2029,7 @@ Error VulkanContext::prepare_buffers() {
VkResult err;
- // Ensure no more than FRAME_LAG renderings are outstanding
+ // Ensure no more than FRAME_LAG renderings are outstanding.
vkWaitForFences(device, 1, &fences[frame_index], VK_TRUE, UINT64_MAX);
vkResetFences(device, 1, &fences[frame_index]);
@@ -1860,19 +2043,19 @@ Error VulkanContext::prepare_buffers() {
}
do {
- // Get the index of the next available swapchain image:
+ // Get the index of the next available swapchain image.
err =
fpAcquireNextImageKHR(device, w->swapchain, UINT64_MAX,
w->image_acquired_semaphores[frame_index], VK_NULL_HANDLE, &w->current_buffer);
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
- // swapchain is out of date (e.g. the window was resized) and
- // must be recreated:
+ // Swapchain is out of date (e.g. the window was resized) and
+ // must be recreated.
print_verbose("Vulkan: Early out of date swapchain, recreating.");
- //resize_notify();
+ // resize_notify();
_update_swap_chain(w);
} else if (err == VK_SUBOPTIMAL_KHR) {
- // swapchain is not as optimal as it could be, but the platform's
+ // Swapchain is not as optimal as it could be, but the platform's
// presentation engine will still present the image correctly.
print_verbose("Vulkan: Early suboptimal swapchain.");
break;
@@ -1900,7 +2083,7 @@ Error VulkanContext::swap_buffers() {
#if 0
if (VK_GOOGLE_display_timing_enabled) {
// Look at what happened to previous presents, and make appropriate
- // adjustments in timing:
+ // adjustments in timing.
DemoUpdateTargetIPD(demo);
// Note: a real application would position its geometry to that it's in
@@ -1919,7 +2102,7 @@ Error VulkanContext::swap_buffers() {
uint32_t commands_to_submit = 0;
if (command_buffer_queue[0] == nullptr) {
- //no setup command, but commands to submit, submit from the first and skip command
+ // No setup command, but commands to submit, submit from the first and skip command.
if (command_buffer_count > 1) {
commands_ptr = command_buffer_queue.ptr() + 1;
commands_to_submit = command_buffer_count - 1;
@@ -1930,24 +2113,25 @@ Error VulkanContext::swap_buffers() {
}
VkSemaphore *semaphores_to_acquire = (VkSemaphore *)alloca(windows.size() * sizeof(VkSemaphore));
+ VkPipelineStageFlags *pipe_stage_flags = (VkPipelineStageFlags *)alloca(windows.size() * sizeof(VkPipelineStageFlags));
uint32_t semaphores_to_acquire_count = 0;
for (KeyValue<int, Window> &E : windows) {
Window *w = &E.value;
if (w->semaphore_acquired) {
- semaphores_to_acquire[semaphores_to_acquire_count++] = w->image_acquired_semaphores[frame_index];
+ semaphores_to_acquire[semaphores_to_acquire_count] = w->image_acquired_semaphores[frame_index];
+ pipe_stage_flags[semaphores_to_acquire_count] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ semaphores_to_acquire_count++;
}
}
- VkPipelineStageFlags pipe_stage_flags;
VkSubmitInfo submit_info;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.pNext = nullptr;
- submit_info.pWaitDstStageMask = &pipe_stage_flags;
- pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
submit_info.waitSemaphoreCount = semaphores_to_acquire_count;
submit_info.pWaitSemaphores = semaphores_to_acquire;
+ submit_info.pWaitDstStageMask = pipe_stage_flags;
submit_info.commandBufferCount = commands_to_submit;
submit_info.pCommandBuffers = commands_ptr;
submit_info.signalSemaphoreCount = 1;
@@ -1961,9 +2145,9 @@ Error VulkanContext::swap_buffers() {
if (separate_present_queue) {
// If we are using separate queues, change image ownership to the
// present queue before presenting, waiting for the draw complete
- // semaphore and signalling the ownership released semaphore when finished
+ // semaphore and signalling the ownership released semaphore when finished.
VkFence nullFence = VK_NULL_HANDLE;
- pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ pipe_stage_flags[0] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &draw_complete_semaphores[frame_index];
submit_info.commandBufferCount = 0;
@@ -1988,7 +2172,7 @@ Error VulkanContext::swap_buffers() {
}
// If we are using separate queues, we have to wait for image ownership,
- // otherwise wait for draw complete
+ // otherwise wait for draw complete.
VkPresentInfoKHR present = {
/*sType*/ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
/*pNext*/ nullptr,
@@ -2062,7 +2246,7 @@ Error VulkanContext::swap_buffers() {
uint64_t curtime = getTimeInNanoseconds();
if (curtime == 0) {
// Since we didn't find out the current time, don't give a
- // desiredPresentTime:
+ // desiredPresentTime.
ptime.desiredPresentTime = 0;
} else {
ptime.desiredPresentTime = curtime + (target_IPD >> 1);
@@ -2093,12 +2277,12 @@ Error VulkanContext::swap_buffers() {
frame_index %= FRAME_LAG;
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
- // swapchain is out of date (e.g. the window was resized) and
- // must be recreated:
+ // Swapchain is out of date (e.g. the window was resized) and
+ // must be recreated.
print_verbose("Vulkan: Swapchain is out of date, recreating.");
resize_notify();
} else if (err == VK_SUBOPTIMAL_KHR) {
- // swapchain is not as optimal as it could be, but the platform's
+ // Swapchain is not as optimal as it could be, but the platform's
// presentation engine will still present the image correctly.
print_verbose("Vulkan: Swapchain is suboptimal.");
} else {
@@ -2143,7 +2327,7 @@ VkPhysicalDeviceLimits VulkanContext::get_device_limits() const {
RID VulkanContext::local_device_create() {
LocalDevice ld;
- { //create device
+ { // Create device.
VkResult err;
float queue_priorities[1] = { 0.0 };
VkDeviceQueueCreateInfo queues[2];
@@ -2164,13 +2348,13 @@ RID VulkanContext::local_device_create() {
/*ppEnabledLayerNames */ nullptr,
/*enabledExtensionCount */ enabled_extension_count,
/*ppEnabledExtensionNames */ (const char *const *)extension_names,
- /*pEnabledFeatures */ &physical_device_features, // If specific features are required, pass them in here
+ /*pEnabledFeatures */ &physical_device_features, // If specific features are required, pass them in here.
};
err = vkCreateDevice(gpu, &sdevice, nullptr, &ld.device);
ERR_FAIL_COND_V(err, RID());
}
- { //create graphics queue
+ { // Create graphics queue.
vkGetDeviceQueue(ld.device, graphics_queue_family_index, 0, &ld.queue);
}
@@ -2232,7 +2416,7 @@ void VulkanContext::command_begin_label(VkCommandBuffer p_command_buffer, String
return;
}
- CharString cs = p_label_name.utf8().get_data();
+ CharString cs = p_label_name.utf8();
VkDebugUtilsLabelEXT label;
label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
label.pNext = nullptr;
@@ -2248,7 +2432,7 @@ void VulkanContext::command_insert_label(VkCommandBuffer p_command_buffer, Strin
if (!enabled_debug_utils) {
return;
}
- CharString cs = p_label_name.utf8().get_data();
+ CharString cs = p_label_name.utf8();
VkDebugUtilsLabelEXT label;
label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
label.pNext = nullptr;
@@ -2284,6 +2468,7 @@ void VulkanContext::set_object_name(VkObjectType p_object_type, uint64_t p_objec
String VulkanContext::get_device_vendor_name() const {
return device_vendor;
}
+
String VulkanContext::get_device_name() const {
return device_name;
}
@@ -2292,17 +2477,21 @@ RenderingDevice::DeviceType VulkanContext::get_device_type() const {
return RenderingDevice::DeviceType(device_type);
}
+String VulkanContext::get_device_api_version() const {
+ return vformat("%d.%d.%d", vulkan_major, vulkan_minor, vulkan_patch);
+}
+
String VulkanContext::get_device_pipeline_cache_uuid() const {
return pipeline_cache_id;
}
DisplayServer::VSyncMode VulkanContext::get_vsync_mode(DisplayServer::WindowID p_window) const {
- ERR_FAIL_COND_V_MSG(!windows.has(p_window), DisplayServer::VSYNC_ENABLED, "Could not get VSync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
+ ERR_FAIL_COND_V_MSG(!windows.has(p_window), DisplayServer::VSYNC_ENABLED, "Could not get V-Sync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
return windows[p_window].vsync_mode;
}
void VulkanContext::set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode) {
- ERR_FAIL_COND_MSG(!windows.has(p_window), "Could not set VSync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
+ ERR_FAIL_COND_MSG(!windows.has(p_window), "Could not set V-Sync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
windows[p_window].vsync_mode = p_mode;
_update_swap_chain(&windows[p_window]);
}
diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h
index 67a675f6c6..5cc3b515d9 100644
--- a/drivers/vulkan/vulkan_context.h
+++ b/drivers/vulkan/vulkan_context.h
@@ -34,7 +34,7 @@
#include "core/error/error_list.h"
#include "core/os/mutex.h"
#include "core/string/ustring.h"
-#include "core/templates/map.h"
+#include "core/templates/rb_map.h"
#include "core/templates/rid_owner.h"
#include "servers/display_server.h"
#include "servers/rendering/rendering_device.h"
@@ -45,6 +45,8 @@
#include <vulkan/vulkan.h>
#endif
+#include "vulkan_hooks.h"
+
class VulkanContext {
public:
struct SubgroupCapabilities {
@@ -67,12 +69,25 @@ public:
uint32_t max_instance_count;
};
+ struct VRSCapabilities {
+ bool pipeline_vrs_supported; // We can specify our fragment rate on a pipeline level.
+ bool primitive_vrs_supported; // We can specify our fragment rate on each drawcall.
+ bool attachment_vrs_supported; // We can provide a density map attachment on our framebuffer.
+
+ Size2i min_texel_size;
+ Size2i max_texel_size;
+ };
+
struct ShaderCapabilities {
bool shader_float16_is_supported;
+ bool shader_int8_is_supported;
};
struct StorageBufferCapabilities {
bool storage_buffer_16_bit_access_is_supported;
+ bool uniform_and_storage_buffer_16_bit_access_is_supported;
+ bool storage_push_constant_16_is_supported;
+ bool storage_input_output_16;
};
private:
@@ -82,6 +97,7 @@ private:
FRAME_LAG = 2
};
+ static VulkanHooks *vulkan_hooks;
VkInstance inst = VK_NULL_HANDLE;
VkPhysicalDevice gpu = VK_NULL_HANDLE;
VkPhysicalDeviceProperties gpu_props;
@@ -91,12 +107,13 @@ private:
bool device_initialized = false;
bool inst_initialized = false;
- // Vulkan 1.0 doesn't return version info so we assume this by default until we know otherwise
+ // Vulkan 1.0 doesn't return version info so we assume this by default until we know otherwise.
uint32_t vulkan_major = 1;
uint32_t vulkan_minor = 0;
uint32_t vulkan_patch = 0;
SubgroupCapabilities subgroup_capabilities;
MultiviewCapabilities multiview_capabilities;
+ VRSCapabilities vrs_capabilities;
ShaderCapabilities shader_capabilities;
StorageBufferCapabilities storage_buffer_capabilities;
@@ -110,8 +127,8 @@ private:
// Present queue.
bool queues_initialized = false;
- uint32_t graphics_queue_family_index = 0;
- uint32_t present_queue_family_index = 0;
+ uint32_t graphics_queue_family_index = UINT32_MAX;
+ uint32_t present_queue_family_index = UINT32_MAX;
bool separate_present_queue = false;
VkQueue graphics_queue = VK_NULL_HANDLE;
VkQueue present_queue = VK_NULL_HANDLE;
@@ -154,7 +171,7 @@ private:
RID_Owner<LocalDevice, true> local_device_owner;
- Map<DisplayServer::WindowID, Window> windows;
+ HashMap<DisplayServer::WindowID, Window> windows;
uint32_t swapchainImageCount = 0;
// Commands.
@@ -178,27 +195,28 @@ private:
*/
bool enabled_debug_report = false;
- PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT;
- PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT;
- PFN_vkSubmitDebugUtilsMessageEXT SubmitDebugUtilsMessageEXT;
- PFN_vkCmdBeginDebugUtilsLabelEXT CmdBeginDebugUtilsLabelEXT;
- PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT;
- PFN_vkCmdInsertDebugUtilsLabelEXT CmdInsertDebugUtilsLabelEXT;
- PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT;
- PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
- PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
- PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
- PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR;
- PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR;
- PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR;
- PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR;
- PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR;
- PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR;
- PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR;
- PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR;
- PFN_vkQueuePresentKHR fpQueuePresentKHR;
- PFN_vkGetRefreshCycleDurationGOOGLE fpGetRefreshCycleDurationGOOGLE;
- PFN_vkGetPastPresentationTimingGOOGLE fpGetPastPresentationTimingGOOGLE;
+ PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT = nullptr;
+ PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT = nullptr;
+ PFN_vkSubmitDebugUtilsMessageEXT SubmitDebugUtilsMessageEXT = nullptr;
+ PFN_vkCmdBeginDebugUtilsLabelEXT CmdBeginDebugUtilsLabelEXT = nullptr;
+ PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT = nullptr;
+ PFN_vkCmdInsertDebugUtilsLabelEXT CmdInsertDebugUtilsLabelEXT = nullptr;
+ PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT = nullptr;
+ PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT = nullptr;
+ PFN_vkDebugReportMessageEXT DebugReportMessageEXT = nullptr;
+ PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT = nullptr;
+ PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR = nullptr;
+ PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR = nullptr;
+ PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR = nullptr;
+ PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR = nullptr;
+ PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR = nullptr;
+ PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR = nullptr;
+ PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR = nullptr;
+ PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR = nullptr;
+ PFN_vkQueuePresentKHR fpQueuePresentKHR = nullptr;
+ PFN_vkGetRefreshCycleDurationGOOGLE fpGetRefreshCycleDurationGOOGLE = nullptr;
+ PFN_vkGetPastPresentationTimingGOOGLE fpGetPastPresentationTimingGOOGLE = nullptr;
+ PFN_vkCreateRenderPass2KHR fpCreateRenderPass2KHR = nullptr;
VkDebugUtilsMessengerEXT dbg_messenger = VK_NULL_HANDLE;
VkDebugReportCallbackEXT dbg_debug_report = VK_NULL_HANDLE;
@@ -249,12 +267,16 @@ protected:
Error _get_preferred_validation_layers(uint32_t *count, const char *const **names);
public:
+ // Extension calls.
+ VkResult vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);
+
uint32_t get_vulkan_major() const { return vulkan_major; };
uint32_t get_vulkan_minor() const { return vulkan_minor; };
- SubgroupCapabilities get_subgroup_capabilities() const { return subgroup_capabilities; };
- MultiviewCapabilities get_multiview_capabilities() const { return multiview_capabilities; };
- ShaderCapabilities get_shader_capabilities() const { return shader_capabilities; };
- StorageBufferCapabilities get_storage_buffer_capabilities() const { return storage_buffer_capabilities; };
+ const SubgroupCapabilities &get_subgroup_capabilities() const { return subgroup_capabilities; };
+ const MultiviewCapabilities &get_multiview_capabilities() const { return multiview_capabilities; };
+ const VRSCapabilities &get_vrs_capabilities() const { return vrs_capabilities; };
+ const ShaderCapabilities &get_shader_capabilities() const { return shader_capabilities; };
+ const StorageBufferCapabilities &get_storage_buffer_capabilities() const { return storage_buffer_capabilities; };
VkDevice get_device();
VkPhysicalDevice get_physical_device();
@@ -263,9 +285,12 @@ public:
VkQueue get_graphics_queue() const;
uint32_t get_graphics_queue_family_index() const;
+ static void set_vulkan_hooks(VulkanHooks *p_vulkan_hooks) { vulkan_hooks = p_vulkan_hooks; };
+
void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
int window_get_width(DisplayServer::WindowID p_window = 0);
int window_get_height(DisplayServer::WindowID p_window = 0);
+ bool window_is_valid_swapchain(DisplayServer::WindowID p_window = 0);
void window_destroy(DisplayServer::WindowID p_window_id);
VkFramebuffer window_get_framebuffer(DisplayServer::WindowID p_window = 0);
VkRenderPass window_get_render_pass(DisplayServer::WindowID p_window = 0);
@@ -279,8 +304,8 @@ public:
VkFormat get_screen_format() const;
VkPhysicalDeviceLimits get_device_limits() const;
- void set_setup_buffer(const VkCommandBuffer &pCommandBuffer);
- void append_command_buffer(const VkCommandBuffer &pCommandBuffer);
+ void set_setup_buffer(VkCommandBuffer p_command_buffer);
+ void append_command_buffer(VkCommandBuffer p_command_buffer);
void resize_notify();
void flush(bool p_flush_setup = false, bool p_flush_pending = false);
Error prepare_buffers();
@@ -295,6 +320,7 @@ public:
String get_device_vendor_name() const;
String get_device_name() const;
RenderingDevice::DeviceType get_device_type() const;
+ String get_device_api_version() const;
String get_device_pipeline_cache_uuid() const;
void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode);
@@ -304,4 +330,4 @@ public:
virtual ~VulkanContext();
};
-#endif // VULKAN_DEVICE_H
+#endif // VULKAN_CONTEXT_H
diff --git a/drivers/vulkan/vulkan_hooks.h b/drivers/vulkan/vulkan_hooks.h
new file mode 100644
index 0000000000..dec2042d0d
--- /dev/null
+++ b/drivers/vulkan/vulkan_hooks.h
@@ -0,0 +1,48 @@
+/*************************************************************************/
+/* vulkan_hooks.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (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 VULKAN_HOOKS_H
+#define VULKAN_HOOKS_H
+
+#ifdef USE_VOLK
+#include <volk.h>
+#else
+#include <vulkan/vulkan.h>
+#endif
+
+class VulkanHooks {
+public:
+ virtual bool create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance) { return false; };
+ virtual bool get_physical_device(VkPhysicalDevice *r_device) { return false; };
+ virtual bool create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) { return false; };
+ virtual ~VulkanHooks(){};
+};
+
+#endif // VULKAN_HOOKS_H
diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp
index c7a2d04436..3a62850339 100644
--- a/drivers/wasapi/audio_driver_wasapi.cpp
+++ b/drivers/wasapi/audio_driver_wasapi.cpp
@@ -454,8 +454,9 @@ 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)
+ if (err != OK) {
return err;
+ }
switch (audio_output.channels) {
case 2: // Stereo
@@ -485,8 +486,9 @@ 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)
+ if (err != OK) {
return err;
+ }
// Get the max frames
UINT32 max_frames;
@@ -678,7 +680,7 @@ void AudioDriverWASAPI::write_sample(WORD format_tag, int bits_per_sample, BYTE
}
void AudioDriverWASAPI::thread_func(void *p_udata) {
- AudioDriverWASAPI *ad = (AudioDriverWASAPI *)p_udata;
+ AudioDriverWASAPI *ad = static_cast<AudioDriverWASAPI *>(p_udata);
uint32_t avail_frames = 0;
uint32_t write_ofs = 0;
diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h
index 89ed90e97b..9058077a1f 100644
--- a/drivers/wasapi/audio_driver_wasapi.h
+++ b/drivers/wasapi/audio_driver_wasapi.h
@@ -120,4 +120,5 @@ public:
};
#endif // WASAPI_ENABLED
+
#endif // AUDIO_DRIVER_WASAPI_H
diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp
index 6f3bad12c1..881575d245 100644
--- a/drivers/windows/dir_access_windows.cpp
+++ b/drivers/windows/dir_access_windows.cpp
@@ -185,7 +185,7 @@ Error DirAccessWindows::make_dir(String p_dir) {
return ERR_CANT_CREATE;
}
-String DirAccessWindows::get_current_dir(bool p_include_drive) {
+String DirAccessWindows::get_current_dir(bool p_include_drive) const {
String base = _get_root_path();
if (!base.is_empty()) {
String bd = current_dir.replace("\\", "/").replace_first(base, "");
diff --git a/drivers/windows/dir_access_windows.h b/drivers/windows/dir_access_windows.h
index 78d37074e5..c2835b3347 100644
--- a/drivers/windows/dir_access_windows.h
+++ b/drivers/windows/dir_access_windows.h
@@ -54,33 +54,33 @@ class DirAccessWindows : public DirAccess {
bool _cishidden = false;
public:
- virtual Error list_dir_begin(); ///< This starts dir listing
- virtual String get_next();
- virtual bool current_is_dir() const;
- virtual bool current_is_hidden() const;
- virtual void list_dir_end(); ///<
+ virtual Error list_dir_begin() override; ///< This starts dir listing
+ virtual String get_next() override;
+ virtual bool current_is_dir() const override;
+ virtual bool current_is_hidden() const override;
+ virtual void list_dir_end() override; ///<
- virtual int get_drive_count();
- virtual String get_drive(int p_drive);
+ virtual int get_drive_count() override;
+ virtual String get_drive(int p_drive) override;
- virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
- virtual String get_current_dir(bool p_include_drive = true); ///< return current dir location
+ virtual Error change_dir(String p_dir) override; ///< can be relative or absolute, return false on success
+ virtual String get_current_dir(bool p_include_drive = true) const override; ///< return current dir location
- virtual bool file_exists(String p_file);
- virtual bool dir_exists(String p_dir);
+ virtual bool file_exists(String p_file) override;
+ virtual bool dir_exists(String p_dir) override;
- virtual Error make_dir(String p_dir);
+ virtual Error make_dir(String p_dir) override;
- virtual Error rename(String p_path, String p_new_path);
- virtual Error remove(String p_path);
+ virtual Error rename(String p_path, String p_new_path) override;
+ virtual Error remove(String p_path) override;
- virtual bool is_link(String p_file) { return false; };
- virtual String read_link(String p_file) { return p_file; };
- virtual Error create_link(String p_source, String p_target) { return FAILED; };
+ virtual bool is_link(String p_file) override { return false; };
+ virtual String read_link(String p_file) override { return p_file; };
+ virtual Error create_link(String p_source, String p_target) override { return FAILED; };
- uint64_t get_space_left();
+ uint64_t get_space_left() override;
- virtual String get_filesystem_type() const;
+ virtual String get_filesystem_type() const override;
DirAccessWindows();
~DirAccessWindows();
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index cfd5d65f60..1a66d19373 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -59,11 +59,10 @@ void FileAccessWindows::check_errors() const {
}
Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
+ _close();
+
path_src = p_path;
path = fix_path(p_path);
- if (f) {
- close();
- }
const WCHAR *mode_string;
@@ -87,7 +86,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
if (!S_ISREG(st.st_mode)) {
return ERR_FILE_CANT_OPEN;
}
- };
+ }
#ifdef TOOLS_ENABLED
// Windows is case insensitive, but all other platforms are sensitive to it
@@ -134,7 +133,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
}
}
-void FileAccessWindows::close() {
+void FileAccessWindows::_close() {
if (!f) {
return;
}
@@ -269,7 +268,7 @@ uint64_t FileAccessWindows::get_buffer(uint8_t *p_dst, uint64_t p_length) const
uint64_t read = fread(p_dst, 1, p_length, f);
check_errors();
return read;
-};
+}
Error FileAccessWindows::get_error() const {
return last_error;
@@ -326,8 +325,9 @@ bool FileAccessWindows::file_exists(const String &p_name) {
uint64_t FileAccessWindows::_get_modified_time(const String &p_file) {
String file = fix_path(p_file);
- if (file.ends_with("/") && file != "/")
+ if (file.ends_with("/") && file != "/") {
file = file.substr(0, file.length() - 1);
+ }
struct _stat st;
int rv = _wstat((LPCWSTR)(file.utf16().get_data()), &st);
@@ -349,7 +349,7 @@ Error FileAccessWindows::_set_unix_permissions(const String &p_file, uint32_t p_
}
FileAccessWindows::~FileAccessWindows() {
- close();
+ _close();
}
#endif // WINDOWS_ENABLED
diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h
index 93d37c3b5a..8629bb936b 100644
--- a/drivers/windows/file_access_windows.h
+++ b/drivers/windows/file_access_windows.h
@@ -48,35 +48,36 @@ class FileAccessWindows : public FileAccess {
String path_src;
String save_path;
+ void _close();
+
public:
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual void close(); ///< close a file
- virtual bool is_open() const; ///< true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
- virtual String get_path() const; /// returns the path for the current open file
- virtual String get_path_absolute() const; /// returns the absolute path for the current open file
+ virtual String get_path() const override; /// returns the path for the current open file
+ virtual String get_path_absolute() const override; /// returns the absolute path for the current open file
- virtual void seek(uint64_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual uint64_t get_position() const; ///< get position in the file
- virtual uint64_t get_length() const; ///< get size of the file
+ virtual void seek(uint64_t p_position) override; ///< seek to a given position
+ virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file
+ virtual uint64_t get_position() const override; ///< get position in the file
+ virtual uint64_t get_length() const override; ///< get size of the file
- virtual bool eof_reached() const; ///< reading passed EOF
+ virtual bool eof_reached() const override; ///< reading passed EOF
- virtual uint8_t get_8() const; ///< get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint8_t get_8() const override; ///< get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual Error get_error() const; ///< get last error
+ virtual Error get_error() const override; ///< get last error
- virtual void flush();
- virtual void store_8(uint8_t p_dest); ///< store a byte
- virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override; ///< store a byte
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
- virtual bool file_exists(const String &p_name); ///< return true if a file exists
+ virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
- uint64_t _get_modified_time(const String &p_file);
- virtual uint32_t _get_unix_permissions(const String &p_file);
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
+ uint64_t _get_modified_time(const String &p_file) override;
+ virtual uint32_t _get_unix_permissions(const String &p_file) override;
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override;
FileAccessWindows() {}
virtual ~FileAccessWindows();
diff --git a/drivers/winmidi/midi_driver_winmidi.h b/drivers/winmidi/midi_driver_winmidi.h
index 6572ba0c16..e42f3df4cf 100644
--- a/drivers/winmidi/midi_driver_winmidi.h
+++ b/drivers/winmidi/midi_driver_winmidi.h
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef WINMIDI_ENABLED
-
#ifndef MIDI_DRIVER_WINMIDI_H
#define MIDI_DRIVER_WINMIDI_H
+#ifdef WINMIDI_ENABLED
+
#include "core/os/midi_driver.h"
#include "core/templates/vector.h"
@@ -57,5 +57,6 @@ public:
virtual ~MIDIDriverWinMidi();
};
-#endif // MIDI_DRIVER_WINMIDI_H
#endif // WINMIDI_ENABLED
+
+#endif // MIDI_DRIVER_WINMIDI_H
diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp
index 03fdfda23d..c32c7cf1e5 100644
--- a/drivers/xaudio2/audio_driver_xaudio2.cpp
+++ b/drivers/xaudio2/audio_driver_xaudio2.cpp
@@ -84,7 +84,7 @@ Error AudioDriverXAudio2::init() {
}
void AudioDriverXAudio2::thread_func(void *p_udata) {
- AudioDriverXAudio2 *ad = (AudioDriverXAudio2 *)p_udata;
+ AudioDriverXAudio2 *ad = static_cast<AudioDriverXAudio2 *>(p_udata);
while (!ad->exit_thread) {
if (!ad->active) {
diff --git a/drivers/xaudio2/audio_driver_xaudio2.h b/drivers/xaudio2/audio_driver_xaudio2.h
index 9072269a0e..81432ceb8e 100644
--- a/drivers/xaudio2/audio_driver_xaudio2.h
+++ b/drivers/xaudio2/audio_driver_xaudio2.h
@@ -106,4 +106,4 @@ public:
~AudioDriverXAudio2() {}
};
-#endif
+#endif // AUDIO_DRIVER_XAUDIO2_H