summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/SCsub1
-rw-r--r--drivers/alsa/asound-so_wrap.c96
-rw-r--r--drivers/alsa/asound-so_wrap.h40
-rw-r--r--drivers/alsa/audio_driver_alsa.cpp58
-rw-r--r--drivers/alsa/audio_driver_alsa.h58
-rw-r--r--drivers/alsamidi/midi_driver_alsamidi.cpp242
-rw-r--r--drivers/alsamidi/midi_driver_alsamidi.h96
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.cpp60
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.h58
-rw-r--r--drivers/coremidi/midi_driver_coremidi.cpp58
-rw-r--r--drivers/coremidi/midi_driver_coremidi.h58
-rw-r--r--drivers/gl_context/SCsub2
-rw-r--r--drivers/gles3/effects/copy_effects.cpp101
-rw-r--r--drivers/gles3/effects/copy_effects.h62
-rw-r--r--drivers/gles3/environment/fog.cpp60
-rw-r--r--drivers/gles3/environment/fog.h60
-rw-r--r--drivers/gles3/environment/gi.cpp58
-rw-r--r--drivers/gles3/environment/gi.h58
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp2087
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.h255
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp141
-rw-r--r--drivers/gles3/rasterizer_gles3.h65
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp580
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h196
-rw-r--r--drivers/gles3/shader_gles3.cpp120
-rw-r--r--drivers/gles3/shader_gles3.h88
-rw-r--r--drivers/gles3/shaders/SCsub5
-rw-r--r--drivers/gles3/shaders/canvas.glsl543
-rw-r--r--drivers/gles3/shaders/canvas_occlusion.glsl68
-rw-r--r--drivers/gles3/shaders/canvas_sdf.glsl205
-rw-r--r--drivers/gles3/shaders/canvas_shadow.glsl60
-rw-r--r--drivers/gles3/shaders/canvas_uniforms_inc.glsl42
-rw-r--r--drivers/gles3/shaders/copy.glsl5
-rw-r--r--drivers/gles3/shaders/cubemap_filter.glsl4
-rw-r--r--drivers/gles3/shaders/particles.glsl501
-rw-r--r--drivers/gles3/shaders/particles_copy.glsl122
-rw-r--r--drivers/gles3/shaders/scene.glsl152
-rw-r--r--drivers/gles3/shaders/skeleton.glsl269
-rw-r--r--drivers/gles3/shaders/sky.glsl13
-rw-r--r--drivers/gles3/shaders/stdlib_inc.glsl18
-rw-r--r--drivers/gles3/shaders/tonemap.glsl20
-rw-r--r--drivers/gles3/storage/config.cpp92
-rw-r--r--drivers/gles3/storage/config.h70
-rw-r--r--drivers/gles3/storage/light_storage.cpp193
-rw-r--r--drivers/gles3/storage/light_storage.h154
-rw-r--r--drivers/gles3/storage/material_storage.cpp728
-rw-r--r--drivers/gles3/storage/material_storage.h159
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp711
-rw-r--r--drivers/gles3/storage/mesh_storage.h113
-rw-r--r--drivers/gles3/storage/particles_storage.cpp1278
-rw-r--r--drivers/gles3/storage/particles_storage.h373
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.cpp101
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.h65
-rw-r--r--drivers/gles3/storage/texture_storage.cpp1282
-rw-r--r--drivers/gles3/storage/texture_storage.h241
-rw-r--r--drivers/gles3/storage/utilities.cpp300
-rw-r--r--drivers/gles3/storage/utilities.h145
-rw-r--r--drivers/png/image_loader_png.cpp60
-rw-r--r--drivers/png/image_loader_png.h60
-rw-r--r--drivers/png/png_driver_common.cpp60
-rw-r--r--drivers/png/png_driver_common.h58
-rw-r--r--drivers/png/resource_saver_png.cpp58
-rw-r--r--drivers/png/resource_saver_png.h58
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp60
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.h62
-rw-r--r--drivers/pulseaudio/pulse-so_wrap.c152
-rw-r--r--drivers/pulseaudio/pulse-so_wrap.h110
-rw-r--r--drivers/register_driver_types.cpp69
-rw-r--r--drivers/register_driver_types.h58
-rw-r--r--drivers/spirv-reflect/SCsub17
-rw-r--r--drivers/unix/dir_access_unix.cpp86
-rw-r--r--drivers/unix/dir_access_unix.h62
-rw-r--r--drivers/unix/file_access_unix.cpp91
-rw-r--r--drivers/unix/file_access_unix.h64
-rw-r--r--drivers/unix/ip_unix.cpp58
-rw-r--r--drivers/unix/ip_unix.h58
-rw-r--r--drivers/unix/net_socket_posix.cpp90
-rw-r--r--drivers/unix/net_socket_posix.h58
-rw-r--r--drivers/unix/os_unix.cpp138
-rw-r--r--drivers/unix/os_unix.h78
-rw-r--r--drivers/unix/syslog_logger.cpp58
-rw-r--r--drivers/unix/syslog_logger.h58
-rw-r--r--drivers/unix/thread_posix.cpp64
-rw-r--r--drivers/unix/thread_posix.h60
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp1132
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h106
-rw-r--r--drivers/vulkan/vulkan_context.cpp930
-rw-r--r--drivers/vulkan/vulkan_context.h104
-rw-r--r--drivers/vulkan/vulkan_hooks.h58
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp109
-rw-r--r--drivers/wasapi/audio_driver_wasapi.h64
-rw-r--r--drivers/windows/dir_access_windows.cpp94
-rw-r--r--drivers/windows/dir_access_windows.h58
-rw-r--r--drivers/windows/file_access_windows.cpp111
-rw-r--r--drivers/windows/file_access_windows.h66
-rw-r--r--drivers/winmidi/midi_driver_winmidi.cpp58
-rw-r--r--drivers/winmidi/midi_driver_winmidi.h58
-rw-r--r--drivers/xaudio2/audio_driver_xaudio2.cpp58
-rw-r--r--drivers/xaudio2/audio_driver_xaudio2.h58
99 files changed, 11485 insertions, 6274 deletions
diff --git a/drivers/SCsub b/drivers/SCsub
index dd81fc645c..276b99e10b 100644
--- a/drivers/SCsub
+++ b/drivers/SCsub
@@ -31,7 +31,6 @@ if env["opengl3"]:
# Core dependencies
SConscript("png/SCsub")
-SConscript("spirv-reflect/SCsub")
env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/alsa/asound-so_wrap.c b/drivers/alsa/asound-so_wrap.c
index 65624bcb70..6f9c5408d5 100644
--- a/drivers/alsa/asound-so_wrap.c
+++ b/drivers/alsa/asound-so_wrap.c
@@ -1,12 +1,11 @@
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by /home/hp/Projects/godot/pulse/generate-wrapper.py 0.3 on 2021-02-22 19:22:12
-// flags: /home/hp/Projects/godot/pulse/generate-wrapper.py --include /usr/include/alsa/asoundlib.h --sys-include <alsa/asoundlib.h> --soname libasound.so.2 --init-name asound --omit-prefix snd_pcm_sw_params_set_tstamp_type --omit-prefix snd_pcm_status_get_audio_htstamp_report --omit-prefix snd_pcm_sw_params_get_tstamp_type --omit-prefix snd_pcm_status_set_audio_htstamp_config --output-header asound-so_wrap.h --output-implementation asound-so_wrap.c
+// generated by ../dynload-wrapper/generate-wrapper.py 0.3 on 2023-01-12 10:26:13
+// flags: ../dynload-wrapper/generate-wrapper.py --include ./thirdparty/linuxbsd_headers/alsa/asoundlib.h --sys-include "thirdparty/linuxbsd_headers/alsa/asoundlib.h" --soname libasound.so.2 --init-name asound --omit-prefix snd_pcm_sw_params_set_tstamp_type --omit-prefix snd_pcm_status_get_audio_htstamp_report --omit-prefix snd_pcm_sw_params_get_tstamp_type --omit-prefix snd_pcm_status_set_audio_htstamp_config --output-header ./drivers/alsa/asound-so_wrap.h --output-implementation ./drivers/alsa/asound-so_wrap.c
//
#include <stdint.h>
#define snd_asoundlib_version snd_asoundlib_version_dylibloader_orig_asound
-#define snd_dlpath snd_dlpath_dylibloader_orig_asound
#define snd_dlopen snd_dlopen_dylibloader_orig_asound
#define snd_dlsym snd_dlsym_dylibloader_orig_asound
#define snd_dlclose snd_dlclose_dylibloader_orig_asound
@@ -40,7 +39,6 @@
#define snd_strerror snd_strerror_dylibloader_orig_asound
#define snd_lib_error_set_handler snd_lib_error_set_handler_dylibloader_orig_asound
#define snd_lib_error_set_local snd_lib_error_set_local_dylibloader_orig_asound
-#define snd_config_topdir snd_config_topdir_dylibloader_orig_asound
#define snd_config_top snd_config_top_dylibloader_orig_asound
#define snd_config_load snd_config_load_dylibloader_orig_asound
#define snd_config_load_override snd_config_load_override_dylibloader_orig_asound
@@ -58,9 +56,6 @@
#define snd_config_expand snd_config_expand_dylibloader_orig_asound
#define snd_config_evaluate snd_config_evaluate_dylibloader_orig_asound
#define snd_config_add snd_config_add_dylibloader_orig_asound
-#define snd_config_add_before snd_config_add_before_dylibloader_orig_asound
-#define snd_config_add_after snd_config_add_after_dylibloader_orig_asound
-#define snd_config_remove snd_config_remove_dylibloader_orig_asound
#define snd_config_delete snd_config_delete_dylibloader_orig_asound
#define snd_config_delete_compound_members snd_config_delete_compound_members_dylibloader_orig_asound
#define snd_config_copy snd_config_copy_dylibloader_orig_asound
@@ -78,7 +73,6 @@
#define snd_config_imake_safe_string snd_config_imake_safe_string_dylibloader_orig_asound
#define snd_config_imake_pointer snd_config_imake_pointer_dylibloader_orig_asound
#define snd_config_get_type snd_config_get_type_dylibloader_orig_asound
-#define snd_config_is_array snd_config_is_array_dylibloader_orig_asound
#define snd_config_set_id snd_config_set_id_dylibloader_orig_asound
#define snd_config_set_integer snd_config_set_integer_dylibloader_orig_asound
#define snd_config_set_integer64 snd_config_set_integer64_dylibloader_orig_asound
@@ -423,7 +417,6 @@
#define snd_pcm_areas_silence snd_pcm_areas_silence_dylibloader_orig_asound
#define snd_pcm_area_copy snd_pcm_area_copy_dylibloader_orig_asound
#define snd_pcm_areas_copy snd_pcm_areas_copy_dylibloader_orig_asound
-#define snd_pcm_areas_copy_wrap snd_pcm_areas_copy_wrap_dylibloader_orig_asound
#define snd_pcm_hook_get_pcm snd_pcm_hook_get_pcm_dylibloader_orig_asound
#define snd_pcm_hook_get_private snd_pcm_hook_get_private_dylibloader_orig_asound
#define snd_pcm_hook_set_private snd_pcm_hook_set_private_dylibloader_orig_asound
@@ -1015,7 +1008,6 @@
#define snd_mixer_selem_id_get_index snd_mixer_selem_id_get_index_dylibloader_orig_asound
#define snd_mixer_selem_id_set_name snd_mixer_selem_id_set_name_dylibloader_orig_asound
#define snd_mixer_selem_id_set_index snd_mixer_selem_id_set_index_dylibloader_orig_asound
-#define snd_mixer_selem_id_parse snd_mixer_selem_id_parse_dylibloader_orig_asound
#define snd_seq_open snd_seq_open_dylibloader_orig_asound
#define snd_seq_open_lconf snd_seq_open_lconf_dylibloader_orig_asound
#define snd_seq_name snd_seq_name_dylibloader_orig_asound
@@ -1284,9 +1276,8 @@
#define snd_midi_event_encode snd_midi_event_encode_dylibloader_orig_asound
#define snd_midi_event_encode_byte snd_midi_event_encode_byte_dylibloader_orig_asound
#define snd_midi_event_decode snd_midi_event_decode_dylibloader_orig_asound
-#include <alsa/asoundlib.h>
+#include "thirdparty/linuxbsd_headers/alsa/asoundlib.h"
#undef snd_asoundlib_version
-#undef snd_dlpath
#undef snd_dlopen
#undef snd_dlsym
#undef snd_dlclose
@@ -1320,7 +1311,6 @@
#undef snd_strerror
#undef snd_lib_error_set_handler
#undef snd_lib_error_set_local
-#undef snd_config_topdir
#undef snd_config_top
#undef snd_config_load
#undef snd_config_load_override
@@ -1338,9 +1328,6 @@
#undef snd_config_expand
#undef snd_config_evaluate
#undef snd_config_add
-#undef snd_config_add_before
-#undef snd_config_add_after
-#undef snd_config_remove
#undef snd_config_delete
#undef snd_config_delete_compound_members
#undef snd_config_copy
@@ -1358,7 +1345,6 @@
#undef snd_config_imake_safe_string
#undef snd_config_imake_pointer
#undef snd_config_get_type
-#undef snd_config_is_array
#undef snd_config_set_id
#undef snd_config_set_integer
#undef snd_config_set_integer64
@@ -1703,7 +1689,6 @@
#undef snd_pcm_areas_silence
#undef snd_pcm_area_copy
#undef snd_pcm_areas_copy
-#undef snd_pcm_areas_copy_wrap
#undef snd_pcm_hook_get_pcm
#undef snd_pcm_hook_get_private
#undef snd_pcm_hook_set_private
@@ -2295,7 +2280,6 @@
#undef snd_mixer_selem_id_get_index
#undef snd_mixer_selem_id_set_name
#undef snd_mixer_selem_id_set_index
-#undef snd_mixer_selem_id_parse
#undef snd_seq_open
#undef snd_seq_open_lconf
#undef snd_seq_name
@@ -2567,8 +2551,7 @@
#include <dlfcn.h>
#include <stdio.h>
const char* (*snd_asoundlib_version_dylibloader_wrapper_asound)( void);
-int (*snd_dlpath_dylibloader_wrapper_asound)( char*, size_t,const char*);
-void* (*snd_dlopen_dylibloader_wrapper_asound)(const char*, int, char*, size_t);
+void* (*snd_dlopen_dylibloader_wrapper_asound)(const char*, int);
void* (*snd_dlsym_dylibloader_wrapper_asound)( void*,const char*,const char*);
int (*snd_dlclose_dylibloader_wrapper_asound)( void*);
int (*snd_async_add_handler_dylibloader_wrapper_asound)( snd_async_handler_t**, int, snd_async_callback_t, void*);
@@ -2601,7 +2584,6 @@ int (*snd_output_flush_dylibloader_wrapper_asound)( snd_output_t*);
const char* (*snd_strerror_dylibloader_wrapper_asound)( int);
int (*snd_lib_error_set_handler_dylibloader_wrapper_asound)( snd_lib_error_handler_t);
snd_local_error_handler_t (*snd_lib_error_set_local_dylibloader_wrapper_asound)( snd_local_error_handler_t);
-const char* (*snd_config_topdir_dylibloader_wrapper_asound)( void);
int (*snd_config_top_dylibloader_wrapper_asound)( snd_config_t**);
int (*snd_config_load_dylibloader_wrapper_asound)( snd_config_t*, snd_input_t*);
int (*snd_config_load_override_dylibloader_wrapper_asound)( snd_config_t*, snd_input_t*);
@@ -2619,9 +2601,6 @@ int (*snd_config_search_definition_dylibloader_wrapper_asound)( snd_config_t*,co
int (*snd_config_expand_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*,const char*, snd_config_t*, snd_config_t**);
int (*snd_config_evaluate_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*, snd_config_t*, snd_config_t**);
int (*snd_config_add_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*);
-int (*snd_config_add_before_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*);
-int (*snd_config_add_after_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*);
-int (*snd_config_remove_dylibloader_wrapper_asound)( snd_config_t*);
int (*snd_config_delete_dylibloader_wrapper_asound)( snd_config_t*);
int (*snd_config_delete_compound_members_dylibloader_wrapper_asound)(const snd_config_t*);
int (*snd_config_copy_dylibloader_wrapper_asound)( snd_config_t**, snd_config_t*);
@@ -2639,7 +2618,6 @@ int (*snd_config_imake_string_dylibloader_wrapper_asound)( snd_config_t**,const
int (*snd_config_imake_safe_string_dylibloader_wrapper_asound)( snd_config_t**,const char*,const char*);
int (*snd_config_imake_pointer_dylibloader_wrapper_asound)( snd_config_t**,const char*,const void*);
snd_config_type_t (*snd_config_get_type_dylibloader_wrapper_asound)(const snd_config_t*);
-int (*snd_config_is_array_dylibloader_wrapper_asound)(const snd_config_t*);
int (*snd_config_set_id_dylibloader_wrapper_asound)( snd_config_t*,const char*);
int (*snd_config_set_integer_dylibloader_wrapper_asound)( snd_config_t*, long);
int (*snd_config_set_integer64_dylibloader_wrapper_asound)( snd_config_t*, long long);
@@ -2984,7 +2962,6 @@ int (*snd_pcm_area_silence_dylibloader_wrapper_asound)(const snd_pcm_channel_are
int (*snd_pcm_areas_silence_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t, unsigned int, snd_pcm_uframes_t, snd_pcm_format_t);
int (*snd_pcm_area_copy_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t,const snd_pcm_channel_area_t*, snd_pcm_uframes_t, unsigned int, snd_pcm_format_t);
int (*snd_pcm_areas_copy_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t,const snd_pcm_channel_area_t*, snd_pcm_uframes_t, unsigned int, snd_pcm_uframes_t, snd_pcm_format_t);
-int (*snd_pcm_areas_copy_wrap_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t,const snd_pcm_uframes_t,const snd_pcm_channel_area_t*, snd_pcm_uframes_t,const snd_pcm_uframes_t,const unsigned int, snd_pcm_uframes_t,const snd_pcm_format_t);
snd_pcm_t* (*snd_pcm_hook_get_pcm_dylibloader_wrapper_asound)( snd_pcm_hook_t*);
void* (*snd_pcm_hook_get_private_dylibloader_wrapper_asound)( snd_pcm_hook_t*);
void (*snd_pcm_hook_set_private_dylibloader_wrapper_asound)( snd_pcm_hook_t*, void*);
@@ -3576,7 +3553,6 @@ const char* (*snd_mixer_selem_id_get_name_dylibloader_wrapper_asound)(const snd_
unsigned int (*snd_mixer_selem_id_get_index_dylibloader_wrapper_asound)(const snd_mixer_selem_id_t*);
void (*snd_mixer_selem_id_set_name_dylibloader_wrapper_asound)( snd_mixer_selem_id_t*,const char*);
void (*snd_mixer_selem_id_set_index_dylibloader_wrapper_asound)( snd_mixer_selem_id_t*, unsigned int);
-int (*snd_mixer_selem_id_parse_dylibloader_wrapper_asound)( snd_mixer_selem_id_t*,const char*);
int (*snd_seq_open_dylibloader_wrapper_asound)( snd_seq_t**,const char*, int, int);
int (*snd_seq_open_lconf_dylibloader_wrapper_asound)( snd_seq_t**,const char*, int, int, snd_config_t*);
const char* (*snd_seq_name_dylibloader_wrapper_asound)( snd_seq_t*);
@@ -3864,14 +3840,6 @@ int initialize_asound(int verbose) {
fprintf(stderr, "%s\n", error);
}
}
-// snd_dlpath
- *(void **) (&snd_dlpath_dylibloader_wrapper_asound) = dlsym(handle, "snd_dlpath");
- if (verbose) {
- error = dlerror();
- if (error != NULL) {
- fprintf(stderr, "%s\n", error);
- }
- }
// snd_dlopen
*(void **) (&snd_dlopen_dylibloader_wrapper_asound) = dlsym(handle, "snd_dlopen");
if (verbose) {
@@ -4136,14 +4104,6 @@ int initialize_asound(int verbose) {
fprintf(stderr, "%s\n", error);
}
}
-// snd_config_topdir
- *(void **) (&snd_config_topdir_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_topdir");
- if (verbose) {
- error = dlerror();
- if (error != NULL) {
- fprintf(stderr, "%s\n", error);
- }
- }
// snd_config_top
*(void **) (&snd_config_top_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_top");
if (verbose) {
@@ -4280,30 +4240,6 @@ int initialize_asound(int verbose) {
fprintf(stderr, "%s\n", error);
}
}
-// snd_config_add_before
- *(void **) (&snd_config_add_before_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_add_before");
- if (verbose) {
- error = dlerror();
- if (error != NULL) {
- fprintf(stderr, "%s\n", error);
- }
- }
-// snd_config_add_after
- *(void **) (&snd_config_add_after_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_add_after");
- if (verbose) {
- error = dlerror();
- if (error != NULL) {
- fprintf(stderr, "%s\n", error);
- }
- }
-// snd_config_remove
- *(void **) (&snd_config_remove_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_remove");
- if (verbose) {
- error = dlerror();
- if (error != NULL) {
- fprintf(stderr, "%s\n", error);
- }
- }
// snd_config_delete
*(void **) (&snd_config_delete_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_delete");
if (verbose) {
@@ -4440,14 +4376,6 @@ int initialize_asound(int verbose) {
fprintf(stderr, "%s\n", error);
}
}
-// snd_config_is_array
- *(void **) (&snd_config_is_array_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_is_array");
- if (verbose) {
- error = dlerror();
- if (error != NULL) {
- fprintf(stderr, "%s\n", error);
- }
- }
// snd_config_set_id
*(void **) (&snd_config_set_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_set_id");
if (verbose) {
@@ -7200,14 +7128,6 @@ int initialize_asound(int verbose) {
fprintf(stderr, "%s\n", error);
}
}
-// snd_pcm_areas_copy_wrap
- *(void **) (&snd_pcm_areas_copy_wrap_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_areas_copy_wrap");
- if (verbose) {
- error = dlerror();
- if (error != NULL) {
- fprintf(stderr, "%s\n", error);
- }
- }
// snd_pcm_hook_get_pcm
*(void **) (&snd_pcm_hook_get_pcm_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hook_get_pcm");
if (verbose) {
@@ -11936,14 +11856,6 @@ int initialize_asound(int verbose) {
fprintf(stderr, "%s\n", error);
}
}
-// snd_mixer_selem_id_parse
- *(void **) (&snd_mixer_selem_id_parse_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_id_parse");
- if (verbose) {
- error = dlerror();
- if (error != NULL) {
- fprintf(stderr, "%s\n", error);
- }
- }
// snd_seq_open
*(void **) (&snd_seq_open_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_open");
if (verbose) {
diff --git a/drivers/alsa/asound-so_wrap.h b/drivers/alsa/asound-so_wrap.h
index 5332d74152..ab54f4e8cf 100644
--- a/drivers/alsa/asound-so_wrap.h
+++ b/drivers/alsa/asound-so_wrap.h
@@ -2,13 +2,12 @@
#define DYLIBLOAD_WRAPPER_ASOUND
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by /home/hp/Projects/godot/pulse/generate-wrapper.py 0.3 on 2021-02-22 19:22:12
-// flags: /home/hp/Projects/godot/pulse/generate-wrapper.py --include /usr/include/alsa/asoundlib.h --sys-include <alsa/asoundlib.h> --soname libasound.so.2 --init-name asound --omit-prefix snd_pcm_sw_params_set_tstamp_type --omit-prefix snd_pcm_status_get_audio_htstamp_report --omit-prefix snd_pcm_sw_params_get_tstamp_type --omit-prefix snd_pcm_status_set_audio_htstamp_config --output-header asound-so_wrap.h --output-implementation asound-so_wrap.c
+// generated by ../dynload-wrapper/generate-wrapper.py 0.3 on 2023-01-12 10:26:13
+// flags: ../dynload-wrapper/generate-wrapper.py --include ./thirdparty/linuxbsd_headers/alsa/asoundlib.h --sys-include "thirdparty/linuxbsd_headers/alsa/asoundlib.h" --soname libasound.so.2 --init-name asound --omit-prefix snd_pcm_sw_params_set_tstamp_type --omit-prefix snd_pcm_status_get_audio_htstamp_report --omit-prefix snd_pcm_sw_params_get_tstamp_type --omit-prefix snd_pcm_status_set_audio_htstamp_config --output-header ./drivers/alsa/asound-so_wrap.h --output-implementation ./drivers/alsa/asound-so_wrap.c
//
#include <stdint.h>
#define snd_asoundlib_version snd_asoundlib_version_dylibloader_orig_asound
-#define snd_dlpath snd_dlpath_dylibloader_orig_asound
#define snd_dlopen snd_dlopen_dylibloader_orig_asound
#define snd_dlsym snd_dlsym_dylibloader_orig_asound
#define snd_dlclose snd_dlclose_dylibloader_orig_asound
@@ -42,7 +41,6 @@
#define snd_strerror snd_strerror_dylibloader_orig_asound
#define snd_lib_error_set_handler snd_lib_error_set_handler_dylibloader_orig_asound
#define snd_lib_error_set_local snd_lib_error_set_local_dylibloader_orig_asound
-#define snd_config_topdir snd_config_topdir_dylibloader_orig_asound
#define snd_config_top snd_config_top_dylibloader_orig_asound
#define snd_config_load snd_config_load_dylibloader_orig_asound
#define snd_config_load_override snd_config_load_override_dylibloader_orig_asound
@@ -60,9 +58,6 @@
#define snd_config_expand snd_config_expand_dylibloader_orig_asound
#define snd_config_evaluate snd_config_evaluate_dylibloader_orig_asound
#define snd_config_add snd_config_add_dylibloader_orig_asound
-#define snd_config_add_before snd_config_add_before_dylibloader_orig_asound
-#define snd_config_add_after snd_config_add_after_dylibloader_orig_asound
-#define snd_config_remove snd_config_remove_dylibloader_orig_asound
#define snd_config_delete snd_config_delete_dylibloader_orig_asound
#define snd_config_delete_compound_members snd_config_delete_compound_members_dylibloader_orig_asound
#define snd_config_copy snd_config_copy_dylibloader_orig_asound
@@ -80,7 +75,6 @@
#define snd_config_imake_safe_string snd_config_imake_safe_string_dylibloader_orig_asound
#define snd_config_imake_pointer snd_config_imake_pointer_dylibloader_orig_asound
#define snd_config_get_type snd_config_get_type_dylibloader_orig_asound
-#define snd_config_is_array snd_config_is_array_dylibloader_orig_asound
#define snd_config_set_id snd_config_set_id_dylibloader_orig_asound
#define snd_config_set_integer snd_config_set_integer_dylibloader_orig_asound
#define snd_config_set_integer64 snd_config_set_integer64_dylibloader_orig_asound
@@ -425,7 +419,6 @@
#define snd_pcm_areas_silence snd_pcm_areas_silence_dylibloader_orig_asound
#define snd_pcm_area_copy snd_pcm_area_copy_dylibloader_orig_asound
#define snd_pcm_areas_copy snd_pcm_areas_copy_dylibloader_orig_asound
-#define snd_pcm_areas_copy_wrap snd_pcm_areas_copy_wrap_dylibloader_orig_asound
#define snd_pcm_hook_get_pcm snd_pcm_hook_get_pcm_dylibloader_orig_asound
#define snd_pcm_hook_get_private snd_pcm_hook_get_private_dylibloader_orig_asound
#define snd_pcm_hook_set_private snd_pcm_hook_set_private_dylibloader_orig_asound
@@ -1017,7 +1010,6 @@
#define snd_mixer_selem_id_get_index snd_mixer_selem_id_get_index_dylibloader_orig_asound
#define snd_mixer_selem_id_set_name snd_mixer_selem_id_set_name_dylibloader_orig_asound
#define snd_mixer_selem_id_set_index snd_mixer_selem_id_set_index_dylibloader_orig_asound
-#define snd_mixer_selem_id_parse snd_mixer_selem_id_parse_dylibloader_orig_asound
#define snd_seq_open snd_seq_open_dylibloader_orig_asound
#define snd_seq_open_lconf snd_seq_open_lconf_dylibloader_orig_asound
#define snd_seq_name snd_seq_name_dylibloader_orig_asound
@@ -1286,9 +1278,8 @@
#define snd_midi_event_encode snd_midi_event_encode_dylibloader_orig_asound
#define snd_midi_event_encode_byte snd_midi_event_encode_byte_dylibloader_orig_asound
#define snd_midi_event_decode snd_midi_event_decode_dylibloader_orig_asound
-#include <alsa/asoundlib.h>
+#include "thirdparty/linuxbsd_headers/alsa/asoundlib.h"
#undef snd_asoundlib_version
-#undef snd_dlpath
#undef snd_dlopen
#undef snd_dlsym
#undef snd_dlclose
@@ -1322,7 +1313,6 @@
#undef snd_strerror
#undef snd_lib_error_set_handler
#undef snd_lib_error_set_local
-#undef snd_config_topdir
#undef snd_config_top
#undef snd_config_load
#undef snd_config_load_override
@@ -1340,9 +1330,6 @@
#undef snd_config_expand
#undef snd_config_evaluate
#undef snd_config_add
-#undef snd_config_add_before
-#undef snd_config_add_after
-#undef snd_config_remove
#undef snd_config_delete
#undef snd_config_delete_compound_members
#undef snd_config_copy
@@ -1360,7 +1347,6 @@
#undef snd_config_imake_safe_string
#undef snd_config_imake_pointer
#undef snd_config_get_type
-#undef snd_config_is_array
#undef snd_config_set_id
#undef snd_config_set_integer
#undef snd_config_set_integer64
@@ -1705,7 +1691,6 @@
#undef snd_pcm_areas_silence
#undef snd_pcm_area_copy
#undef snd_pcm_areas_copy
-#undef snd_pcm_areas_copy_wrap
#undef snd_pcm_hook_get_pcm
#undef snd_pcm_hook_get_private
#undef snd_pcm_hook_set_private
@@ -2297,7 +2282,6 @@
#undef snd_mixer_selem_id_get_index
#undef snd_mixer_selem_id_set_name
#undef snd_mixer_selem_id_set_index
-#undef snd_mixer_selem_id_parse
#undef snd_seq_open
#undef snd_seq_open_lconf
#undef snd_seq_name
@@ -2570,7 +2554,6 @@
extern "C" {
#endif
#define snd_asoundlib_version snd_asoundlib_version_dylibloader_wrapper_asound
-#define snd_dlpath snd_dlpath_dylibloader_wrapper_asound
#define snd_dlopen snd_dlopen_dylibloader_wrapper_asound
#define snd_dlsym snd_dlsym_dylibloader_wrapper_asound
#define snd_dlclose snd_dlclose_dylibloader_wrapper_asound
@@ -2604,7 +2587,6 @@ extern "C" {
#define snd_strerror snd_strerror_dylibloader_wrapper_asound
#define snd_lib_error_set_handler snd_lib_error_set_handler_dylibloader_wrapper_asound
#define snd_lib_error_set_local snd_lib_error_set_local_dylibloader_wrapper_asound
-#define snd_config_topdir snd_config_topdir_dylibloader_wrapper_asound
#define snd_config_top snd_config_top_dylibloader_wrapper_asound
#define snd_config_load snd_config_load_dylibloader_wrapper_asound
#define snd_config_load_override snd_config_load_override_dylibloader_wrapper_asound
@@ -2622,9 +2604,6 @@ extern "C" {
#define snd_config_expand snd_config_expand_dylibloader_wrapper_asound
#define snd_config_evaluate snd_config_evaluate_dylibloader_wrapper_asound
#define snd_config_add snd_config_add_dylibloader_wrapper_asound
-#define snd_config_add_before snd_config_add_before_dylibloader_wrapper_asound
-#define snd_config_add_after snd_config_add_after_dylibloader_wrapper_asound
-#define snd_config_remove snd_config_remove_dylibloader_wrapper_asound
#define snd_config_delete snd_config_delete_dylibloader_wrapper_asound
#define snd_config_delete_compound_members snd_config_delete_compound_members_dylibloader_wrapper_asound
#define snd_config_copy snd_config_copy_dylibloader_wrapper_asound
@@ -2642,7 +2621,6 @@ extern "C" {
#define snd_config_imake_safe_string snd_config_imake_safe_string_dylibloader_wrapper_asound
#define snd_config_imake_pointer snd_config_imake_pointer_dylibloader_wrapper_asound
#define snd_config_get_type snd_config_get_type_dylibloader_wrapper_asound
-#define snd_config_is_array snd_config_is_array_dylibloader_wrapper_asound
#define snd_config_set_id snd_config_set_id_dylibloader_wrapper_asound
#define snd_config_set_integer snd_config_set_integer_dylibloader_wrapper_asound
#define snd_config_set_integer64 snd_config_set_integer64_dylibloader_wrapper_asound
@@ -2987,7 +2965,6 @@ extern "C" {
#define snd_pcm_areas_silence snd_pcm_areas_silence_dylibloader_wrapper_asound
#define snd_pcm_area_copy snd_pcm_area_copy_dylibloader_wrapper_asound
#define snd_pcm_areas_copy snd_pcm_areas_copy_dylibloader_wrapper_asound
-#define snd_pcm_areas_copy_wrap snd_pcm_areas_copy_wrap_dylibloader_wrapper_asound
#define snd_pcm_hook_get_pcm snd_pcm_hook_get_pcm_dylibloader_wrapper_asound
#define snd_pcm_hook_get_private snd_pcm_hook_get_private_dylibloader_wrapper_asound
#define snd_pcm_hook_set_private snd_pcm_hook_set_private_dylibloader_wrapper_asound
@@ -3579,7 +3556,6 @@ extern "C" {
#define snd_mixer_selem_id_get_index snd_mixer_selem_id_get_index_dylibloader_wrapper_asound
#define snd_mixer_selem_id_set_name snd_mixer_selem_id_set_name_dylibloader_wrapper_asound
#define snd_mixer_selem_id_set_index snd_mixer_selem_id_set_index_dylibloader_wrapper_asound
-#define snd_mixer_selem_id_parse snd_mixer_selem_id_parse_dylibloader_wrapper_asound
#define snd_seq_open snd_seq_open_dylibloader_wrapper_asound
#define snd_seq_open_lconf snd_seq_open_lconf_dylibloader_wrapper_asound
#define snd_seq_name snd_seq_name_dylibloader_wrapper_asound
@@ -3849,8 +3825,7 @@ extern "C" {
#define snd_midi_event_encode_byte snd_midi_event_encode_byte_dylibloader_wrapper_asound
#define snd_midi_event_decode snd_midi_event_decode_dylibloader_wrapper_asound
extern const char* (*snd_asoundlib_version_dylibloader_wrapper_asound)( void);
-extern int (*snd_dlpath_dylibloader_wrapper_asound)( char*, size_t,const char*);
-extern void* (*snd_dlopen_dylibloader_wrapper_asound)(const char*, int, char*, size_t);
+extern void* (*snd_dlopen_dylibloader_wrapper_asound)(const char*, int);
extern void* (*snd_dlsym_dylibloader_wrapper_asound)( void*,const char*,const char*);
extern int (*snd_dlclose_dylibloader_wrapper_asound)( void*);
extern int (*snd_async_add_handler_dylibloader_wrapper_asound)( snd_async_handler_t**, int, snd_async_callback_t, void*);
@@ -3883,7 +3858,6 @@ extern int (*snd_output_flush_dylibloader_wrapper_asound)( snd_output_t*);
extern const char* (*snd_strerror_dylibloader_wrapper_asound)( int);
extern int (*snd_lib_error_set_handler_dylibloader_wrapper_asound)( snd_lib_error_handler_t);
extern snd_local_error_handler_t (*snd_lib_error_set_local_dylibloader_wrapper_asound)( snd_local_error_handler_t);
-extern const char* (*snd_config_topdir_dylibloader_wrapper_asound)( void);
extern int (*snd_config_top_dylibloader_wrapper_asound)( snd_config_t**);
extern int (*snd_config_load_dylibloader_wrapper_asound)( snd_config_t*, snd_input_t*);
extern int (*snd_config_load_override_dylibloader_wrapper_asound)( snd_config_t*, snd_input_t*);
@@ -3901,9 +3875,6 @@ extern int (*snd_config_search_definition_dylibloader_wrapper_asound)( snd_confi
extern int (*snd_config_expand_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*,const char*, snd_config_t*, snd_config_t**);
extern int (*snd_config_evaluate_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*, snd_config_t*, snd_config_t**);
extern int (*snd_config_add_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*);
-extern int (*snd_config_add_before_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*);
-extern int (*snd_config_add_after_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*);
-extern int (*snd_config_remove_dylibloader_wrapper_asound)( snd_config_t*);
extern int (*snd_config_delete_dylibloader_wrapper_asound)( snd_config_t*);
extern int (*snd_config_delete_compound_members_dylibloader_wrapper_asound)(const snd_config_t*);
extern int (*snd_config_copy_dylibloader_wrapper_asound)( snd_config_t**, snd_config_t*);
@@ -3921,7 +3892,6 @@ extern int (*snd_config_imake_string_dylibloader_wrapper_asound)( snd_config_t**
extern int (*snd_config_imake_safe_string_dylibloader_wrapper_asound)( snd_config_t**,const char*,const char*);
extern int (*snd_config_imake_pointer_dylibloader_wrapper_asound)( snd_config_t**,const char*,const void*);
extern snd_config_type_t (*snd_config_get_type_dylibloader_wrapper_asound)(const snd_config_t*);
-extern int (*snd_config_is_array_dylibloader_wrapper_asound)(const snd_config_t*);
extern int (*snd_config_set_id_dylibloader_wrapper_asound)( snd_config_t*,const char*);
extern int (*snd_config_set_integer_dylibloader_wrapper_asound)( snd_config_t*, long);
extern int (*snd_config_set_integer64_dylibloader_wrapper_asound)( snd_config_t*, long long);
@@ -4266,7 +4236,6 @@ extern int (*snd_pcm_area_silence_dylibloader_wrapper_asound)(const snd_pcm_chan
extern int (*snd_pcm_areas_silence_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t, unsigned int, snd_pcm_uframes_t, snd_pcm_format_t);
extern int (*snd_pcm_area_copy_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t,const snd_pcm_channel_area_t*, snd_pcm_uframes_t, unsigned int, snd_pcm_format_t);
extern int (*snd_pcm_areas_copy_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t,const snd_pcm_channel_area_t*, snd_pcm_uframes_t, unsigned int, snd_pcm_uframes_t, snd_pcm_format_t);
-extern int (*snd_pcm_areas_copy_wrap_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t,const snd_pcm_uframes_t,const snd_pcm_channel_area_t*, snd_pcm_uframes_t,const snd_pcm_uframes_t,const unsigned int, snd_pcm_uframes_t,const snd_pcm_format_t);
extern snd_pcm_t* (*snd_pcm_hook_get_pcm_dylibloader_wrapper_asound)( snd_pcm_hook_t*);
extern void* (*snd_pcm_hook_get_private_dylibloader_wrapper_asound)( snd_pcm_hook_t*);
extern void (*snd_pcm_hook_set_private_dylibloader_wrapper_asound)( snd_pcm_hook_t*, void*);
@@ -4858,7 +4827,6 @@ extern const char* (*snd_mixer_selem_id_get_name_dylibloader_wrapper_asound)(con
extern unsigned int (*snd_mixer_selem_id_get_index_dylibloader_wrapper_asound)(const snd_mixer_selem_id_t*);
extern void (*snd_mixer_selem_id_set_name_dylibloader_wrapper_asound)( snd_mixer_selem_id_t*,const char*);
extern void (*snd_mixer_selem_id_set_index_dylibloader_wrapper_asound)( snd_mixer_selem_id_t*, unsigned int);
-extern int (*snd_mixer_selem_id_parse_dylibloader_wrapper_asound)( snd_mixer_selem_id_t*,const char*);
extern int (*snd_seq_open_dylibloader_wrapper_asound)( snd_seq_t**,const char*, int, int);
extern int (*snd_seq_open_lconf_dylibloader_wrapper_asound)( snd_seq_t**,const char*, int, int, snd_config_t*);
extern const char* (*snd_seq_name_dylibloader_wrapper_asound)( snd_seq_t*);
diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp
index f4c87da9e9..09e4f48204 100644
--- a/drivers/alsa/audio_driver_alsa.cpp
+++ b/drivers/alsa/audio_driver_alsa.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* audio_driver_alsa.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* audio_driver_alsa.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#include "audio_driver_alsa.h"
diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h
index fa1dba38ed..6e9cf4dba9 100644
--- a/drivers/alsa/audio_driver_alsa.h
+++ b/drivers/alsa/audio_driver_alsa.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* audio_driver_alsa.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* audio_driver_alsa.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef AUDIO_DRIVER_ALSA_H
#define AUDIO_DRIVER_ALSA_H
diff --git a/drivers/alsamidi/midi_driver_alsamidi.cpp b/drivers/alsamidi/midi_driver_alsamidi.cpp
index d2a0076023..81472fe70c 100644
--- a/drivers/alsamidi/midi_driver_alsamidi.cpp
+++ b/drivers/alsamidi/midi_driver_alsamidi.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* midi_driver_alsamidi.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* midi_driver_alsamidi.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 ALSAMIDI_ENABLED
@@ -37,85 +37,135 @@
#include <errno.h>
-static int get_message_size(uint8_t message) {
- switch (message & 0xF0) {
- case 0x80: // note off
- case 0x90: // note on
- case 0xA0: // aftertouch
- case 0xB0: // continuous controller
- case 0xE0: // pitch bend
- case 0xF2: // song position pointer
- return 3;
-
- case 0xC0: // patch change
- case 0xD0: // channel pressure
- case 0xF1: // time code quarter frame
- case 0xF3: // song select
+MIDIDriverALSAMidi::MessageCategory MIDIDriverALSAMidi::msg_category(uint8_t msg_part) {
+ if (msg_part >= 0xf8) {
+ return MessageCategory::RealTime;
+ } else if (msg_part >= 0xf0) {
+ // System Exclusive begin/end are specified as System Common Category messages,
+ // but we separate them here and give them their own categories as their
+ // behavior is significantly different.
+ if (msg_part == 0xf0) {
+ return MessageCategory::SysExBegin;
+ } else if (msg_part == 0xf7) {
+ return MessageCategory::SysExEnd;
+ }
+ return MessageCategory::SystemCommon;
+ } else if (msg_part >= 0x80) {
+ return MessageCategory::Voice;
+ }
+ return MessageCategory::Data;
+}
+
+size_t MIDIDriverALSAMidi::msg_expected_data(uint8_t status_byte) {
+ if (msg_category(status_byte) == MessageCategory::Voice) {
+ // Voice messages have a channel number in the status byte, mask it out.
+ status_byte &= 0xf0;
+ }
+
+ switch (status_byte) {
+ case 0x80: // Note Off
+ case 0x90: // Note On
+ case 0xA0: // Polyphonic Key Pressure (Aftertouch)
+ case 0xB0: // Control Change (CC)
+ case 0xE0: // Pitch Bend Change
+ case 0xF2: // Song Position Pointer
return 2;
- case 0xF0: // SysEx start
- case 0xF4: // reserved
- case 0xF5: // reserved
- case 0xF6: // tune request
- case 0xF7: // SysEx end
- case 0xF8: // timing clock
- case 0xF9: // reserved
- case 0xFA: // start
- case 0xFB: // continue
- case 0xFC: // stop
- case 0xFD: // reserved
- case 0xFE: // active sensing
- case 0xFF: // reset
+ case 0xC0: // Program Change
+ case 0xD0: // Channel Pressure (Aftertouch)
+ case 0xF1: // MIDI Time Code Quarter Frame
+ case 0xF3: // Song Select
return 1;
}
- return 256;
+ return 0;
+}
+
+void MIDIDriverALSAMidi::InputConnection::parse_byte(uint8_t byte, MIDIDriverALSAMidi &driver,
+ uint64_t timestamp) {
+ switch (msg_category(byte)) {
+ case MessageCategory::RealTime:
+ // Real-Time messages are single byte messages that can
+ // occur at any point.
+ // We pass them straight through.
+ driver.receive_input_packet(timestamp, &byte, 1);
+ break;
+
+ case MessageCategory::Data:
+ // We don't currently forward System Exclusive messages so skip their data.
+ // Collect any expected data for other message types.
+ if (!skipping_sys_ex && expected_data > received_data) {
+ buffer[received_data + 1] = byte;
+ received_data++;
+
+ // Forward a complete message and reset relevant state.
+ if (received_data == expected_data) {
+ driver.receive_input_packet(timestamp, buffer, received_data + 1);
+ received_data = 0;
+
+ if (msg_category(buffer[0]) != MessageCategory::Voice) {
+ // Voice Category messages can be sent with "running status".
+ // This means they don't resend the status byte until it changes.
+ // For other categories, we reset expected data, to require a new status byte.
+ expected_data = 0;
+ }
+ }
+ }
+ break;
+
+ case MessageCategory::SysExBegin:
+ buffer[0] = byte;
+ skipping_sys_ex = true;
+ break;
+
+ case MessageCategory::SysExEnd:
+ expected_data = 0;
+ skipping_sys_ex = false;
+ break;
+
+ case MessageCategory::Voice:
+ case MessageCategory::SystemCommon:
+ buffer[0] = byte;
+ received_data = 0;
+ expected_data = msg_expected_data(byte);
+ skipping_sys_ex = false;
+ if (expected_data == 0) {
+ driver.receive_input_packet(timestamp, &byte, 1);
+ }
+ break;
+ }
+}
+
+int MIDIDriverALSAMidi::InputConnection::read_in(MIDIDriverALSAMidi &driver, uint64_t timestamp) {
+ int ret;
+ do {
+ uint8_t byte = 0;
+ ret = snd_rawmidi_read(rawmidi_ptr, &byte, 1);
+
+ if (ret < 0) {
+ if (ret != -EAGAIN) {
+ ERR_PRINT("snd_rawmidi_read error: " + String(snd_strerror(ret)));
+ }
+ } else {
+ parse_byte(byte, driver, timestamp);
+ }
+ } while (ret > 0);
+
+ return ret;
}
void MIDIDriverALSAMidi::thread_func(void *p_udata) {
MIDIDriverALSAMidi *md = static_cast<MIDIDriverALSAMidi *>(p_udata);
uint64_t timestamp = 0;
- uint8_t buffer[256];
- int expected_size = 255;
- int bytes = 0;
while (!md->exit_thread.is_set()) {
- int ret;
-
md->lock();
- for (int i = 0; i < md->connected_inputs.size(); i++) {
- snd_rawmidi_t *midi_in = md->connected_inputs[i];
- do {
- uint8_t byte = 0;
- ret = snd_rawmidi_read(midi_in, &byte, 1);
- if (ret < 0) {
- if (ret != -EAGAIN) {
- ERR_PRINT("snd_rawmidi_read error: " + String(snd_strerror(ret)));
- }
- } else {
- if (byte & 0x80) {
- // Flush previous packet if there is any
- if (bytes) {
- md->receive_input_packet(timestamp, buffer, bytes);
- bytes = 0;
- }
- expected_size = get_message_size(byte);
- // After a SysEx start, all bytes are data until a SysEx end, so
- // we're going to end the command at the SES, and let the common
- // driver ignore the following data bytes.
- }
+ InputConnection *connections = md->connected_inputs.ptrw();
+ size_t connection_count = md->connected_inputs.size();
- if (bytes < 256) {
- buffer[bytes++] = byte;
- // If we know the size of the current packet receive it if it reached the expected size
- if (bytes >= expected_size) {
- md->receive_input_packet(timestamp, buffer, bytes);
- bytes = 0;
- }
- }
- }
- } while (ret > 0);
+ for (size_t i = 0; i < connection_count; i++) {
+ connections[i].read_in(*md, timestamp);
}
md->unlock();
@@ -139,7 +189,7 @@ Error MIDIDriverALSAMidi::open() {
snd_rawmidi_t *midi_in;
int ret = snd_rawmidi_open(&midi_in, nullptr, name, SND_RAWMIDI_NONBLOCK);
if (ret >= 0) {
- connected_inputs.insert(i++, midi_in);
+ connected_inputs.insert(i++, InputConnection(midi_in));
}
}
@@ -160,7 +210,7 @@ void MIDIDriverALSAMidi::close() {
thread.wait_to_finish();
for (int i = 0; i < connected_inputs.size(); i++) {
- snd_rawmidi_t *midi_in = connected_inputs[i];
+ snd_rawmidi_t *midi_in = connected_inputs[i].rawmidi_ptr;
snd_rawmidi_close(midi_in);
}
connected_inputs.clear();
@@ -179,7 +229,7 @@ PackedStringArray MIDIDriverALSAMidi::get_connected_inputs() {
lock();
for (int i = 0; i < connected_inputs.size(); i++) {
- snd_rawmidi_t *midi_in = connected_inputs[i];
+ snd_rawmidi_t *midi_in = connected_inputs[i].rawmidi_ptr;
snd_rawmidi_info_t *info;
snd_rawmidi_info_malloc(&info);
diff --git a/drivers/alsamidi/midi_driver_alsamidi.h b/drivers/alsamidi/midi_driver_alsamidi.h
index ac3530b1b2..3c6300411c 100644
--- a/drivers/alsamidi/midi_driver_alsamidi.h
+++ b/drivers/alsamidi/midi_driver_alsamidi.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* midi_driver_alsamidi.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* midi_driver_alsamidi.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 MIDI_DRIVER_ALSAMIDI_H
#define MIDI_DRIVER_ALSAMIDI_H
@@ -46,12 +46,48 @@ class MIDIDriverALSAMidi : public MIDIDriver {
Thread thread;
Mutex mutex;
- Vector<snd_rawmidi_t *> connected_inputs;
+ class InputConnection {
+ public:
+ InputConnection() = default;
+ InputConnection(snd_rawmidi_t *midi_in) :
+ rawmidi_ptr{ midi_in } {}
+
+ // Read in and parse available data, forwarding any complete messages through the driver.
+ int read_in(MIDIDriverALSAMidi &driver, uint64_t timestamp);
+
+ snd_rawmidi_t *rawmidi_ptr = nullptr;
+
+ private:
+ static const size_t MSG_BUFFER_SIZE = 3;
+ uint8_t buffer[MSG_BUFFER_SIZE] = { 0 };
+ size_t expected_data = 0;
+ size_t received_data = 0;
+ bool skipping_sys_ex = false;
+ void parse_byte(uint8_t byte, MIDIDriverALSAMidi &driver, uint64_t timestamp);
+ };
+
+ Vector<InputConnection> connected_inputs;
SafeFlag exit_thread;
static void thread_func(void *p_udata);
+ enum class MessageCategory {
+ Data,
+ Voice,
+ SysExBegin,
+ SystemCommon, // excluding System Exclusive Begin/End
+ SysExEnd,
+ RealTime,
+ };
+
+ // If the passed byte is a status byte, return the associated message category,
+ // else return MessageCategory::Data.
+ static MessageCategory msg_category(uint8_t msg_part);
+
+ // Return the number of data bytes expected for the provided status byte.
+ static size_t msg_expected_data(uint8_t status_byte);
+
void lock() const;
void unlock() const;
diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp
index 1db85e2a60..219529d2f6 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.cpp
+++ b/drivers/coreaudio/audio_driver_coreaudio.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* audio_driver_coreaudio.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* audio_driver_coreaudio.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 COREAUDIO_ENABLED
@@ -632,7 +632,7 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
ERR_FAIL_COND(result != noErr);
if (capture) {
- // Reset audio input to keep synchronisation.
+ // Reset audio input to keep synchronization.
input_position = 0;
input_size = 0;
}
diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h
index aac5077bb1..675265757b 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.h
+++ b/drivers/coreaudio/audio_driver_coreaudio.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* audio_driver_coreaudio.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* audio_driver_coreaudio.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef AUDIO_DRIVER_COREAUDIO_H
#define AUDIO_DRIVER_COREAUDIO_H
diff --git a/drivers/coremidi/midi_driver_coremidi.cpp b/drivers/coremidi/midi_driver_coremidi.cpp
index dc69ab9472..7a1b278562 100644
--- a/drivers/coremidi/midi_driver_coremidi.cpp
+++ b/drivers/coremidi/midi_driver_coremidi.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* midi_driver_coremidi.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* midi_driver_coremidi.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 COREMIDI_ENABLED
diff --git a/drivers/coremidi/midi_driver_coremidi.h b/drivers/coremidi/midi_driver_coremidi.h
index ac2ad99eb3..38fb515664 100644
--- a/drivers/coremidi/midi_driver_coremidi.h
+++ b/drivers/coremidi/midi_driver_coremidi.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* midi_driver_coremidi.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* midi_driver_coremidi.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 MIDI_DRIVER_COREMIDI_H
#define MIDI_DRIVER_COREMIDI_H
diff --git a/drivers/gl_context/SCsub b/drivers/gl_context/SCsub
index 7e8bd22960..2204c486c6 100644
--- a/drivers/gl_context/SCsub
+++ b/drivers/gl_context/SCsub
@@ -6,7 +6,7 @@ if env["platform"] in ["haiku", "macos", "windows", "linuxbsd"]:
# Thirdparty source files
thirdparty_dir = "#thirdparty/glad/"
thirdparty_sources = [
- "glad.c",
+ "gl.c",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
diff --git a/drivers/gles3/effects/copy_effects.cpp b/drivers/gles3/effects/copy_effects.cpp
index de0181f887..b8c56018dc 100644
--- a/drivers/gles3/effects/copy_effects.cpp
+++ b/drivers/gles3/effects/copy_effects.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* copy_effects.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
@@ -114,19 +114,23 @@ CopyEffects::~CopyEffects() {
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);
+void CopyEffects::copy_to_rect(const Rect2 &p_rect) {
+ bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION);
+ if (!success) {
+ return;
+ }
+
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);
+ draw_screen_quad();
}
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);
+ bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_DEFAULT);
+ if (!success) {
+ return;
+ }
+
+ draw_screen_triangle();
}
void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region) {
@@ -144,8 +148,8 @@ void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, con
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);
+ glBlitFramebuffer(source_region.position.x, source_region.position.y, source_region.position.x + source_region.size.x, source_region.position.y + source_region.size.y,
+ dest_region.position.x, dest_region.position.y, dest_region.position.x + dest_region.size.x, dest_region.position.y + dest_region.size.y, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[i % 2]);
source_region = dest_region;
}
@@ -155,11 +159,26 @@ void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, con
}
void CopyEffects::set_color(const Color &p_color, const Rect2i &p_region) {
- copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
+ bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
+ if (!success) {
+ return;
+ }
+
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);
+ draw_screen_quad();
+}
+
+void CopyEffects::draw_screen_triangle() {
+ glBindVertexArray(screen_triangle_array);
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+ glBindVertexArray(0);
+}
+
+void CopyEffects::draw_screen_quad() {
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
index b863e76579..38f79b96a6 100644
--- a/drivers/gles3/effects/copy_effects.h
+++ b/drivers/gles3/effects/copy_effects.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* copy_effects.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
@@ -61,10 +61,12 @@ public:
~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_to_rect(const Rect2 &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);
+ void draw_screen_triangle();
+ void draw_screen_quad();
};
} //namespace GLES3
diff --git a/drivers/gles3/environment/fog.cpp b/drivers/gles3/environment/fog.cpp
index 02d88f6871..87470b454b 100644
--- a/drivers/gles3/environment/fog.cpp
+++ b/drivers/gles3/environment/fog.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* fog.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* fog.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
@@ -43,7 +43,7 @@ RID Fog::fog_volume_allocate() {
void Fog::fog_volume_initialize(RID p_rid) {
}
-void Fog::fog_free(RID p_rid) {
+void Fog::fog_volume_free(RID p_rid) {
}
void Fog::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) {
diff --git a/drivers/gles3/environment/fog.h b/drivers/gles3/environment/fog.h
index 350eb459cf..99f2e27c44 100644
--- a/drivers/gles3/environment/fog.h
+++ b/drivers/gles3/environment/fog.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* fog.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
@@ -46,7 +46,7 @@ public:
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_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;
diff --git a/drivers/gles3/environment/gi.cpp b/drivers/gles3/environment/gi.cpp
index 5b16d3539f..8beee25c64 100644
--- a/drivers/gles3/environment/gi.cpp
+++ b/drivers/gles3/environment/gi.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* gi.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
diff --git a/drivers/gles3/environment/gi.h b/drivers/gles3/environment/gi.h
index 5b0aad380e..713c3ef3a5 100644
--- a/drivers/gles3/environment/gi.h
+++ b/drivers/gles3/environment/gi.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* gi.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index c1d203be28..89b1c1889e 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* rasterizer_canvas_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. */
-/*************************************************************************/
+/**************************************************************************/
+/* rasterizer_canvas_gles3.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#include "rasterizer_canvas_gles3.h"
@@ -36,26 +36,14 @@
#include "rasterizer_scene_gles3.h"
#include "core/config/project_settings.h"
+#include "core/math/geometry_2d.h"
#include "servers/rendering/rendering_server_default.h"
#include "storage/config.h"
#include "storage/material_storage.h"
#include "storage/mesh_storage.h"
+#include "storage/particles_storage.h"
#include "storage/texture_storage.h"
-#ifndef GLES_OVER_GL
-#define glClearDepth glClearDepthf
-#endif
-
-//static const GLenum gl_primitive[] = {
-// GL_POINTS,
-// GL_LINES,
-// GL_LINE_STRIP,
-// GL_LINE_LOOP,
-// GL_TRIANGLES,
-// GL_TRIANGLE_STRIP,
-// GL_TRIANGLE_FAN
-//};
-
void RasterizerCanvasGLES3::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) {
p_mat4[0] = p_transform.columns[0][0];
p_mat4[1] = p_transform.columns[0][1];
@@ -115,18 +103,208 @@ void RasterizerCanvasGLES3::_update_transform_to_mat4(const Transform3D &p_trans
p_mat4[15] = 1;
}
-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) {
+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_light_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::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
+ if (state.canvas_instance_data_buffers[state.current_buffer].fence != GLsync()) {
+ GLint syncStatus;
+ glGetSynciv(state.canvas_instance_data_buffers[state.current_buffer].fence, GL_SYNC_STATUS, sizeof(GLint), nullptr, &syncStatus);
+ if (syncStatus == GL_UNSIGNALED) {
+ // If older than 2 frames, wait for sync OpenGL can have up to 3 frames in flight, any more and we need to sync anyway.
+ if (state.canvas_instance_data_buffers[state.current_buffer].last_frame_used < RSG::rasterizer->get_frame_number() - 2) {
+#ifndef WEB_ENABLED
+ // On web, we do nothing as the glSubBufferData will force a sync anyway and WebGL does not like waiting.
+ glClientWaitSync(state.canvas_instance_data_buffers[state.current_buffer].fence, 0, 100000000); // wait for up to 100ms
+#endif
+ } else {
+ // Used in last frame or frame before that. OpenGL can get up to two frames behind, so these buffers may still be in use
+ // Allocate a new buffer and use that.
+ _allocate_instance_data_buffer();
+ }
+ } else {
+ // Already finished all rendering commands, we can use it.
+ state.canvas_instance_data_buffers[state.current_buffer].last_frame_used = RSG::rasterizer->get_frame_number();
+ glDeleteSync(state.canvas_instance_data_buffers[state.current_buffer].fence);
+ state.canvas_instance_data_buffers[state.current_buffer].fence = GLsync();
+ }
+ }
+
+ //setup directional lights if exist
+
+ uint32_t light_count = 0;
+ uint32_t directional_light_count = 0;
+ {
+ Light *l = p_directional_light_list;
+ uint32_t index = 0;
+
+ while (l) {
+ if (index == data.max_lights_per_render) {
+ l->render_index_cache = -1;
+ l = l->next_ptr;
+ continue;
+ }
+
+ CanvasLight *clight = canvas_light_owner.get_or_null(l->light_internal);
+ if (!clight) { //unused or invalid texture
+ l->render_index_cache = -1;
+ l = l->next_ptr;
+ ERR_CONTINUE(!clight);
+ }
+
+ Vector2 canvas_light_dir = l->xform_cache.columns[1].normalized();
+
+ state.light_uniforms[index].position[0] = -canvas_light_dir.x;
+ state.light_uniforms[index].position[1] = -canvas_light_dir.y;
+
+ _update_transform_2d_to_mat2x4(clight->shadow.directional_xform, state.light_uniforms[index].shadow_matrix);
+
+ state.light_uniforms[index].height = l->height; //0..1 here
+
+ for (int i = 0; i < 4; i++) {
+ state.light_uniforms[index].shadow_color[i] = uint8_t(CLAMP(int32_t(l->shadow_color[i] * 255.0), 0, 255));
+ state.light_uniforms[index].color[i] = l->color[i];
+ }
+
+ state.light_uniforms[index].color[3] = l->energy; //use alpha for energy, so base color can go separate
+
+ if (state.shadow_fb != 0) {
+ state.light_uniforms[index].shadow_pixel_size = (1.0 / state.shadow_texture_size) * (1.0 + l->shadow_smooth);
+ state.light_uniforms[index].shadow_z_far_inv = 1.0 / clight->shadow.z_far;
+ state.light_uniforms[index].shadow_y_ofs = clight->shadow.y_offset;
+ } else {
+ state.light_uniforms[index].shadow_pixel_size = 1.0;
+ state.light_uniforms[index].shadow_z_far_inv = 1.0;
+ state.light_uniforms[index].shadow_y_ofs = 0;
+ }
+
+ state.light_uniforms[index].flags = l->blend_mode << LIGHT_FLAGS_BLEND_SHIFT;
+ state.light_uniforms[index].flags |= l->shadow_filter << LIGHT_FLAGS_FILTER_SHIFT;
+
+ if (clight->shadow.enabled) {
+ state.light_uniforms[index].flags |= LIGHT_FLAGS_HAS_SHADOW;
+ }
+
+ l->render_index_cache = index;
+
+ index++;
+ l = l->next_ptr;
+ }
+
+ light_count = index;
+ directional_light_count = light_count;
+ state.using_directional_lights = directional_light_count > 0;
+ }
+
+ //setup lights if exist
+
+ {
+ Light *l = p_light_list;
+ uint32_t index = light_count;
+
+ while (l) {
+ if (index == data.max_lights_per_render) {
+ l->render_index_cache = -1;
+ l = l->next_ptr;
+ continue;
+ }
+
+ CanvasLight *clight = canvas_light_owner.get_or_null(l->light_internal);
+ if (!clight) { //unused or invalid texture
+ l->render_index_cache = -1;
+ l = l->next_ptr;
+ ERR_CONTINUE(!clight);
+ }
+ Transform2D to_light_xform = (p_canvas_transform * l->light_shader_xform).affine_inverse();
+
+ Vector2 canvas_light_pos = p_canvas_transform.xform(l->xform.get_origin()); //convert light position to canvas coordinates, as all computation is done in canvas coords to avoid precision loss
+ state.light_uniforms[index].position[0] = canvas_light_pos.x;
+ state.light_uniforms[index].position[1] = canvas_light_pos.y;
+
+ _update_transform_2d_to_mat2x4(to_light_xform, state.light_uniforms[index].matrix);
+ _update_transform_2d_to_mat2x4(l->xform_cache.affine_inverse(), state.light_uniforms[index].shadow_matrix);
- // TODO: Setup lights
+ state.light_uniforms[index].height = l->height * (p_canvas_transform.columns[0].length() + p_canvas_transform.columns[1].length()) * 0.5; //approximate height conversion to the canvas size, since all calculations are done in canvas coords to avoid precision loss
+ for (int i = 0; i < 4; i++) {
+ state.light_uniforms[index].shadow_color[i] = uint8_t(CLAMP(int32_t(l->shadow_color[i] * 255.0), 0, 255));
+ state.light_uniforms[index].color[i] = l->color[i];
+ }
+
+ state.light_uniforms[index].color[3] = l->energy; //use alpha for energy, so base color can go separate
+
+ if (state.shadow_fb != 0) {
+ state.light_uniforms[index].shadow_pixel_size = (1.0 / state.shadow_texture_size) * (1.0 + l->shadow_smooth);
+ state.light_uniforms[index].shadow_z_far_inv = 1.0 / clight->shadow.z_far;
+ state.light_uniforms[index].shadow_y_ofs = clight->shadow.y_offset;
+ } else {
+ state.light_uniforms[index].shadow_pixel_size = 1.0;
+ state.light_uniforms[index].shadow_z_far_inv = 1.0;
+ state.light_uniforms[index].shadow_y_ofs = 0;
+ }
+
+ state.light_uniforms[index].flags = l->blend_mode << LIGHT_FLAGS_BLEND_SHIFT;
+ state.light_uniforms[index].flags |= l->shadow_filter << LIGHT_FLAGS_FILTER_SHIFT;
+
+ if (clight->shadow.enabled) {
+ state.light_uniforms[index].flags |= LIGHT_FLAGS_HAS_SHADOW;
+ }
+
+ if (clight->texture.is_valid()) {
+ Rect2 atlas_rect = GLES3::TextureStorage::get_singleton()->texture_atlas_get_texture_rect(clight->texture);
+ state.light_uniforms[index].atlas_rect[0] = atlas_rect.position.x;
+ state.light_uniforms[index].atlas_rect[1] = atlas_rect.position.y;
+ state.light_uniforms[index].atlas_rect[2] = atlas_rect.size.width;
+ state.light_uniforms[index].atlas_rect[3] = atlas_rect.size.height;
+
+ } else {
+ state.light_uniforms[index].atlas_rect[0] = 0;
+ state.light_uniforms[index].atlas_rect[1] = 0;
+ state.light_uniforms[index].atlas_rect[2] = 0;
+ state.light_uniforms[index].atlas_rect[3] = 0;
+ }
+
+ l->render_index_cache = index;
+
+ index++;
+ l = l->next_ptr;
+ }
+
+ light_count = index;
+ }
+
+ if (light_count > 0) {
+ glBindBufferBase(GL_UNIFORM_BUFFER, LIGHT_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer].light_ubo);
+
+#ifdef WEB_ENABLED
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(LightUniform) * light_count, state.light_uniforms);
+#else
+ // On Desktop and mobile we map the memory without synchronizing for maximum speed.
+ void *ubo = glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(LightUniform) * light_count, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
+ memcpy(ubo, state.light_uniforms, sizeof(LightUniform) * light_count);
+ glUnmapBuffer(GL_UNIFORM_BUFFER);
+#endif
+
+ GLuint texture_atlas = texture_storage->texture_atlas_get_texture();
+ if (texture_atlas == 0) {
+ GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE));
+ texture_atlas = tex->tex_id;
+ }
+ glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 2);
+ glBindTexture(GL_TEXTURE_2D, texture_atlas);
+ GLuint shadow_tex = state.shadow_texture;
+ if (shadow_tex == 0) {
+ GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE));
+ shadow_tex = tex->tex_id;
+ }
+ glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 3);
+ glBindTexture(GL_TEXTURE_2D, shadow_tex);
+ }
{
//update canvas state uniform buffer
@@ -134,9 +312,14 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
Size2i ssize = texture_storage->render_target_get_size(p_to_render_target);
+ // If we've overridden the render target's color texture, then we need
+ // to invert the Y axis, so 2D texture appear right side up.
+ // We're probably rendering directly to an XR device.
+ float y_scale = texture_storage->render_target_get_override_color(p_to_render_target).is_valid() ? -2.0f : 2.0f;
+
Transform3D screen_transform;
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));
+ screen_transform.scale(Vector3(2.0f / ssize.width, y_scale / 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);
@@ -155,13 +338,10 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x;
state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y;
- // 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;
+ state_buffer.directional_light_count = directional_light_count;
Vector2 canvas_scale = p_canvas_transform.get_scale();
@@ -180,7 +360,8 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
state_buffer.sdf_to_tex[3] = -sdf_tex_rect.position.y / sdf_tex_rect.size.height;
state_buffer.tex_to_sdf = 1.0 / ((canvas_scale.x + canvas_scale.y) * 0.5);
- glBindBufferBase(GL_UNIFORM_BUFFER, BASE_UNIFORM_LOCATION, state.canvas_state_buffer);
+
+ glBindBufferBase(GL_UNIFORM_BUFFER, BASE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer].state_ubo);
glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), &state_buffer, GL_STREAM_DRAW);
GLuint global_buffer = material_storage->global_shader_parameters_get_uniform_buffer();
@@ -189,23 +370,33 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
+ glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 5);
+ glBindTexture(GL_TEXTURE_2D, texture_storage->render_target_get_sdf_texture(p_to_render_target));
+
{
state.default_filter = p_default_filter;
state.default_repeat = p_default_repeat;
}
+ Size2 render_target_size = texture_storage->render_target_get_size(p_to_render_target);
+ glViewport(0, 0, render_target_size.x, render_target_size.y);
+
r_sdf_used = false;
int item_count = 0;
bool backbuffer_cleared = false;
bool time_used = false;
- bool material_screen_texture_found = false;
+ bool material_screen_texture_cached = false;
+ bool material_screen_texture_mipmaps_cached = false;
Rect2 back_buffer_rect;
bool backbuffer_copy = false;
bool backbuffer_gen_mipmaps = false;
+ bool update_skeletons = false;
Item *ci = p_item_list;
Item *canvas_group_owner = nullptr;
+ uint32_t starting_index = 0;
+
while (ci) {
if (ci->copy_back_buffer && canvas_group_owner == nullptr) {
backbuffer_copy = true;
@@ -223,10 +414,12 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
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) {
+ if (!material_screen_texture_cached) {
backbuffer_copy = true;
back_buffer_rect = Rect2();
backbuffer_gen_mipmaps = md->shader_data->uses_screen_texture_mipmaps;
+ } else if (!material_screen_texture_mipmaps_cached) {
+ backbuffer_gen_mipmaps = md->shader_data->uses_screen_texture_mipmaps;
}
}
@@ -239,17 +432,37 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
}
}
+ if (ci->skeleton.is_valid()) {
+ const Item::Command *c = ci->commands;
+
+ while (c) {
+ if (c->type == Item::Command::TYPE_MESH) {
+ const Item::CommandMesh *cm = static_cast<const Item::CommandMesh *>(c);
+ if (cm->mesh_instance.is_valid()) {
+ mesh_storage->mesh_instance_check_for_update(cm->mesh_instance);
+ update_skeletons = true;
+ }
+ }
+ c = c->next;
+ }
+ }
+
if (ci->canvas_group_owner != nullptr) {
if (canvas_group_owner == nullptr) {
+ if (update_skeletons) {
+ mesh_storage->update_mesh_instances();
+ update_skeletons = false;
+ }
// Canvas group begins here, render until before this item
-
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, r_sdf_used);
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) {
+ if (ci->canvas_group_owner->canvas_group->mode != RS::CANVAS_GROUP_MODE_TRANSPARENT) {
+ Rect2i group_rect = ci->canvas_group_owner->global_rect_cache;
texture_storage->render_target_copy_to_back_buffer(p_to_render_target, group_rect, false);
+ if (ci->canvas_group_owner->canvas_group->mode == RS::CANVAS_GROUP_MODE_CLIP_AND_DRAW) {
+ items[item_count++] = ci->canvas_group_owner;
+ }
} else if (!backbuffer_cleared) {
texture_storage->render_target_clear_back_buffer(p_to_render_target, Rect2i(), Color(0, 0, 0, 0));
backbuffer_cleared = true;
@@ -268,7 +481,11 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
}
if (ci == canvas_group_owner) {
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, true);
+ if (update_skeletons) {
+ mesh_storage->update_mesh_instances();
+ update_skeletons = false;
+ }
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, r_sdf_used, true);
item_count = 0;
if (ci->canvas_group->blur_mipmaps) {
@@ -276,25 +493,44 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
}
canvas_group_owner = nullptr;
+ // Backbuffer is dirty now and needs to be re-cleared if another CanvasGroup needs it.
+ backbuffer_cleared = false;
}
if (backbuffer_copy) {
+ if (update_skeletons) {
+ mesh_storage->update_mesh_instances();
+ update_skeletons = false;
+ }
//render anything pending, including clearing if no items
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, r_sdf_used);
item_count = 0;
texture_storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, backbuffer_gen_mipmaps);
backbuffer_copy = false;
- material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies
+ backbuffer_gen_mipmaps = false;
+ material_screen_texture_cached = true; // After a backbuffer copy, screen texture makes no further copies.
+ material_screen_texture_mipmaps_cached = backbuffer_gen_mipmaps;
+ }
+
+ if (backbuffer_gen_mipmaps) {
+ texture_storage->render_target_gen_back_buffer_mipmaps(p_to_render_target, back_buffer_rect);
+
+ backbuffer_gen_mipmaps = false;
+ material_screen_texture_mipmaps_cached = true;
}
// just add all items for now
items[item_count++] = ci;
if (!ci->next || item_count == MAX_RENDER_ITEMS - 1) {
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
+ if (update_skeletons) {
+ mesh_storage->update_mesh_instances();
+ update_skeletons = false;
+ }
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, r_sdf_used);
//then reset
item_count = 0;
}
@@ -306,153 +542,146 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
RenderingServerDefault::redraw_request();
}
+ state.canvas_instance_data_buffers[state.current_buffer].fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+
// Clear out state used in 2D pass
reset_canvas();
+ state.current_buffer = (state.current_buffer + 1) % state.canvas_instance_data_buffers.size();
}
-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();
+void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, uint32_t &r_last_index, bool &r_sdf_used, bool p_to_backbuffer) {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
- Item *current_clip = nullptr;
-
- Transform2D canvas_transform_inverse = p_canvas_transform_inverse;
canvas_begin(p_to_render_target, p_to_backbuffer);
- RID prev_material;
+ if (p_item_count <= 0) {
+ // Nothing to draw, just call canvas_begin() to clear the render target and return.
+ return;
+ }
+
uint32_t index = 0;
- GLES3::CanvasShaderData::BlendMode last_blend_mode = GLES3::CanvasShaderData::BLEND_MODE_MIX;
- Color last_blend_color;
- GLES3::CanvasShaderData *shader_data_cache = nullptr;
+ Item *current_clip = nullptr;
+
+ // Record Batches.
+ // First item always forms its own batch.
+ bool batch_broken = false;
+ _new_batch(batch_broken, index);
- 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;
+ // Override the start position and index as we want to start from where we finished off last time.
+ state.canvas_instance_batches[state.current_batch_index].start = r_last_index;
+ index = 0;
for (int i = 0; i < p_item_count; i++) {
Item *ci = items[i];
- if (current_clip != ci->final_clip_owner) {
- _render_batch(index);
-
+ if (ci->final_clip_owner != state.canvas_instance_batches[state.current_batch_index].clip) {
+ _new_batch(batch_broken, index);
+ state.canvas_instance_batches[state.current_batch_index].clip = ci->final_clip_owner;
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;
-
- if (material.is_null() && ci->canvas_group != nullptr) {
- material = default_canvas_group_material;
+ if (ci->canvas_group != nullptr) {
+ if (ci->canvas_group->mode == RS::CANVAS_GROUP_MODE_CLIP_AND_DRAW) {
+ if (!p_to_backbuffer) {
+ material = default_clip_children_material;
+ }
+ } else {
+ if (material.is_null()) {
+ if (ci->canvas_group->mode == RS::CANVAS_GROUP_MODE_CLIP_ONLY) {
+ material = default_clip_children_material;
+ } else {
+ material = default_canvas_group_material;
+ }
+ }
+ }
}
- if (material != prev_material) {
- _render_batch(index);
+ GLES3::CanvasShaderData *shader_data_cache = nullptr;
+ if (material != state.canvas_instance_batches[state.current_batch_index].material) {
+ _new_batch(batch_broken, 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));
}
+ shader_data_cache = nullptr;
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;
+
+ state.canvas_instance_batches[state.current_batch_index].material = material;
+ state.canvas_instance_batches[state.current_batch_index].material_data = material_data;
}
GLES3::CanvasShaderData::BlendMode blend_mode = shader_data_cache ? shader_data_cache->blend_mode : GLES3::CanvasShaderData::BLEND_MODE_MIX;
- _render_item(p_to_render_target, ci, canvas_transform_inverse, current_clip, p_lights, index, blend_mode, last_blend_mode, last_blend_color);
- }
- // Render last command
- _render_batch(index);
-}
-
-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, GLES3::CanvasShaderData::BlendMode p_blend_mode, GLES3::CanvasShaderData::BlendMode &r_last_blend_mode, Color &r_last_blend_color) {
- // 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;
-
- if (p_item->texture_filter != RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT) {
- current_filter = p_item->texture_filter;
+ _record_item_commands(ci, p_to_render_target, p_canvas_transform_inverse, current_clip, blend_mode, p_lights, index, batch_broken, r_sdf_used);
}
- if (p_item->texture_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) {
- current_repeat = p_item->texture_repeat;
+ if (index == 0) {
+ // Nothing to render, just return.
+ state.current_batch_index = 0;
+ state.canvas_instance_batches.clear();
+ return;
}
- Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform;
- Transform2D draw_transform; // Used by transform command
-
- Color base_color = p_item->final_modulate;
-
- uint32_t base_flags = 0;
+ // Copy over all data needed for rendering.
+ glBindBuffer(GL_ARRAY_BUFFER, state.canvas_instance_data_buffers[state.current_buffer].buffer);
+#ifdef WEB_ENABLED
+ glBufferSubData(GL_ARRAY_BUFFER, r_last_index * sizeof(InstanceData), sizeof(InstanceData) * index, state.instance_data_array);
+#else
+ // On Desktop and mobile we map the memory without synchronizing for maximum speed.
+ void *buffer = glMapBufferRange(GL_ARRAY_BUFFER, r_last_index * sizeof(InstanceData), index * sizeof(InstanceData), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
+ memcpy(buffer, state.instance_data_array, index * sizeof(InstanceData));
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+#endif
- bool reclip = false;
+ glDisable(GL_SCISSOR_TEST);
+ current_clip = nullptr;
- bool skipping = false;
+ GLES3::CanvasShaderData::BlendMode last_blend_mode = GLES3::CanvasShaderData::BLEND_MODE_MIX;
- const Item::Command *c = p_item->commands;
- while (c) {
- if (skipping && c->type != Item::Command::TYPE_ANIMATION_SLICE) {
- c = c->next;
- continue;
- }
+ state.current_tex = RID();
- 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 (uint32_t i = 0; i <= state.current_batch_index; i++) {
+ //setup clip
+ if (current_clip != state.canvas_instance_batches[i].clip) {
+ current_clip = state.canvas_instance_batches[i].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);
+ }
}
- 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;
- state.instance_data_array[r_index].lights[i] = uint32_t(0);
+ GLES3::CanvasMaterialData *material_data = state.canvas_instance_batches[i].material_data;
+ CanvasShaderGLES3::ShaderVariant variant = state.canvas_instance_batches[i].shader_variant;
+ uint64_t specialization = 0;
+ specialization |= uint64_t(state.canvas_instance_batches[i].lights_disabled);
+ specialization |= uint64_t(!GLES3::Config::get_singleton()->float_texture_supported) << 1;
+ RID shader_version = data.canvas_shader_default_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();
+ shader_version = material_data->shader_data->version;
+ }
}
- 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].flags = base_flags | (state.instance_data_array[r_index == 0 ? 0 : r_index - 1].flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config
-
- GLES3::CanvasShaderData::BlendMode blend_mode = p_blend_mode;
- Color blend_color;
-
- if (c->type == Item::Command::TYPE_RECT) {
- const Item::CommandRect *rect = static_cast<const Item::CommandRect *>(c);
- if (rect->flags & CANVAS_RECT_LCD) {
- blend_mode = GLES3::CanvasShaderData::BLEND_MODE_LCD;
- blend_color = rect->modulate;
- }
+ bool success = GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(shader_version, variant, specialization);
+ if (!success) {
+ continue;
}
- if (r_last_blend_mode != blend_mode || r_last_blend_color != blend_color) {
- _render_batch(r_index);
+ GLES3::CanvasShaderData::BlendMode blend_mode = state.canvas_instance_batches[i].blend_mode;
- if (r_last_blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) {
+ 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) {
@@ -463,7 +692,6 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
switch (blend_mode) {
case GLES3::CanvasShaderData::BLEND_MODE_DISABLED: {
// Nothing to do here.
-
} break;
case GLES3::CanvasShaderData::BLEND_MODE_LCD: {
glBlendEquation(GL_FUNC_ADD);
@@ -472,6 +700,7 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
} else {
glBlendFuncSeparate(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_ZERO, GL_ONE);
}
+ Color blend_color = state.canvas_instance_batches[state.current_batch_index].blend_color;
glBlendColor(blend_color.r, blend_color.g, blend_color.b, blend_color.a);
} break;
@@ -520,32 +749,149 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
} break;
}
- r_last_blend_mode = blend_mode;
- r_last_blend_color = blend_color;
+ last_blend_mode = blend_mode;
+ }
+
+ _render_batch(p_lights, i);
+ }
+
+ state.current_batch_index = 0;
+ state.canvas_instance_batches.clear();
+ r_last_index += index;
+}
+
+void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_render_target, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used) {
+ RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? state.default_filter : p_item->texture_filter;
+
+ if (texture_filter != state.canvas_instance_batches[state.current_batch_index].filter) {
+ _new_batch(r_batch_broken, r_index);
+
+ state.canvas_instance_batches[state.current_batch_index].filter = texture_filter;
+ }
+
+ RenderingServer::CanvasItemTextureRepeat texture_repeat = p_item->texture_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? state.default_repeat : p_item->texture_repeat;
+
+ if (texture_repeat != state.canvas_instance_batches[state.current_batch_index].repeat) {
+ _new_batch(r_batch_broken, r_index);
+
+ state.canvas_instance_batches[state.current_batch_index].repeat = texture_repeat;
+ }
+
+ Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform;
+ Transform2D draw_transform; // Used by transform command
+
+ Color base_color = p_item->final_modulate;
+ uint32_t base_flags = 0;
+ Size2 texpixel_size;
+
+ bool reclip = false;
+
+ bool skipping = false;
+
+ // TODO: consider making lights a per-batch property and then baking light operations in the shader for better performance.
+ uint32_t lights[4] = { 0, 0, 0, 0 };
+
+ uint16_t light_count = 0;
+
+ {
+ Light *light = p_lights;
+
+ while (light) {
+ if (light->render_index_cache >= 0 && p_item->light_mask & light->item_mask && p_item->z_final >= light->z_min && p_item->z_final <= light->z_max && p_item->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache)) {
+ uint32_t light_index = light->render_index_cache;
+ lights[light_count >> 2] |= light_index << ((light_count & 3) * 8);
+
+ light_count++;
+
+ if (light_count == data.max_lights_per_item - 1) {
+ break;
+ }
+ }
+ light = light->next_ptr;
+ }
+
+ base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT;
+ }
+
+ bool lights_disabled = light_count == 0 && !state.using_directional_lights;
+
+ if (lights_disabled != state.canvas_instance_batches[state.current_batch_index].lights_disabled) {
+ _new_batch(r_batch_broken, r_index);
+ state.canvas_instance_batches[state.current_batch_index].lights_disabled = lights_disabled;
+ }
+
+ const Item::Command *c = p_item->commands;
+ while (c) {
+ if (skipping && c->type != Item::Command::TYPE_ANIMATION_SLICE) {
+ c = c->next;
+ continue;
+ }
+
+ 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);
+ }
+
+ // Zero out most fields.
+ 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;
+ state.instance_data_array[r_index].lights[i] = 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] = lights[0];
+ state.instance_data_array[r_index].lights[1] = lights[1];
+ state.instance_data_array[r_index].lights[2] = lights[2];
+ state.instance_data_array[r_index].lights[3] = lights[3];
+
+ state.instance_data_array[r_index].flags = base_flags | (state.instance_data_array[r_index == 0 ? 0 : r_index - 1].flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config
+
+ Color blend_color;
+ if (c->type == Item::Command::TYPE_RECT) {
+ const Item::CommandRect *rect = static_cast<const Item::CommandRect *>(c);
+ if (rect->flags & CANVAS_RECT_LCD) {
+ p_blend_mode = GLES3::CanvasShaderData::BLEND_MODE_LCD;
+ blend_color = rect->modulate * base_color;
+ }
+ }
+
+ if (p_blend_mode != state.canvas_instance_batches[state.current_batch_index].blend_mode || blend_color != state.canvas_instance_batches[state.current_batch_index].blend_color) {
+ _new_batch(r_batch_broken, r_index);
+ state.canvas_instance_batches[state.current_batch_index].blend_mode = p_blend_mode;
+ state.canvas_instance_batches[state.current_batch_index].blend_color = blend_color;
}
switch (c->type) {
case Item::Command::TYPE_RECT: {
const Item::CommandRect *rect = static_cast<const Item::CommandRect *>(c);
- if (rect->flags & CANVAS_RECT_TILE) {
- current_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED;
+ if (rect->flags & CANVAS_RECT_TILE && state.canvas_instance_batches[state.current_batch_index].repeat != RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED) {
+ _new_batch(r_batch_broken, r_index);
+ state.canvas_instance_batches[state.current_batch_index].repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED;
}
- 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;
+ if (rect->texture != state.canvas_instance_batches[state.current_batch_index].tex || state.canvas_instance_batches[state.current_batch_index].command_type != Item::Command::TYPE_RECT) {
+ _new_batch(r_batch_broken, r_index);
+ state.canvas_instance_batches[state.current_batch_index].tex = rect->texture;
+ state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_RECT;
+ state.canvas_instance_batches[state.current_batch_index].command = c;
+ state.canvas_instance_batches[state.current_batch_index].shader_variant = 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);
+
+ _prepare_canvas_texture(rect->texture, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
Rect2 src_rect;
Rect2 dst_rect;
if (rect->texture != RID()) {
- 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);
+ src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * texpixel_size, rect->source.size * texpixel_size) : Rect2(0, 0, 1, 1);
dst_rect = Rect2(rect->rect.position, rect->rect.size);
if (dst_rect.size.width < 0) {
@@ -559,10 +905,12 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
if (rect->flags & CANVAS_RECT_FLIP_H) {
src_rect.size.x *= -1;
+ state.instance_data_array[r_index].flags |= FLAGS_FLIP_H;
}
if (rect->flags & CANVAS_RECT_FLIP_V) {
src_rect.size.y *= -1;
+ state.instance_data_array[r_index].flags |= FLAGS_FLIP_V;
}
if (rect->flags & CANVAS_RECT_TRANSPOSE) {
@@ -613,36 +961,32 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
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;
- r_index++;
- if (r_index >= state.max_instances_per_batch - 1) {
- _render_batch(r_index);
- }
+ _add_to_batch(r_index, r_batch_broken);
} break;
case Item::Command::TYPE_NINEPATCH: {
const Item::CommandNinePatch *np = static_cast<const Item::CommandNinePatch *>(c);
- 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;
+ if (np->texture != state.canvas_instance_batches[state.current_batch_index].tex || state.canvas_instance_batches[state.current_batch_index].command_type != Item::Command::TYPE_NINEPATCH) {
+ _new_batch(r_batch_broken, r_index);
+ state.canvas_instance_batches[state.current_batch_index].tex = np->texture;
+ state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_NINEPATCH;
+ state.canvas_instance_batches[state.current_batch_index].command = c;
+ state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_NINEPATCH;
}
- //bind textures
- _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);
+ _prepare_canvas_texture(np->texture, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
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()) {
- state.current_pixel_size = Size2(1, 1);
+ texpixel_size = Size2(1, 1);
src_rect = Rect2(0, 0, 1, 1);
} else {
if (np->source != Rect2()) {
- 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);
+ 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);
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;
@@ -678,32 +1022,26 @@ 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];
- r_index++;
- if (r_index >= state.max_instances_per_batch - 1) {
- _render_batch(r_index);
- }
+ _add_to_batch(r_index, r_batch_broken);
// Restore if overridden.
- 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;
+ 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;
} break;
case Item::Command::TYPE_POLYGON: {
const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c);
- PolygonBuffers *pb = polygon_buffers.polygons.getptr(polygon->polygon.polygon_id);
- ERR_CONTINUE(!pb);
+ // Polygon's can't be batched, so always create a new batch
+ _new_batch(r_batch_broken, r_index);
- if (polygon->texture != state.current_tex || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_POLYGON) {
- _render_batch(r_index);
+ state.canvas_instance_batches[state.current_batch_index].tex = polygon->texture;
+ state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_POLYGON;
+ state.canvas_instance_batches[state.current_batch_index].command = c;
+ state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_ATTRIBUTES;
- state.current_primitive_points = 0;
- state.current_command = Item::Command::TYPE_POLYGON;
- }
- _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);
+ _prepare_canvas_texture(polygon->texture, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
- state.current_primitive = polygon->primitive;
state.instance_data_array[r_index].modulation[0] = base_color.r;
state.instance_data_array[r_index].modulation[1] = base_color.g;
state.instance_data_array[r_index].modulation[2] = base_color.b;
@@ -715,39 +1053,22 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
state.instance_data_array[r_index].ninepatch_margins[j] = 0;
}
- _bind_instance_data_buffer(1);
- glBindVertexArray(pb->vertex_array);
-
- 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);
- } else {
- glDrawArrays(prim[polygon->primitive], 0, pb->count);
- }
- glBindVertexArray(0);
- 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);
- }
+ _add_to_batch(r_index, r_batch_broken);
} break;
case Item::Command::TYPE_PRIMITIVE: {
const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c);
- 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;
+ if (primitive->point_count != state.canvas_instance_batches[state.current_batch_index].primitive_points || state.canvas_instance_batches[state.current_batch_index].command_type != Item::Command::TYPE_PRIMITIVE) {
+ _new_batch(r_batch_broken, r_index);
+ state.canvas_instance_batches[state.current_batch_index].tex = primitive->texture;
+ state.canvas_instance_batches[state.current_batch_index].primitive_points = primitive->point_count;
+ state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_PRIMITIVE;
+ state.canvas_instance_batches[state.current_batch_index].command = c;
+ state.canvas_instance_batches[state.current_batch_index].shader_variant = 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);
+
+ _prepare_canvas_texture(state.canvas_instance_batches[state.current_batch_index].tex, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
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;
@@ -758,97 +1079,86 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
state.instance_data_array[r_index].colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r);
state.instance_data_array[r_index].colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b);
}
- r_index++;
+
+ _add_to_batch(r_index, r_batch_broken);
+
if (primitive->point_count == 4) {
- // Reset base data
+ // Reset base data.
_update_transform_2d_to_mat2x3(base_transform * draw_transform, state.instance_data_array[r_index].world);
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].flags = base_flags | (state.instance_data_array[r_index == 0 ? 0 : r_index - 1].flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config
+ state.instance_data_array[r_index].flags = base_flags | (state.instance_data_array[r_index - 1].flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config
for (uint32_t j = 0; j < 3; j++) {
- //second half of triangle
- state.instance_data_array[r_index].points[j * 2 + 0] = primitive->points[j + 1].x;
- state.instance_data_array[r_index].points[j * 2 + 1] = primitive->points[j + 1].y;
- state.instance_data_array[r_index].uvs[j * 2 + 0] = primitive->uvs[j + 1].x;
- state.instance_data_array[r_index].uvs[j * 2 + 1] = primitive->uvs[j + 1].y;
- Color col = primitive->colors[j + 1] * base_color;
+ int offset = j == 0 ? 0 : 1;
+ // Second triangle in the quad. Uses vertices 0, 2, 3.
+ state.instance_data_array[r_index].points[j * 2 + 0] = primitive->points[j + offset].x;
+ state.instance_data_array[r_index].points[j * 2 + 1] = primitive->points[j + offset].y;
+ state.instance_data_array[r_index].uvs[j * 2 + 0] = primitive->uvs[j + offset].x;
+ state.instance_data_array[r_index].uvs[j * 2 + 1] = primitive->uvs[j + offset].y;
+ Color col = primitive->colors[j + offset] * base_color;
state.instance_data_array[r_index].colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r);
state.instance_data_array[r_index].colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b);
}
- r_index++;
- }
- if (r_index >= state.max_instances_per_batch - 1) {
- _render_batch(r_index);
+
+ _add_to_batch(r_index, r_batch_broken);
}
} break;
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);
- 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;
+ // Mesh's can't be batched, so always create a new batch
+ _new_batch(r_batch_broken, r_index);
+ Color modulate(1, 1, 1, 1);
+ state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_ATTRIBUTES;
if (c->type == Item::Command::TYPE_MESH) {
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
- mesh = m->mesh;
- mesh_instance = m->mesh_instance;
- texture = m->texture;
- modulate = m->modulate;
+ state.canvas_instance_batches[state.current_batch_index].tex = m->texture;
_update_transform_2d_to_mat2x3(base_transform * draw_transform * m->transform, state.instance_data_array[r_index].world);
+ modulate = m->modulate;
+
} else if (c->type == Item::Command::TYPE_MULTIMESH) {
const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c);
- RID multimesh = mm->multimesh;
- mesh = mesh_storage->multimesh_get_mesh(multimesh);
- texture = mm->texture;
+ state.canvas_instance_batches[state.current_batch_index].tex = mm->texture;
+ state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_INSTANCED;
- if (mesh_storage->multimesh_get_transform_format(multimesh) != RS::MULTIMESH_TRANSFORM_2D) {
- break;
- }
+ } else if (c->type == Item::Command::TYPE_PARTICLES) {
+ GLES3::ParticlesStorage *particles_storage = GLES3::ParticlesStorage::get_singleton();
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
- instance_count = mesh_storage->multimesh_get_instances_to_draw(multimesh);
+ const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c);
+ RID particles = pt->particles;
+ state.canvas_instance_batches[state.current_batch_index].tex = pt->texture;
+ state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_INSTANCED;
- if (instance_count == 0) {
- break;
- }
+ if (particles_storage->particles_has_collision(particles) && texture_storage->render_target_is_sdf_enabled(p_render_target)) {
+ // Pass collision information.
+ Transform2D xform = p_item->final_transform;
- 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);
- }
+ GLuint sdf_texture = texture_storage->render_target_get_sdf_texture(p_render_target);
- // TODO: implement particles here
+ Rect2 to_screen;
+ {
+ Rect2 sdf_rect = texture_storage->render_target_get_sdf_rect(p_render_target);
- if (mesh.is_null()) {
- break;
- }
+ to_screen.size = Vector2(1.0 / sdf_rect.size.width, 1.0 / sdf_rect.size.height);
+ to_screen.position = -sdf_rect.position * to_screen.size;
+ }
- 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;
+ particles_storage->particles_set_canvas_sdf_collision(pt->particles, true, xform, to_screen, sdf_texture);
+ } else {
+ particles_storage->particles_set_canvas_sdf_collision(pt->particles, false, Transform2D(), Rect2(), 0);
+ }
+ r_sdf_used |= particles_storage->particles_has_collision(particles);
}
- _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);
- }
+ state.canvas_instance_batches[state.current_batch_index].command = c;
+ state.canvas_instance_batches[state.current_batch_index].command_type = c->type;
- uint32_t surf_count = mesh_storage->mesh_get_surface_count(mesh);
+ _prepare_canvas_texture(state.canvas_instance_batches[state.current_batch_index].tex, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
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;
@@ -860,75 +1170,9 @@ 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++) {
- void *surface = mesh_storage->mesh_get_surface(mesh, j);
-
- RS::PrimitiveType primitive = mesh_storage->mesh_surface_get_primitive(surface);
- ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX);
-
- 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);
- }
-
- 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);
- }
- }
+ _add_to_batch(r_index, r_batch_broken);
} break;
+
case Item::Command::TYPE_TRANSFORM: {
const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c);
draw_transform = transform->xform;
@@ -938,30 +1182,30 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
const Item::CommandClipIgnore *ci = static_cast<const Item::CommandClipIgnore *>(c);
if (current_clip) {
if (ci->ignore != reclip) {
+ _new_batch(r_batch_broken, r_index);
if (ci->ignore) {
- glDisable(GL_SCISSOR_TEST);
+ state.canvas_instance_batches[state.current_batch_index].clip = nullptr;
reclip = true;
} else {
- // Scissor area is already set
- glEnable(GL_SCISSOR_TEST);
+ state.canvas_instance_batches[state.current_batch_index].clip = current_clip;
reclip = false;
}
}
}
} break;
+
case Item::Command::TYPE_ANIMATION_SLICE: {
- /*
const Item::CommandAnimationSlice *as = static_cast<const Item::CommandAnimationSlice *>(c);
- double current_time = RendererCompositorRD::singleton->get_total_time();
+ double current_time = RSG::rasterizer->get_total_time();
double local_time = Math::fposmod(current_time - as->offset, as->animation_length);
skipping = !(local_time >= as->slice_begin && local_time < as->slice_end);
RenderingServerDefault::redraw_request(); // animation visible means redraw request
- */
} break;
}
c = c->next;
+ r_batch_broken = false;
}
if (current_clip && reclip) {
@@ -970,101 +1214,822 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
}
}
-void RasterizerCanvasGLES3::_render_batch(uint32_t &r_index) {
- 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);
- } else {
- static const GLenum prim[5] = { GL_POINTS, GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLES };
- glDrawArraysInstanced(prim[state.current_primitive_points], 0, state.current_primitive_points, r_index);
- }
- glBindBuffer(GL_UNIFORM_BUFFER, 0);
+void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
+ ERR_FAIL_COND(!state.canvas_instance_batches[state.current_batch_index].command);
- 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();
- //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];
- state.instance_data_array[0].ninepatch_margins[i] = state.instance_data_array[r_index].ninepatch_margins[i];
- state.instance_data_array[0].src_rect[i] = state.instance_data_array[r_index].src_rect[i];
- state.instance_data_array[0].dst_rect[i] = state.instance_data_array[r_index].dst_rect[i];
- state.instance_data_array[0].lights[i] = state.instance_data_array[r_index].lights[i];
- }
- state.instance_data_array[0].flags = state.instance_data_array[r_index].flags;
- state.instance_data_array[0].color_texture_pixel_size[0] = state.instance_data_array[r_index].color_texture_pixel_size[0];
- state.instance_data_array[0].color_texture_pixel_size[1] = state.instance_data_array[r_index].color_texture_pixel_size[1];
-
- state.instance_data_array[0].pad[0] = state.instance_data_array[r_index].pad[0];
- state.instance_data_array[0].pad[1] = state.instance_data_array[r_index].pad[1];
- for (int i = 0; i < 6; i++) {
- state.instance_data_array[0].world[i] = state.instance_data_array[r_index].world[i];
- }
+ // Used by Polygon and Mesh.
+ static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP };
- r_index = 0;
+ _bind_canvas_texture(state.canvas_instance_batches[p_index].tex, state.canvas_instance_batches[p_index].filter, state.canvas_instance_batches[p_index].repeat);
+
+ switch (state.canvas_instance_batches[p_index].command_type) {
+ case Item::Command::TYPE_RECT:
+ case Item::Command::TYPE_NINEPATCH: {
+ glBindVertexArray(data.indexed_quad_array);
+ glBindBuffer(GL_ARRAY_BUFFER, state.canvas_instance_data_buffers[state.current_buffer].buffer);
+ uint32_t range_start = state.canvas_instance_batches[p_index].start * sizeof(InstanceData);
+ _enable_attributes(range_start, false);
+
+ glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0, state.canvas_instance_batches[p_index].instance_count);
+ glBindVertexArray(0);
+
+ } break;
+
+ case Item::Command::TYPE_POLYGON: {
+ const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(state.canvas_instance_batches[p_index].command);
+
+ PolygonBuffers *pb = polygon_buffers.polygons.getptr(polygon->polygon.polygon_id);
+ ERR_FAIL_COND(!pb);
+
+ glBindVertexArray(pb->vertex_array);
+ glBindBuffer(GL_ARRAY_BUFFER, state.canvas_instance_data_buffers[state.current_buffer].buffer);
+
+ uint32_t range_start = state.canvas_instance_batches[p_index].start * sizeof(InstanceData);
+ _enable_attributes(range_start, false);
+
+ if (pb->color_disabled && pb->color != Color(1.0, 1.0, 1.0, 1.0)) {
+ glVertexAttrib4f(RS::ARRAY_COLOR, pb->color.r, pb->color.g, pb->color.b, pb->color.a);
+ }
+
+ if (pb->index_buffer != 0) {
+ glDrawElementsInstanced(prim[polygon->primitive], pb->count, GL_UNSIGNED_INT, nullptr, 1);
+ } else {
+ glDrawArraysInstanced(prim[polygon->primitive], 0, pb->count, 1);
+ }
+ glBindVertexArray(0);
+
+ if (pb->color_disabled && pb->color != Color(1.0, 1.0, 1.0, 1.0)) {
+ // 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: {
+ glBindVertexArray(data.canvas_quad_array);
+ glBindBuffer(GL_ARRAY_BUFFER, state.canvas_instance_data_buffers[state.current_buffer].buffer);
+ uint32_t range_start = state.canvas_instance_batches[p_index].start * sizeof(InstanceData);
+ _enable_attributes(range_start, true);
+
+ const GLenum primitive[5] = { GL_POINTS, GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLES };
+ int instance_count = state.canvas_instance_batches[p_index].instance_count;
+ ERR_FAIL_COND(instance_count <= 0);
+ if (instance_count >= 1) {
+ glDrawArraysInstanced(primitive[state.canvas_instance_batches[p_index].primitive_points], 0, state.canvas_instance_batches[p_index].primitive_points, instance_count);
+ }
+
+ } break;
+
+ case Item::Command::TYPE_MESH:
+ case Item::Command::TYPE_MULTIMESH:
+ case Item::Command::TYPE_PARTICLES: {
+ GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
+ GLES3::ParticlesStorage *particles_storage = GLES3::ParticlesStorage::get_singleton();
+ RID mesh;
+ RID mesh_instance;
+ uint32_t instance_count = 1;
+ GLuint instance_buffer = 0;
+ uint32_t instance_stride = 0;
+ uint32_t instance_color_offset = 0;
+ bool instance_uses_color = false;
+ bool instance_uses_custom_data = false;
+
+ if (state.canvas_instance_batches[p_index].command_type == Item::Command::TYPE_MESH) {
+ const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(state.canvas_instance_batches[p_index].command);
+ mesh = m->mesh;
+ mesh_instance = m->mesh_instance;
+
+ } else if (state.canvas_instance_batches[p_index].command_type == Item::Command::TYPE_MULTIMESH) {
+ const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(state.canvas_instance_batches[p_index].command);
+ RID multimesh = mm->multimesh;
+ mesh = mesh_storage->multimesh_get_mesh(multimesh);
+
+ if (mesh_storage->multimesh_get_transform_format(multimesh) != RS::MULTIMESH_TRANSFORM_2D) {
+ break;
+ }
+
+ instance_count = mesh_storage->multimesh_get_instances_to_draw(multimesh);
+
+ if (instance_count == 0) {
+ break;
+ }
+
+ instance_buffer = mesh_storage->multimesh_get_gl_buffer(multimesh);
+ instance_stride = mesh_storage->multimesh_get_stride(multimesh);
+ instance_color_offset = mesh_storage->multimesh_get_color_offset(multimesh);
+ instance_uses_color = mesh_storage->multimesh_uses_colors(multimesh);
+ instance_uses_custom_data = mesh_storage->multimesh_uses_custom_data(multimesh);
+
+ } else if (state.canvas_instance_batches[p_index].command_type == Item::Command::TYPE_PARTICLES) {
+ const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(state.canvas_instance_batches[p_index].command);
+ RID particles = pt->particles;
+ mesh = particles_storage->particles_get_draw_pass_mesh(particles, 0);
+
+ ERR_BREAK(particles_storage->particles_get_mode(particles) != RS::PARTICLES_MODE_2D);
+ particles_storage->particles_request_process(particles);
+
+ if (particles_storage->particles_is_inactive(particles)) {
+ break;
+ }
+
+ RenderingServerDefault::redraw_request(); // Active particles means redraw request.
+
+ int dpc = particles_storage->particles_get_draw_passes(particles);
+ if (dpc == 0) {
+ break; // Nothing to draw.
+ }
+
+ instance_count = particles_storage->particles_get_amount(particles);
+ instance_buffer = particles_storage->particles_get_gl_buffer(particles);
+ instance_stride = 12; // 8 bytes for instance transform and 4 bytes for packed color and custom.
+ instance_color_offset = 8; // 8 bytes for instance transform.
+ instance_uses_color = true;
+ instance_uses_custom_data = true;
+ }
+
+ ERR_FAIL_COND(mesh.is_null());
+
+ uint32_t surf_count = mesh_storage->mesh_get_surface_count(mesh);
+
+ for (uint32_t j = 0; j < surf_count; j++) {
+ void *surface = mesh_storage->mesh_get_surface(mesh, j);
+
+ RS::PrimitiveType primitive = mesh_storage->mesh_surface_get_primitive(surface);
+ ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX);
+
+ 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);
+ }
+
+ index_array_gl = mesh_storage->mesh_surface_get_index_buffer(surface, 0);
+ bool use_index_buffer = false;
+ glBindVertexArray(vertex_array_gl);
+ glBindBuffer(GL_ARRAY_BUFFER, state.canvas_instance_data_buffers[state.current_buffer].buffer);
+
+ uint32_t range_start = state.canvas_instance_batches[p_index].start * sizeof(InstanceData);
+ _enable_attributes(range_start, false, instance_count);
+
+ if (index_array_gl != 0) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_gl);
+ use_index_buffer = true;
+ }
+
+ if (instance_count > 1) {
+ if (instance_buffer == 0) {
+ break;
+ }
+ // Bind instance buffers.
+ glBindBuffer(GL_ARRAY_BUFFER, instance_buffer);
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, instance_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0));
+ glVertexAttribDivisor(1, 1);
+ glEnableVertexAttribArray(2);
+ glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, instance_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 4));
+ glVertexAttribDivisor(2, 1);
+
+ if (instance_uses_color || instance_uses_custom_data) {
+ glEnableVertexAttribArray(5);
+ glVertexAttribIPointer(5, 4, GL_UNSIGNED_INT, instance_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(instance_color_offset * sizeof(float)));
+ glVertexAttribDivisor(5, 1);
+ }
+ }
+
+ GLenum primitive_gl = prim[int(primitive)];
+
+ 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);
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ if (instance_count > 1) {
+ glDisableVertexAttribArray(5);
+ glDisableVertexAttribArray(6);
+ glDisableVertexAttribArray(7);
+ glDisableVertexAttribArray(8);
+ }
+ }
+
+ } break;
+ case Item::Command::TYPE_TRANSFORM:
+ case Item::Command::TYPE_CLIP_IGNORE:
+ case Item::Command::TYPE_ANIMATION_SLICE: {
+ // Can ignore these as they only impact batch creation.
+ } break;
}
}
-void RasterizerCanvasGLES3::_bind_instance_data_buffer(uint32_t p_max_index) {
- if (p_max_index == 0) {
+void RasterizerCanvasGLES3::_add_to_batch(uint32_t &r_index, bool &r_batch_broken) {
+ if (r_index >= data.max_instances_per_buffer - 1) {
+ ERR_PRINT_ONCE("Trying to draw too many items. Please increase maximum number of items in the project settings 'rendering/gl_compatibility/item_buffer_size'");
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]);
- }
+
+ if (state.canvas_instance_batches[state.current_batch_index].instance_count >= data.max_instances_per_batch) {
+ _new_batch(r_batch_broken, r_index);
}
- glBindBufferBase(GL_UNIFORM_BUFFER, INSTANCE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer]);
-#ifdef WEB_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
+ state.canvas_instance_batches[state.current_batch_index].instance_count++;
+ r_index++;
+}
+
+void RasterizerCanvasGLES3::_new_batch(bool &r_batch_broken, uint32_t &r_index) {
+ if (state.canvas_instance_batches.size() == 0) {
+ state.canvas_instance_batches.push_back(Batch());
+ return;
+ }
+
+ if (r_batch_broken || state.canvas_instance_batches[state.current_batch_index].instance_count == 0) {
+ return;
+ }
+
+ r_batch_broken = true;
+
+ // Copy the properties of the current batch, we will manually update the things that changed.
+ Batch new_batch = state.canvas_instance_batches[state.current_batch_index];
+ new_batch.instance_count = 0;
+ new_batch.start = state.canvas_instance_batches[state.current_batch_index].start + state.canvas_instance_batches[state.current_batch_index].instance_count;
+
+ state.current_batch_index++;
+ state.canvas_instance_batches.push_back(new_batch);
}
+void RasterizerCanvasGLES3::_enable_attributes(uint32_t p_start, bool p_primitive, uint32_t p_rate) {
+ uint32_t split = p_primitive ? 11 : 12;
+ for (uint32_t i = 6; i < split; i++) {
+ glEnableVertexAttribArray(i);
+ glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, sizeof(InstanceData), CAST_INT_TO_UCHAR_PTR(p_start + (i - 6) * 4 * sizeof(float)));
+ glVertexAttribDivisor(i, p_rate);
+ }
+ for (uint32_t i = split; i <= 13; i++) {
+ glEnableVertexAttribArray(i);
+ glVertexAttribIPointer(i, 4, GL_UNSIGNED_INT, sizeof(InstanceData), CAST_INT_TO_UCHAR_PTR(p_start + (i - 6) * 4 * sizeof(float)));
+ glVertexAttribDivisor(i, p_rate);
+ }
+}
RID RasterizerCanvasGLES3::light_create() {
- return RID();
+ CanvasLight canvas_light;
+ return canvas_light_owner.make_rid(canvas_light);
}
void RasterizerCanvasGLES3::light_set_texture(RID p_rid, RID p_texture) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+
+ CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
+ ERR_FAIL_COND(!cl);
+ if (cl->texture == p_texture) {
+ return;
+ }
+ if (cl->texture.is_valid()) {
+ texture_storage->texture_remove_from_texture_atlas(cl->texture);
+ }
+ cl->texture = p_texture;
+
+ if (cl->texture.is_valid()) {
+ texture_storage->texture_add_to_texture_atlas(cl->texture);
+ }
}
void RasterizerCanvasGLES3::light_set_use_shadow(RID p_rid, bool p_enable) {
+ CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
+ ERR_FAIL_COND(!cl);
+
+ cl->shadow.enabled = p_enable;
}
void RasterizerCanvasGLES3::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) {
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
+ CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
+ ERR_FAIL_COND(!cl->shadow.enabled);
+
+ _update_shadow_atlas();
+
+ cl->shadow.z_far = p_far;
+ cl->shadow.y_offset = float(p_shadow_index * 2 + 1) / float(data.max_lights_per_render * 2);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, state.shadow_fb);
+ glViewport(0, p_shadow_index * 2, state.shadow_texture_size, 2);
+
+ glDepthMask(GL_TRUE);
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glDisable(GL_BLEND);
+
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(0, p_shadow_index * 2, state.shadow_texture_size, 2);
+ glClearColor(p_far, p_far, p_far, 1.0);
+ glClearDepth(1.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glCullFace(GL_BACK);
+ glDisable(GL_CULL_FACE);
+ RS::CanvasOccluderPolygonCullMode cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
+
+ CanvasOcclusionShaderGLES3::ShaderVariant variant = config->float_texture_supported ? CanvasOcclusionShaderGLES3::MODE_SHADOW : CanvasOcclusionShaderGLES3::MODE_SHADOW_RGBA;
+ bool success = shadow_render.shader.version_bind_shader(shadow_render.shader_version, variant);
+ if (!success) {
+ return;
+ }
+
+ for (int i = 0; i < 4; i++) {
+ glViewport((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2);
+
+ Projection projection;
+ {
+ real_t fov = 90;
+ real_t nearp = p_near;
+ real_t farp = p_far;
+ real_t aspect = 1.0;
+
+ real_t ymax = nearp * Math::tan(Math::deg_to_rad(fov * 0.5));
+ real_t ymin = -ymax;
+ real_t xmin = ymin * aspect;
+ real_t xmax = ymax * aspect;
+
+ projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp);
+ }
+
+ Vector3 cam_target = Basis::from_euler(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0));
+
+ projection = projection * Projection(Transform3D().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse());
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::PROJECTION, projection, shadow_render.shader_version, variant);
+
+ static const Vector2 directions[4] = { Vector2(1, 0), Vector2(0, 1), Vector2(-1, 0), Vector2(0, -1) };
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::DIRECTION, directions[i].x, directions[i].y, shadow_render.shader_version, variant);
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::Z_FAR, p_far, shadow_render.shader_version, variant);
+
+ LightOccluderInstance *instance = p_occluders;
+
+ while (instance) {
+ OccluderPolygon *co = occluder_polygon_owner.get_or_null(instance->occluder);
+
+ if (!co || co->vertex_array == 0 || !(p_light_mask & instance->light_mask)) {
+ instance = instance->next;
+ continue;
+ }
+
+ Transform2D modelview = p_light_xform * instance->xform_cache;
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW1, modelview.columns[0][0], modelview.columns[1][0], 0, modelview.columns[2][0], shadow_render.shader_version, variant);
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW2, modelview.columns[0][1], modelview.columns[1][1], 0, modelview.columns[2][1], shadow_render.shader_version, variant);
+
+ if (co->cull_mode != cull_mode) {
+ if (co->cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED) {
+ glDisable(GL_CULL_FACE);
+ } else {
+ if (cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED) {
+ // Last time was disabled, so enable and set proper face.
+ glEnable(GL_CULL_FACE);
+ }
+ glCullFace(co->cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE ? GL_FRONT : GL_BACK);
+ }
+ cull_mode = co->cull_mode;
+ }
+
+ glBindVertexArray(co->vertex_array);
+ glDrawElements(GL_TRIANGLES, 3 * co->line_point_count, GL_UNSIGNED_SHORT, 0);
+
+ instance = instance->next;
+ }
+ }
+
+ glBindVertexArray(0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
}
void RasterizerCanvasGLES3::light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) {
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
+ CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
+ ERR_FAIL_COND(!cl->shadow.enabled);
+
+ _update_shadow_atlas();
+
+ Vector2 light_dir = p_light_xform.columns[1].normalized();
+
+ Vector2 center = p_clip_rect.get_center();
+
+ float to_edge_distance = ABS(light_dir.dot(p_clip_rect.get_support(light_dir)) - light_dir.dot(center));
+
+ Vector2 from_pos = center - light_dir * (to_edge_distance + p_cull_distance);
+ float distance = to_edge_distance * 2.0 + p_cull_distance;
+ float half_size = p_clip_rect.size.length() * 0.5; //shadow length, must keep this no matter the angle
+
+ cl->shadow.z_far = distance;
+ cl->shadow.y_offset = float(p_shadow_index * 2 + 1) / float(data.max_lights_per_render * 2);
+
+ Transform2D to_light_xform;
+
+ to_light_xform[2] = from_pos;
+ to_light_xform[1] = light_dir;
+ to_light_xform[0] = -light_dir.orthogonal();
+
+ to_light_xform.invert();
+
+ glBindFramebuffer(GL_FRAMEBUFFER, state.shadow_fb);
+ glViewport(0, p_shadow_index * 2, state.shadow_texture_size, 2);
+
+ glDepthMask(GL_TRUE);
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glDisable(GL_BLEND);
+
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(0, p_shadow_index * 2, state.shadow_texture_size, 2);
+ glClearColor(1.0, 1.0, 1.0, 1.0);
+ glClearDepth(1.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glCullFace(GL_BACK);
+ glDisable(GL_CULL_FACE);
+ RS::CanvasOccluderPolygonCullMode cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
+
+ CanvasOcclusionShaderGLES3::ShaderVariant variant = config->float_texture_supported ? CanvasOcclusionShaderGLES3::MODE_SHADOW : CanvasOcclusionShaderGLES3::MODE_SHADOW_RGBA;
+ bool success = shadow_render.shader.version_bind_shader(shadow_render.shader_version, variant);
+ if (!success) {
+ return;
+ }
+
+ Projection projection;
+ projection.set_orthogonal(-half_size, half_size, -0.5, 0.5, 0.0, distance);
+ projection = projection * Projection(Transform3D().looking_at(Vector3(0, 1, 0), Vector3(0, 0, -1)).affine_inverse());
+
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::PROJECTION, projection, shadow_render.shader_version, variant);
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::DIRECTION, 0.0, 1.0, shadow_render.shader_version, variant);
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::Z_FAR, distance, shadow_render.shader_version, variant);
+
+ LightOccluderInstance *instance = p_occluders;
+
+ while (instance) {
+ OccluderPolygon *co = occluder_polygon_owner.get_or_null(instance->occluder);
+
+ if (!co || co->vertex_array == 0 || !(p_light_mask & instance->light_mask)) {
+ instance = instance->next;
+ continue;
+ }
+
+ Transform2D modelview = to_light_xform * instance->xform_cache;
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW1, modelview.columns[0][0], modelview.columns[1][0], 0, modelview.columns[2][0], shadow_render.shader_version, variant);
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW2, modelview.columns[0][1], modelview.columns[1][1], 0, modelview.columns[2][1], shadow_render.shader_version, variant);
+
+ if (co->cull_mode != cull_mode) {
+ if (co->cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED) {
+ glDisable(GL_CULL_FACE);
+ } else {
+ if (cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED) {
+ // Last time was disabled, so enable and set proper face.
+ glEnable(GL_CULL_FACE);
+ }
+ glCullFace(co->cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE ? GL_FRONT : GL_BACK);
+ }
+ cull_mode = co->cull_mode;
+ }
+
+ glBindVertexArray(co->vertex_array);
+ glDrawElements(GL_TRIANGLES, 3 * co->line_point_count, GL_UNSIGNED_SHORT, 0);
+
+ instance = instance->next;
+ }
+
+ Transform2D to_shadow;
+ to_shadow.columns[0].x = 1.0 / -(half_size * 2.0);
+ to_shadow.columns[2].x = 0.5;
+
+ cl->shadow.directional_xform = to_shadow * to_light_xform;
+
+ glBindVertexArray(0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_CULL_FACE);
+}
+
+void RasterizerCanvasGLES3::_update_shadow_atlas() {
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
+ if (state.shadow_fb == 0) {
+ glActiveTexture(GL_TEXTURE0);
+
+ glGenFramebuffers(1, &state.shadow_fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, state.shadow_fb);
+
+ glGenRenderbuffers(1, &state.shadow_depth_buffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, state.shadow_depth_buffer);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, state.shadow_texture_size, data.max_lights_per_render * 2);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, state.shadow_depth_buffer);
+
+ glGenTextures(1, &state.shadow_texture);
+ glBindTexture(GL_TEXTURE_2D, state.shadow_texture);
+ if (config->float_texture_supported) {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, state.shadow_texture_size, data.max_lights_per_render * 2, 0, GL_RED, GL_FLOAT, nullptr);
+ } else {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, state.shadow_texture_size, data.max_lights_per_render * 2, 0, GL_RGBA, 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_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, state.shadow_texture, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ glDeleteFramebuffers(1, &state.shadow_fb);
+ glDeleteTextures(1, &state.shadow_texture);
+ glDeleteRenderbuffers(1, &state.shadow_depth_buffer);
+ state.shadow_fb = 0;
+ state.shadow_texture = 0;
+ state.shadow_depth_buffer = 0;
+ WARN_PRINT("Could not create CanvasItem shadow atlas, status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
+ }
}
void RasterizerCanvasGLES3::render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+
+ GLuint fb = texture_storage->render_target_get_sdf_framebuffer(p_render_target);
+ Rect2i rect = texture_storage->render_target_get_sdf_rect(p_render_target);
+
+ Transform2D to_sdf;
+ to_sdf.columns[0] *= rect.size.width;
+ to_sdf.columns[1] *= rect.size.height;
+ to_sdf.columns[2] = rect.position;
+
+ Transform2D to_clip;
+ to_clip.columns[0] *= 2.0;
+ to_clip.columns[1] *= 2.0;
+ to_clip.columns[2] = -Vector2(1.0, 1.0);
+
+ to_clip = to_clip * to_sdf.affine_inverse();
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fb);
+ glViewport(0, 0, rect.size.width, rect.size.height);
+
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_SCISSOR_TEST);
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ CanvasOcclusionShaderGLES3::ShaderVariant variant = CanvasOcclusionShaderGLES3::MODE_SDF;
+ bool success = shadow_render.shader.version_bind_shader(shadow_render.shader_version, variant);
+ if (!success) {
+ return;
+ }
+
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::PROJECTION, Projection(), shadow_render.shader_version, variant);
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::DIRECTION, 0.0, 0.0, shadow_render.shader_version, variant);
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::Z_FAR, 0.0, shadow_render.shader_version, variant);
+
+ LightOccluderInstance *instance = p_occluders;
+
+ while (instance) {
+ OccluderPolygon *oc = occluder_polygon_owner.get_or_null(instance->occluder);
+
+ if (!oc || oc->sdf_vertex_array == 0) {
+ instance = instance->next;
+ continue;
+ }
+
+ Transform2D modelview = to_clip * instance->xform_cache;
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW1, modelview.columns[0][0], modelview.columns[1][0], 0, modelview.columns[2][0], shadow_render.shader_version, variant);
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW2, modelview.columns[0][1], modelview.columns[1][1], 0, modelview.columns[2][1], shadow_render.shader_version, variant);
+
+ glBindVertexArray(oc->sdf_vertex_array);
+ glDrawElements(oc->sdf_is_lines ? GL_LINES : GL_TRIANGLES, oc->sdf_index_count, GL_UNSIGNED_INT, 0);
+
+ instance = instance->next;
+ }
+
+ texture_storage->render_target_sdf_process(p_render_target); //done rendering, process it
+ glBindVertexArray(0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
RID RasterizerCanvasGLES3::occluder_polygon_create() {
- return RID();
+ OccluderPolygon occluder;
+
+ return occluder_polygon_owner.make_rid(occluder);
}
void RasterizerCanvasGLES3::occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) {
+ OccluderPolygon *oc = occluder_polygon_owner.get_or_null(p_occluder);
+ ERR_FAIL_COND(!oc);
+
+ Vector<Vector2> lines;
+
+ if (p_points.size()) {
+ int lc = p_points.size() * 2;
+
+ lines.resize(lc - (p_closed ? 0 : 2));
+ {
+ Vector2 *w = lines.ptrw();
+ const Vector2 *r = p_points.ptr();
+
+ int max = lc / 2;
+ if (!p_closed) {
+ max--;
+ }
+ for (int i = 0; i < max; i++) {
+ Vector2 a = r[i];
+ Vector2 b = r[(i + 1) % (lc / 2)];
+ w[i * 2 + 0] = a;
+ w[i * 2 + 1] = b;
+ }
+ }
+ }
+
+ if (oc->line_point_count != lines.size() && oc->vertex_array != 0) {
+ glDeleteVertexArrays(1, &oc->vertex_array);
+ glDeleteBuffers(1, &oc->vertex_buffer);
+ glDeleteBuffers(1, &oc->index_buffer);
+
+ oc->vertex_array = 0;
+ oc->vertex_buffer = 0;
+ oc->index_buffer = 0;
+ }
+
+ if (lines.size()) {
+ Vector<uint8_t> geometry;
+ Vector<uint8_t> indices;
+ int lc = lines.size();
+
+ geometry.resize(lc * 6 * sizeof(float));
+ indices.resize(lc * 3 * sizeof(uint16_t));
+
+ {
+ uint8_t *vw = geometry.ptrw();
+ float *vwptr = reinterpret_cast<float *>(vw);
+ uint8_t *iw = indices.ptrw();
+ uint16_t *iwptr = (uint16_t *)iw;
+
+ const Vector2 *lr = lines.ptr();
+
+ const int POLY_HEIGHT = 16384;
+
+ for (int i = 0; i < lc / 2; i++) {
+ vwptr[i * 12 + 0] = lr[i * 2 + 0].x;
+ vwptr[i * 12 + 1] = lr[i * 2 + 0].y;
+ vwptr[i * 12 + 2] = POLY_HEIGHT;
+
+ vwptr[i * 12 + 3] = lr[i * 2 + 1].x;
+ vwptr[i * 12 + 4] = lr[i * 2 + 1].y;
+ vwptr[i * 12 + 5] = POLY_HEIGHT;
+
+ vwptr[i * 12 + 6] = lr[i * 2 + 1].x;
+ vwptr[i * 12 + 7] = lr[i * 2 + 1].y;
+ vwptr[i * 12 + 8] = -POLY_HEIGHT;
+
+ vwptr[i * 12 + 9] = lr[i * 2 + 0].x;
+ vwptr[i * 12 + 10] = lr[i * 2 + 0].y;
+ vwptr[i * 12 + 11] = -POLY_HEIGHT;
+
+ iwptr[i * 6 + 0] = i * 4 + 0;
+ iwptr[i * 6 + 1] = i * 4 + 1;
+ iwptr[i * 6 + 2] = i * 4 + 2;
+
+ iwptr[i * 6 + 3] = i * 4 + 2;
+ iwptr[i * 6 + 4] = i * 4 + 3;
+ iwptr[i * 6 + 5] = i * 4 + 0;
+ }
+ }
+
+ if (oc->vertex_array == 0) {
+ oc->line_point_count = lc;
+ glGenVertexArrays(1, &oc->vertex_array);
+ glBindVertexArray(oc->vertex_array);
+ glGenBuffers(1, &oc->vertex_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, oc->vertex_buffer);
+
+ glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(float), geometry.ptr(), GL_STATIC_DRAW);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
+
+ glGenBuffers(1, &oc->index_buffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oc->index_buffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * lc * sizeof(uint16_t), indices.ptr(), GL_STATIC_DRAW);
+ glBindVertexArray(0);
+ } else {
+ glBindVertexArray(oc->vertex_array);
+ glBindBuffer(GL_ARRAY_BUFFER, oc->vertex_buffer);
+ glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(float), geometry.ptr(), GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oc->index_buffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * lc * sizeof(uint16_t), indices.ptr(), GL_STATIC_DRAW);
+ }
+ }
+
+ // sdf
+
+ Vector<int> sdf_indices;
+
+ if (p_points.size()) {
+ if (p_closed) {
+ sdf_indices = Geometry2D::triangulate_polygon(p_points);
+ oc->sdf_is_lines = false;
+ } else {
+ int max = p_points.size();
+ sdf_indices.resize(max * 2);
+
+ int *iw = sdf_indices.ptrw();
+ for (int i = 0; i < max; i++) {
+ iw[i * 2 + 0] = i;
+ iw[i * 2 + 1] = (i + 1) % max;
+ }
+ oc->sdf_is_lines = true;
+ }
+ }
+
+ if (oc->sdf_index_count != sdf_indices.size() && oc->sdf_point_count != p_points.size() && oc->sdf_vertex_array != 0) {
+ glDeleteVertexArrays(1, &oc->sdf_vertex_array);
+ glDeleteBuffers(1, &oc->sdf_vertex_buffer);
+ glDeleteBuffers(1, &oc->sdf_index_buffer);
+
+ oc->sdf_vertex_array = 0;
+ oc->sdf_vertex_buffer = 0;
+ oc->sdf_index_buffer = 0;
+
+ oc->sdf_index_count = sdf_indices.size();
+ oc->sdf_point_count = p_points.size();
+ }
+
+ if (sdf_indices.size()) {
+ if (oc->sdf_vertex_array == 0) {
+ oc->sdf_index_count = sdf_indices.size();
+ oc->sdf_point_count = p_points.size();
+ glGenVertexArrays(1, &oc->sdf_vertex_array);
+ glBindVertexArray(oc->sdf_vertex_array);
+ glGenBuffers(1, &oc->sdf_vertex_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, oc->sdf_vertex_buffer);
+
+ glBufferData(GL_ARRAY_BUFFER, p_points.size() * 2 * sizeof(float), p_points.to_byte_array().ptr(), GL_STATIC_DRAW);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
+
+ glGenBuffers(1, &oc->sdf_index_buffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oc->sdf_index_buffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sdf_indices.size() * sizeof(uint32_t), sdf_indices.to_byte_array().ptr(), GL_STATIC_DRAW);
+ glBindVertexArray(0);
+ } else {
+ glBindBuffer(GL_ARRAY_BUFFER, oc->sdf_vertex_buffer);
+ glBufferData(GL_ARRAY_BUFFER, p_points.size() * 2 * sizeof(float), p_points.to_byte_array().ptr(), GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oc->sdf_index_buffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sdf_indices.size() * sizeof(uint32_t), sdf_indices.to_byte_array().ptr(), GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+ }
}
void RasterizerCanvasGLES3::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) {
+ OccluderPolygon *oc = occluder_polygon_owner.get_or_null(p_occluder);
+ ERR_FAIL_COND(!oc);
+ oc->cull_mode = p_mode;
}
void RasterizerCanvasGLES3::set_shadow_texture_size(int p_size) {
+ GLES3::Config *config = GLES3::Config::get_singleton();
+ p_size = nearest_power_of_2_templated(p_size);
+ if (p_size == state.shadow_texture_size) {
+ return;
+ }
+
+ if (p_size > config->max_texture_size) {
+ p_size = config->max_texture_size;
+ WARN_PRINT("Attempting to set CanvasItem shadow atlas size to " + itos(p_size) + " which is beyond limit of " + itos(config->max_texture_size) + "supported by hardware.");
+ }
+
+ state.shadow_texture_size = p_size;
}
bool RasterizerCanvasGLES3::free(RID p_rid) {
+ if (canvas_light_owner.owns(p_rid)) {
+ CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
+ ERR_FAIL_COND_V(!cl, false);
+ canvas_light_owner.free(p_rid);
+ } else if (occluder_polygon_owner.owns(p_rid)) {
+ occluder_polygon_set_shape(p_rid, Vector<Vector2>(), false);
+ occluder_polygon_owner.free(p_rid);
+ } else {
+ return false;
+ }
+
return true;
}
@@ -1088,12 +2053,12 @@ void RasterizerCanvasGLES3::canvas_begin(RID p_to_render_target, bool p_to_backb
glBindTexture(GL_TEXTURE_2D, render_target->backbuffer);
}
- if (render_target->is_transparent) {
+ if (render_target->is_transparent || p_to_backbuffer) {
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);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
}
if (render_target && render_target->clear_requested) {
@@ -1109,38 +2074,39 @@ void RasterizerCanvasGLES3::canvas_begin(RID p_to_render_target, bool p_to_backb
glBindTexture(GL_TEXTURE_2D, tex->tex_id);
}
-void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index) {
+void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLES3::Config *config = GLES3::Config::get_singleton();
if (p_texture == RID()) {
- p_texture = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE);
+ p_texture = default_canvas_texture;
}
- if (state.current_tex == p_texture) {
- return; //nothing to do, its the same
+ if (state.current_tex == p_texture && state.current_filter_mode == p_base_filter && state.current_repeat_mode == p_base_repeat) {
+ return;
}
+
state.current_tex = p_texture;
+ state.current_filter_mode = p_base_filter;
+ state.current_repeat_mode = p_base_repeat;
GLES3::CanvasTexture *ct = nullptr;
GLES3::Texture *t = texture_storage->get_texture(p_texture);
if (t) {
- //regular texture
- if (!t->canvas_texture) {
- t->canvas_texture = memnew(GLES3::CanvasTexture);
- t->canvas_texture->diffuse = p_texture;
- }
-
+ ERR_FAIL_COND(!t->canvas_texture);
ct = t->canvas_texture;
+ if (t->render_target) {
+ t->render_target->used_in_frame = true;
+ }
} else {
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);
+ _bind_canvas_texture(default_canvas_texture, p_base_filter, p_base_repeat);
return;
}
@@ -1153,66 +2119,100 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe
GLES3::Texture *texture = texture_storage->get_texture(ct->diffuse);
if (!texture) {
- 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);
+ GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex->tex_id);
} else {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture->tex_id);
-
- state.current_tex = p_texture;
- state.current_tex_ptr = texture;
- ct->size_cache = Size2i(texture->width, texture->height);
-
texture->gl_set_filter(filter);
texture->gl_set_repeat(repeat);
+ if (texture->render_target) {
+ texture->render_target->used_in_frame = true;
+ }
}
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 + GLES3::Config::get_singleton()->max_texture_image_units - 6);
+ glActiveTexture(GL_TEXTURE0 + config->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 {
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->gl_set_filter(filter);
- texture->gl_set_repeat(repeat);
+ normal_map->gl_set_filter(filter);
+ normal_map->gl_set_repeat(repeat);
+ if (normal_map->render_target) {
+ normal_map->render_target->used_in_frame = true;
+ }
}
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 + 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 {
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->gl_set_filter(filter);
- texture->gl_set_repeat(repeat);
+ specular_map->gl_set_filter(filter);
+ specular_map->gl_set_repeat(repeat);
+ if (specular_map->render_target) {
+ specular_map->render_target->used_in_frame = true;
+ }
+ }
+}
+
+void RasterizerCanvasGLES3::_prepare_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index, Size2 &r_texpixel_size) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+
+ if (p_texture == RID()) {
+ p_texture = default_canvas_texture;
+ }
+
+ GLES3::CanvasTexture *ct = nullptr;
+
+ GLES3::Texture *t = texture_storage->get_texture(p_texture);
+
+ if (t) {
+ //regular texture
+ if (!t->canvas_texture) {
+ t->canvas_texture = memnew(GLES3::CanvasTexture);
+ t->canvas_texture->diffuse = p_texture;
+ }
+
+ ct = t->canvas_texture;
+ } else {
+ ct = texture_storage->get_canvas_texture(p_texture);
+ }
+
+ if (!ct) {
+ // Invalid Texture RID.
+ _prepare_canvas_texture(default_canvas_texture, p_base_filter, p_base_repeat, r_index, r_texpixel_size);
+ return;
+ }
+
+ GLES3::Texture *texture = texture_storage->get_texture(ct->diffuse);
+ Size2i size_cache;
+ if (!texture) {
+ ct->diffuse = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE);
+ GLES3::Texture *tex = texture_storage->get_texture(ct->diffuse);
+ size_cache = Size2i(tex->width, tex->height);
+ } else {
+ size_cache = Size2i(texture->width, texture->height);
}
- if (ct->use_specular_cache) {
+ GLES3::Texture *normal_map = texture_storage->get_texture(ct->normal_map);
+
+ if (ct->specular_color.a < 0.999) {
state.instance_data_array[r_index].flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
} else {
state.instance_data_array[r_index].flags &= ~FLAGS_DEFAULT_SPECULAR_MAP_USED;
}
- if (ct->use_normal_cache) {
+ if (normal_map) {
state.instance_data_array[r_index].flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
} else {
state.instance_data_array[r_index].flags &= ~FLAGS_DEFAULT_NORMAL_MAP_USED;
@@ -1223,11 +2223,11 @@ 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));
- state.current_pixel_size.x = 1.0 / float(ct->size_cache.x);
- state.current_pixel_size.y = 1.0 / float(ct->size_cache.y);
+ r_texpixel_size.x = 1.0 / float(size_cache.x);
+ r_texpixel_size.y = 1.0 / float(size_cache.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;
+ 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;
}
void RasterizerCanvasGLES3::reset_canvas() {
@@ -1237,16 +2237,16 @@ void RasterizerCanvasGLES3::reset_canvas() {
glEnable(GL_BLEND);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
+ glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 2);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 3);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glActiveTexture(GL_TEXTURE0);
+
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
-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, 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) {
}
@@ -1277,7 +2277,6 @@ RendererCanvasRender::PolygonID RasterizerCanvasGLES3::request_polygon(const Vec
polygon_buffer.resize(buffer_size * sizeof(float));
{
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
uint8_t *r = polygon_buffer.ptrw();
float *fptr = reinterpret_cast<float *>(r);
uint32_t *uptr = (uint32_t *)r;
@@ -1386,7 +2385,6 @@ RendererCanvasRender::PolygonID RasterizerCanvasGLES3::request_polygon(const Vec
}
glGenBuffers(1, &pb.index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pb.index_buffer);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, p_indices.size() * 4, nullptr, GL_STATIC_DRAW); // TODO may not be necessary
glBufferData(GL_ELEMENT_ARRAY_BUFFER, p_indices.size() * 4, index_buffer.ptr(), GL_STATIC_DRAW);
pb.count = p_indices.size();
}
@@ -1419,17 +2417,30 @@ void RasterizerCanvasGLES3::free_polygon(PolygonID p_polygon) {
// Creates a new uniform buffer and uses it right away
// This expands the instance buffer continually
-// In theory allocations can reach as high as number_of_draw_calls * 3 frames
+// In theory allocations can reach as high as number of windows * 3 frames
// because OpenGL can start rendering subsequent frames before finishing the current one
void RasterizerCanvasGLES3::_allocate_instance_data_buffer() {
- GLuint new_buffer;
- glGenBuffers(1, &new_buffer);
- glBindBuffer(GL_UNIFORM_BUFFER, new_buffer);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(InstanceData) * state.max_instances_per_batch, nullptr, GL_DYNAMIC_DRAW);
+ GLuint new_buffers[3];
+ glGenBuffers(3, new_buffers);
+ // Batch UBO.
+ glBindBuffer(GL_ARRAY_BUFFER, new_buffers[0]);
+ glBufferData(GL_ARRAY_BUFFER, data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW);
+ // Light uniform buffer.
+ glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[1]);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(LightUniform) * data.max_lights_per_render, nullptr, GL_STREAM_DRAW);
+ // State buffer.
+ glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[2]);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), nullptr, GL_STREAM_DRAW);
+
state.current_buffer = (state.current_buffer + 1);
- state.canvas_instance_data_buffers.insert(state.current_buffer, new_buffer);
- state.fences.insert(state.current_buffer, GLsync());
+ DataBuffer db;
+ db.buffer = new_buffers[0];
+ db.light_ubo = new_buffers[1];
+ db.state_ubo = new_buffers[2];
+ db.last_frame_used = RSG::rasterizer->get_frame_number();
+ state.canvas_instance_data_buffers.insert(state.current_buffer, db);
state.current_buffer = state.current_buffer % state.canvas_instance_data_buffers.size();
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
@@ -1445,9 +2456,11 @@ RasterizerCanvasGLES3 *RasterizerCanvasGLES3::get_singleton() {
RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
singleton = this;
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
GLES3::Config *config = GLES3::Config::get_singleton();
+ polygon_buffers.last_id = 1;
// quad buffer
{
glGenBuffers(1, &data.canvas_quad_vertices);
@@ -1571,39 +2584,66 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
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;
+ data.max_lights_per_render = 64;
+ data.max_instances_per_batch = 128;
} else {
- state.max_lights_per_render = 256;
- state.max_instances_per_batch = 512;
+ data.max_lights_per_render = 256;
+ data.max_instances_per_batch = 2048;
}
- // Reserve 64 Uniform Buffers for instance data
- state.canvas_instance_data_buffers.resize(64);
- 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);
+ // Reserve 3 Uniform Buffers for instance data Frame N, N+1 and N+2
+ data.max_instances_per_buffer = MAX(data.max_instances_per_batch, uint32_t(GLOBAL_GET("rendering/gl_compatibility/item_buffer_size")));
+ data.max_instance_buffer_size = data.max_instances_per_buffer * sizeof(InstanceData); // 16,384 instances * 128 bytes = 2,097,152 bytes = 2,048 kb
+ state.canvas_instance_data_buffers.resize(3);
+ state.canvas_instance_batches.reserve(200);
+
+ for (int i = 0; i < 3; i++) {
+ GLuint new_buffers[3];
+ glGenBuffers(3, new_buffers);
+ // Batch UBO.
+ glBindBuffer(GL_ARRAY_BUFFER, new_buffers[0]);
+ glBufferData(GL_ARRAY_BUFFER, data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW);
+ // Light uniform buffer.
+ glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[1]);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(LightUniform) * data.max_lights_per_render, nullptr, GL_STREAM_DRAW);
+ // State buffer.
+ glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[2]);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), nullptr, GL_STREAM_DRAW);
+ DataBuffer db;
+ db.buffer = new_buffers[0];
+ db.light_ubo = new_buffers[1];
+ db.state_ubo = new_buffers[2];
+ db.last_frame_used = 0;
+ db.fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+ state.canvas_instance_data_buffers[i] = db;
}
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
- state.instance_data_array = memnew_arr(InstanceData, state.max_instances_per_batch);
+ state.instance_data_array = memnew_arr(InstanceData, data.max_instances_per_buffer);
+ state.light_uniforms = memnew_arr(LightUniform, data.max_lights_per_render);
- glGenBuffers(1, &state.canvas_state_buffer);
- glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_state_buffer);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), nullptr, GL_STREAM_DRAW);
- glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ {
+ const uint32_t indices[6] = { 0, 2, 1, 3, 2, 0 };
+ glGenVertexArrays(1, &data.indexed_quad_array);
+ glBindVertexArray(data.indexed_quad_array);
+ glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices);
+ glGenBuffers(1, &data.indexed_quad_buffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.indexed_quad_buffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * 6, indices, GL_STATIC_DRAW);
+ glBindVertexArray(0);
+ }
String global_defines;
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";
+ global_defines += "#define MAX_LIGHTS " + itos(data.max_lights_per_render) + "\n";
+ global_defines += "#define MAX_DRAW_DATA_INSTANCES " + itos(data.max_instances_per_batch) + "\n";
- 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);
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.initialize(global_defines, 1);
+ data.canvas_shader_default_version = GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_create();
+
+ shadow_render.shader.initialize();
+ shadow_render.shader_version = shadow_render.shader.version_create();
{
default_canvas_group_shader = material_storage->shader_allocate();
@@ -1614,8 +2654,10 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
shader_type canvas_item;
+uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
+
void fragment() {
- vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
+ vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
if (c.a > 0.0001) {
c.rgb /= c.a;
@@ -1630,18 +2672,44 @@ void fragment() {
material_storage->material_set_shader(default_canvas_group_material, default_canvas_group_shader);
}
- state.current_shader_version = state.canvas_shader_default_version;
+ {
+ default_clip_children_shader = material_storage->shader_allocate();
+ material_storage->shader_initialize(default_clip_children_shader);
+
+ material_storage->shader_set_code(default_clip_children_shader, R"(
+// Default clip children shader.
+
+shader_type canvas_item;
+
+uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
+
+void fragment() {
+ vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
+ COLOR.rgb = c.rgb;
+}
+)");
+ default_clip_children_material = material_storage->material_allocate();
+ material_storage->material_initialize(default_clip_children_material);
+
+ material_storage->material_set_shader(default_clip_children_material, default_clip_children_shader);
+ }
+
+ default_canvas_texture = texture_storage->canvas_texture_allocate();
+ texture_storage->canvas_texture_initialize(default_canvas_texture);
+
state.time = 0.0;
}
RasterizerCanvasGLES3::~RasterizerCanvasGLES3() {
- GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
-
- memdelete_arr(state.instance_data_array);
+ singleton = nullptr;
- GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_free(state.canvas_shader_default_version);
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ material_storage->shaders.canvas_shader.version_free(data.canvas_shader_default_version);
+ shadow_render.shader.version_free(shadow_render.shader_version);
material_storage->material_free(default_canvas_group_material);
material_storage->shader_free(default_canvas_group_shader);
+ material_storage->material_free(default_clip_children_material);
+ material_storage->shader_free(default_clip_children_shader);
singleton = nullptr;
glDeleteBuffers(1, &data.canvas_quad_vertices);
@@ -1649,6 +2717,19 @@ RasterizerCanvasGLES3::~RasterizerCanvasGLES3() {
glDeleteBuffers(1, &data.canvas_quad_vertices);
glDeleteVertexArrays(1, &data.canvas_quad_array);
+
+ GLES3::TextureStorage::get_singleton()->canvas_texture_free(default_canvas_texture);
+ memdelete_arr(state.instance_data_array);
+ memdelete_arr(state.light_uniforms);
+
+ if (state.shadow_fb != 0) {
+ glDeleteFramebuffers(1, &state.shadow_fb);
+ glDeleteTextures(1, &state.shadow_texture);
+ glDeleteRenderbuffers(1, &state.shadow_depth_buffer);
+ state.shadow_fb = 0;
+ state.shadow_texture = 0;
+ state.shadow_depth_buffer = 0;
+ }
}
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h
index 372ac00493..916e12057c 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.h
+++ b/drivers/gles3/rasterizer_canvas_gles3.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* rasterizer_canvas_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. */
-/*************************************************************************/
+/**************************************************************************/
+/* rasterizer_canvas_gles3.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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_CANVAS_GLES3_H
#define RASTERIZER_CANVAS_GLES3_H
@@ -40,6 +40,7 @@
#include "storage/texture_storage.h"
#include "shaders/canvas.glsl.gen.h"
+#include "shaders/canvas_occlusion.glsl.gen.h"
class RasterizerSceneGLES3;
@@ -74,6 +75,9 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender {
FLAGS_USE_MSDF = (1 << 28),
FLAGS_USE_LCD = (1 << 29),
+
+ FLAGS_FLIP_H = (1 << 30),
+ FLAGS_FLIP_V = (1 << 31),
};
enum {
@@ -96,6 +100,63 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender {
DEFAULT_MAX_LIGHTS_PER_RENDER = 256,
};
+ /******************/
+ /**** LIGHTING ****/
+ /******************/
+
+ struct CanvasLight {
+ RID texture;
+ struct {
+ bool enabled = false;
+ float z_far;
+ float y_offset;
+ Transform2D directional_xform;
+ } shadow;
+ };
+
+ RID_Owner<CanvasLight> canvas_light_owner;
+
+ struct OccluderPolygon {
+ RS::CanvasOccluderPolygonCullMode cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
+ int line_point_count = 0;
+ GLuint vertex_buffer = 0;
+ GLuint vertex_array = 0;
+ GLuint index_buffer = 0;
+
+ int sdf_point_count = 0;
+ int sdf_index_count = 0;
+ GLuint sdf_vertex_buffer = 0;
+ GLuint sdf_vertex_array = 0;
+ GLuint sdf_index_buffer = 0;
+ bool sdf_is_lines = false;
+ };
+
+ RID_Owner<OccluderPolygon> occluder_polygon_owner;
+
+ void _update_shadow_atlas();
+
+ struct {
+ CanvasOcclusionShaderGLES3 shader;
+ RID shader_version;
+ } shadow_render;
+
+ struct LightUniform {
+ float matrix[8]; //light to texture coordinate matrix
+ float shadow_matrix[8]; //light to shadow coordinate matrix
+ float color[4];
+
+ uint8_t shadow_color[4];
+ uint32_t flags; //index to light texture
+ float shadow_pixel_size;
+ float height;
+
+ float position[2];
+ float shadow_z_far_inv;
+ float shadow_y_ofs;
+
+ float atlas_rect[4];
+ };
+
public:
enum {
BASE_UNIFORM_LOCATION = 0,
@@ -125,6 +186,23 @@ public:
uint32_t pad2;
};
+ struct PolygonBuffers {
+ GLuint vertex_buffer = 0;
+ GLuint vertex_array = 0;
+ GLuint index_buffer = 0;
+ int count = 0;
+ bool color_disabled = false;
+ Color color;
+ };
+
+ struct {
+ HashMap<PolygonID, PolygonBuffers> polygons;
+ PolygonID last_id = 0;
+ } polygon_buffers;
+
+ RendererCanvasRender::PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) override;
+ void free_polygon(PolygonID p_polygon) override;
+
struct InstanceData {
float world[6];
float color_texture_pixel_size[2];
@@ -156,42 +234,86 @@ public:
GLuint canvas_quad_vertices;
GLuint canvas_quad_array;
+ GLuint indexed_quad_buffer;
+ GLuint indexed_quad_array;
+
GLuint particle_quad_vertices;
GLuint particle_quad_array;
GLuint ninepatch_vertices;
GLuint ninepatch_elements;
+
+ RID canvas_shader_default_version;
+
+ uint32_t max_lights_per_render = 256;
+ uint32_t max_lights_per_item = 16;
+ uint32_t max_instances_per_batch = 512;
+ uint32_t max_instances_per_buffer = 16384;
+ uint32_t max_instance_buffer_size = 16384 * 128;
} data;
+ struct Batch {
+ // Position in the UBO measured in bytes
+ uint32_t start = 0;
+ uint32_t instance_count = 0;
+
+ RID tex;
+ RS::CanvasItemTextureFilter filter = RS::CANVAS_ITEM_TEXTURE_FILTER_MAX;
+ RS::CanvasItemTextureRepeat repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX;
+
+ GLES3::CanvasShaderData::BlendMode blend_mode = GLES3::CanvasShaderData::BLEND_MODE_MIX;
+ Color blend_color = Color(1.0, 1.0, 1.0, 1.0);
+
+ Item *clip = nullptr;
+
+ RID material;
+ GLES3::CanvasMaterialData *material_data = nullptr;
+ CanvasShaderGLES3::ShaderVariant shader_variant = CanvasShaderGLES3::MODE_QUAD;
+
+ const Item::Command *command = nullptr;
+ Item::Command::Type command_type = Item::Command::TYPE_ANIMATION_SLICE; // Can default to any type that doesn't form a batch.
+ uint32_t primitive_points = 0;
+
+ bool lights_disabled = false;
+ };
+
+ // DataBuffer contains our per-frame data. I.e. the resources that are updated each frame.
+ // We track them and ensure that they don't get reused until at least 2 frames have passed
+ // to avoid the GPU stalling to wait for a resource to become available.
+ struct DataBuffer {
+ GLuint buffer = 0;
+ GLuint light_ubo = 0;
+ GLuint state_ubo = 0;
+ uint64_t last_frame_used = -3;
+ GLsync fence = GLsync();
+ };
+
struct State {
- GLuint canvas_state_buffer;
- LocalVector<GLuint> canvas_instance_data_buffers;
- LocalVector<GLsync> fences;
+ LocalVector<DataBuffer> canvas_instance_data_buffers;
+ LocalVector<Batch> canvas_instance_batches;
uint32_t current_buffer = 0;
+ uint32_t current_buffer_index = 0;
+ uint32_t current_batch_index = 0;
InstanceData *instance_data_array = nullptr;
- bool canvas_texscreen_used;
- RID canvas_shader_current_version;
- RID canvas_shader_default_version;
- RID current_tex = RID();
- Size2 current_pixel_size = Size2();
- RID current_normal = RID();
- RID current_specular = RID();
- 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;
+ LightUniform *light_uniforms = nullptr;
+
+ GLuint shadow_texture = 0;
+ GLuint shadow_depth_buffer = 0;
+ GLuint shadow_fb = 0;
+ int shadow_texture_size = 2048;
+
+ bool using_directional_lights = false;
+
+ RID current_tex;
+ RS::CanvasItemTextureFilter current_filter_mode = RS::CANVAS_ITEM_TEXTURE_FILTER_MAX;
+ RS::CanvasItemTextureRepeat current_repeat_mode = RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX;
bool transparent_render_target = false;
double time = 0.0;
- uint32_t max_lights_per_render;
- uint32_t max_lights_per_item;
- uint32_t max_instances_per_batch;
-
RS::CanvasItemTextureFilter default_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
RS::CanvasItemTextureRepeat default_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
} state;
@@ -201,6 +323,8 @@ public:
RID default_canvas_texture;
RID default_canvas_group_material;
RID default_canvas_group_shader;
+ RID default_clip_children_material;
+ RID default_clip_children_shader;
typedef void Texture;
@@ -210,9 +334,6 @@ public:
void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
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;
RID light_create() override;
void light_set_texture(RID p_rid, RID p_texture) override;
@@ -229,31 +350,19 @@ 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);
-
- struct PolygonBuffers {
- GLuint vertex_buffer;
- GLuint vertex_array;
- GLuint index_buffer;
- int count;
- bool color_disabled = false;
- Color color;
- };
-
- struct {
- HashMap<PolygonID, PolygonBuffers> polygons;
- PolygonID last_id;
- } polygon_buffers;
-
- RendererCanvasRender::PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) override;
- void free_polygon(PolygonID p_polygon) override;
+ void _bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat);
+ void _prepare_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index, Size2 &r_texpixel_size);
void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) override;
- void _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, GLES3::CanvasShaderData::BlendMode p_blend_mode, GLES3::CanvasShaderData::BlendMode &r_last_blend_mode, Color &r_last_blend_color);
- void _render_batch(uint32_t &p_max_index);
- void _bind_instance_data_buffer(uint32_t p_max_index);
+ void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, uint32_t &r_last_index, bool &r_sdf_used, bool p_to_backbuffer = false);
+ void _record_item_commands(const Item *p_item, RID p_render_target, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_break_batch, bool &r_sdf_used);
+ void _render_batch(Light *p_lights, uint32_t p_index);
+ bool _bind_material(GLES3::CanvasMaterialData *p_material_data, CanvasShaderGLES3::ShaderVariant p_variant, uint64_t p_specialization);
+ void _new_batch(bool &r_batch_broken, uint32_t &r_index);
+ void _add_to_batch(uint32_t &r_index, bool &r_batch_broken);
void _allocate_instance_data_buffer();
+ void _align_instance_data_buffer(uint32_t &r_index);
+ void _enable_attributes(uint32_t p_start, bool p_primitive, uint32_t p_rate = 1);
void set_time(double p_time);
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index cc96294ca5..672dcacd88 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* rasterizer_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. */
-/*************************************************************************/
+/**************************************************************************/
+/* rasterizer_gles3.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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_gles3.h"
#include "storage/utilities.h"
@@ -100,9 +100,8 @@ void RasterizerGLES3::begin_frame(double frame_step) {
canvas->set_time(time_total);
scene->set_time(time_total, frame_step);
- GLES3::Utilities *utilities = GLES3::Utilities::get_singleton();
- utilities->info.render_final = utilities->info.render;
- utilities->info.render.reset();
+ GLES3::Utilities *utils = GLES3::Utilities::get_singleton();
+ utils->_capture_timestamps_begin();
//scene->iteration();
}
@@ -200,7 +199,7 @@ void RasterizerGLES3::finalize() {
RasterizerGLES3::RasterizerGLES3() {
#ifdef GLAD_ENABLED
- if (!gladLoadGL()) {
+ if (!gladLoaderLoadGL()) {
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,
@@ -272,42 +271,60 @@ RasterizerGLES3::~RasterizerGLES3() {
}
void RasterizerGLES3::prepare_for_blitting_render_targets() {
+ // This is a hack, but this function is called one time after all viewports have been updated.
+ // So it marks the end of the frame for all viewports
+ // In the OpenGL renderer we have to call end_frame for each viewport so we can swap the
+ // buffers for each window before proceeding to the next.
+ // This allows us to only increment the frame after all viewports are done.
+ GLES3::Utilities *utils = GLES3::Utilities::get_singleton();
+ utils->capture_timestamps_end();
}
-void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect) {
- GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer) {
+ GLES3::RenderTarget *rt = GLES3::TextureStorage::get_singleton()->get_render_target(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);
+ // We normally render to the render target upside down, so flip Y when blitting to the screen.
+ bool flip_y = true;
+ if (rt->overridden.color.is_valid()) {
+ // If we've overridden the render target's color texture, that means we
+ // didn't render upside down, so we don't need to flip it.
+ // We're probably rendering directly to an XR device.
+ flip_y = false;
+ }
- if (rt->external.fbo != 0) {
- glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->external.fbo);
+ GLuint read_fbo = 0;
+ if (rt->view_count > 1) {
+ glGenFramebuffers(1, &read_fbo);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, read_fbo);
+ glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, p_layer);
} else {
glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo);
}
+
glReadBuffer(GL_COLOR_ATTACHMENT0);
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);
+ Vector2i screen_rect_end = p_screen_rect.get_end();
+ glBlitFramebuffer(0, 0, rt->size.x, rt->size.y,
+ p_screen_rect.position.x, flip_y ? screen_rect_end.y : p_screen_rect.position.y, screen_rect_end.x, flip_y ? p_screen_rect.position.y : screen_rect_end.y,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ if (read_fbo != 0) {
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glDeleteFramebuffers(1, &read_fbo);
+ }
}
// 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) {
- // 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];
RID rid_rt = blit.render_target;
Rect2 dst_rect = blit.dst_rect;
- _blit_render_target_to_screen(rid_rt, p_screen, dst_rect);
+ _blit_render_target_to_screen(rid_rt, p_screen, dst_rect, blit.multi_view.use_layer ? blit.multi_view.layer : 0);
}
}
@@ -316,18 +333,14 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
return;
}
- Size2i win_size = DisplayServer::get_singleton()->screen_get_size();
+ Size2i win_size = DisplayServer::get_singleton()->window_get_size();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, win_size.width, win_size.height);
- glDisable(GL_BLEND);
+ glEnable(GL_BLEND);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
glDepthMask(GL_FALSE);
- if (false) {
- // if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
- glClearColor(0.0, 0.0, 0.0, 0.0);
- } else {
- glClearColor(p_color.r, p_color.g, p_color.b, 1.0);
- }
+ glClearColor(p_color.r, p_color.g, p_color.b, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
RID texture = texture_storage->texture_allocate();
@@ -353,14 +366,24 @@ 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();
}
+ // Flip Y.
+ screenrect.position.y = win_size.y - screenrect.position.y;
+ screenrect.size.y = -screenrect.size.y;
+
+ // Normalize texture coordinates to window size.
+ screenrect.position /= win_size;
+ screenrect.size /= win_size;
+
GLES3::Texture *t = texture_storage->get_texture(texture);
- glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 1);
+ t->gl_set_filter(p_use_filter ? RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR : RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
+ glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, t->tex_id);
+ copy_effects->copy_to_rect(screenrect);
glBindTexture(GL_TEXTURE_2D, 0);
- texture_storage->texture_free(texture);
-
end_frame(true);
+
+ texture_storage->texture_free(texture);
}
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h
index 97543af0d5..446c6af338 100644
--- a/drivers/gles3/rasterizer_gles3.h
+++ b/drivers/gles3/rasterizer_gles3.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* rasterizer_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. */
-/*************************************************************************/
+/**************************************************************************/
+/* rasterizer_gles3.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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_GLES3_H
#define RASTERIZER_GLES3_H
@@ -68,7 +68,7 @@ protected:
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);
+ void _blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer);
public:
RendererUtilities *get_utilities() { return utilities; }
@@ -103,8 +103,9 @@ public:
low_end = true;
}
- uint64_t get_frame_number() const { return frame; }
- double get_frame_delta_time() const { return delta; }
+ _ALWAYS_INLINE_ uint64_t get_frame_number() const { return frame; }
+ _ALWAYS_INLINE_ double get_frame_delta_time() const { return delta; }
+ _ALWAYS_INLINE_ double get_total_time() const { return time_total; }
RasterizerGLES3();
~RasterizerGLES3();
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index dae26b1e5f..9547435607 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* rasterizer_scene_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. */
-/*************************************************************************/
+/**************************************************************************/
+/* rasterizer_scene_gles3.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#include "rasterizer_scene_gles3.h"
#include "core/config/project_settings.h"
@@ -34,8 +34,8 @@
#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/particles_storage.h"
#include "storage/texture_storage.h"
#ifdef GLES3_ENABLED
@@ -51,6 +51,9 @@ RenderGeometryInstance *RasterizerSceneGLES3::geometry_instance_create(RID p_bas
ginstance->data->base = p_base;
ginstance->data->base_type = type;
+ ginstance->data->dependency_tracker.userdata = ginstance;
+ ginstance->data->dependency_tracker.changed_callback = _geometry_instance_dependency_changed;
+ ginstance->data->dependency_tracker.deleted_callback = _geometry_instance_dependency_deleted;
ginstance->_mark_dirty();
@@ -70,7 +73,7 @@ void RasterizerSceneGLES3::GeometryInstanceGLES3::pair_light_instances(const RID
spot_lights.clear();
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]);
+ RS::LightType type = GLES3::LightStorage::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) {
@@ -188,7 +191,7 @@ void RasterizerSceneGLES3::_geometry_instance_add_surface_with_material(Geometry
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)) {
+ if (p_material->shader_data->uses_depth_prepass_alpha && !(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;
}
@@ -200,7 +203,7 @@ void RasterizerSceneGLES3::_geometry_instance_add_surface_with_material(Geometry
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) {
+ 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_prepass_alpha && !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));
@@ -315,6 +318,8 @@ void RasterizerSceneGLES3::_geometry_instance_add_surface(GeometryInstanceGLES3
void RasterizerSceneGLES3::_geometry_instance_update(RenderGeometryInstance *p_geometry_instance) {
GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
+ GLES3::ParticlesStorage *particles_storage = GLES3::ParticlesStorage::get_singleton();
+
GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
if (ginstance->data->dirty_dependencies) {
@@ -362,6 +367,26 @@ void RasterizerSceneGLES3::_geometry_instance_update(RenderGeometryInstance *p_g
} break;
case RS::INSTANCE_PARTICLES: {
+ int draw_passes = particles_storage->particles_get_draw_passes(ginstance->data->base);
+
+ for (int j = 0; j < draw_passes; j++) {
+ RID mesh = particles_storage->particles_get_draw_pass_mesh(ginstance->data->base, j);
+ if (!mesh.is_valid()) {
+ continue;
+ }
+
+ 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 k = 0; k < surface_count; k++) {
+ _geometry_instance_add_surface(ginstance, k, materials[k], mesh);
+ }
+ }
+ }
+
+ ginstance->instance_count = particles_storage->particles_get_amount(ginstance->data->base);
} break;
default: {
@@ -383,10 +408,23 @@ void RasterizerSceneGLES3::_geometry_instance_update(RenderGeometryInstance *p_g
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) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_PARTICLES;
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
+
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
+
+ if (!particles_storage->particles_is_using_local_coords(ginstance->data->base)) {
+ store_transform = false;
+ }
+
} else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
+ if (mesh_storage->skeleton_is_valid(ginstance->data->skeleton)) {
+ if (ginstance->data->dirty_dependencies) {
+ mesh_storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker);
+ }
+ }
}
ginstance->store_transform_cache = store_transform;
@@ -399,32 +437,6 @@ void RasterizerSceneGLES3::_geometry_instance_update(RenderGeometryInstance *p_g
ginstance->dirty_list_element.remove_from_list();
}
-/* SHADOW ATLAS API */
-
-RID RasterizerSceneGLES3::shadow_atlas_create() {
- return RID();
-}
-
-void RasterizerSceneGLES3::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) {
-}
-
-void RasterizerSceneGLES3::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
-}
-
-bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) {
- return false;
-}
-
-void RasterizerSceneGLES3::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) {
-}
-
-int RasterizerSceneGLES3::get_directional_light_shadow_size(RID p_light_intance) {
- return 0;
-}
-
-void RasterizerSceneGLES3::set_directional_shadow_count(int p_count) {
-}
-
/* SKY API */
void RasterizerSceneGLES3::_free_sky_data(Sky *p_sky) {
@@ -622,10 +634,11 @@ void RasterizerSceneGLES3::_setup_sky(const RenderDataGLES3 *p_render_data, cons
sky->reflection_dirty = true;
}
+ glBindBufferBase(GL_UNIFORM_BUFFER, SKY_DIRECTIONAL_LIGHT_UNIFORM_LOCATION, sky_globals.directional_light_buffer);
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]);
+ GLES3::LightInstance *li = GLES3::LightStorage::get_singleton()->get_light_instance(p_lights[i]);
if (!li) {
continue;
}
@@ -683,6 +696,7 @@ void RasterizerSceneGLES3::_setup_sky(const RenderDataGLES3 *p_render_data, cons
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;
+ sky_globals.last_frame_directional_lights[i].enabled = false;
}
}
@@ -704,7 +718,6 @@ void RasterizerSceneGLES3::_setup_sky(const RenderDataGLES3 *p_render_data, cons
}
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);
@@ -736,7 +749,6 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection,
RS::EnvironmentBG background = environment_get_background(p_env);
if (sky) {
- ERR_FAIL_COND(!sky);
sky_material = sky->material;
if (sky_material.is_valid()) {
@@ -776,14 +788,18 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection,
}
Basis sky_transform = environment_get_sky_orientation(p_env);
sky_transform.invert();
- sky_transform = p_transform.basis * sky_transform;
+ sky_transform = sky_transform * p_transform.basis;
+
+ bool success = material_storage->shaders.sky_shader.version_bind_shader(shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ if (!success) {
+ return;
+ }
- 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);
- GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::ORIENTATION, sky_transform, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, camera.columns[2][0], camera.columns[0][0], camera.columns[2][1], camera.columns[1][1], shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
glBindVertexArray(sky_globals.screen_triangle_array);
glDrawArrays(GL_TRIANGLES, 0, 3);
@@ -874,15 +890,18 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
Projection cm;
cm.set_perspective(90, 1, 0.01, 10.0);
Projection correction;
- correction.set_depth_correction(true);
+ correction.columns[1][1] = -1.0;
cm = correction * cm;
- GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_bind_shader(shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+ bool success = material_storage->shaders.sky_shader.version_bind_shader(shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+ if (!success) {
+ return;
+ }
- 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);
- GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+ material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+ material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+ material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, cm.columns[2][0], cm.columns[0][0], cm.columns[2][1], cm.columns[1][1], shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+ material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
glBindVertexArray(sky_globals.screen_triangle_array);
@@ -891,7 +910,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
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);
+ material_storage->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);
}
@@ -972,7 +991,10 @@ void RasterizerSceneGLES3::_filter_sky_radiance(Sky *p_sky, int p_base_layer) {
glViewport(0, 0, size, size);
glBindVertexArray(sky_globals.screen_triangle_array);
- material_storage->shaders.cubemap_filter_shader.version_bind_shader(scene_globals.cubemap_filter_shader_version, mode);
+ bool success = material_storage->shaders.cubemap_filter_shader.version_bind_shader(scene_globals.cubemap_filter_shader_version, mode);
+ if (!success) {
+ return;
+ }
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 };
@@ -1046,10 +1068,6 @@ void RasterizerSceneGLES3::environment_glow_set_use_bicubic_upscale(bool p_enabl
glow_bicubic_upscale = p_enable;
}
-void RasterizerSceneGLES3::environment_glow_set_use_high_quality(bool p_enable) {
- glow_high_quality = p_enable;
-}
-
void RasterizerSceneGLES3::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) {
}
@@ -1084,38 +1102,6 @@ void RasterizerSceneGLES3::positional_soft_shadow_filter_set_quality(RS::ShadowQ
void RasterizerSceneGLES3::directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) {
}
-RID RasterizerSceneGLES3::light_instance_create(RID p_light) {
- 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 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) {
-}
-
RID RasterizerSceneGLES3::fog_volume_instance_create(RID p_fog_volume) {
return RID();
}
@@ -1134,57 +1120,6 @@ Vector3 RasterizerSceneGLES3::fog_volume_instance_get_position(RID p_fog_volume_
return Vector3();
}
-RID RasterizerSceneGLES3::reflection_atlas_create() {
- return RID();
-}
-
-int RasterizerSceneGLES3::reflection_atlas_get_size(RID p_ref_atlas) const {
- return 0;
-}
-
-void RasterizerSceneGLES3::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) {
-}
-
-RID RasterizerSceneGLES3::reflection_probe_instance_create(RID p_probe) {
- return RID();
-}
-
-void RasterizerSceneGLES3::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) {
-}
-
-void RasterizerSceneGLES3::reflection_probe_release_atlas_index(RID p_instance) {
-}
-
-bool RasterizerSceneGLES3::reflection_probe_instance_needs_redraw(RID p_instance) {
- return false;
-}
-
-bool RasterizerSceneGLES3::reflection_probe_instance_has_reflection(RID p_instance) {
- return false;
-}
-
-bool RasterizerSceneGLES3::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) {
- return false;
-}
-
-bool RasterizerSceneGLES3::reflection_probe_instance_postprocess_step(RID p_instance) {
- return true;
-}
-
-RID RasterizerSceneGLES3::decal_instance_create(RID p_decal) {
- return RID();
-}
-
-void RasterizerSceneGLES3::decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) {
-}
-
-RID RasterizerSceneGLES3::lightmap_instance_create(RID p_lightmap) {
- return RID();
-}
-
-void RasterizerSceneGLES3::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) {
-}
-
RID RasterizerSceneGLES3::voxel_gi_instance_create(RID p_voxel_gi) {
return RID();
}
@@ -1235,12 +1170,17 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
for (int i = 0; i < (int)p_render_data->instances->size(); i++) {
GeometryInstanceGLES3 *inst = static_cast<GeometryInstanceGLES3 *>((*p_render_data->instances)[i]);
+ Vector3 center = inst->transform.origin;
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);
+ if (inst->use_aabb_center) {
+ center = inst->transformed_aabb.get_support(-near_plane.normal);
+ }
+ inst->depth = near_plane.distance_to(center) - inst->sorting_offset;
} 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);
+ if (inst->use_aabb_center) {
+ center = inst->transformed_aabb.position + (inst->transformed_aabb.size * 0.5);
+ }
+ inst->depth = p_render_data->cam_transform.origin.distance_to(center) - inst->sorting_offset;
}
uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15);
@@ -1257,13 +1197,13 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
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]);
+ inst->omni_light_gl_cache[j] = GLES3::LightStorage::get_singleton()->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->spot_light_gl_cache[j] = GLES3::LightStorage::get_singleton()->light_instance_get_gl_id(inst->spot_lights[j]);
}
}
}
@@ -1276,12 +1216,13 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
// 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);
+ // Get the LOD support points on the mesh AABB.
+ Vector3 lod_support_min = inst->transformed_aabb.get_support(p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z));
+ Vector3 lod_support_max = inst->transformed_aabb.get_support(-p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z));
- 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);
+ // Get the distances to those points on the AABB from the camera origin.
+ float distance_min = (float)p_render_data->cam_transform.origin.distance_to(lod_support_min);
+ float distance_max = (float)p_render_data->cam_transform.origin.distance_to(lod_support_max);
float distance = 0.0;
@@ -1298,8 +1239,8 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
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);
+ uint32_t indices = 0;
+ 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);
@@ -1374,13 +1315,27 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
// 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);
+ correction.columns[1][1] = p_flip_y ? -1.0 : 1.0;
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.camera_visible_layers = p_render_data->camera_visible_layers;
+
+ if (p_render_data->view_count > 1) {
+ for (uint32_t v = 0; v < p_render_data->view_count; v++) {
+ projection = correction * p_render_data->view_projection[v];
+ GLES3::MaterialStorage::store_camera(projection, scene_state.multiview_ubo.projection_matrix_view[v]);
+ GLES3::MaterialStorage::store_camera(projection.inverse(), scene_state.multiview_ubo.inv_projection_matrix_view[v]);
+
+ scene_state.multiview_ubo.eye_offset[v][0] = p_render_data->view_eye_offset[v].x;
+ scene_state.multiview_ubo.eye_offset[v][1] = p_render_data->view_eye_offset[v].y;
+ scene_state.multiview_ubo.eye_offset[v][2] = p_render_data->view_eye_offset[v].z;
+ scene_state.multiview_ubo.eye_offset[v][3] = 0.0;
+ }
+ }
scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
@@ -1483,6 +1438,15 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
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);
+
+ if (p_render_data->view_count > 1) {
+ if (scene_state.multiview_buffer == 0) {
+ glGenBuffers(1, &scene_state.multiview_buffer);
+ }
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::MultiviewUBO), &scene_state.multiview_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
@@ -1501,7 +1465,7 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
int num_lights = lights.size();
for (int i = 0; i < num_lights; i++) {
- LightInstance *li = light_instance_owner.get_or_null(lights[i]);
+ GLES3::LightInstance *li = GLES3::LightStorage::get_singleton()->get_light_instance(lights[i]);
if (!li) {
continue;
}
@@ -1571,8 +1535,6 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
}
}
- li->gl_id = r_omni_light_count;
-
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++;
@@ -1596,8 +1558,6 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
}
}
- 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++;
@@ -1606,12 +1566,12 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
}
if (r_omni_light_count) {
- SortArray<InstanceSort<LightInstance>> sorter;
+ SortArray<InstanceSort<GLES3::LightInstance>> sorter;
sorter.sort(scene_state.omni_light_sort, r_omni_light_count);
}
if (r_spot_light_count) {
- SortArray<InstanceSort<LightInstance>> sorter;
+ SortArray<InstanceSort<GLES3::LightInstance>> sorter;
sorter.sort(scene_state.spot_light_sort, r_spot_light_count);
}
@@ -1619,9 +1579,12 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
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 < r_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;
+ GLES3::LightInstance *li = (i < r_omni_light_count) ? scene_state.omni_light_sort[index].instance : scene_state.spot_light_sort[index].instance;
+ real_t distance = (i < r_omni_light_count) ? scene_state.omni_light_sort[index].depth : scene_state.spot_light_sort[index].depth;
RID base = li->light;
+ li->gl_id = index;
+
Transform3D light_transform = li->transform;
Vector3 pos = inverse_transform.xform(light_transform.origin);
@@ -1648,13 +1611,11 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
// 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.
@@ -1718,7 +1679,7 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
-void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_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::render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_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, RenderingMethod::RenderInfo *r_render_info) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLES3::Config *config = GLES3::Config::get_singleton();
RENDER_TIMESTAMP("Setup 3D Scene");
@@ -1729,6 +1690,9 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
ERR_FAIL_COND(rb.is_null());
}
+ GLES3::RenderTarget *rt = texture_storage->get_render_target(rb->render_target);
+ ERR_FAIL_COND(!rt);
+
// Assign render data
// Use the format from rendererRD
RenderDataGLES3 render_data;
@@ -1740,6 +1704,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
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.camera_visible_layers = p_camera_data->visible_layers;
render_data.view_count = p_camera_data->view_count;
for (uint32_t v = 0; v < p_camera_data->view_count; v++) {
@@ -1760,7 +1725,6 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
// 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;
@@ -1777,7 +1741,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
render_data.reflection_probes = &empty;
}
- bool reverse_cull = false;
+ bool reverse_cull = render_data.cam_transform.basis.determinant() < 0;
///////////
// Fill Light lists here
@@ -1817,8 +1781,20 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
scene_state.ubo.emissive_exposure_normalization = -1.0; // Use default exposure normalization.
+ bool flip_y = !render_data.reflection_probe.is_valid();
+
+ if (rt->overridden.color.is_valid()) {
+ // If we've overridden the render target's color texture, then don't render upside down.
+ // We're probably rendering directly to an XR device.
+ flip_y = false;
+ }
+ if (!flip_y) {
+ // If we're rendering right-side up, then we need to change the winding order.
+ glFrontFace(GL_CW);
+ }
+
_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);
+ _setup_environment(&render_data, render_data.reflection_probe.is_valid(), screen_size, flip_y, clear_color, false);
_fill_render_list(RENDER_LIST_OPAQUE, &render_data, PASS_MODE_COLOR);
render_list[RENDER_LIST_OPAQUE].sort_by_key();
@@ -1880,7 +1856,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
Projection projection = render_data.cam_projection;
if (render_data.reflection_probe.is_valid()) {
Projection correction;
- correction.set_depth_correction(true);
+ correction.columns[1][1] = -1.0;
projection = correction * render_data.cam_projection;
}
@@ -1899,7 +1875,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
}
}
- glBindFramebuffer(GL_FRAMEBUFFER, rb->framebuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
glViewport(0, 0, rb->width, rb->height);
// Do depth prepass if it's explicitly enabled
@@ -1924,8 +1900,11 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
glColorMask(0, 0, 0, 0);
glClearDepth(1.0f);
glClear(GL_DEPTH_BUFFER_BIT);
+ uint64_t spec_constant = SceneShaderGLES3::DISABLE_FOG | SceneShaderGLES3::DISABLE_LIGHT_DIRECTIONAL |
+ SceneShaderGLES3::DISABLE_LIGHTMAP | SceneShaderGLES3::DISABLE_LIGHT_OMNI |
+ SceneShaderGLES3::DISABLE_LIGHT_SPOT;
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, 0, use_wireframe);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, spec_constant, 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);
@@ -1962,16 +1941,16 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
glClearBufferfv(GL_COLOR, 0, clear_color.components);
}
RENDER_TIMESTAMP("Render Opaque Pass");
- uint32_t spec_constant_base_flags = 0;
+ uint64_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;
+ spec_constant_base_flags |= SceneShaderGLES3::DISABLE_LIGHT_DIRECTIONAL;
}
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;
+ spec_constant_base_flags |= SceneShaderGLES3::DISABLE_FOG;
}
}
// Render Opaque Objects.
@@ -2005,6 +1984,11 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
_render_list_template<PASS_MODE_COLOR_TRANSPARENT>(&render_list_params_alpha, &render_data, 0, render_list[RENDER_LIST_ALPHA].elements.size(), true);
+ if (!flip_y) {
+ // Restore the default winding order.
+ glFrontFace(GL_CCW);
+ }
+
if (rb.is_valid()) {
_render_buffers_debug_draw(rb, p_shadow_atlas, p_occluder_debug_tex);
}
@@ -2015,6 +1999,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
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::ParticlesStorage *particles_storage = GLES3::ParticlesStorage::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();
@@ -2026,8 +2011,15 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
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
+ uint64_t prev_spec_constants = 0;
- SceneShaderGLES3::ShaderVariant shader_variant = SceneShaderGLES3::MODE_COLOR; // Assigned to silence wrong -Wmaybe-initialized.
+ // Specializations constants used by all instances in the scene.
+ uint64_t base_spec_constants = p_params->spec_constant_base_flags;
+
+ if (p_render_data->view_count > 1) {
+ base_spec_constants |= SceneShaderGLES3::USE_MULTIVIEW;
+ }
switch (p_pass_mode) {
case PASS_MODE_COLOR:
@@ -2042,19 +2034,21 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
} break;
}
- if (p_pass_mode == PASS_MODE_COLOR || p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) {
+ if constexpr (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;
+ base_spec_constants |= SceneShaderGLES3::USE_RADIANCE_MAP;
}
glBindTexture(GL_TEXTURE_CUBE_MAP, texture_to_bind);
}
}
+ bool should_request_redraw = false;
+
for (uint32_t i = p_from_element; i < p_to_element; i++) {
const GeometryInstanceSurface *surf = p_params->elements[i];
GeometryInstanceGLES3 *inst = surf->owner;
@@ -2067,13 +2061,11 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
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) {
+ if constexpr (p_pass_mode == PASS_MODE_SHADOW) {
shader = surf->shader_shadow;
material_data = surf->material_shadow;
mesh_surface = surf->surface_shadow;
@@ -2087,7 +2079,12 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
continue;
}
- if (p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) {
+ //request a redraw if one of the shaders uses TIME
+ if (shader->uses_time) {
+ should_request_redraw = true;
+ }
+
+ if constexpr (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);
@@ -2114,9 +2111,9 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
scene_state.current_depth_draw = shader->depth_draw;
}
- if (p_pass_mode == PASS_MODE_COLOR_TRANSPARENT || p_pass_mode == PASS_MODE_COLOR_ADDITIVE) {
+ if constexpr (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) {
+ if constexpr (p_pass_mode == PASS_MODE_COLOR_ADDITIVE) {
desired_blend_mode = GLES3::SceneShaderData::BLEND_MODE_ADD;
} else {
desired_blend_mode = shader->blend_mode;
@@ -2211,6 +2208,9 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
glBindVertexArray(vertex_array_gl);
}
prev_vertex_array_gl = vertex_array_gl;
+
+ // Invalidate the previous index array
+ prev_index_array_gl = 0;
}
bool use_index_buffer = index_array_gl != 0;
@@ -2234,61 +2234,94 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
SceneShaderGLES3::ShaderVariant instance_variant = shader_variant;
if (inst->instance_count > 0) {
+ // Will need to use instancing to draw (either MultiMesh or Particles).
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);
+ uint64_t spec_constants = base_spec_constants;
+
+ if (inst->omni_light_count == 0) {
+ spec_constants |= SceneShaderGLES3::DISABLE_LIGHT_OMNI;
+ }
+
+ if (inst->spot_light_count == 0) {
+ spec_constants |= SceneShaderGLES3::DISABLE_LIGHT_SPOT;
+ }
+
+ if (prev_shader != shader || prev_variant != instance_variant || spec_constants != prev_spec_constants) {
+ bool success = material_storage->shaders.scene_shader.version_bind_shader(shader->version, instance_variant, spec_constants);
+ if (!success) {
+ continue;
+ }
+
float opaque_prepass_threshold = 0.0;
- if (p_pass_mode == PASS_MODE_DEPTH) {
+ if constexpr (p_pass_mode == PASS_MODE_DEPTH) {
opaque_prepass_threshold = 0.99;
- } else if (p_pass_mode == PASS_MODE_SHADOW) {
+ } else if constexpr (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);
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OPAQUE_PREPASS_THRESHOLD, opaque_prepass_threshold, shader->version, instance_variant, spec_constants);
prev_shader = shader;
prev_variant = instance_variant;
+ prev_spec_constants = spec_constants;
}
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);
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT, inst->omni_light_count, shader->version, instance_variant, spec_constants);
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT, inst->spot_light_count, shader->version, instance_variant, spec_constants);
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());
+ glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::OMNI_LIGHT_INDICES, shader->version, instance_variant, spec_constants), 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());
+ glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES, shader->version, instance_variant, spec_constants), 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);
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant, spec_constants);
if (inst->instance_count > 0) {
- // Using MultiMesh.
+ // Using MultiMesh or Particles.
// 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);
+ GLuint instance_buffer = 0;
+ uint32_t stride = 0;
+ if (inst->flags_cache & INSTANCE_DATA_FLAG_PARTICLES) {
+ instance_buffer = particles_storage->particles_get_gl_buffer(inst->data->base);
+ stride = 16; // 12 bytes for instance transform and 4 bytes for packed color and custom.
+ } else {
+ instance_buffer = mesh_storage->multimesh_get_gl_buffer(inst->data->base);
+ stride = mesh_storage->multimesh_get_stride(inst->data->base);
+ }
+
+ if (instance_buffer == 0) {
+ // Instance buffer not initialized yet. Skip rendering for now.
+ continue;
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, instance_buffer);
+
glEnableVertexAttribArray(12);
- glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0));
+ glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, 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));
+ glVertexAttribPointer(13, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(sizeof(float) * 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 (!(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D)) {
+ glEnableVertexAttribArray(14);
+ glVertexAttribPointer(14, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(sizeof(float) * 8));
+ glVertexAttribDivisor(14, 1);
+ }
- if (mesh_storage->multimesh_uses_colors(inst->data->base) || mesh_storage->multimesh_uses_custom_data(inst->data->base)) {
+ if ((inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR) || (inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA)) {
+ uint32_t color_custom_offset = inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D ? 8 : 12;
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)));
+ glVertexAttribIPointer(15, 4, GL_UNSIGNED_INT, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(color_custom_offset * sizeof(float)));
glVertexAttribDivisor(15, 1);
}
if (use_index_buffer) {
@@ -2311,12 +2344,83 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
glDisableVertexAttribArray(15);
}
}
+
+ // Make the actual redraw request
+ if (should_request_redraw) {
+ RenderingServerDefault::redraw_request();
+ }
}
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) {
+ GLES3::ParticlesStorage *particles_storage = GLES3::ParticlesStorage::get_singleton();
+
+ ERR_FAIL_COND(!particles_storage->particles_collision_is_heightfield(p_collider));
+ Vector3 extents = particles_storage->particles_collision_get_extents(p_collider) * p_transform.basis.get_scale();
+ Projection cm;
+ cm.set_orthogonal(-extents.x, extents.x, -extents.z, extents.z, 0, extents.y * 2.0);
+
+ Vector3 cam_pos = p_transform.origin;
+ cam_pos.y += extents.y;
+
+ Transform3D cam_xform;
+ cam_xform.set_look_at(cam_pos, cam_pos - p_transform.basis.get_column(Vector3::AXIS_Y), -p_transform.basis.get_column(Vector3::AXIS_Z).normalized());
+
+ GLuint fb = particles_storage->particles_collision_get_heightfield_framebuffer(p_collider);
+ Size2i fb_size = particles_storage->particles_collision_get_heightfield_size(p_collider);
+
+ RENDER_TIMESTAMP("Setup GPUParticlesCollisionHeightField3D");
+
+ RenderDataGLES3 render_data;
+
+ render_data.cam_projection = cm;
+ render_data.cam_transform = cam_xform;
+ render_data.view_projection[0] = cm;
+ render_data.inv_cam_transform = render_data.cam_transform.affine_inverse();
+ render_data.cam_orthogonal = true;
+ render_data.z_near = 0.0;
+ render_data.z_far = cm.get_z_far();
+
+ render_data.instances = &p_instances;
+
+ _setup_environment(&render_data, true, Vector2(fb_size), true, Color(), false);
+
+ PassMode pass_mode = PASS_MODE_SHADOW;
+
+ _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
+ render_list[RENDER_LIST_SECONDARY].sort_by_key();
+
+ RENDER_TIMESTAMP("Render Collider Heightfield");
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fb);
+ glViewport(0, 0, fb_size.width, fb_size.height);
+
+ GLuint global_buffer = GLES3::MaterialStorage::get_singleton()->global_shader_parameters_get_uniform_buffer();
+
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_GLOBALS_UNIFORM_LOCATION, global_buffer);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+ glDisable(GL_BLEND);
+ glDepthMask(GL_TRUE);
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ 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_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, 31, false);
+
+ _render_list_template<PASS_MODE_SHADOW>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_SECONDARY].elements.size());
+
+ glColorMask(1, 1, 1, 1);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void RasterizerSceneGLES3::set_time(double p_time, double p_step) {
@@ -2390,10 +2494,8 @@ bool RasterizerSceneGLES3::free(RID p_rid) {
ERR_FAIL_COND_V(!sky, false);
_free_sky_data(sky);
sky_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 if (GLES3::LightStorage::get_singleton()->owns_light_instance(p_rid)) {
+ GLES3::LightStorage::get_singleton()->light_instance_free(p_rid);
} else if (RSG::camera_attributes->owns_camera_attributes(p_rid)) {
//not much to delete, just free it
RSG::camera_attributes->camera_attributes_free(p_rid);
@@ -2433,13 +2535,13 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() {
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);
+ scene_state.omni_light_sort = memnew_arr(InstanceSort<GLES3::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);
+ scene_state.spot_light_sort = memnew_arr(InstanceSort<GLES3::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);
@@ -2469,7 +2571,7 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() {
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";
+ global_defines += "\n#define MAX_FORWARD_LIGHTS uint(" + 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);
@@ -2480,7 +2582,7 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() {
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).
+// Default 3D material shader.
shader_type spatial;
@@ -2509,7 +2611,6 @@ void fragment() {
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);
}
{
@@ -2517,7 +2618,6 @@ void fragment() {
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);
}
{
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index 04658b10ad..7977e562c0 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* rasterizer_scene_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. */
-/*************************************************************************/
+/**************************************************************************/
+/* rasterizer_scene_gles3.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef RASTERIZER_SCENE_GLES3_H
#define RASTERIZER_SCENE_GLES3_H
@@ -44,6 +44,7 @@
#include "shader_gles3.h"
#include "shaders/cubemap_filter.glsl.gen.h"
#include "shaders/sky.glsl.gen.h"
+#include "storage/light_storage.h"
#include "storage/material_storage.h"
#include "storage/render_scene_buffers_gles3.h"
#include "storage/utilities.h"
@@ -73,6 +74,7 @@ enum SceneUniformLocation {
SCENE_OMNILIGHT_UNIFORM_LOCATION,
SCENE_SPOTLIGHT_UNIFORM_LOCATION,
SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
+ SCENE_MULTIVIEW_UNIFORM_LOCATION,
};
enum SkyUniformLocation {
@@ -83,22 +85,15 @@ enum SkyUniformLocation {
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 {
Ref<RenderSceneBuffersGLES3> render_buffers;
bool transparent_bg = false;
- Transform3D cam_transform = Transform3D();
- Transform3D inv_cam_transform = Transform3D();
- Projection cam_projection = Projection();
+ Transform3D cam_transform;
+ Transform3D inv_cam_transform;
+ Projection cam_projection;
bool cam_orthogonal = false;
+ uint32_t camera_visible_layers = 0xFFFFFFFF;
// For stereo rendering
uint32_t view_count = 1;
@@ -111,20 +106,19 @@ struct RenderDataGLES3 {
const PagedArray<RenderGeometryInstance *> *instances = nullptr;
const PagedArray<RID> *lights = nullptr;
const PagedArray<RID> *reflection_probes = nullptr;
- RID environment = RID();
- RID camera_attributes = RID();
- RID reflection_probe = RID();
+ RID environment;
+ RID camera_attributes;
+ RID reflection_probe;
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;
+ RenderingMethod::RenderInfo *render_info = nullptr;
};
class RasterizerCanvasGLES3;
@@ -183,34 +177,6 @@ private:
};
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
@@ -304,12 +270,13 @@ private:
};
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_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
+ INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 7,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 8,
+ INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 9,
+ INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 10,
+ INSTANCE_DATA_FLAG_PARTICLES = 1 << 11,
INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14,
@@ -367,9 +334,20 @@ private:
float fog_light_color[3];
float fog_sun_scatter;
+ uint32_t camera_visible_layers;
+ uint32_t pad1;
+ uint32_t pad2;
+ uint32_t pad3;
};
static_assert(sizeof(UBO) % 16 == 0, "Scene UBO size must be a multiple of 16 bytes");
+ struct MultiviewUBO {
+ float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
+ float inv_projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
+ float eye_offset[RendererSceneRender::MAX_RENDER_VIEWS][4];
+ };
+ static_assert(sizeof(MultiviewUBO) % 16 == 0, "Multiview UBO size must be a multiple of 16 bytes");
+
struct TonemapUBO {
float exposure = 1.0;
float white = 1.0;
@@ -380,6 +358,8 @@ private:
UBO ubo;
GLuint ubo_buffer = 0;
+ MultiviewUBO multiview_ubo;
+ GLuint multiview_buffer = 0;
GLuint tonemap_buffer = 0;
bool used_depth_prepass = false;
@@ -397,8 +377,8 @@ private:
LightData *omni_lights = nullptr;
LightData *spot_lights = nullptr;
- InstanceSort<LightInstance> *omni_light_sort;
- InstanceSort<LightInstance> *spot_light_sort;
+ InstanceSort<GLES3::LightInstance> *omni_light_sort;
+ InstanceSort<GLES3::LightInstance> *spot_light_sort;
GLuint omni_light_buffer = 0;
GLuint spot_light_buffer = 0;
uint32_t omni_light_count = 0;
@@ -412,10 +392,10 @@ private:
GeometryInstanceSurface **elements = nullptr;
int element_count = 0;
bool reverse_cull = false;
- uint32_t spec_constant_base_flags = 0;
+ uint64_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) {
+ RenderListParameters(GeometryInstanceSurface **p_elements, int p_element_count, bool p_reverse_cull, uint64_t p_spec_constant_base_flags, bool p_force_wireframe = false) {
elements = p_elements;
element_count = p_element_count;
reverse_cull = p_reverse_cull;
@@ -517,7 +497,6 @@ protected:
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 */
@@ -597,24 +576,13 @@ protected:
public:
static RasterizerSceneGLES3 *get_singleton() { return singleton; }
- RasterizerCanvasGLES3 *canvas;
+ RasterizerCanvasGLES3 *canvas = nullptr;
RenderGeometryInstance *geometry_instance_create(RID p_base) override;
void geometry_instance_free(RenderGeometryInstance *p_geometry_instance) override;
uint32_t geometry_instance_get_pair_mask() override;
- /* SHADOW ATLAS API */
-
- RID shadow_atlas_create() override;
- void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override;
- void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
- bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override;
-
- void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
- int get_directional_light_shadow_size(RID p_light_intance) override;
- void set_directional_shadow_count(int p_count) override;
-
/* SDFGI UPDATE */
void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override {}
@@ -641,7 +609,6 @@ public:
/* ENVIRONMENT API */
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_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override;
@@ -665,45 +632,12 @@ public:
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 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;
RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const override;
Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const override;
- RID reflection_atlas_create() override;
- int reflection_atlas_get_size(RID p_ref_atlas) const override;
- void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override;
-
- RID reflection_probe_instance_create(RID p_probe) override;
- void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override;
- void reflection_probe_release_atlas_index(RID p_instance) override;
- bool reflection_probe_instance_needs_redraw(RID p_instance) override;
- bool reflection_probe_instance_has_reflection(RID p_instance) override;
- bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override;
- bool reflection_probe_instance_postprocess_step(RID p_instance) override;
-
- RID decal_instance_create(RID p_decal) override;
- void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override;
-
- RID lightmap_instance_create(RID p_lightmap) override;
- void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
-
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;
@@ -711,7 +645,7 @@ public:
void voxel_gi_set_quality(RS::VoxelGIQuality) override;
- void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_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_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) 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;
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index 033f10dbc5..71caf3b8e3 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/drivers/gles3/shader_gles3.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* shader_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. */
-/*************************************************************************/
+/**************************************************************************/
+/* shader_gles3.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#include "shader_gles3.h"
@@ -36,6 +36,11 @@
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
+static String _mkid(const String &p_id) {
+ String id = "m_" + p_id.replace("__", "_dus_");
+ return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl
+}
+
void ShaderGLES3::_add_stage(const char *p_code, StageType p_stage_type) {
Vector<String> lines = String(p_code).split("\n");
@@ -92,7 +97,7 @@ void ShaderGLES3::_add_stage(const char *p_code, StageType p_stage_type) {
}
}
-void ShaderGLES3::_setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_name, int p_uniform_count, const char **p_uniform_names, int p_ubo_count, const UBOPair *p_ubos, int p_texture_count, const TexUnitPair *p_tex_units, int p_specialization_count, const Specialization *p_specializations, int p_variant_count, const char **p_variants) {
+void ShaderGLES3::_setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_name, int p_uniform_count, const char **p_uniform_names, int p_ubo_count, const UBOPair *p_ubos, int p_feedback_count, const Feedback *p_feedback, int p_texture_count, const TexUnitPair *p_tex_units, int p_specialization_count, const Specialization *p_specializations, int p_variant_count, const char **p_variants) {
name = p_name;
if (p_vertex_code) {
@@ -118,6 +123,8 @@ void ShaderGLES3::_setup(const char *p_vertex_code, const char *p_fragment_code,
}
variant_defines = p_variants;
variant_count = p_variant_count;
+ feedbacks = p_feedback;
+ feedback_count = p_feedback_count;
StringBuilder tohash;
/*
@@ -142,7 +149,7 @@ RID ShaderGLES3::version_create() {
return version_owner.make_rid(version);
}
-void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template, uint64_t p_specialization) {
+void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, StageType p_stage_type, uint64_t p_specialization) {
#ifdef GLES_OVER_GL
builder.append("#version 330\n");
builder.append("#define USE_GLES_OVER_GL\n");
@@ -171,6 +178,24 @@ void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant
}
builder.append("\n"); //make sure defines begin at newline
+ // Insert multiview extension loading, because it needs to appear before
+ // any non-preprocessor code (like the "precision highp..." lines below).
+ builder.append("#ifdef USE_MULTIVIEW\n");
+ builder.append("#if defined(GL_OVR_multiview2)\n");
+ builder.append("#extension GL_OVR_multiview2 : require\n");
+ builder.append("#elif defined(GL_OVR_multiview)\n");
+ builder.append("#extension GL_OVR_multiview : require\n");
+ builder.append("#endif\n");
+ if (p_stage_type == StageType::STAGE_TYPE_VERTEX) {
+ builder.append("layout(num_views=2) in;\n");
+ }
+ builder.append("#define ViewIndex gl_ViewID_OVR\n");
+ builder.append("#define MAX_VIEWS 2\n");
+ builder.append("#else\n");
+ builder.append("#define ViewIndex 0\n");
+ builder.append("#define MAX_VIEWS 1\n");
+ builder.append("#endif\n");
+
// Default to highp precision unless specified otherwise.
builder.append("precision highp float;\n");
builder.append("precision highp int;\n");
@@ -180,8 +205,9 @@ void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant
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];
+ const StageTemplate &stage_template = stage_templates[p_stage_type];
+ for (uint32_t i = 0; i < stage_template.chunks.size(); i++) {
+ const StageTemplate::Chunk &chunk = stage_template.chunks[i];
switch (chunk.type) {
case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: {
builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment)
@@ -224,7 +250,7 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_
//vertex stage
{
StringBuilder builder;
- _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_VERTEX], p_specialization);
+ _build_variant_code(builder, p_variant, p_version, STAGE_TYPE_VERTEX, p_specialization);
spec.vert_id = glCreateShader(GL_VERTEX_SHADER);
String builder_string = builder.as_string();
@@ -272,7 +298,7 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_
//fragment stage
{
StringBuilder builder;
- _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_FRAGMENT], p_specialization);
+ _build_variant_code(builder, p_variant, p_version, STAGE_TYPE_FRAGMENT, p_specialization);
spec.frag_id = glCreateShader(GL_FRAGMENT_SHADER);
String builder_string = builder.as_string();
@@ -320,9 +346,21 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_
glAttachShader(spec.id, spec.frag_id);
glAttachShader(spec.id, spec.vert_id);
- //for (int i = 0; i < attribute_pair_count; i++) {
- // glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name);
- //}
+ // If feedback exists, set it up.
+
+ if (feedback_count) {
+ Vector<const char *> feedback;
+ for (int i = 0; i < feedback_count; i++) {
+ if (feedbacks[i].specialization == 0 || (feedbacks[i].specialization & p_specialization)) {
+ // Specialization for this feedback is enabled
+ feedback.push_back(feedbacks[i].name);
+ }
+ }
+
+ if (feedback.size()) {
+ glTransformFeedbackVaryings(spec.id, feedback.size(), feedback.ptr(), GL_INTERLEAVED_ATTRIBS);
+ }
+ }
glLinkProgram(spec.id);
@@ -392,7 +430,7 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_
}
// textures
for (int i = 0; i < p_version->texture_uniforms.size(); i++) {
- String native_uniform_name = p_version->texture_uniforms[i];
+ String native_uniform_name = _mkid(p_version->texture_uniforms[i]);
GLint location = glGetUniformLocation(spec.id, (native_uniform_name).ascii().get_data());
glUniform1i(location, i + base_texture_index);
}
@@ -413,7 +451,7 @@ RS::ShaderNativeSourceCode ShaderGLES3::version_get_native_source_code(RID p_ver
{
StringBuilder builder;
- _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_VERTEX], specialization_default_mask);
+ _build_variant_code(builder, i, version, STAGE_TYPE_VERTEX, specialization_default_mask);
RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "vertex";
@@ -425,7 +463,7 @@ RS::ShaderNativeSourceCode ShaderGLES3::version_get_native_source_code(RID p_ver
//fragment stage
{
StringBuilder builder;
- _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_FRAGMENT], specialization_default_mask);
+ _build_variant_code(builder, i, version, STAGE_TYPE_FRAGMENT, specialization_default_mask);
RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "fragment";
diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h
index 2b72549b5b..0b2ecbaca6 100644
--- a/drivers/gles3/shader_gles3.h
+++ b/drivers/gles3/shader_gles3.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* shader_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. */
-/*************************************************************************/
+/**************************************************************************/
+/* shader_gles3.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef SHADER_GLES3_H
#define SHADER_GLES3_H
@@ -70,15 +70,20 @@ protected:
bool default_value = false;
};
+ struct Feedback {
+ const char *name;
+ uint64_t specialization;
+ };
+
private:
//versions
CharString general_defines;
// 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
+ // Variants use #ifdefs to toggle behavior on and off to change behavior 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, or doing a depth prepass vs a color pass)
+ // Specializations use #ifdefs to toggle behavior 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 behavior 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;
@@ -153,7 +158,7 @@ private:
StageTemplate stage_templates[STAGE_TYPE_MAX];
- void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template, uint64_t p_specialization);
+ void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, StageType p_stage_type, uint64_t p_specialization);
void _add_stage(const char *p_code, StageType p_stage_type);
@@ -165,6 +170,8 @@ private:
int uniform_count = 0;
const UBOPair *ubo_pairs = nullptr;
int ubo_count = 0;
+ const Feedback *feedbacks;
+ int feedback_count = 0;
const TexUnitPair *texunit_pairs = nullptr;
int texunit_pair_count = 0;
int specialization_count = 0;
@@ -178,13 +185,13 @@ private:
protected:
ShaderGLES3();
- void _setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_name, int p_uniform_count, const char **p_uniform_names, int p_ubo_count, const UBOPair *p_ubos, int p_texture_count, const TexUnitPair *p_tex_units, int p_specialization_count, const Specialization *p_specializations, int p_variant_count, const char **p_variants);
+ void _setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_name, int p_uniform_count, const char **p_uniform_names, int p_ubo_count, const UBOPair *p_ubos, int p_feedback_count, const Feedback *p_feedback, int p_texture_count, const TexUnitPair *p_tex_units, int p_specialization_count, const Specialization *p_specializations, int p_variant_count, const char **p_variants);
- _FORCE_INLINE_ void _version_bind_shader(RID p_version, int p_variant, uint64_t p_specialization) {
- ERR_FAIL_INDEX(p_variant, variant_count);
+ _FORCE_INLINE_ bool _version_bind_shader(RID p_version, int p_variant, uint64_t p_specialization) {
+ ERR_FAIL_INDEX_V(p_variant, variant_count, false);
Version *version = version_owner.get_or_null(p_version);
- ERR_FAIL_COND(!version);
+ ERR_FAIL_COND_V(!version, false);
if (version->variants.size() == 0) {
_initialize_version(version); //may lack initialization
@@ -208,11 +215,14 @@ protected:
spec = version->variants[p_variant].lookup_ptr(specialization_default_mask);
}
- ERR_FAIL_COND(!spec); // Should never happen
- ERR_FAIL_COND(!spec->ok); // Should never happen
+ if (!spec || !spec->ok) {
+ WARN_PRINT_ONCE("shader failed to compile, unable to bind shader.");
+ return false;
+ }
glUseProgram(spec->id);
current_shader = spec;
+ return true;
}
_FORCE_INLINE_ int _version_get_uniform(int p_which, RID p_version, int p_variant, uint64_t p_specialization) {
diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub
index 83ffe8b1e1..34713e7e29 100644
--- a/drivers/gles3/shaders/SCsub
+++ b/drivers/gles3/shaders/SCsub
@@ -17,3 +17,8 @@ if "GLES3_GLSL" in env["BUILDERS"]:
env.GLES3_GLSL("scene.glsl")
env.GLES3_GLSL("sky.glsl")
env.GLES3_GLSL("cubemap_filter.glsl")
+ env.GLES3_GLSL("canvas_occlusion.glsl")
+ env.GLES3_GLSL("canvas_sdf.glsl")
+ env.GLES3_GLSL("particles.glsl")
+ env.GLES3_GLSL("particles_copy.glsl")
+ env.GLES3_GLSL("skeleton.glsl")
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 5ec25327be..1631c65385 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -10,6 +10,8 @@ mode_instanced = #define USE_ATTRIBUTES \n#define USE_INSTANCING
#[specializations]
DISABLE_LIGHTING = false
+USE_RGBA_SHADOWS = false
+SINGLE_INSTANCE = false
#[vertex]
@@ -18,18 +20,80 @@ layout(location = 0) in vec2 vertex_attrib;
layout(location = 3) in vec4 color_attrib;
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 // USE_INSTANCING
+
+#endif // USE_ATTRIBUTES
+
+#include "stdlib_inc.glsl"
+
+layout(location = 6) in highp vec4 attrib_A;
+layout(location = 7) in highp vec4 attrib_B;
+layout(location = 8) in highp vec4 attrib_C;
+layout(location = 9) in highp vec4 attrib_D;
+layout(location = 10) in highp vec4 attrib_E;
+#ifdef USE_PRIMITIVE
+layout(location = 11) in highp uvec4 attrib_F;
+#else
+layout(location = 11) in highp vec4 attrib_F;
#endif
+layout(location = 12) in highp uvec4 attrib_G;
+layout(location = 13) in highp uvec4 attrib_H;
+
+#define read_draw_data_world_x attrib_A.xy
+#define read_draw_data_world_y attrib_A.zw
+#define read_draw_data_world_ofs attrib_B.xy
+#define read_draw_data_color_texture_pixel_size attrib_B.zw
+
+#ifdef USE_PRIMITIVE
+
+#define read_draw_data_point_a attrib_C.xy
+#define read_draw_data_point_b attrib_C.zw
+#define read_draw_data_point_c attrib_D.xy
+#define read_draw_data_uv_a attrib_D.zw
+#define read_draw_data_uv_b attrib_E.xy
+#define read_draw_data_uv_c attrib_E.zw
+
+#define read_draw_data_color_a_rg attrib_F.x
+#define read_draw_data_color_a_ba attrib_F.y
+#define read_draw_data_color_b_rg attrib_F.z
+#define read_draw_data_color_b_ba attrib_F.w
+#define read_draw_data_color_c_rg attrib_G.x
+#define read_draw_data_color_c_ba attrib_G.y
+#else
+
+#define read_draw_data_modulation attrib_C
+#define read_draw_data_ninepatch_margins attrib_D
+#define read_draw_data_dst_rect attrib_E
+#define read_draw_data_src_rect attrib_F
+
+#endif
+
+#define read_draw_data_flags attrib_G.z
+#define read_draw_data_specular_shininess attrib_G.w
+#define read_draw_data_lights attrib_H
+
+// Varyings so the per-instance info can be used in the fragment shader
+flat out vec4 varying_A;
+flat out vec2 varying_B;
+#ifndef USE_PRIMITIVE
+flat out vec4 varying_C;
+#ifndef USE_ATTRIBUTES
+#ifdef USE_NINEPATCH
+
+flat out vec2 varying_D;
#endif
+flat out vec4 varying_E;
+#endif
+#endif
+flat out uvec2 varying_F;
+flat out uvec4 varying_G;
// This needs to be outside clang-format so the ubo comment is in the right place
#ifdef MATERIAL_UNIFORMS_USED
@@ -41,14 +105,10 @@ layout(std140) uniform MaterialUniforms{ //ubo:4
#endif
/* clang-format on */
#include "canvas_uniforms_inc.glsl"
-#include "stdlib_inc.glsl"
-
-uniform sampler2D transforms_texture; //texunit:-1
out vec2 uv_interp;
out vec4 color_interp;
out vec2 vertex_interp;
-flat out int draw_data_instance;
#ifdef USE_NINEPATCH
@@ -59,43 +119,48 @@ out vec2 pixel_size_interp;
#GLOBALS
void main() {
+ varying_A = vec4(read_draw_data_world_x, read_draw_data_world_y);
+ varying_B = read_draw_data_color_texture_pixel_size;
+#ifndef USE_PRIMITIVE
+ varying_C = read_draw_data_ninepatch_margins;
+
+#ifndef USE_ATTRIBUTES
+#ifdef USE_NINEPATCH
+ varying_D = vec2(read_draw_data_dst_rect.z, read_draw_data_dst_rect.w);
+#endif // USE_NINEPATCH
+ varying_E = read_draw_data_src_rect;
+#endif // !USE_ATTRIBUTES
+#endif // USE_PRIMITIVE
+
+ varying_F = uvec2(read_draw_data_flags, read_draw_data_specular_shininess);
+ varying_G = read_draw_data_lights;
+
vec4 instance_custom = vec4(0.0);
- draw_data_instance = gl_InstanceID;
-#ifdef USE_PRIMITIVE
- //weird bug,
- //this works
+#ifdef USE_PRIMITIVE
vec2 vertex;
vec2 uv;
vec4 color;
- if (gl_VertexID == 0) {
- vertex = draw_data[draw_data_instance].point_a;
- uv = draw_data[draw_data_instance].uv_a;
- color = vec4(unpackHalf2x16(draw_data[draw_data_instance].color_a_rg), unpackHalf2x16(draw_data[draw_data_instance].color_a_ba));
- } else if (gl_VertexID == 1) {
- vertex = draw_data[draw_data_instance].point_b;
- uv = draw_data[draw_data_instance].uv_b;
- color = vec4(unpackHalf2x16(draw_data[draw_data_instance].color_b_rg), unpackHalf2x16(draw_data[draw_data_instance].color_b_ba));
+ if (gl_VertexID % 3 == 0) {
+ vertex = read_draw_data_point_a;
+ uv = read_draw_data_uv_a;
+ color = vec4(unpackHalf2x16(read_draw_data_color_a_rg), unpackHalf2x16(read_draw_data_color_a_ba));
+ } else if (gl_VertexID % 3 == 1) {
+ vertex = read_draw_data_point_b;
+ uv = read_draw_data_uv_b;
+ color = vec4(unpackHalf2x16(read_draw_data_color_b_rg), unpackHalf2x16(read_draw_data_color_b_ba));
} else {
- vertex = draw_data[draw_data_instance].point_c;
- uv = draw_data[draw_data_instance].uv_c;
- color = vec4(unpackHalf2x16(draw_data[draw_data_instance].color_c_rg), unpackHalf2x16(draw_data[draw_data_instance].color_c_ba));
+ vertex = read_draw_data_point_c;
+ uv = read_draw_data_uv_c;
+ color = vec4(unpackHalf2x16(read_draw_data_color_c_rg), unpackHalf2x16(read_draw_data_color_c_ba));
}
- uvec4 bones = uvec4(0, 0, 0, 0);
- 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;
+ vec4 color = color_attrib * read_draw_data_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;
@@ -103,30 +168,30 @@ void main() {
#endif
#else
+ vec2 vertex_base_arr[6] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 1.0));
+ vec2 vertex_base = vertex_base_arr[gl_VertexID % 6];
- 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));
- vec2 vertex_base = vertex_base_arr[gl_VertexID];
-
- vec2 uv = draw_data[draw_data_instance].src_rect.xy + abs(draw_data[draw_data_instance].src_rect.zw) * ((draw_data[draw_data_instance].flags & FLAGS_TRANSPOSE_RECT) != uint(0) ? vertex_base.yx : vertex_base.xy);
- vec4 color = draw_data[draw_data_instance].modulation;
- vec2 vertex = draw_data[draw_data_instance].dst_rect.xy + abs(draw_data[draw_data_instance].dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(draw_data[draw_data_instance].src_rect.zw, vec2(0.0, 0.0)));
- uvec4 bones = uvec4(0, 0, 0, 0);
+ vec2 uv = read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw) * ((read_draw_data_flags & FLAGS_TRANSPOSE_RECT) != uint(0) ? vertex_base.yx : vertex_base.xy);
+ vec4 color = read_draw_data_modulation;
+ vec2 vertex = read_draw_data_dst_rect.xy + abs(read_draw_data_dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(read_draw_data_src_rect.zw, vec2(0.0, 0.0)));
#endif
- 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));
+ mat4 model_matrix = mat4(vec4(read_draw_data_world_x, 0.0, 0.0), vec4(read_draw_data_world_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(read_draw_data_world_ofs, 0.0, 1.0));
#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 !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
- if (bool(draw_data[draw_data_instance].flags & FLAGS_USING_PARTICLES)) {
+ if (bool(read_draw_data_flags & FLAGS_USING_PARTICLES)) {
//scale by texture size
- vertex /= draw_data[draw_data_instance].color_texture_pixel_size;
+ vertex /= read_draw_data_color_texture_pixel_size;
}
#endif
+ vec2 color_texture_pixel_size = read_draw_data_color_texture_pixel_size;
+
#ifdef USE_POINT_SIZE
float point_size = 1.0;
#endif
@@ -135,7 +200,7 @@ void main() {
}
#ifdef USE_NINEPATCH
- pixel_size_interp = abs(draw_data[draw_data_instance].dst_rect.zw) * vertex_base;
+ pixel_size_interp = abs(read_draw_data_dst_rect.zw) * vertex_base;
#endif
#if !defined(SKIP_TRANSFORM_USED)
@@ -151,48 +216,6 @@ void main() {
uv += 1e-5;
}
-#ifdef USE_ATTRIBUTES
-#if 0
- if (bool(draw_data[draw_data_instance].flags & FLAGS_USE_SKELETON) && bone_weights != vec4(0.0)) { //must be a valid bone
- //skeleton transform
- ivec4 bone_indicesi = ivec4(bone_indices);
-
- uvec2 tex_ofs = bone_indicesi.x * 2;
-
- mat2x4 m;
- m = mat2x4(
- texelFetch(skeleton_buffer, tex_ofs + 0),
- texelFetch(skeleton_buffer, tex_ofs + 1)) *
- bone_weights.x;
-
- tex_ofs = bone_indicesi.y * 2;
-
- m += mat2x4(
- texelFetch(skeleton_buffer, tex_ofs + 0),
- texelFetch(skeleton_buffer, tex_ofs + 1)) *
- bone_weights.y;
-
- tex_ofs = bone_indicesi.z * 2;
-
- m += mat2x4(
- texelFetch(skeleton_buffer, tex_ofs + 0),
- texelFetch(skeleton_buffer, tex_ofs + 1)) *
- bone_weights.z;
-
- tex_ofs = bone_indicesi.w * 2;
-
- m += mat2x4(
- texelFetch(skeleton_buffer, tex_ofs + 0),
- texelFetch(skeleton_buffer, tex_ofs + 1)) *
- bone_weights.w;
-
- mat4 bone_matrix = skeleton_data.skeleton_transform * transpose(mat4(m[0], m[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))) * skeleton_data.skeleton_transform_inverse;
-
- //outvec = bone_matrix * outvec;
- }
-#endif
-#endif
-
vertex = (canvas_transform * vec4(vertex, 0.0, 1.0)).xy;
vertex_interp = vertex;
@@ -210,19 +233,9 @@ void main() {
#include "canvas_uniforms_inc.glsl"
#include "stdlib_inc.glsl"
-uniform sampler2D atlas_texture; //texunit:-2
-uniform sampler2D shadow_atlas_texture; //texunit:-3
-uniform sampler2D screen_texture; //texunit:-4
-uniform sampler2D sdf_texture; //texunit:-5
-uniform sampler2D normal_texture; //texunit:-6
-uniform sampler2D specular_texture; //texunit:-7
-
-uniform sampler2D color_texture; //texunit:0
-
in vec2 uv_interp;
-in vec4 color_interp;
in vec2 vertex_interp;
-flat in int draw_data_instance;
+in vec4 color_interp;
#ifdef USE_NINEPATCH
@@ -230,6 +243,47 @@ in vec2 pixel_size_interp;
#endif
+// Can all be flat as they are the same for the whole batched instance
+flat in vec4 varying_A;
+flat in vec2 varying_B;
+#define read_draw_data_world_x varying_A.xy
+#define read_draw_data_world_y varying_A.zw
+#define read_draw_data_color_texture_pixel_size varying_B
+
+#ifndef USE_PRIMITIVE
+flat in vec4 varying_C;
+#define read_draw_data_ninepatch_margins varying_C
+
+#ifndef USE_ATTRIBUTES
+#ifdef USE_NINEPATCH
+
+flat in vec2 varying_D;
+#define read_draw_data_dst_rect_z varying_D.x
+#define read_draw_data_dst_rect_w varying_D.y
+#endif
+
+flat in vec4 varying_E;
+#define read_draw_data_src_rect varying_E
+#endif // USE_ATTRIBUTES
+#endif // USE_PRIMITIVE
+
+flat in uvec2 varying_F;
+flat in uvec4 varying_G;
+#define read_draw_data_flags varying_F.x
+#define read_draw_data_specular_shininess varying_F.y
+#define read_draw_data_lights varying_G
+
+#ifndef DISABLE_LIGHTING
+uniform sampler2D atlas_texture; //texunit:-2
+uniform sampler2D shadow_atlas_texture; //texunit:-3
+#endif // DISABLE_LIGHTING
+uniform sampler2D color_buffer; //texunit:-4
+uniform sampler2D sdf_texture; //texunit:-5
+uniform sampler2D normal_texture; //texunit:-6
+uniform sampler2D specular_texture; //texunit:-7
+
+uniform sampler2D color_texture; //texunit:0
+
layout(location = 0) out vec4 frag_color;
#ifdef MATERIAL_UNIFORMS_USED
@@ -241,13 +295,19 @@ layout(std140) uniform MaterialUniforms{
};
#endif
+#GLOBALS
+
+float vec4_to_float(vec4 p_vec) {
+ return dot(p_vec, vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) * 2.0 - 1.0;
+}
+
vec2 screen_uv_to_sdf(vec2 p_uv) {
return screen_to_sdf * p_uv;
}
float texture_sdf(vec2 p_sdf) {
vec2 uv = p_sdf * sdf_to_tex.xy + sdf_to_tex.zw;
- float d = texture(sdf_texture, uv).r;
+ float d = vec4_to_float(texture(sdf_texture, uv));
d *= SDF_MAX_LENGTH;
return d * tex_to_sdf;
}
@@ -257,16 +317,15 @@ vec2 texture_sdf_normal(vec2 p_sdf) {
const float EPSILON = 0.001;
return normalize(vec2(
- texture(sdf_texture, uv + vec2(EPSILON, 0.0)).r - texture(sdf_texture, uv - vec2(EPSILON, 0.0)).r,
- texture(sdf_texture, uv + vec2(0.0, EPSILON)).r - texture(sdf_texture, uv - vec2(0.0, EPSILON)).r));
+ vec4_to_float(texture(sdf_texture, uv + vec2(EPSILON, 0.0))) - vec4_to_float(texture(sdf_texture, uv - vec2(EPSILON, 0.0))),
+ vec4_to_float(texture(sdf_texture, uv + vec2(0.0, EPSILON))) - vec4_to_float(texture(sdf_texture, uv - vec2(0.0, EPSILON)))));
}
vec2 sdf_to_screen_uv(vec2 p_sdf) {
return p_sdf * sdf_to_screen;
}
-#GLOBALS
-
+#ifndef DISABLE_LIGHTING
#ifdef LIGHT_CODE_USED
vec4 light_compute(
@@ -281,6 +340,14 @@ vec4 light_compute(
vec2 uv,
vec4 color, bool is_directional) {
vec4 light = vec4(0.0);
+ vec3 light_direction = vec3(0.0);
+
+ if (is_directional) {
+ light_direction = normalize(mix(vec3(light_position.xy, 0.0), vec3(0, 0, 1), light_position.z));
+ light_position = vec3(0.0);
+ } else {
+ light_direction = normalize(light_position - light_vertex);
+ }
#CODE : LIGHT
@@ -289,49 +356,6 @@ vec4 light_compute(
#endif
-#ifdef USE_NINEPATCH
-
-float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, float margin_begin, float margin_end, int np_repeat, inout int draw_center) {
- float tex_size = 1.0 / tex_pixel_size;
-
- if (pixel < margin_begin) {
- return pixel * tex_pixel_size;
- } else if (pixel >= draw_size - margin_end) {
- return (tex_size - (draw_size - pixel)) * tex_pixel_size;
- } else {
- if (!bool(draw_data[draw_data_instance].flags & FLAGS_NINEPACH_DRAW_CENTER)) {
- draw_center--;
- }
-
- // np_repeat is passed as uniform using NinePatchRect::AxisStretchMode enum.
- if (np_repeat == 0) { // Stretch.
- // Convert to ratio.
- float ratio = (pixel - margin_begin) / (draw_size - margin_begin - margin_end);
- // Scale to source texture.
- return (margin_begin + ratio * (tex_size - margin_begin - margin_end)) * tex_pixel_size;
- } else if (np_repeat == 1) { // Tile.
- // Convert to offset.
- float ofs = mod((pixel - margin_begin), tex_size - margin_begin - margin_end);
- // Scale to source texture.
- return (margin_begin + ofs) * tex_pixel_size;
- } else if (np_repeat == 2) { // Tile Fit.
- // Calculate scale.
- float src_area = draw_size - margin_begin - margin_end;
- float dst_area = tex_size - margin_begin - margin_end;
- float scale = max(1.0, floor(src_area / max(dst_area, 0.0000001) + 0.5));
- // Convert to ratio.
- float ratio = (pixel - margin_begin) / src_area;
- ratio = mod(ratio * scale, 1.0);
- // Scale to source texture.
- return (margin_begin + ratio * dst_area) * tex_pixel_size;
- } else { // Shouldn't happen, but silences compiler warning.
- return 0.0;
- }
- }
-}
-
-#endif
-
vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 light_color, vec4 specular_shininess, bool specular_shininess_used) {
float cNdotL = max(0.0, dot(normal, light_vec));
@@ -355,6 +379,20 @@ vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 lig
}
}
+#ifdef USE_RGBA_SHADOWS
+
+#define SHADOW_DEPTH(m_uv) (dot(textureLod(shadow_atlas_texture, (m_uv), 0.0), vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) * 2.0 - 1.0)
+
+#else
+
+#define SHADOW_DEPTH(m_uv) (textureLod(shadow_atlas_texture, (m_uv), 0.0).r)
+
+#endif
+
+/* clang-format off */
+#define SHADOW_TEST(m_uv) { highp float sd = SHADOW_DEPTH(m_uv); shadow += step(sd, shadow_uv.z / shadow_uv.w); }
+/* clang-format on */
+
//float distance = length(shadow_pos);
vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
#ifdef LIGHT_CODE_USED
@@ -362,40 +400,38 @@ vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
vec3 shadow_modulate
#endif
) {
- float shadow;
- uint shadow_mode = light_data[light_base].flags & LIGHT_FLAGS_FILTER_MASK;
+ float shadow = 0.0;
+ uint shadow_mode = light_array[light_base].flags & LIGHT_FLAGS_FILTER_MASK;
if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) {
- shadow = textureProjLod(shadow_atlas_texture, shadow_uv, 0.0).x;
+ SHADOW_TEST(shadow_uv.xy);
} else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) {
- vec4 shadow_pixel_size = vec4(light_data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
- shadow = 0.0;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
+ vec2 shadow_pixel_size = vec2(light_array[light_base].shadow_pixel_size, 0.0);
+ SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 2.0);
+ SHADOW_TEST(shadow_uv.xy - shadow_pixel_size);
+ SHADOW_TEST(shadow_uv.xy);
+ SHADOW_TEST(shadow_uv.xy + shadow_pixel_size);
+ SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 2.0);
shadow /= 5.0;
} else { //PCF13
- vec4 shadow_pixel_size = vec4(light_data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
- shadow = 0.0;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 6.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 5.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 4.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 3.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 3.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 4.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 5.0, 0.0).x;
- shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 6.0, 0.0).x;
+ vec2 shadow_pixel_size = vec2(light_array[light_base].shadow_pixel_size, 0.0);
+ SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 6.0);
+ SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 5.0);
+ SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 4.0);
+ SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 3.0);
+ SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 2.0);
+ SHADOW_TEST(shadow_uv.xy - shadow_pixel_size);
+ SHADOW_TEST(shadow_uv.xy);
+ SHADOW_TEST(shadow_uv.xy + shadow_pixel_size);
+ SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 2.0);
+ SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 3.0);
+ SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 4.0);
+ SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 5.0);
+ SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 6.0);
shadow /= 13.0;
}
- vec4 shadow_color = unpackUnorm4x8(light_data[light_base].shadow_color);
+ vec4 shadow_color = godot_unpackUnorm4x8(light_array[light_base].shadow_color);
#ifdef LIGHT_CODE_USED
shadow_color.rgb *= shadow_modulate;
#endif
@@ -406,7 +442,7 @@ vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
}
void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) {
- uint blend_mode = light_data[light_base].flags & LIGHT_FLAGS_BLEND_MASK;
+ uint blend_mode = light_array[light_base].flags & LIGHT_FLAGS_BLEND_MASK;
switch (blend_mode) {
case LIGHT_FLAGS_BLEND_MODE_ADD: {
@@ -421,6 +457,51 @@ void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) {
}
}
+#endif
+
+#ifdef USE_NINEPATCH
+
+float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, float margin_begin, float margin_end, int np_repeat, inout int draw_center) {
+ float tex_size = 1.0 / tex_pixel_size;
+
+ if (pixel < margin_begin) {
+ return pixel * tex_pixel_size;
+ } else if (pixel >= draw_size - margin_end) {
+ return (tex_size - (draw_size - pixel)) * tex_pixel_size;
+ } else {
+ if (!bool(read_draw_data_flags & FLAGS_NINEPACH_DRAW_CENTER)) {
+ draw_center--;
+ }
+
+ // np_repeat is passed as uniform using NinePatchRect::AxisStretchMode enum.
+ if (np_repeat == 0) { // Stretch.
+ // Convert to ratio.
+ float ratio = (pixel - margin_begin) / (draw_size - margin_begin - margin_end);
+ // Scale to source texture.
+ return (margin_begin + ratio * (tex_size - margin_begin - margin_end)) * tex_pixel_size;
+ } else if (np_repeat == 1) { // Tile.
+ // Convert to offset.
+ float ofs = mod((pixel - margin_begin), tex_size - margin_begin - margin_end);
+ // Scale to source texture.
+ return (margin_begin + ofs) * tex_pixel_size;
+ } else if (np_repeat == 2) { // Tile Fit.
+ // Calculate scale.
+ float src_area = draw_size - margin_begin - margin_end;
+ float dst_area = tex_size - margin_begin - margin_end;
+ float scale = max(1.0, floor(src_area / max(dst_area, 0.0000001) + 0.5));
+ // Convert to ratio.
+ float ratio = (pixel - margin_begin) / src_area;
+ ratio = mod(ratio * scale, 1.0);
+ // Scale to source texture.
+ return (margin_begin + ratio * dst_area) * tex_pixel_size;
+ } else { // Shouldn't happen, but silences compiler warning.
+ return 0.0;
+ }
+ }
+}
+
+#endif
+
float msdf_median(float r, float g, float b, float a) {
return min(max(min(r, g), min(max(r, g), b)), a);
}
@@ -436,28 +517,26 @@ void main() {
int draw_center = 2;
uv = vec2(
- map_ninepatch_axis(pixel_size_interp.x, abs(draw_data[draw_data_instance].dst_rect.z), draw_data[draw_data_instance].color_texture_pixel_size.x, draw_data[draw_data_instance].ninepatch_margins.x, draw_data[draw_data_instance].ninepatch_margins.z, int(draw_data[draw_data_instance].flags >> FLAGS_NINEPATCH_H_MODE_SHIFT) & 0x3, draw_center),
- map_ninepatch_axis(pixel_size_interp.y, abs(draw_data[draw_data_instance].dst_rect.w), draw_data[draw_data_instance].color_texture_pixel_size.y, draw_data[draw_data_instance].ninepatch_margins.y, draw_data[draw_data_instance].ninepatch_margins.w, int(draw_data[draw_data_instance].flags >> FLAGS_NINEPATCH_V_MODE_SHIFT) & 0x3, draw_center));
+ map_ninepatch_axis(pixel_size_interp.x, abs(read_draw_data_dst_rect_z), read_draw_data_color_texture_pixel_size.x, read_draw_data_ninepatch_margins.x, read_draw_data_ninepatch_margins.z, int(read_draw_data_flags >> FLAGS_NINEPATCH_H_MODE_SHIFT) & 0x3, draw_center),
+ map_ninepatch_axis(pixel_size_interp.y, abs(read_draw_data_dst_rect_w), read_draw_data_color_texture_pixel_size.y, read_draw_data_ninepatch_margins.y, read_draw_data_ninepatch_margins.w, int(read_draw_data_flags >> FLAGS_NINEPATCH_V_MODE_SHIFT) & 0x3, draw_center));
if (draw_center == 0) {
color.a = 0.0;
}
- uv = uv * draw_data[draw_data_instance].src_rect.zw + draw_data[draw_data_instance].src_rect.xy; //apply region if needed
+ uv = uv * read_draw_data_src_rect.zw + read_draw_data_src_rect.xy; //apply region if needed
#endif
- if (bool(draw_data[draw_data_instance].flags & FLAGS_CLIP_RECT_UV)) {
- uv = clamp(uv, draw_data[draw_data_instance].src_rect.xy, draw_data[draw_data_instance].src_rect.xy + abs(draw_data[draw_data_instance].src_rect.zw));
+ if (bool(read_draw_data_flags & FLAGS_CLIP_RECT_UV)) {
+ uv = clamp(uv, read_draw_data_src_rect.xy, read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw));
}
#endif
#ifndef USE_PRIMITIVE
- if (bool(draw_data[draw_data_instance].flags & FLAGS_USE_MSDF)) {
- float px_range = draw_data[draw_data_instance].ninepatch_margins.x;
- float outline_thickness = draw_data[draw_data_instance].ninepatch_margins.y;
- //float reserved1 = draw_data[draw_data_instance].ninepatch_margins.z;
- //float reserved2 = draw_data[draw_data_instance].ninepatch_margins.w;
+ if (bool(read_draw_data_flags & FLAGS_USE_MSDF)) {
+ float px_range = read_draw_data_ninepatch_margins.x;
+ float outline_thickness = read_draw_data_ninepatch_margins.y;
vec4 msdf_sample = texture(color_texture, uv);
vec2 msdf_size = vec2(textureSize(color_texture, 0));
@@ -473,7 +552,7 @@ void main() {
float a = clamp(d * px_size + 0.5, 0.0, 1.0);
color.a = a * color.a;
}
- } else if (bool(draw_data[draw_data_instance].flags & FLAGS_USE_LCD)) {
+ } else if (bool(read_draw_data_flags & FLAGS_USE_LCD)) {
vec4 lcd_sample = texture(color_texture, uv);
if (lcd_sample.a == 1.0) {
color.rgb = lcd_sample.rgb * color.a;
@@ -487,8 +566,8 @@ void main() {
color *= texture(color_texture, uv);
}
- uint light_count = (draw_data[draw_data_instance].flags >> FLAGS_LIGHT_COUNT_SHIFT) & uint(0xF); //max 16 lights
- bool using_light = light_count > uint(0) || directional_light_count > uint(0);
+ uint light_count = (read_draw_data_flags >> uint(FLAGS_LIGHT_COUNT_SHIFT)) & uint(0xF); //max 16 lights
+ bool using_light = light_count > 0u || directional_light_count > 0u;
vec3 normal;
@@ -498,8 +577,14 @@ void main() {
bool normal_used = false;
#endif
- if (normal_used || (using_light && bool(draw_data[draw_data_instance].flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
+ if (normal_used || (using_light && bool(read_draw_data_flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
normal.xy = texture(normal_texture, uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0);
+ if (bool(read_draw_data_flags & FLAGS_FLIP_H)) {
+ normal.x = -normal.x;
+ }
+ if (bool(read_draw_data_flags & FLAGS_FLIP_V)) {
+ normal.y = -normal.y;
+ }
normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
normal_used = true;
} else {
@@ -515,9 +600,9 @@ void main() {
bool specular_shininess_used = false;
#endif
- if (specular_shininess_used || (using_light && normal_used && bool(draw_data[draw_data_instance].flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
+ if (specular_shininess_used || (using_light && normal_used && bool(read_draw_data_flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
specular_shininess = texture(specular_texture, uv);
- specular_shininess *= unpackUnorm4x8(draw_data[draw_data_instance].specular_shininess);
+ specular_shininess *= godot_unpackUnorm4x8(read_draw_data_specular_shininess);
specular_shininess_used = true;
} else {
specular_shininess = vec4(1.0);
@@ -529,6 +614,8 @@ void main() {
vec2 screen_uv = vec2(0.0);
#endif
+ vec2 color_texture_pixel_size = read_draw_data_color_texture_pixel_size.xy;
+
vec3 light_vertex = vec3(vertex, 0.0);
vec2 shadow_vertex = vertex;
@@ -549,15 +636,12 @@ void main() {
if (normal_used) {
//convert by item transform
- normal.xy = mat2(normalize(draw_data[draw_data_instance].world_x), normalize(draw_data[draw_data_instance].world_y)) * normal.xy;
+ normal.xy = mat2(normalize(read_draw_data_world_x), normalize(read_draw_data_world_y)) * normal.xy;
//convert by canvas transform
normal = normalize((canvas_normal_transform * vec4(normal, 0.0)).xyz);
}
- vec3 base_color = color.rgb;
- if (bool(draw_data[draw_data_instance].flags & FLAGS_USING_LIGHT_MASK)) {
- color = vec4(0.0); //invisible by default due to using light mask
- }
+ vec4 base_color = color;
#ifdef MODE_LIGHT_ONLY
color = vec4(0.0);
@@ -567,28 +651,32 @@ void main() {
#if !defined(DISABLE_LIGHTING) && !defined(MODE_UNSHADED)
- for (uint i = uint(0); i < directional_light_count; i++) {
+ // Directional Lights
+
+ for (uint i = 0u; i < directional_light_count; i++) {
uint light_base = i;
- vec2 direction = light_data[light_base].position;
- vec4 light_color = light_data[light_base].color;
+ vec2 direction = light_array[light_base].position;
+ vec4 light_color = light_array[light_base].color;
#ifdef LIGHT_CODE_USED
vec4 shadow_modulate = vec4(1.0);
- light_color = light_compute(light_vertex, vec3(direction, light_data[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, true);
+ light_color = light_compute(light_vertex, vec3(direction, light_array[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, base_color, true);
#else
if (normal_used) {
- vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_data[light_base].height));
- light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used);
+ vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_array[light_base].height));
+ light_color.rgb = light_normal_compute(light_vec, normal, base_color.rgb, light_color.rgb, specular_shininess, specular_shininess_used);
+ } else {
+ light_color.rgb *= base_color.rgb;
}
#endif
- if (bool(light_data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
- vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_data[light_base].shadow_matrix[0], light_data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
+ if (bool(light_array[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
+ vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array[light_base].shadow_matrix[0], light_array[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
- vec4 shadow_uv = vec4(shadow_pos.x, light_data[light_base].shadow_y_ofs, shadow_pos.y * light_data[light_base].shadow_zfar_inv, 1.0);
+ vec4 shadow_uv = vec4(shadow_pos.x, light_array[light_base].shadow_y_ofs, shadow_pos.y * light_array[light_base].shadow_zfar_inv, 1.0);
light_color = light_shadow_compute(light_base, light_color, shadow_uv
#ifdef LIGHT_CODE_USED
@@ -603,50 +691,51 @@ void main() {
// Positional Lights
- for (uint i = uint(0); i < MAX_LIGHTS_PER_ITEM; i++) {
+ for (uint i = 0u; i < MAX_LIGHTS_PER_ITEM; i++) {
if (i >= light_count) {
break;
}
uint light_base;
- if (i < uint(8)) {
- if (i < uint(4)) {
- light_base = draw_data[draw_data_instance].lights.x;
+ if (i < 8u) {
+ if (i < 4u) {
+ light_base = read_draw_data_lights[0];
} else {
- light_base = draw_data[draw_data_instance].lights.y;
+ light_base = read_draw_data_lights[1];
}
} else {
- if (i < uint(12)) {
- light_base = draw_data[draw_data_instance].lights.z;
+ if (i < 12u) {
+ light_base = read_draw_data_lights[2];
} else {
- light_base = draw_data[draw_data_instance].lights.w;
+ light_base = read_draw_data_lights[3];
}
}
- light_base >>= (i & uint(3)) * uint(8);
+ light_base >>= (i & 3u) * 8u;
light_base &= uint(0xFF);
- vec2 tex_uv = (vec4(vertex, 0.0, 1.0) * mat4(light_data[light_base].texture_matrix[0], light_data[light_base].texture_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
- vec2 tex_uv_atlas = tex_uv * light_data[light_base].atlas_rect.zw + light_data[light_base].atlas_rect.xy;
+ vec2 tex_uv = (vec4(vertex, 0.0, 1.0) * mat4(light_array[light_base].texture_matrix[0], light_array[light_base].texture_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
+ vec2 tex_uv_atlas = tex_uv * light_array[light_base].atlas_rect.zw + light_array[light_base].atlas_rect.xy;
vec4 light_color = textureLod(atlas_texture, tex_uv_atlas, 0.0);
- vec4 light_base_color = light_data[light_base].color;
+ vec4 light_base_color = light_array[light_base].color;
#ifdef LIGHT_CODE_USED
vec4 shadow_modulate = vec4(1.0);
- vec3 light_position = vec3(light_data[light_base].position, light_data[light_base].height);
+ vec3 light_position = vec3(light_array[light_base].position, light_array[light_base].height);
light_color.rgb *= light_base_color.rgb;
- light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, false);
+ light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, uv, base_color, false);
#else
light_color.rgb *= light_base_color.rgb * light_base_color.a;
if (normal_used) {
- vec3 light_pos = vec3(light_data[light_base].position, light_data[light_base].height);
+ vec3 light_pos = vec3(light_array[light_base].position, light_array[light_base].height);
vec3 pos = light_vertex;
vec3 light_vec = normalize(light_pos - pos);
- float cNdotL = max(0.0, dot(normal, light_vec));
- light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used);
+ light_color.rgb = light_normal_compute(light_vec, normal, base_color.rgb, light_color.rgb, specular_shininess, specular_shininess_used);
+ } else {
+ light_color.rgb *= base_color.rgb;
}
#endif
if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) {
@@ -654,37 +743,37 @@ void main() {
light_color.a = 0.0;
}
- if (bool(light_data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
- vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_data[light_base].shadow_matrix[0], light_data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
+ if (bool(light_array[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
+ vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array[light_base].shadow_matrix[0], light_array[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
vec2 pos_norm = normalize(shadow_pos);
vec2 pos_abs = abs(pos_norm);
vec2 pos_box = pos_norm / max(pos_abs.x, pos_abs.y);
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;
+ float dist;
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;
+ dist = shadow_pos.x;
} else {
tex_ofs = pos_box.x * -0.125 + (0.25 + 0.125);
- distance = shadow_pos.y;
+ dist = shadow_pos.y;
}
} else {
if (pos_rot.x < 0.0) {
tex_ofs = pos_box.y * -0.125 + (0.5 + 0.125);
- distance = -shadow_pos.x;
+ dist = -shadow_pos.x;
} else {
tex_ofs = pos_box.x * 0.125 + (0.75 + 0.125);
- distance = -shadow_pos.y;
+ dist = -shadow_pos.y;
}
}
- distance *= light_data[light_base].shadow_zfar_inv;
+ dist *= light_array[light_base].shadow_zfar_inv;
//float distance = length(shadow_pos);
- vec4 shadow_uv = vec4(tex_ofs, light_data[light_base].shadow_y_ofs, distance, 1.0);
+ vec4 shadow_uv = vec4(tex_ofs, light_array[light_base].shadow_y_ofs, dist, 1.0);
light_color = light_shadow_compute(light_base, light_color, shadow_uv
#ifdef LIGHT_CODE_USED
@@ -696,7 +785,7 @@ void main() {
light_blend_compute(light_base, light_color, color.rgb);
}
-#endif // UNSHADED
+#endif
frag_color = color;
}
diff --git a/drivers/gles3/shaders/canvas_occlusion.glsl b/drivers/gles3/shaders/canvas_occlusion.glsl
new file mode 100644
index 0000000000..512800839a
--- /dev/null
+++ b/drivers/gles3/shaders/canvas_occlusion.glsl
@@ -0,0 +1,68 @@
+/* clang-format off */
+#[modes]
+
+mode_sdf =
+mode_shadow = #define MODE_SHADOW
+mode_shadow_RGBA = #define MODE_SHADOW \n#define USE_RGBA_SHADOWS
+
+#[specializations]
+
+#[vertex]
+
+layout(location = 0) in vec3 vertex;
+
+uniform highp mat4 projection;
+uniform highp vec4 modelview1;
+uniform highp vec4 modelview2;
+uniform highp vec2 direction;
+uniform highp float z_far;
+
+#ifdef MODE_SHADOW
+out float depth;
+#endif
+
+void main() {
+ highp vec4 vtx = vec4(vertex, 1.0) * mat4(modelview1, modelview2, vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
+
+#ifdef MODE_SHADOW
+ depth = dot(direction, vtx.xy);
+#endif
+ gl_Position = projection * vtx;
+}
+
+#[fragment]
+
+
+uniform highp mat4 projection;
+uniform highp vec4 modelview1;
+uniform highp vec4 modelview2;
+uniform highp vec2 direction;
+uniform highp float z_far;
+
+#ifdef MODE_SHADOW
+in highp float depth;
+#endif
+
+#ifdef USE_RGBA_SHADOWS
+layout(location = 0) out lowp vec4 out_buf;
+#else
+layout(location = 0) out highp float out_buf;
+#endif
+
+void main() {
+ float out_depth = 1.0;
+
+#ifdef MODE_SHADOW
+ out_depth = depth / z_far;
+#endif
+
+#ifdef USE_RGBA_SHADOWS
+ out_depth = clamp(out_depth, -1.0, 1.0);
+ out_depth = out_depth * 0.5 + 0.5;
+ highp vec4 comp = fract(out_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);
+ out_buf = comp;
+#else
+ out_buf = out_depth;
+#endif
+}
diff --git a/drivers/gles3/shaders/canvas_sdf.glsl b/drivers/gles3/shaders/canvas_sdf.glsl
new file mode 100644
index 0000000000..424ec22457
--- /dev/null
+++ b/drivers/gles3/shaders/canvas_sdf.glsl
@@ -0,0 +1,205 @@
+/* clang-format off */
+#[modes]
+
+mode_load = #define MODE_LOAD
+mode_load_shrink = #define MODE_LOAD_SHRINK
+mode_process = #define MODE_PROCESS
+mode_store = #define MODE_STORE
+mode_store_shrink = #define MODE_STORE_SHRINK
+
+#[specializations]
+
+#[vertex]
+
+layout(location = 0) in vec2 vertex_attrib;
+
+/* clang-format on */
+
+uniform ivec2 size;
+uniform int stride;
+uniform int shift;
+uniform ivec2 base_size;
+
+void main() {
+ gl_Position = vec4(vertex_attrib, 1.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#define SDF_MAX_LENGTH 16384.0
+
+#if defined(MODE_LOAD) || defined(MODE_LOAD_SHRINK)
+uniform lowp sampler2D src_pixels;//texunit:0
+#else
+uniform highp isampler2D src_process;//texunit:0
+#endif
+
+uniform ivec2 size;
+uniform int stride;
+uniform int shift;
+uniform ivec2 base_size;
+
+#if defined(MODE_LOAD) || defined(MODE_LOAD_SHRINK) || defined(MODE_PROCESS)
+layout(location = 0) out ivec4 distance_field;
+#else
+layout(location = 0) out vec4 distance_field;
+#endif
+
+vec4 float_to_vec4(float p_float) {
+ highp vec4 comp = fract(p_float * 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);
+ return comp;
+}
+
+void main() {
+ ivec2 pos = ivec2(gl_FragCoord.xy);
+
+#ifdef MODE_LOAD
+
+ bool solid = texelFetch(src_pixels, pos, 0).r > 0.5;
+ distance_field = solid ? ivec4(ivec2(-32767), 0, 0) : ivec4(ivec2(32767), 0, 0);
+#endif
+
+#ifdef MODE_LOAD_SHRINK
+
+ int s = 1 << shift;
+ ivec2 base = pos << shift;
+ ivec2 center = base + ivec2(shift);
+
+ ivec2 rel = ivec2(32767);
+ float d = 1e20;
+ int found = 0;
+ int solid_found = 0;
+ for (int i = 0; i < s; i++) {
+ for (int j = 0; j < s; j++) {
+ ivec2 src_pos = base + ivec2(i, j);
+ if (any(greaterThanEqual(src_pos, base_size))) {
+ continue;
+ }
+ bool solid = texelFetch(src_pixels, src_pos, 0).r > 0.5;
+ if (solid) {
+ float dist = length(vec2(src_pos - center));
+ if (dist < d) {
+ d = dist;
+ rel = src_pos;
+ }
+ solid_found++;
+ }
+ found++;
+ }
+ }
+
+ if (solid_found == found) {
+ //mark solid only if all are solid
+ rel = ivec2(-32767);
+ }
+
+ distance_field = ivec4(rel, 0, 0);
+#endif
+
+#ifdef MODE_PROCESS
+
+ ivec2 base = pos << shift;
+ ivec2 center = base + ivec2(shift);
+
+ ivec2 rel = texelFetch(src_process, pos, 0).xy;
+
+ bool solid = rel.x < 0;
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
+ if (center != rel) {
+ //only process if it does not point to itself
+ const int ofs_table_size = 8;
+ const ivec2 ofs_table[ofs_table_size] = ivec2[](
+ ivec2(-1, -1),
+ ivec2(0, -1),
+ ivec2(+1, -1),
+
+ ivec2(-1, 0),
+ ivec2(+1, 0),
+
+ ivec2(-1, +1),
+ ivec2(0, +1),
+ ivec2(+1, +1));
+
+ float dist = length(vec2(rel - center));
+ for (int i = 0; i < ofs_table_size; i++) {
+ ivec2 src_pos = pos + ofs_table[i] * stride;
+ if (any(lessThan(src_pos, ivec2(0))) || any(greaterThanEqual(src_pos, size))) {
+ continue;
+ }
+ ivec2 src_rel = texelFetch(src_process, src_pos, 0).xy;
+ bool src_solid = src_rel.x < 0;
+ if (src_solid) {
+ src_rel = -src_rel - ivec2(1);
+ }
+
+ if (src_solid != solid) {
+ src_rel = ivec2(src_pos << shift); //point to itself if of different type
+ }
+
+ float src_dist = length(vec2(src_rel - center));
+ if (src_dist < dist) {
+ dist = src_dist;
+ rel = src_rel;
+ }
+ }
+ }
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
+ distance_field = ivec4(rel, 0, 0);
+#endif
+
+#ifdef MODE_STORE
+
+ ivec2 rel = texelFetch(src_process, pos, 0).xy;
+
+ bool solid = rel.x < 0;
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
+ float d = length(vec2(rel - pos));
+
+ if (solid) {
+ d = -d;
+ }
+
+ d /= SDF_MAX_LENGTH;
+ d = clamp(d, -1.0, 1.0);
+ distance_field = float_to_vec4(d*0.5+0.5);
+
+#endif
+
+#ifdef MODE_STORE_SHRINK
+
+ ivec2 base = pos << shift;
+ ivec2 center = base + ivec2(shift);
+
+ ivec2 rel = texelFetch(src_process, pos, 0).xy;
+
+ bool solid = rel.x < 0;
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
+ float d = length(vec2(rel - center));
+
+ if (solid) {
+ d = -d;
+ }
+ d /= SDF_MAX_LENGTH;
+ d = clamp(d, -1.0, 1.0);
+ distance_field = float_to_vec4(d*0.5+0.5);
+
+#endif
+}
diff --git a/drivers/gles3/shaders/canvas_shadow.glsl b/drivers/gles3/shaders/canvas_shadow.glsl
deleted file mode 100644
index 94485abd11..0000000000
--- a/drivers/gles3/shaders/canvas_shadow.glsl
+++ /dev/null
@@ -1,60 +0,0 @@
-/* clang-format off */
-[vertex]
-
-#ifdef USE_GLES_OVER_GL
-#define lowp
-#define mediump
-#define highp
-#else
-precision highp float;
-precision highp int;
-#endif
-
-layout(location = 0) in highp vec3 vertex;
-
-uniform highp mat4 projection_matrix;
-/* clang-format on */
-uniform highp mat4 light_matrix;
-uniform highp mat4 model_matrix;
-uniform highp float distance_norm;
-
-out highp vec4 position_interp;
-
-void main() {
- gl_Position = projection_matrix * (light_matrix * (model_matrix * vec4(vertex, 1.0)));
- position_interp = gl_Position;
-}
-
-/* clang-format off */
-[fragment]
-
-#ifdef USE_GLES_OVER_GL
-#define lowp
-#define mediump
-#define highp
-#else
-#if defined(USE_HIGHP_PRECISION)
-precision highp float;
-precision highp int;
-#else
-precision mediump float;
-precision mediump int;
-#endif
-#endif
-
-in highp vec4 position_interp;
-/* clang-format on */
-
-void main() {
- highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias
-
-#ifdef USE_RGBA_SHADOWS
-
- highp vec4 comp = fract(depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0));
- comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);
- frag_color = comp;
-#else
-
- frag_color = vec4(depth);
-#endif
-}
diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
index 6b61fe9375..d53c0fcb26 100644
--- a/drivers/gles3/shaders/canvas_uniforms_inc.glsl
+++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
@@ -27,37 +27,8 @@
#define FLAGS_USE_MSDF uint(1 << 28)
#define FLAGS_USE_LCD uint(1 << 29)
-// must be always 128 bytes long
-struct DrawData {
- vec2 world_x;
- vec2 world_y;
- vec2 world_ofs;
- vec2 color_texture_pixel_size;
-#ifdef USE_PRIMITIVE
- vec2 point_a;
- vec2 point_b;
- vec2 point_c;
- vec2 uv_a;
- vec2 uv_b;
- vec2 uv_c;
- uint color_a_rg;
- uint color_a_ba;
- uint color_b_rg;
- uint color_b_ba;
- uint color_c_rg;
- uint color_c_ba;
-#else
- vec4 modulation;
- vec4 ninepatch_margins;
- vec4 dst_rect; //for built-in rect and UV
- vec4 src_rect;
- uint pad;
- uint pad2;
-#endif
- uint flags;
- uint specular_shininess;
- uvec4 lights;
-};
+#define FLAGS_FLIP_H uint(1 << 30)
+#define FLAGS_FLIP_V uint(1 << 31)
layout(std140) uniform GlobalShaderUniformData { //ubo:1
vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
@@ -82,6 +53,7 @@ layout(std140) uniform CanvasData { //ubo:0
uint pad2;
};
+#ifndef DISABLE_LIGHTING
#define LIGHT_FLAGS_BLEND_MASK uint(3 << 16)
#define LIGHT_FLAGS_BLEND_MODE_ADD uint(0 << 16)
#define LIGHT_FLAGS_BLEND_MODE_SUB uint(1 << 16)
@@ -112,10 +84,6 @@ struct Light {
};
layout(std140) uniform LightData { //ubo:2
- Light light_data[MAX_LIGHTS];
-};
-
-layout(std140) uniform DrawDataInstances { //ubo:3
-
- DrawData draw_data[MAX_DRAW_DATA_INSTANCES];
+ Light light_array[MAX_LIGHTS];
};
+#endif // DISABLE_LIGHTING
diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl
index ca2fc7e36d..796ba79c2e 100644
--- a/drivers/gles3/shaders/copy.glsl
+++ b/drivers/gles3/shaders/copy.glsl
@@ -2,7 +2,7 @@
#[modes]
mode_default = #define MODE_SIMPLE_COPY
-mode_copy_section = #define USE_COPY_SECTION
+mode_copy_section = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY
mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR
mode_mipmap = #define MODE_MIPMAP
mode_simple_color = #define MODE_SIMPLE_COLOR \n#define USE_COPY_SECTION
@@ -25,8 +25,7 @@ void main() {
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 + uv_interp.xy * copy_section.zw) * 2.0 - 1.0;
#endif
}
diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl
index 88464876f1..6fcb23204d 100644
--- a/drivers/gles3/shaders/cubemap_filter.glsl
+++ b/drivers/gles3/shaders/cubemap_filter.glsl
@@ -31,7 +31,7 @@ uniform samplerCube source_cube; //texunit:0
uniform int face_id;
#ifndef MODE_DIRECT_WRITE
-uniform int sample_count;
+uniform uint sample_count;
uniform vec4 sample_directions_mip[MAX_SAMPLE_COUNT];
uniform float weight;
#endif
@@ -105,7 +105,7 @@ void main() {
T[1] = cross(N, T[0]);
T[2] = N;
- for (int sample_num = 0; sample_num < sample_count; sample_num++) {
+ for (uint sample_num = 0u; 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;
diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl
new file mode 100644
index 0000000000..f8741a22ab
--- /dev/null
+++ b/drivers/gles3/shaders/particles.glsl
@@ -0,0 +1,501 @@
+/* clang-format off */
+#[modes]
+
+mode_default =
+
+#[specializations]
+
+MODE_3D = false
+USERDATA1_USED = false
+USERDATA2_USED = false
+USERDATA3_USED = false
+USERDATA4_USED = false
+USERDATA5_USED = false
+USERDATA6_USED = false
+
+#[vertex]
+
+#define SDF_MAX_LENGTH 16384.0
+
+layout(std140) uniform GlobalShaderUniformData { //ubo:1
+ vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
+};
+
+// 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:2
+
+#MATERIAL_UNIFORMS
+
+};
+#endif
+
+/* clang-format on */
+
+#define MAX_ATTRACTORS 32
+
+#define ATTRACTOR_TYPE_SPHERE uint(0)
+#define ATTRACTOR_TYPE_BOX uint(1)
+#define ATTRACTOR_TYPE_VECTOR_FIELD uint(2)
+
+struct Attractor {
+ mat4 transform;
+ vec4 extents; // Extents or radius. w-channel is padding.
+
+ uint type;
+ float strength;
+ float attenuation;
+ float directionality;
+};
+
+#define MAX_COLLIDERS 32
+
+#define COLLIDER_TYPE_SPHERE uint(0)
+#define COLLIDER_TYPE_BOX uint(1)
+#define COLLIDER_TYPE_SDF uint(2)
+#define COLLIDER_TYPE_HEIGHT_FIELD uint(3)
+#define COLLIDER_TYPE_2D_SDF uint(4)
+
+struct Collider {
+ mat4 transform;
+ vec4 extents; // Extents or radius. w-channel is padding.
+
+ uint type;
+ float scale;
+ float pad0;
+ float pad1;
+};
+
+layout(std140) uniform FrameData { //ubo:0
+ bool emitting;
+ uint cycle;
+ float system_phase;
+ float prev_system_phase;
+
+ float explosiveness;
+ float randomness;
+ float time;
+ float delta;
+
+ float particle_size;
+ float pad0;
+ float pad1;
+ float pad2;
+
+ uint random_seed;
+ uint attractor_count;
+ uint collider_count;
+ uint frame;
+
+ mat4 emission_transform;
+
+ Attractor attractors[MAX_ATTRACTORS];
+ Collider colliders[MAX_COLLIDERS];
+};
+
+#define PARTICLE_FLAG_ACTIVE uint(1)
+#define PARTICLE_FLAG_STARTED uint(2)
+#define PARTICLE_FLAG_TRAILED uint(4)
+#define PARTICLE_FRAME_MASK uint(0xFFFF)
+#define PARTICLE_FRAME_SHIFT uint(16)
+
+// ParticleData
+layout(location = 0) in highp vec4 color;
+layout(location = 1) in highp vec4 velocity_flags;
+layout(location = 2) in highp vec4 custom;
+layout(location = 3) in highp vec4 xform_1;
+layout(location = 4) in highp vec4 xform_2;
+#ifdef MODE_3D
+layout(location = 5) in highp vec4 xform_3;
+#endif
+#ifdef USERDATA1_USED
+layout(location = 6) in highp vec4 userdata1;
+#endif
+#ifdef USERDATA2_USED
+layout(location = 7) in highp vec4 userdata2;
+#endif
+#ifdef USERDATA3_USED
+layout(location = 8) in highp vec4 userdata3;
+#endif
+#ifdef USERDATA4_USED
+layout(location = 9) in highp vec4 userdata4;
+#endif
+#ifdef USERDATA5_USED
+layout(location = 10) in highp vec4 userdata5;
+#endif
+#ifdef USERDATA6_USED
+layout(location = 11) in highp vec4 userdata6;
+#endif
+
+out highp vec4 out_color; //tfb:
+out highp vec4 out_velocity_flags; //tfb:
+out highp vec4 out_custom; //tfb:
+out highp vec4 out_xform_1; //tfb:
+out highp vec4 out_xform_2; //tfb:
+#ifdef MODE_3D
+out highp vec4 out_xform_3; //tfb:MODE_3D
+#endif
+#ifdef USERDATA1_USED
+out highp vec4 out_userdata1; //tfb:USERDATA1_USED
+#endif
+#ifdef USERDATA2_USED
+out highp vec4 out_userdata2; //tfb:USERDATA2_USED
+#endif
+#ifdef USERDATA3_USED
+out highp vec4 out_userdata3; //tfb:USERDATA3_USED
+#endif
+#ifdef USERDATA4_USED
+out highp vec4 out_userdata4; //tfb:USERDATA4_USED
+#endif
+#ifdef USERDATA5_USED
+out highp vec4 out_userdata5; //tfb:USERDATA5_USED
+#endif
+#ifdef USERDATA6_USED
+out highp vec4 out_userdata6; //tfb:USERDATA6_USED
+#endif
+
+uniform sampler2D height_field_texture; //texunit:0
+
+uniform float lifetime;
+uniform bool clear;
+uniform uint total_particles;
+uniform bool use_fractional_delta;
+
+uint hash(uint x) {
+ x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
+ x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
+ x = (x >> uint(16)) ^ x;
+ return x;
+}
+
+vec3 safe_normalize(vec3 direction) {
+ const float EPSILON = 0.001;
+ if (length(direction) < EPSILON) {
+ return vec3(0.0);
+ }
+ return normalize(direction);
+}
+
+// Needed whenever 2D sdf texture is read from as it is packed in RGBA8.
+float vec4_to_float(vec4 p_vec) {
+ return dot(p_vec, vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) * 2.0 - 1.0;
+}
+
+#GLOBALS
+
+void main() {
+ bool apply_forces = true;
+ bool apply_velocity = true;
+ float local_delta = delta;
+
+ float mass = 1.0;
+
+ bool restart = false;
+
+ bool restart_position = false;
+ bool restart_rotation_scale = false;
+ bool restart_velocity = false;
+ bool restart_color = false;
+ bool restart_custom = false;
+
+ mat4 xform = mat4(1.0);
+ uint flags = 0u;
+
+ if (clear) {
+ out_color = vec4(1.0);
+ out_custom = vec4(0.0);
+ out_velocity_flags = vec4(0.0);
+ } else {
+ out_color = color;
+ out_velocity_flags = velocity_flags;
+ out_custom = custom;
+ xform[0] = xform_1;
+ xform[1] = xform_2;
+#ifdef MODE_3D
+ xform[2] = xform_3;
+#endif
+ xform = transpose(xform);
+ flags = floatBitsToUint(velocity_flags.w);
+ }
+
+ //clear started flag if set
+ flags &= ~PARTICLE_FLAG_STARTED;
+
+ bool collided = false;
+ vec3 collision_normal = vec3(0.0);
+ float collision_depth = 0.0;
+
+ vec3 attractor_force = vec3(0.0);
+
+#if !defined(DISABLE_VELOCITY)
+
+ if (bool(flags & PARTICLE_FLAG_ACTIVE)) {
+ xform[3].xyz += out_velocity_flags.xyz * local_delta;
+ }
+#endif
+ uint index = uint(gl_VertexID);
+ if (emitting) {
+ float restart_phase = float(index) / float(total_particles);
+
+ if (randomness > 0.0) {
+ uint seed = cycle;
+ if (restart_phase >= system_phase) {
+ seed -= uint(1);
+ }
+ seed *= uint(total_particles);
+ seed += index;
+ float random = float(hash(seed) % uint(65536)) / 65536.0;
+ restart_phase += randomness * random * 1.0 / float(total_particles);
+ }
+
+ restart_phase *= (1.0 - explosiveness);
+
+ if (system_phase > prev_system_phase) {
+ // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed
+
+ if (restart_phase >= prev_system_phase && restart_phase < system_phase) {
+ restart = true;
+ if (use_fractional_delta) {
+ local_delta = (system_phase - restart_phase) * lifetime;
+ }
+ }
+
+ } else if (delta > 0.0) {
+ if (restart_phase >= prev_system_phase) {
+ restart = true;
+ if (use_fractional_delta) {
+ local_delta = (1.0 - restart_phase + system_phase) * lifetime;
+ }
+
+ } else if (restart_phase < system_phase) {
+ restart = true;
+ if (use_fractional_delta) {
+ local_delta = (system_phase - restart_phase) * lifetime;
+ }
+ }
+ }
+
+ if (restart) {
+ flags = emitting ? (PARTICLE_FLAG_ACTIVE | PARTICLE_FLAG_STARTED | (cycle << PARTICLE_FRAME_SHIFT)) : 0u;
+ restart_position = true;
+ restart_rotation_scale = true;
+ restart_velocity = true;
+ restart_color = true;
+ restart_custom = true;
+ }
+ }
+
+ bool particle_active = bool(flags & PARTICLE_FLAG_ACTIVE);
+
+ uint particle_number = (flags >> PARTICLE_FRAME_SHIFT) * uint(total_particles) + index;
+
+ if (restart && particle_active) {
+#CODE : START
+ }
+
+ if (particle_active) {
+ for (uint i = 0u; i < attractor_count; i++) {
+ vec3 dir;
+ float amount;
+ vec3 rel_vec = xform[3].xyz - attractors[i].transform[3].xyz;
+ vec3 local_pos = rel_vec * mat3(attractors[i].transform);
+
+ switch (attractors[i].type) {
+ case ATTRACTOR_TYPE_SPHERE: {
+ dir = safe_normalize(rel_vec);
+ float d = length(local_pos) / attractors[i].extents.x;
+ if (d > 1.0) {
+ continue;
+ }
+ amount = max(0.0, 1.0 - d);
+ } break;
+ case ATTRACTOR_TYPE_BOX: {
+ dir = safe_normalize(rel_vec);
+
+ vec3 abs_pos = abs(local_pos / attractors[i].extents.xyz);
+ float d = max(abs_pos.x, max(abs_pos.y, abs_pos.z));
+ if (d > 1.0) {
+ continue;
+ }
+ amount = max(0.0, 1.0 - d);
+
+ } break;
+ case ATTRACTOR_TYPE_VECTOR_FIELD: {
+ } break;
+ }
+ amount = pow(amount, attractors[i].attenuation);
+ dir = safe_normalize(mix(dir, attractors[i].transform[2].xyz, attractors[i].directionality));
+ attractor_force -= amount * dir * attractors[i].strength;
+ }
+
+ float particle_size = particle_size;
+
+#ifdef USE_COLLISION_SCALE
+
+ particle_size *= dot(vec3(length(xform[0].xyz), length(xform[1].xyz), length(xform[2].xyz)), vec3(0.33333333333));
+
+#endif
+
+ if (collider_count == 1u && colliders[0].type == COLLIDER_TYPE_2D_SDF) {
+ //2D collision
+
+ vec2 pos = xform[3].xy;
+ vec4 to_sdf_x = colliders[0].transform[0];
+ vec4 to_sdf_y = colliders[0].transform[1];
+ vec2 sdf_pos = vec2(dot(vec4(pos, 0, 1), to_sdf_x), dot(vec4(pos, 0, 1), to_sdf_y));
+
+ vec4 sdf_to_screen = vec4(colliders[0].extents.xyz, colliders[0].scale);
+
+ vec2 uv_pos = sdf_pos * sdf_to_screen.xy + sdf_to_screen.zw;
+
+ if (all(greaterThan(uv_pos, vec2(0.0))) && all(lessThan(uv_pos, vec2(1.0)))) {
+ vec2 pos2 = pos + vec2(0, particle_size);
+ vec2 sdf_pos2 = vec2(dot(vec4(pos2, 0, 1), to_sdf_x), dot(vec4(pos2, 0, 1), to_sdf_y));
+ float sdf_particle_size = distance(sdf_pos, sdf_pos2);
+
+ float d = vec4_to_float(texture(height_field_texture, uv_pos)) * SDF_MAX_LENGTH;
+
+ d -= sdf_particle_size;
+
+ if (d < 0.0) {
+ const float EPSILON = 0.001;
+ vec2 n = normalize(vec2(
+ vec4_to_float(texture(height_field_texture, uv_pos + vec2(EPSILON, 0.0))) - vec4_to_float(texture(height_field_texture, uv_pos - vec2(EPSILON, 0.0))),
+ vec4_to_float(texture(height_field_texture, uv_pos + vec2(0.0, EPSILON))) - vec4_to_float(texture(height_field_texture, uv_pos - vec2(0.0, EPSILON)))));
+
+ collided = true;
+ sdf_pos2 = sdf_pos + n * d;
+ pos2 = vec2(dot(vec4(sdf_pos2, 0, 1), colliders[0].transform[2]), dot(vec4(sdf_pos2, 0, 1), colliders[0].transform[3]));
+
+ n = pos - pos2;
+
+ collision_normal = normalize(vec3(n, 0.0));
+ collision_depth = length(n);
+ }
+ }
+
+ } else {
+ for (uint i = 0u; i < collider_count; i++) {
+ vec3 normal;
+ float depth;
+ bool col = false;
+
+ vec3 rel_vec = xform[3].xyz - colliders[i].transform[3].xyz;
+ vec3 local_pos = rel_vec * mat3(colliders[i].transform);
+
+ switch (colliders[i].type) {
+ case COLLIDER_TYPE_SPHERE: {
+ float d = length(rel_vec) - (particle_size + colliders[i].extents.x);
+
+ if (d < 0.0) {
+ col = true;
+ depth = -d;
+ normal = normalize(rel_vec);
+ }
+
+ } break;
+ case COLLIDER_TYPE_BOX: {
+ vec3 abs_pos = abs(local_pos);
+ vec3 sgn_pos = sign(local_pos);
+
+ if (any(greaterThan(abs_pos, colliders[i].extents.xyz))) {
+ //point outside box
+
+ vec3 closest = min(abs_pos, colliders[i].extents.xyz);
+ vec3 rel = abs_pos - closest;
+ depth = length(rel) - particle_size;
+ if (depth < 0.0) {
+ col = true;
+ normal = mat3(colliders[i].transform) * (normalize(rel) * sgn_pos);
+ depth = -depth;
+ }
+ } else {
+ //point inside box
+ vec3 axis_len = colliders[i].extents.xyz - abs_pos;
+ // there has to be a faster way to do this?
+ if (all(lessThan(axis_len.xx, axis_len.yz))) {
+ normal = vec3(1, 0, 0);
+ } else if (all(lessThan(axis_len.yy, axis_len.xz))) {
+ normal = vec3(0, 1, 0);
+ } else {
+ normal = vec3(0, 0, 1);
+ }
+
+ col = true;
+ depth = dot(normal * axis_len, vec3(1)) + particle_size;
+ normal = mat3(colliders[i].transform) * (normal * sgn_pos);
+ }
+
+ } break;
+ case COLLIDER_TYPE_SDF: {
+ } break;
+ case COLLIDER_TYPE_HEIGHT_FIELD: {
+ vec3 local_pos_bottom = local_pos;
+ local_pos_bottom.y -= particle_size;
+
+ if (any(greaterThan(abs(local_pos_bottom), colliders[i].extents.xyz))) {
+ continue;
+ }
+ const float DELTA = 1.0 / 8192.0;
+
+ vec3 uvw_pos = vec3(local_pos_bottom / colliders[i].extents.xyz) * 0.5 + 0.5;
+
+ float y = 1.0 - texture(height_field_texture, uvw_pos.xz).r;
+
+ if (y > uvw_pos.y) {
+ //inside heightfield
+
+ vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz;
+ vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(height_field_texture, uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * colliders[i].extents.xyz;
+ vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(height_field_texture, uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * colliders[i].extents.xyz;
+
+ normal = normalize(cross(pos1 - pos2, pos1 - pos3));
+ float local_y = (vec3(local_pos / colliders[i].extents.xyz) * 0.5 + 0.5).y;
+
+ col = true;
+ depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
+ }
+
+ } break;
+ }
+
+ if (col) {
+ if (!collided) {
+ collided = true;
+ collision_normal = normal;
+ collision_depth = depth;
+ } else {
+ vec3 c = collision_normal * collision_depth;
+ c += normal * max(0.0, depth - dot(normal, c));
+ collision_normal = normalize(c);
+ collision_depth = length(c);
+ }
+ }
+ }
+ }
+ }
+
+ if (particle_active) {
+#CODE : PROCESS
+ }
+
+ flags &= ~PARTICLE_FLAG_ACTIVE;
+ if (particle_active) {
+ flags |= PARTICLE_FLAG_ACTIVE;
+ }
+
+ xform = transpose(xform);
+ out_xform_1 = xform[0];
+ out_xform_2 = xform[1];
+#ifdef MODE_3D
+ out_xform_3 = xform[2];
+#endif
+ out_velocity_flags.w = uintBitsToFloat(flags);
+}
+
+/* clang-format off */
+#[fragment]
+
+void main() {
+}
+/* clang-format on */
diff --git a/drivers/gles3/shaders/particles_copy.glsl b/drivers/gles3/shaders/particles_copy.glsl
new file mode 100644
index 0000000000..f273cb7b64
--- /dev/null
+++ b/drivers/gles3/shaders/particles_copy.glsl
@@ -0,0 +1,122 @@
+/* clang-format off */
+#[modes]
+
+mode_default =
+
+#[specializations]
+
+MODE_3D = false
+
+#[vertex]
+
+#include "stdlib_inc.glsl"
+
+// ParticleData
+layout(location = 0) in highp vec4 color;
+layout(location = 1) in highp vec4 velocity_flags;
+layout(location = 2) in highp vec4 custom;
+layout(location = 3) in highp vec4 xform_1;
+layout(location = 4) in highp vec4 xform_2;
+#ifdef MODE_3D
+layout(location = 5) in highp vec4 xform_3;
+#endif
+
+/* clang-format on */
+out highp vec4 out_xform_1; //tfb:
+out highp vec4 out_xform_2; //tfb:
+#ifdef MODE_3D
+out highp vec4 out_xform_3; //tfb:MODE_3D
+#endif
+flat out highp uvec4 instance_color_custom_data; //tfb:
+
+uniform lowp vec3 sort_direction;
+uniform highp float frame_remainder;
+
+uniform highp vec3 align_up;
+uniform highp uint align_mode;
+
+uniform highp mat4 inv_emission_transform;
+
+#define TRANSFORM_ALIGN_DISABLED uint(0)
+#define TRANSFORM_ALIGN_Z_BILLBOARD uint(1)
+#define TRANSFORM_ALIGN_Y_TO_VELOCITY uint(2)
+#define TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY uint(3)
+
+#define PARTICLE_FLAG_ACTIVE uint(1)
+
+void main() {
+ mat4 txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); // zero scale, becomes invisible.
+ if (bool(floatBitsToUint(velocity_flags.w) & PARTICLE_FLAG_ACTIVE)) {
+#ifdef MODE_3D
+ txform = transpose(mat4(xform_1, xform_2, xform_3, vec4(0.0, 0.0, 0.0, 1.0)));
+#else
+ txform = transpose(mat4(xform_1, xform_2, vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)));
+#endif
+
+ switch (align_mode) {
+ case TRANSFORM_ALIGN_DISABLED: {
+ } break; //nothing
+ case TRANSFORM_ALIGN_Z_BILLBOARD: {
+ mat3 local = mat3(normalize(cross(align_up, sort_direction)), align_up, sort_direction);
+ local = local * mat3(txform);
+ txform[0].xyz = local[0];
+ txform[1].xyz = local[1];
+ txform[2].xyz = local[2];
+
+ } break;
+ case TRANSFORM_ALIGN_Y_TO_VELOCITY: {
+ vec3 v = velocity_flags.xyz;
+ float s = (length(txform[0]) + length(txform[1]) + length(txform[2])) / 3.0;
+ if (length(v) > 0.0) {
+ txform[1].xyz = normalize(v);
+ } else {
+ txform[1].xyz = normalize(txform[1].xyz);
+ }
+
+ txform[0].xyz = normalize(cross(txform[1].xyz, txform[2].xyz));
+ txform[2].xyz = vec3(0.0, 0.0, 1.0) * s;
+ txform[0].xyz *= s;
+ txform[1].xyz *= s;
+ } break;
+ case TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY: {
+ vec3 sv = velocity_flags.xyz - sort_direction * dot(sort_direction, velocity_flags.xyz); //screen velocity
+ float s = (length(txform[0]) + length(txform[1]) + length(txform[2])) / 3.0;
+
+ if (length(sv) == 0.0) {
+ sv = align_up;
+ }
+
+ sv = normalize(sv);
+
+ txform[0].xyz = normalize(cross(sv, sort_direction)) * s;
+ txform[1].xyz = sv * s;
+ txform[2].xyz = sort_direction * s;
+
+ } break;
+ }
+
+ txform[3].xyz += velocity_flags.xyz * frame_remainder;
+
+#ifndef MODE_3D
+ // In global mode, bring 2D particles to local coordinates
+ // as they will be drawn with the node position as origin.
+ txform = inv_emission_transform * txform;
+#endif
+
+ txform = transpose(txform);
+ }
+
+ instance_color_custom_data = uvec4(packHalf2x16(color.xy), packHalf2x16(color.zw), packHalf2x16(custom.xy), packHalf2x16(custom.zw));
+ out_xform_1 = txform[0];
+ out_xform_2 = txform[1];
+#ifdef MODE_3D
+ out_xform_3 = txform[2];
+#endif
+}
+
+/* clang-format off */
+#[fragment]
+
+void main() {
+}
+/* clang-format on */
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index c7fdd6ebd8..52ff70f746 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -16,6 +16,7 @@ DISABLE_LIGHT_OMNI = false
DISABLE_LIGHT_SPOT = false
DISABLE_FOG = false
USE_RADIANCE_MAP = true
+USE_MULTIVIEW = false
#[vertex]
@@ -101,7 +102,7 @@ vec3 oct_to_vec3(vec2 e) {
vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
float t = max(-v.z, 0.0);
v.xy += t * -sign(v.xy);
- return v;
+ return normalize(v);
}
#ifdef USE_INSTANCING
@@ -128,7 +129,7 @@ layout(std140) uniform SceneData { // ubo:2
mediump float ambient_color_sky_mix;
bool material_uv2_mode;
- float pad2;
+ float emissive_exposure_normalization;
bool use_ambient_light;
bool use_ambient_cubemap;
bool use_reflection_cubemap;
@@ -141,7 +142,7 @@ layout(std140) uniform SceneData { // ubo:2
uint directional_light_count;
float z_far;
float z_near;
- float pad;
+ float IBL_exposure_normalization;
bool fog_enabled;
float fog_density;
@@ -150,9 +151,22 @@ layout(std140) uniform SceneData { // ubo:2
vec3 fog_light_color;
float fog_sun_scatter;
+ uint camera_visible_layers;
+ uint pad3;
+ uint pad4;
+ uint pad5;
}
scene_data;
+#ifdef USE_MULTIVIEW
+layout(std140) uniform MultiviewData { // ubo:8
+ highp mat4 projection_matrix_view[MAX_VIEWS];
+ highp mat4 inv_projection_matrix_view[MAX_VIEWS];
+ highp vec4 eye_offset[MAX_VIEWS];
+}
+multiview_data;
+#endif
+
uniform highp mat4 world_transform;
#ifdef USE_LIGHTMAP
@@ -187,7 +201,7 @@ out vec3 tangent_interp;
out vec3 binormal_interp;
#endif
-#if defined(MATERIAL_UNIFORMS_USED)
+#ifdef MATERIAL_UNIFORMS_USED
/* clang-format off */
layout(std140) uniform MaterialUniforms { // ubo:3
@@ -250,8 +264,14 @@ void main() {
#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;
+
+#ifdef USE_MULTIVIEW
+ mat4 projection_matrix = multiview_data.projection_matrix_view[ViewIndex];
+ mat4 inv_projection_matrix = multiview_data.inv_projection_matrix_view[ViewIndex];
+#else
+ mat4 projection_matrix = scene_data.projection_matrix;
+ mat4 inv_projection_matrix = scene_data.inv_projection_matrix;
+#endif //USE_MULTIVIEW
#ifdef USE_INSTANCING
vec4 instance_custom = vec4(unpackHalf2x16(instance_color_custom_data.z), unpackHalf2x16(instance_color_custom_data.w));
@@ -339,7 +359,6 @@ void main() {
/* clang-format off */
#[fragment]
-
// Default to SPECULAR_SCHLICK_GGX.
#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_TOON)
#define SPECULAR_SCHLICK_GGX
@@ -351,7 +370,9 @@ void main() {
#endif
#endif
+#ifndef MODE_RENDER_DEPTH
#include "tonemap_inc.glsl"
+#endif
#include "stdlib_inc.glsl"
/* texture unit usage, N is max_texture_unity-N
@@ -413,7 +434,7 @@ layout(std140) uniform GlobalShaderUniformData { //ubo:1
/* Material Uniforms */
-#if defined(MATERIAL_UNIFORMS_USED)
+#ifdef MATERIAL_UNIFORMS_USED
/* clang-format off */
layout(std140) uniform MaterialUniforms { // ubo:3
@@ -438,7 +459,7 @@ layout(std140) uniform SceneData { // ubo:2
mediump float ambient_color_sky_mix;
bool material_uv2_mode;
- float pad2;
+ float emissive_exposure_normalization;
bool use_ambient_light;
bool use_ambient_cubemap;
bool use_reflection_cubemap;
@@ -451,7 +472,7 @@ layout(std140) uniform SceneData { // ubo:2
uint directional_light_count;
float z_far;
float z_near;
- float pad;
+ float IBL_exposure_normalization;
bool fog_enabled;
float fog_density;
@@ -460,17 +481,29 @@ layout(std140) uniform SceneData { // ubo:2
vec3 fog_light_color;
float fog_sun_scatter;
+ uint camera_visible_layers;
+ uint pad3;
+ uint pad4;
+ uint pad5;
}
scene_data;
+#ifdef USE_MULTIVIEW
+layout(std140) uniform MultiviewData { // ubo:8
+ highp mat4 projection_matrix_view[MAX_VIEWS];
+ highp mat4 inv_projection_matrix_view[MAX_VIEWS];
+ highp vec4 eye_offset[MAX_VIEWS];
+}
+multiview_data;
+#endif
+
/* clang-format off */
#GLOBALS
/* clang-format on */
-//directional light data
-
+// Directional light data.
#ifndef DISABLE_LIGHT_DIRECTIONAL
struct DirectionalLightData {
@@ -486,11 +519,12 @@ layout(std140) uniform DirectionalLights { // ubo:7
DirectionalLightData directional_lights[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
};
-#endif
+#endif // !DISABLE_LIGHT_DIRECTIONAL
+
+// Omni and spot light data.
+#if !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
-// omni and spot
-#if !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT)
-struct LightData { //this structure needs to be as packed as possible
+struct LightData { // This structure needs to be as packed as possible.
highp vec3 position;
highp float inv_radius;
@@ -505,33 +539,36 @@ struct LightData { //this structure needs to be as packed as possible
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;
+uniform uint omni_light_count;
#endif
#ifndef DISABLE_LIGHT_SPOT
-
layout(std140) uniform SpotLightData { // ubo:6
-
LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
};
uniform uint spot_light_indices[MAX_FORWARD_LIGHTS];
-uniform int spot_light_count;
+uniform uint spot_light_count;
#endif
#ifdef USE_ADDITIVE_LIGHTING
uniform highp samplerCubeShadow positional_shadow; // texunit:-4
#endif
-#endif // !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT)
+#endif // !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
-uniform highp sampler2D screen_texture; // texunit:-5
+#ifdef USE_MULTIVIEW
+uniform highp sampler2DArray depth_buffer; // texunit:-6
+uniform highp sampler2DArray color_buffer; // texunit:-5
+#else
uniform highp sampler2D depth_buffer; // texunit:-6
+uniform highp sampler2D color_buffer; // texunit:-5
+#endif
uniform highp mat4 world_transform;
uniform mediump float opaque_prepass_threshold;
@@ -546,6 +583,7 @@ vec3 F0(float metallic, float specular, vec3 albedo) {
}
#if !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
+
float D_GGX(float cos_theta_m, float alpha) {
float a = cos_theta_m * alpha;
float k = alpha / (1.0 - cos_theta_m * cos_theta_m + a * a);
@@ -602,7 +640,6 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
/* clang-format off */
-
#CODE : LIGHT
/* clang-format on */
@@ -629,14 +666,12 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance
#if defined(DIFFUSE_LAMBERT_WRAP)
- // energy conserving lambert wrap shader
- diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness)));
+ // Energy conserving lambert wrap shader.
+ // https://web.archive.org/web/20210228210901/http://blog.stevemcauley.com/2011/12/03/energy-conserving-wrapped-diffuse/
+ diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))) * (1.0 / M_PI);
#elif defined(DIFFUSE_TOON)
-
- diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL);
-
+ diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL) * (1.0 / M_PI);
#elif defined(DIFFUSE_BURLEY)
-
{
float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5;
float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV);
@@ -644,7 +679,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL;
}
#else
- // lambert
+ // Lambert
diffuse_brdf_NL = cNdotL * (1.0 / M_PI);
#endif
@@ -655,7 +690,8 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
#endif
#if defined(LIGHT_RIM_USED)
- float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0));
+ // Epsilon min to prevent pow(0, 0) singularity which results in undefined behavior.
+ float rim_light = pow(max(1e-4, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0));
diffuse_light += rim_light * rim * mix(vec3(1.0), albedo, rim_tint) * light_color;
#endif
}
@@ -680,7 +716,6 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
// shlick+ggx as default
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;
@@ -688,7 +723,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
float YdotH = dot(B, H);
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 // LIGHT_ANISOTROPY_USED
+#else
float D = D_GGX(cNdotH, alpha_ggx);
float G = V_GGX(cNdotL, cNdotV, alpha_ggx);
#endif // LIGHT_ANISOTROPY_USED
@@ -728,10 +763,10 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 1.0));
#endif
-#endif //defined(LIGHT_CODE_USED)
+#endif // LIGHT_CODE_USED
}
-float get_omni_attenuation(float distance, float inv_range, float decay) {
+float get_omni_spot_attenuation(float distance, float inv_range, float decay) {
float nd = distance * inv_range;
nd *= nd;
nd *= nd; // nd^4
@@ -740,6 +775,7 @@ float get_omni_attenuation(float distance, float inv_range, float decay) {
return nd * pow(max(distance, 0.0001), -decay);
}
+#ifndef DISABLE_LIGHT_OMNI
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,
@@ -756,7 +792,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
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);
+ float omni_attenuation = get_omni_spot_attenuation(light_length, omni_lights[idx].inv_radius, omni_lights[idx].attenuation);
vec3 color = omni_lights[idx].color;
float size_A = 0.0;
@@ -781,7 +817,9 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
diffuse_light,
specular_light);
}
+#endif // !DISABLE_LIGHT_OMNI
+#ifndef DISABLE_LIGHT_SPOT
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,
@@ -800,7 +838,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
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);
+ float spot_attenuation = get_omni_spot_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));
@@ -829,7 +867,9 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
#endif
diffuse_light, specular_light);
}
-#endif // !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT)
+#endif // !DISABLE_LIGHT_SPOT
+
+#endif // !defined(DISABLE_LIGHT_DIRECTIONAL) || !defined(DISABLE_LIGHT_OMNI) || !defined(DISABLE_LIGHT_SPOT)
#ifndef MODE_RENDER_DEPTH
vec4 fog_process(vec3 vertex) {
@@ -883,7 +923,12 @@ vec4 fog_process(vec3 vertex) {
void main() {
//lay out everything, whatever is unused is optimized away anyway
vec3 vertex = vertex_interp;
+#ifdef USE_MULTIVIEW
+ vec3 view = -normalize(vertex_interp - multiview_data.eye_offset[ViewIndex].xyz);
+#else
vec3 view = -normalize(vertex_interp);
+#endif
+ highp mat4 model_matrix = world_transform;
vec3 albedo = vec3(1.0);
vec3 backlight = vec3(0.0);
vec4 transmittance_color = vec4(0.0, 0.0, 0.0, 1.0);
@@ -1022,15 +1067,11 @@ void main() {
fog = fog_process(vertex);
}
#endif // !DISABLE_FOG
-#endif //!CUSTOM_FOG_USED
+#endif // !CUSTOM_FOG_USED
uint fog_rg = packHalf2x16(fog.rg);
uint fog_ba = packHalf2x16(fog.ba);
-#endif //!MODE_RENDER_DEPTH
-
-#ifndef MODE_RENDER_DEPTH
-
// Convert colors to linear
albedo = srgb_to_linear(albedo);
emission = srgb_to_linear(emission);
@@ -1063,7 +1104,7 @@ void main() {
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 = textureLod(radiance_map, ref_vec, sqrt(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;
@@ -1095,9 +1136,15 @@ void main() {
#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;
+ {
+#if defined(AMBIENT_LIGHT_DISABLED)
+ ambient_light = vec3(0.0, 0.0, 0.0);
+#else
+ ambient_light *= albedo.rgb;
+ ambient_light *= ao;
+#endif // AMBIENT_LIGHT_DISABLED
+ }
// convert ao to direct light ao
ao = mix(1.0, ao, ao_light_affect);
@@ -1119,7 +1166,7 @@ void main() {
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 * f0 + env.y * clamp(50.0 * f0.g, 0.0, 1.0);
+ specular_light *= env.x * f0 + env.y * clamp(50.0 * f0.g, metallic, 1.0);
#endif
}
@@ -1145,10 +1192,10 @@ void main() {
diffuse_light,
specular_light);
}
-#endif //!DISABLE_LIGHT_DIRECTIONAL
+#endif // !DISABLE_LIGHT_DIRECTIONAL
#ifndef DISABLE_LIGHT_OMNI
- for (int i = 0; i < MAX_FORWARD_LIGHTS; i++) {
+ for (uint i = 0u; i < MAX_FORWARD_LIGHTS; i++) {
if (i >= omni_light_count) {
break;
}
@@ -1171,7 +1218,7 @@ void main() {
#endif // !DISABLE_LIGHT_OMNI
#ifndef DISABLE_LIGHT_SPOT
- for (int i = 0; i < MAX_FORWARD_LIGHTS; i++) {
+ for (uint i = 0u; i < MAX_FORWARD_LIGHTS; i++) {
if (i >= spot_light_count) {
break;
}
@@ -1192,9 +1239,10 @@ void main() {
#endif
diffuse_light, specular_light);
}
-
#endif // !DISABLE_LIGHT_SPOT
+
#endif // !MODE_UNSHADED
+
#endif // !MODE_RENDER_DEPTH
#if defined(USE_SHADOW_TO_OPACITY)
diff --git a/drivers/gles3/shaders/skeleton.glsl b/drivers/gles3/shaders/skeleton.glsl
new file mode 100644
index 0000000000..a1e3c098f4
--- /dev/null
+++ b/drivers/gles3/shaders/skeleton.glsl
@@ -0,0 +1,269 @@
+/* clang-format off */
+#[modes]
+
+mode_base_pass =
+mode_blend_pass = #define MODE_BLEND_PASS
+
+#[specializations]
+
+MODE_2D = true
+USE_BLEND_SHAPES = false
+USE_SKELETON = false
+USE_NORMAL = false
+USE_TANGENT = false
+FINAL_PASS = false
+USE_EIGHT_WEIGHTS = false
+
+#[vertex]
+
+#include "stdlib_inc.glsl"
+
+#ifdef MODE_2D
+#define VFORMAT vec2
+#else
+#define VFORMAT vec3
+#endif
+
+#ifdef FINAL_PASS
+#define OFORMAT vec2
+#else
+#define OFORMAT uvec2
+#endif
+
+// These come from the source mesh and the output from previous passes.
+layout(location = 0) in highp VFORMAT in_vertex;
+#ifdef MODE_BLEND_PASS
+#ifdef USE_NORMAL
+layout(location = 1) in highp uvec2 in_normal;
+#endif
+#ifdef USE_TANGENT
+layout(location = 2) in highp uvec2 in_tangent;
+#endif
+#else // MODE_BLEND_PASS
+#ifdef USE_NORMAL
+layout(location = 1) in highp vec2 in_normal;
+#endif
+#ifdef USE_TANGENT
+layout(location = 2) in highp vec2 in_tangent;
+#endif
+#endif // MODE_BLEND_PASS
+
+#ifdef USE_SKELETON
+#ifdef USE_EIGHT_WEIGHTS
+layout(location = 10) in highp uvec4 in_bone_attrib;
+layout(location = 11) in highp uvec4 in_bone_attrib2;
+layout(location = 12) in mediump vec4 in_weight_attrib;
+layout(location = 13) in mediump vec4 in_weight_attrib2;
+#else
+layout(location = 10) in highp uvec4 in_bone_attrib;
+layout(location = 11) in mediump vec4 in_weight_attrib;
+#endif
+
+uniform mediump sampler2D skeleton_texture; // texunit:0
+#endif
+
+/* clang-format on */
+#ifdef MODE_BLEND_PASS
+layout(location = 3) in highp VFORMAT blend_vertex;
+#ifdef USE_NORMAL
+layout(location = 4) in highp vec2 blend_normal;
+#endif
+#ifdef USE_TANGENT
+layout(location = 5) in highp vec2 blend_tangent;
+#endif
+#endif // MODE_BLEND_PASS
+
+out highp VFORMAT out_vertex; //tfb:
+
+#ifdef USE_NORMAL
+flat out highp OFORMAT out_normal; //tfb:USE_NORMAL
+#endif
+#ifdef USE_TANGENT
+flat out highp OFORMAT out_tangent; //tfb:USE_TANGENT
+#endif
+
+#ifdef USE_BLEND_SHAPES
+uniform highp float blend_weight;
+uniform lowp float blend_shape_count;
+#endif
+
+vec2 signNotZero(vec2 v) {
+ return mix(vec2(-1.0), vec2(1.0), greaterThanEqual(v.xy, vec2(0.0)));
+}
+
+vec3 oct_to_vec3(vec2 oct) {
+ oct = oct * 2.0 - 1.0;
+ vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));
+ if (v.z < 0.0) {
+ v.xy = (1.0 - abs(v.yx)) * signNotZero(v.xy);
+ }
+ return normalize(v);
+}
+
+vec2 vec3_to_oct(vec3 e) {
+ e /= abs(e.x) + abs(e.y) + abs(e.z);
+ vec2 oct = e.z >= 0.0f ? e.xy : (vec2(1.0f) - abs(e.yx)) * signNotZero(e.xy);
+ return oct * 0.5f + 0.5f;
+}
+
+vec4 oct_to_tang(vec2 oct_sign_encoded) {
+ // Binormal sign encoded in y component
+ vec2 oct = vec2(oct_sign_encoded.x, abs(oct_sign_encoded.y) * 2.0 - 1.0);
+ return vec4(oct_to_vec3(oct), sign(oct_sign_encoded.y));
+}
+
+vec2 tang_to_oct(vec4 base) {
+ vec2 oct = vec3_to_oct(base.xyz);
+ // Encode binormal sign in y component
+ oct.y = oct.y * 0.5f + 0.5f;
+ oct.y = base.w >= 0.0f ? oct.y : 1.0 - oct.y;
+ return oct;
+}
+
+// Our original input for normals and tangents is 2 16-bit floats.
+// Transform Feedback has to write out 32-bits per channel.
+// Octahedral compression requires normalized vectors, but we need to store
+// non-normalized vectors until the very end.
+// Therefore, we will compress our normals into 16 bits using signed-normalized
+// fixed point precision. This works well, because we know that each normal
+// is no larger than |1| so we can normalize by dividing by the number of blend
+// shapes.
+uvec2 vec4_to_vec2(vec4 p_vec) {
+ return uvec2(packSnorm2x16(p_vec.xy), packSnorm2x16(p_vec.zw));
+}
+
+vec4 vec2_to_vec4(uvec2 p_vec) {
+ return vec4(unpackSnorm2x16(p_vec.x), unpackSnorm2x16(p_vec.y));
+}
+
+void main() {
+#ifdef MODE_2D
+ out_vertex = in_vertex;
+
+#ifdef USE_BLEND_SHAPES
+#ifdef MODE_BLEND_PASS
+ out_vertex = in_vertex + blend_vertex * blend_weight;
+#else
+ out_vertex = in_vertex * blend_weight;
+#endif
+#ifdef FINAL_PASS
+ out_vertex = normalize(out_vertex);
+#endif
+#endif // USE_BLEND_SHAPES
+
+#ifdef USE_SKELETON
+
+#define TEX(m) texelFetch(skeleton_texture, ivec2(m % 256u, m / 256u), 0)
+#define GET_BONE_MATRIX(a, b, w) mat2x4(TEX(a), TEX(b)) * w
+
+ uvec4 bones = in_bone_attrib * uvec4(2u);
+ uvec4 bones_a = bones + uvec4(1u);
+
+ highp mat2x4 m = GET_BONE_MATRIX(bones.x, bones_a.x, in_weight_attrib.x);
+ m += GET_BONE_MATRIX(bones.y, bones_a.y, in_weight_attrib.y);
+ m += GET_BONE_MATRIX(bones.z, bones_a.z, in_weight_attrib.z);
+ m += GET_BONE_MATRIX(bones.w, bones_a.w, in_weight_attrib.w);
+
+ mat4 bone_matrix = mat4(m[0], m[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
+
+ //reverse order because its transposed
+ out_vertex = (vec4(out_vertex, 0.0, 1.0) * bone_matrix).xy;
+#endif // USE_SKELETON
+
+#else // MODE_2D
+
+#ifdef USE_BLEND_SHAPES
+#ifdef MODE_BLEND_PASS
+ out_vertex = in_vertex + blend_vertex * blend_weight;
+
+#ifdef USE_NORMAL
+ vec3 normal = vec2_to_vec4(in_normal).xyz * blend_shape_count;
+ vec3 normal_blend = oct_to_vec3(blend_normal) * blend_weight;
+#ifdef FINAL_PASS
+ out_normal = vec3_to_oct(normalize(normal + normal_blend));
+#else
+ out_normal = vec4_to_vec2(vec4(normal + normal_blend, 0.0) / blend_shape_count);
+#endif
+#endif // USE_NORMAL
+
+#ifdef USE_TANGENT
+ vec4 tangent = vec2_to_vec4(in_tangent) * blend_shape_count;
+ vec4 tangent_blend = oct_to_tang(blend_tangent) * blend_weight;
+#ifdef FINAL_PASS
+ out_tangent = tang_to_oct(vec4(normalize(tangent.xyz + tangent_blend.xyz), tangent.w));
+#else
+ out_tangent = vec4_to_vec2(vec4((tangent.xyz + tangent_blend.xyz) / blend_shape_count, tangent.w));
+#endif
+#endif // USE_TANGENT
+
+#else // MODE_BLEND_PASS
+ out_vertex = in_vertex * blend_weight;
+
+#ifdef USE_NORMAL
+ vec3 normal = oct_to_vec3(in_normal);
+ out_normal = vec4_to_vec2(vec4(normal * blend_weight / blend_shape_count, 0.0));
+#endif
+#ifdef USE_TANGENT
+ vec4 tangent = oct_to_tang(in_tangent);
+ out_tangent = vec4_to_vec2(vec4(tangent.rgb * blend_weight / blend_shape_count, tangent.w));
+#endif
+#endif // MODE_BLEND_PASS
+#else // USE_BLEND_SHAPES
+
+ // Make attributes available to the skeleton shader if not written by blend shapes.
+ out_vertex = in_vertex;
+#ifdef USE_NORMAL
+ out_normal = in_normal;
+#endif
+#ifdef USE_TANGENT
+ out_tangent = in_tangent;
+#endif
+#endif // USE_BLEND_SHAPES
+
+#ifdef USE_SKELETON
+
+#define TEX(m) texelFetch(skeleton_texture, ivec2(m % 256u, m / 256u), 0)
+#define GET_BONE_MATRIX(a, b, c, w) mat4(TEX(a), TEX(b), TEX(c), vec4(0.0, 0.0, 0.0, 1.0)) * w
+
+ uvec4 bones = in_bone_attrib * uvec4(3);
+ uvec4 bones_a = bones + uvec4(1);
+ uvec4 bones_b = bones + uvec4(2);
+
+ highp mat4 m;
+ m = GET_BONE_MATRIX(bones.x, bones_a.x, bones_b.x, in_weight_attrib.x);
+ m += GET_BONE_MATRIX(bones.y, bones_a.y, bones_b.y, in_weight_attrib.y);
+ m += GET_BONE_MATRIX(bones.z, bones_a.z, bones_b.z, in_weight_attrib.z);
+ m += GET_BONE_MATRIX(bones.w, bones_a.w, bones_b.w, in_weight_attrib.w);
+
+#ifdef USE_EIGHT_WEIGHTS
+ bones = in_bone_attrib2 * uvec4(3);
+ bones_a = bones + uvec4(1);
+ bones_b = bones + uvec4(2);
+
+ m += GET_BONE_MATRIX(bones.x, bones_a.x, bones_b.x, in_weight_attrib2.x);
+ m += GET_BONE_MATRIX(bones.y, bones_a.y, bones_b.y, in_weight_attrib2.y);
+ m += GET_BONE_MATRIX(bones.z, bones_a.z, bones_b.z, in_weight_attrib2.z);
+ m += GET_BONE_MATRIX(bones.w, bones_a.w, bones_b.w, in_weight_attrib2.w);
+#endif
+
+ // Reverse order because its transposed.
+ out_vertex = (vec4(out_vertex, 1.0) * m).xyz;
+#ifdef USE_NORMAL
+ vec3 vertex_normal = oct_to_vec3(out_normal);
+ out_normal = vec3_to_oct(normalize((vec4(vertex_normal, 0.0) * m).xyz));
+#endif // USE_NORMAL
+#ifdef USE_TANGENT
+ vec4 vertex_tangent = oct_to_tang(out_tangent);
+ out_tangent = tang_to_oct(vec4(normalize((vec4(vertex_tangent.xyz, 0.0) * m).xyz), vertex_tangent.w));
+#endif // USE_TANGENT
+#endif // USE_SKELETON
+#endif // MODE_2D
+}
+
+/* clang-format off */
+#[fragment]
+
+void main() {
+
+}
+/* clang-format on */
diff --git a/drivers/gles3/shaders/sky.glsl b/drivers/gles3/shaders/sky.glsl
index 21f01d2a8f..4c0fe47f6b 100644
--- a/drivers/gles3/shaders/sky.glsl
+++ b/drivers/gles3/shaders/sky.glsl
@@ -104,6 +104,15 @@ uniform uint directional_light_count;
layout(location = 0) out vec4 frag_color;
+#ifdef USE_DEBANDING
+// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
+vec3 interleaved_gradient_noise(vec2 pos) {
+ const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
+ float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0;
+ return vec3(res, -res, res) / 255.0;
+}
+#endif
+
void main() {
vec3 cube_normal;
cube_normal.z = -1.0;
@@ -168,4 +177,8 @@ void main() {
frag_color.rgb = color;
frag_color.a = alpha;
+
+#ifdef USE_DEBANDING
+ frag_color.rgb += interleaved_gradient_noise(gl_FragCoord.xy);
+#endif
}
diff --git a/drivers/gles3/shaders/stdlib_inc.glsl b/drivers/gles3/shaders/stdlib_inc.glsl
index d5051760d7..8d4a24cc1f 100644
--- a/drivers/gles3/shaders/stdlib_inc.glsl
+++ b/drivers/gles3/shaders/stdlib_inc.glsl
@@ -38,23 +38,33 @@ 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) {
+// Compatibility renames. These are exposed with the "godot_" prefix
+// to work around an Adreno bug which was exposing these ES310 functions
+// in ES300 shaders. Internally, we must use the "godot_" prefix, but user shaders
+// will be mapped automatically.
+uint godot_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));
}
-vec4 unpackUnorm4x8(uint p) {
+vec4 godot_unpackUnorm4x8(uint p) {
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) {
+uint godot_packSnorm4x8(vec4 v) {
uvec4 uv = uvec4(round(clamp(v, vec4(-1.0), vec4(1.0)) * 127.0) + 127.0);
return uv.x | uv.y << uint(8) | uv.z << uint(16) | uv.w << uint(24);
}
-vec4 unpackSnorm4x8(uint p) {
+vec4 godot_unpackSnorm4x8(uint p) {
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));
}
+
+#define packUnorm4x8 godot_packUnorm4x8
+#define unpackUnorm4x8 godot_unpackUnorm4x8
+#define packSnorm4x8 godot_packSnorm4x8
+#define unpackSnorm4x8 godot_unpackSnorm4x8
diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl
index a478cf9170..0b769e77f2 100644
--- a/drivers/gles3/shaders/tonemap.glsl
+++ b/drivers/gles3/shaders/tonemap.glsl
@@ -44,7 +44,11 @@ in vec2 uv_interp;
layout(location = 0) out vec4 frag_color;
+#ifdef USE_MULTIVIEW
+uniform highp sampler2DArray source; //texunit:0
+#else
uniform highp sampler2D source; //texunit:0
+#endif
#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7)
#define USING_GLOW // only use glow when at least one glow level is selected
@@ -191,10 +195,17 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) {
const float FXAA_REDUCE_MUL = (1.0 / 8.0);
const float FXAA_SPAN_MAX = 8.0;
+#ifdef USE_MULTIVIEW
+ vec3 rgbNW = textureLod(source, vec3(uv_interp + vec2(-1.0, -1.0) * pixel_size, ViewIndex), 0.0).xyz;
+ vec3 rgbNE = textureLod(source, vec3(uv_interp + vec2(1.0, -1.0) * pixel_size, ViewIndex), 0.0).xyz;
+ vec3 rgbSW = textureLod(source, vec3(uv_interp + vec2(-1.0, 1.0) * pixel_size, ViewIndex), 0.0).xyz;
+ vec3 rgbSE = textureLod(source, vec3(uv_interp + vec2(1.0, 1.0) * pixel_size, ViewIndex), 0.0).xyz;
+#else
vec3 rgbNW = textureLod(source, uv_interp + vec2(-1.0, -1.0) * pixel_size, 0.0).xyz;
vec3 rgbNE = textureLod(source, uv_interp + vec2(1.0, -1.0) * pixel_size, 0.0).xyz;
vec3 rgbSW = textureLod(source, uv_interp + vec2(-1.0, 1.0) * pixel_size, 0.0).xyz;
vec3 rgbSE = textureLod(source, uv_interp + vec2(1.0, 1.0) * pixel_size, 0.0).xyz;
+#endif
vec3 rgbM = color;
vec3 luma = vec3(0.299, 0.587, 0.114);
float lumaNW = dot(rgbNW, luma);
@@ -219,8 +230,13 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) {
dir * rcpDirMin)) *
pixel_size;
+#ifdef USE_MULTIVIEW
+ vec3 rgbA = 0.5 * (textureLod(source, vec3(uv_interp + dir * (1.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz + textureLod(source, vec3(uv_interp + dir * (2.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz);
+ vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source, vec3(uv_interp + dir * -0.5, ViewIndex), 0.0).xyz + textureLod(source, vec3(uv_interp + dir * 0.5, ViewIndex), 0.0).xyz);
+#else
vec3 rgbA = 0.5 * (textureLod(source, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz);
vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source, uv_interp + dir * 0.5, 0.0).xyz);
+#endif
float lumaB = dot(rgbB, luma);
if ((lumaB < lumaMin) || (lumaB > lumaMax)) {
@@ -231,7 +247,11 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) {
}
void main() {
+#ifdef USE_MULTIVIEW
+ vec4 color = textureLod(source, vec3(uv_interp, ViewIndex), 0.0);
+#else
vec4 color = textureLod(source, uv_interp, 0.0);
+#endif
#ifdef USE_FXAA
color.rgb = apply_fxaa(color.rgb, uv_interp, pixel_size);
diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp
index 6cc65e7bb2..d1a83e6851 100644
--- a/drivers/gles3/storage/config.cpp
+++ b/drivers/gles3/storage/config.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* config.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
@@ -34,6 +34,15 @@
#include "core/config/project_settings.h"
#include "core/templates/vector.h"
+#ifdef ANDROID_ENABLED
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#include <GLES3/gl3platform.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#endif
+
using namespace GLES3;
#define _GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
@@ -62,7 +71,7 @@ Config::Config() {
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");
+ float_texture_supported = extensions.has("GL_EXT_color_buffer_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.
@@ -75,26 +84,27 @@ Config::Config() {
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);
+ glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_viewport_size);
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);
+ anisotropic_level = MIN(float(1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"))), anisotropic_level);
+ }
+
+ multiview_supported = extensions.has("GL_OVR_multiview2") || extensions.has("GL_OVR_multiview");
+#ifdef ANDROID_ENABLED
+ if (multiview_supported) {
+ eglFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)eglGetProcAddress("glFramebufferTextureMultiviewOVR");
+ if (eglFramebufferTextureMultiviewOVR == nullptr) {
+ multiview_supported = false;
+ }
}
+#endif
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");
diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h
index b83c83f425..8399502675 100644
--- a/drivers/gles3/storage/config.h
+++ b/drivers/gles3/storage/config.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* config.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* config.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 CONFIG_GLES3_H
#define CONFIG_GLES3_H
@@ -44,6 +44,10 @@
#include OPENGL_INCLUDE_H
#endif
+#ifdef ANDROID_ENABLED
+typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(GLenum, GLenum, GLuint, GLint, GLint, GLsizei);
+#endif
+
namespace GLES3 {
class Config {
@@ -52,13 +56,12 @@ private:
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_viewport_size[2] = { 0, 0 };
int max_uniform_buffer_size = 0;
int max_renderable_elements = 0;
int max_renderable_lights = 0;
@@ -80,6 +83,11 @@ public:
bool support_anisotropic_filter = false;
float anisotropic_level = 0.0f;
+ bool multiview_supported = false;
+#ifdef ANDROID_ENABLED
+ PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC eglFramebufferTextureMultiviewOVR = nullptr;
+#endif
+
static Config *get_singleton() { return singleton; };
Config();
diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp
index 6411590aee..a325f79d8c 100644
--- a/drivers/gles3/storage/light_storage.cpp
+++ b/drivers/gles3/storage/light_storage.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* light_storage.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
@@ -333,6 +333,46 @@ AABB LightStorage::light_get_aabb(RID p_light) const {
ERR_FAIL_V(AABB());
}
+/* LIGHT INSTANCE API */
+
+RID LightStorage::light_instance_create(RID p_light) {
+ 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 = light_get_type(p_light);
+
+ return li;
+}
+
+void LightStorage::light_instance_free(RID p_light_instance) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+ light_instance_owner.free(p_light_instance);
+}
+
+void LightStorage::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 LightStorage::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 LightStorage::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 LightStorage::light_instance_mark_visible(RID p_light_instance) {
+}
+
/* PROBE API */
RID LightStorage::reflection_probe_allocate() {
@@ -419,6 +459,57 @@ float LightStorage::reflection_probe_get_mesh_lod_threshold(RID p_probe) const {
return 0.0;
}
+/* REFLECTION ATLAS */
+
+RID LightStorage::reflection_atlas_create() {
+ return RID();
+}
+
+void LightStorage::reflection_atlas_free(RID p_ref_atlas) {
+}
+
+int LightStorage::reflection_atlas_get_size(RID p_ref_atlas) const {
+ return 0;
+}
+
+void LightStorage::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) {
+}
+
+/* REFLECTION PROBE INSTANCE */
+
+RID LightStorage::reflection_probe_instance_create(RID p_probe) {
+ return RID();
+}
+
+void LightStorage::reflection_probe_instance_free(RID p_instance) {
+}
+
+void LightStorage::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) {
+}
+
+void LightStorage::reflection_probe_release_atlas_index(RID p_instance) {
+}
+
+bool LightStorage::reflection_probe_instance_needs_redraw(RID p_instance) {
+ return false;
+}
+
+bool LightStorage::reflection_probe_instance_has_reflection(RID p_instance) {
+ return false;
+}
+
+bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) {
+ return false;
+}
+
+Ref<RenderSceneBuffers> LightStorage::reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) {
+ return Ref<RenderSceneBuffers>();
+}
+
+bool LightStorage::reflection_probe_instance_postprocess_step(RID p_instance) {
+ return true;
+}
+
/* LIGHTMAP CAPTURE */
RID LightStorage::lightmap_allocate() {
@@ -484,6 +575,18 @@ float LightStorage::lightmap_get_probe_capture_update_speed() const {
return 0;
}
+/* LIGHTMAP INSTANCE */
+
+RID LightStorage::lightmap_instance_create(RID p_lightmap) {
+ return RID();
+}
+
+void LightStorage::lightmap_instance_free(RID p_lightmap) {
+}
+
+void LightStorage::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) {
+}
+
/* LIGHT SHADOW MAPPING */
/*
@@ -584,4 +687,36 @@ void LightStorage::canvas_light_occluder_set_polylines(RID p_occluder, const Poo
}
*/
+/* SHADOW ATLAS API */
+
+RID LightStorage::shadow_atlas_create() {
+ return RID();
+}
+
+void LightStorage::shadow_atlas_free(RID p_atlas) {
+}
+
+void LightStorage::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) {
+}
+
+void LightStorage::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
+}
+
+bool LightStorage::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) {
+ return false;
+}
+
+void LightStorage::shadow_atlas_update(RID p_atlas) {
+}
+
+void LightStorage::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) {
+}
+
+int LightStorage::get_directional_light_shadow_size(RID p_light_intance) {
+ return 0;
+}
+
+void LightStorage::set_directional_shadow_count(int p_count) {
+}
+
#endif // !GLES3_ENABLED
diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h
index f054f0fdc6..8b2bdaf872 100644
--- a/drivers/gles3/storage/light_storage.h
+++ b/drivers/gles3/storage/light_storage.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* light_storage.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
@@ -36,6 +36,7 @@
#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
+#include "drivers/gles3/storage/texture_storage.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/storage/light_storage.h"
#include "servers/rendering/storage/utilities.h"
@@ -75,6 +76,33 @@ struct Light {
Dependency dependency;
};
+/* Light instance */
+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() {}
+};
+
/* REFLECTION PROBE */
struct ReflectionProbe {
@@ -85,7 +113,7 @@ struct ReflectionProbe {
Color ambient_color;
float ambient_color_energy = 1.0;
float max_distance = 0;
- Vector3 extents = Vector3(1, 1, 1);
+ Vector3 extents = Vector3(10, 10, 10);
Vector3 origin_offset;
bool interior = false;
bool box_projection = false;
@@ -127,6 +155,9 @@ private:
/* LIGHT */
mutable RID_Owner<Light, true> light_owner;
+ /* Light instance */
+ mutable RID_Owner<LightInstance> light_instance_owner;
+
/* REFLECTION PROBE */
mutable RID_Owner<ReflectionProbe, true> reflection_probe_owner;
@@ -246,7 +277,7 @@ public:
const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
- return light_owner.owns(light->projector);
+ return TextureStorage::get_singleton()->owns_texture(light->projector);
}
_FORCE_INLINE_ bool light_is_negative(RID p_light) const {
@@ -267,6 +298,28 @@ public:
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;
+ /* LIGHT INSTANCE API */
+
+ LightInstance *get_light_instance(RID p_rid) { return light_instance_owner.get_or_null(p_rid); };
+ bool owns_light_instance(RID p_rid) { return light_instance_owner.owns(p_rid); };
+
+ virtual RID light_instance_create(RID p_light) override;
+ virtual void light_instance_free(RID p_light_instance) override;
+
+ virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override;
+ virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override;
+ virtual 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;
+ virtual 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;
+ }
+
/* PROBE API */
virtual RID reflection_probe_allocate() override;
@@ -297,6 +350,25 @@ public:
virtual float reflection_probe_get_origin_max_distance(RID p_probe) const override;
virtual bool reflection_probe_renders_shadows(RID p_probe) const override;
+ /* REFLECTION ATLAS */
+
+ virtual RID reflection_atlas_create() override;
+ virtual void reflection_atlas_free(RID p_ref_atlas) override;
+ virtual int reflection_atlas_get_size(RID p_ref_atlas) const override;
+ virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override;
+
+ /* REFLECTION PROBE INSTANCE */
+
+ virtual RID reflection_probe_instance_create(RID p_probe) override;
+ virtual void reflection_probe_instance_free(RID p_instance) override;
+ virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override;
+ virtual void reflection_probe_release_atlas_index(RID p_instance) override;
+ virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override;
+ virtual bool reflection_probe_instance_has_reflection(RID p_instance) override;
+ virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override;
+ virtual Ref<RenderSceneBuffers> reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) override;
+ virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override;
+
/* LIGHTMAP CAPTURE */
Lightmap *get_lightmap(RID p_rid) { return lightmap_owner.get_or_null(p_rid); };
@@ -337,6 +409,26 @@ public:
RID canvas_light_occluder_create();
void canvas_light_occluder_set_polylines(RID p_occluder, const LocalVector<Vector2> &p_lines);
*/
+
+ /* LIGHTMAP INSTANCE */
+
+ virtual RID lightmap_instance_create(RID p_lightmap) override;
+ virtual void lightmap_instance_free(RID p_lightmap) override;
+ virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
+
+ /* SHADOW ATLAS API */
+
+ virtual RID shadow_atlas_create() override;
+ virtual void shadow_atlas_free(RID p_atlas) override;
+ virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override;
+ virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
+ virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override;
+
+ virtual void shadow_atlas_update(RID p_atlas) override;
+
+ virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
+ virtual int get_directional_light_shadow_size(RID p_light_intance) override;
+ virtual void set_directional_shadow_count(int p_count) override;
};
} // namespace GLES3
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index 3dbc75392c..50e5c868d3 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* material_storage.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
@@ -34,6 +34,7 @@
#include "config.h"
#include "material_storage.h"
+#include "particles_storage.h"
#include "texture_storage.h"
#include "drivers/gles3/rasterizer_canvas_gles3.h"
@@ -89,7 +90,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
gui[j + 3] = 0; // ignored
}
} else {
- int v = value;
+ uint32_t v = value;
gui[0] = v & 1 ? 1 : 0;
gui[1] = v & 2 ? 1 : 0;
}
@@ -116,7 +117,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
gui[j + 3] = 0; // ignored
}
} else {
- int v = value;
+ uint32_t v = value;
gui[0] = (v & 1) ? 1 : 0;
gui[1] = (v & 2) ? 1 : 0;
gui[2] = (v & 4) ? 1 : 0;
@@ -145,7 +146,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
}
}
} else {
- int v = value;
+ uint32_t v = value;
gui[0] = (v & 1) ? 1 : 0;
gui[1] = (v & 2) ? 1 : 0;
gui[2] = (v & 4) ? 1 : 0;
@@ -714,7 +715,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
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];
+ gui[i * 4 + j] = v.columns[i][j];
}
}
}
@@ -728,7 +729,7 @@ _FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type,
switch (type) {
case ShaderLanguage::TYPE_BOOL: {
uint32_t *gui = (uint32_t *)data;
- *gui = value[0].boolean ? 1 : 0;
+ gui[0] = value[0].boolean ? 1 : 0;
} break;
case ShaderLanguage::TYPE_BVEC2: {
uint32_t *gui = (uint32_t *)data;
@@ -897,7 +898,9 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
case ShaderLanguage::TYPE_BVEC3:
case ShaderLanguage::TYPE_IVEC3:
case ShaderLanguage::TYPE_UVEC3:
- case ShaderLanguage::TYPE_VEC3:
+ case ShaderLanguage::TYPE_VEC3: {
+ memset(data, 0, 12 * p_array_size);
+ } break;
case ShaderLanguage::TYPE_BVEC4:
case ShaderLanguage::TYPE_IVEC4:
case ShaderLanguage::TYPE_UVEC4:
@@ -920,6 +923,104 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
}
///////////////////////////////////////////////////////////////////////////
+// ShaderData
+
+void ShaderData::set_path_hint(const String &p_hint) {
+ path = p_hint;
+}
+
+void ShaderData::set_default_texture_parameter(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;
+ }
+}
+
+Variant ShaderData::get_default_parameter(const StringName &p_parameter) const {
+ if (uniforms.has(p_parameter)) {
+ ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+ Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
+ }
+ return Variant();
+}
+
+void ShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
+ SortArray<Pair<StringName, int>, ShaderLanguage::UniformOrderComparator> sorter;
+ LocalVector<Pair<StringName, int>> filtered_uniforms;
+
+ 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) {
+ filtered_uniforms.push_back(Pair<StringName, int>(E.key, E.value.texture_order + 100000));
+ } else {
+ filtered_uniforms.push_back(Pair<StringName, int>(E.key, E.value.order));
+ }
+ }
+ int uniform_count = filtered_uniforms.size();
+ sorter.sort(filtered_uniforms.ptr(), uniform_count);
+
+ String last_group;
+ for (int i = 0; i < uniform_count; i++) {
+ const StringName &uniform_name = filtered_uniforms[i].first;
+ const ShaderLanguage::ShaderNode::Uniform &uniform = uniforms[uniform_name];
+
+ String group = uniform.group;
+ if (!uniform.subgroup.is_empty()) {
+ group += "::" + uniform.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(uniform);
+ pi.name = uniform_name;
+ p_param_list->push_back(pi);
+ }
+}
+
+void ShaderData::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 ShaderData::is_parameter_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+///////////////////////////////////////////////////////////////////////////
// MaterialData
// Look up table to translate ShaderLanguage::DataType to GL_TEXTURE_*
@@ -958,6 +1059,22 @@ static const GLenum target_from_type[ShaderLanguage::TYPE_MAX] = {
GL_TEXTURE_2D, // TYPE_STRUCT
};
+static const RS::CanvasItemTextureRepeat repeat_from_uniform[ShaderLanguage::REPEAT_DEFAULT + 1] = {
+ RS::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, // ShaderLanguage::TextureRepeat::REPEAT_DISABLE,
+ RS::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED, // ShaderLanguage::TextureRepeat::REPEAT_ENABLE,
+ RS::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED, // ShaderLanguage::TextureRepeat::REPEAT_DEFAULT,
+};
+
+static const RS::CanvasItemTextureFilter filter_from_uniform[ShaderLanguage::FILTER_DEFAULT + 1] = {
+ RS::CanvasItemTextureFilter::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, // ShaderLanguage::TextureFilter::FILTER_NEAREST,
+ RS::CanvasItemTextureFilter::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, // ShaderLanguage::TextureFilter::FILTER_LINEAR,
+ RS::CanvasItemTextureFilter::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, // ShaderLanguage::TextureFilter::FILTER_NEAREST_MIPMAP,
+ RS::CanvasItemTextureFilter::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, // ShaderLanguage::TextureFilter::FILTER_LINEAR_MIPMAP,
+ RS::CanvasItemTextureFilter::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, // ShaderLanguage::TextureFilter::FILTER_NEAREST_MIPMAP_ANISOTROPIC,
+ RS::CanvasItemTextureFilter::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, // ShaderLanguage::TextureFilter::FILTER_LINEAR_MIPMAP_ANISOTROPIC,
+ RS::CanvasItemTextureFilter::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, // ShaderLanguage::TextureFilter::FILTER_DEFAULT,
+};
+
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;
@@ -1340,13 +1457,13 @@ MaterialStorage::MaterialStorage() {
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_PARTICLES] = _create_particles_shader_func;
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_PARTICLES] = _create_particles_material_func;
material_data_request_func[RS::SHADER_SKY] = _create_sky_material_func;
material_data_request_func[RS::SHADER_FOG] = nullptr;
@@ -1379,9 +1496,9 @@ MaterialStorage::MaterialStorage() {
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["CANVAS_MATRIX"] = "canvas_transform";
+ actions.renames["SCREEN_MATRIX"] = "screen_transform";
+ actions.renames["TIME"] = "time";
actions.renames["PI"] = _MKSTR(Math_PI);
actions.renames["TAU"] = _MKSTR(Math_TAU);
actions.renames["E"] = _MKSTR(Math_E);
@@ -1393,19 +1510,20 @@ MaterialStorage::MaterialStorage() {
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["TEXTURE_PIXEL_SIZE"] = "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["SCREEN_PIXEL_SIZE"] = "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_DIRECTION"] = "light_direction";
+ actions.renames["LIGHT_IS_DIRECTIONAL"] = "is_directional";
actions.renames["LIGHT_COLOR"] = "light_color";
actions.renames["LIGHT_ENERGY"] = "light_energy";
actions.renames["LIGHT"] = "light";
@@ -1417,7 +1535,6 @@ MaterialStorage::MaterialStorage() {
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";
@@ -1498,9 +1615,6 @@ MaterialStorage::MaterialStorage() {
actions.renames["POINT_COORD"] = "gl_PointCoord";
actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
actions.renames["SCREEN_UV"] = "screen_uv";
- //actions.renames["SCREEN_TEXTURE"] = "color_buffer"; //Not implemented in 3D yet.
- //actions.renames["DEPTH_TEXTURE"] = "depth_buffer"; // Not implemented in 3D yet.
- //actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer"; // Not implemented in 3D yet
actions.renames["DEPTH"] = "gl_FragDepth";
actions.renames["OUTPUT_IS_SRGB"] = "true";
actions.renames["FOG"] = "fog";
@@ -1517,6 +1631,7 @@ MaterialStorage::MaterialStorage() {
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["CAMERA_VISIBLE_LAYERS"] = "scene_data.camera_visible_layers";
actions.renames["NODE_POSITION_VIEW"] = "(model_matrix * scene_data.view_matrix)[3].xyz";
actions.renames["VIEW_INDEX"] = "ViewIndex";
@@ -1564,7 +1679,6 @@ MaterialStorage::MaterialStorage() {
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";
@@ -1609,32 +1723,32 @@ MaterialStorage::MaterialStorage() {
{
// Setup Particles compiler
- /*
-ShaderCompiler::DefaultIdentifierActions actions;
- actions.renames["COLOR"] = "PARTICLE.color";
- actions.renames["VELOCITY"] = "PARTICLE.velocity";
+ ShaderCompiler::DefaultIdentifierActions actions;
+
+ actions.renames["COLOR"] = "out_color";
+ actions.renames["VELOCITY"] = "out_velocity_flags.xyz";
//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++) {
+ actions.renames["CUSTOM"] = "out_custom";
+ for (int i = 0; i < PARTICLES_MAX_USERDATAS; i++) {
String udname = "USERDATA" + itos(i + 1);
- actions.renames[udname] = "PARTICLE.userdata" + itos(i + 1);
+ actions.renames[udname] = "out_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["TRANSFORM"] = "xform";
+ actions.renames["TIME"] = "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["LIFETIME"] = "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["EMISSION_TRANSFORM"] = "emission_transform";
+ actions.renames["RANDOM_SEED"] = "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";
@@ -1654,20 +1768,12 @@ ShaderCompiler::DefaultIdentifierActions actions;
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.render_mode_defines["collision_use_scale"] = "#define USE_COLLISION_SCALE\n";
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);
- */
+ shaders.compiler_particles.initialize(actions);
}
{
@@ -1715,6 +1821,7 @@ ShaderCompiler::DefaultIdentifierActions actions;
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.render_mode_defines["use_debanding"] = "#define USE_DEBANDING\n";
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
@@ -2209,7 +2316,7 @@ void MaterialStorage::global_shader_parameters_load_settings(bool p_load_texture
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);
+ Dictionary d = GLOBAL_GET(E.name);
ERR_CONTINUE(!d.has("type"));
ERR_CONTINUE(!d.has("value"));
@@ -2309,7 +2416,7 @@ void MaterialStorage::global_shader_parameters_instance_free(RID p_instance) {
global_shader_uniforms.instance_buffer_pos.erase(p_instance);
}
-void MaterialStorage::global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value) {
+void MaterialStorage::global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value, int p_flags_count) {
if (!global_shader_uniforms.instance_buffer_pos.has(p_instance)) {
return; //just not allocated, ignore
}
@@ -2319,7 +2426,9 @@ void MaterialStorage::global_shader_parameters_instance_update(RID p_instance, i
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
+
+ Variant::Type value_type = p_value.get_type();
+ ERR_FAIL_COND_MSG(p_value.get_type() > Variant::COLOR, "Unsupported variant type for instance parameter: " + Variant::get_type_name(value_type)); //anything greater not supported
ShaderLanguage::DataType datatype_from_value[Variant::COLOR + 1] = {
ShaderLanguage::TYPE_MAX, //nil
@@ -2345,9 +2454,24 @@ void MaterialStorage::global_shader_parameters_instance_update(RID p_instance, i
ShaderLanguage::TYPE_VEC4 //color
};
- ShaderLanguage::DataType datatype = datatype_from_value[p_value.get_type()];
+ ShaderLanguage::DataType datatype = ShaderLanguage::TYPE_MAX;
+ if (value_type == Variant::INT && p_flags_count > 0) {
+ switch (p_flags_count) {
+ case 1:
+ datatype = ShaderLanguage::TYPE_BVEC2;
+ break;
+ case 2:
+ datatype = ShaderLanguage::TYPE_BVEC3;
+ break;
+ case 3:
+ datatype = ShaderLanguage::TYPE_BVEC4;
+ break;
+ }
+ } else {
+ datatype = datatype_from_value[value_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
+ ERR_FAIL_COND_MSG(datatype == ShaderLanguage::TYPE_MAX, "Unsupported variant type for instance parameter: " + Variant::get_type_name(value_type)); //anything greater not supported
pos += p_index;
@@ -2448,8 +2572,8 @@ void MaterialStorage::shader_set_code(RID p_shader, const String &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 == "particles") {
+ new_mode = RS::SHADER_PARTICLES;
} else if (mode_string == "spatial") {
new_mode = RS::SHADER_SPATIAL;
} else if (mode_string == "sky") {
@@ -2520,6 +2644,9 @@ void MaterialStorage::shader_set_path_hint(RID p_shader, const String &p_path) {
ERR_FAIL_COND(!shader);
shader->path_hint = p_path;
+ if (shader->data) {
+ shader->data->set_path_hint(p_path);
+ }
}
String MaterialStorage::shader_get_code(RID p_shader) const {
@@ -2632,6 +2759,14 @@ void MaterialStorage::material_free(RID p_rid) {
Material *material = material_owner.get_or_null(p_rid);
ERR_FAIL_COND(!material);
+ // Need to clear texture arrays to prevent spin locking of their RID's.
+ // This happens when the app is being closed.
+ for (KeyValue<StringName, Variant> &E : material->params) {
+ if (E.value.get_type() == Variant::ARRAY) {
+ Array(E.value).clear();
+ }
+ }
+
material_set_shader(p_rid, RID()); //clean up shader
material->dependency.deleted_notify(p_rid);
@@ -2819,7 +2954,6 @@ void CanvasShaderData::set_code(const String &p_code) {
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;
@@ -2833,6 +2967,7 @@ void CanvasShaderData::set_code(const String &p_code) {
blend_mode = BlendMode(blend_modei);
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
+ uses_screen_texture = gen_code.uses_screen_texture;
#if 0
print_line("**compiling shader:");
@@ -2867,85 +3002,6 @@ void CanvasShaderData::set_code(const String &p_code) {
valid = true;
}
-void CanvasShaderData::set_default_texture_parameter(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 ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
- 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_parameter_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;
}
@@ -2954,15 +3010,6 @@ 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);
}
@@ -2985,7 +3032,7 @@ GLES3::ShaderData *GLES3::_create_canvas_shader_func() {
}
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);
+ 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() {
@@ -2998,13 +3045,12 @@ void CanvasMaterialData::bind_uniforms() {
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);
+ if (texture->render_target) {
+ texture->render_target->used_in_frame = true;
+ }
- // 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);
+ texture->gl_set_filter(filter_from_uniform[int(texture_uniforms[ti].filter)]);
+ texture->gl_set_repeat(repeat_from_uniform[int(texture_uniforms[ti].repeat)]);
}
}
@@ -3111,83 +3157,6 @@ void SkyShaderData::set_code(const String &p_code) {
valid = true;
}
-void SkyShaderData::set_default_texture_parameter(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_parameter_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;
}
@@ -3196,15 +3165,6 @@ 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);
}
@@ -3229,7 +3189,7 @@ GLES3::ShaderData *GLES3::_create_sky_shader_func() {
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);
+ 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() {
@@ -3251,13 +3211,12 @@ void SkyMaterialData::bind_uniforms() {
Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
glActiveTexture(GL_TEXTURE0 + ti);
glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
+ if (texture->render_target) {
+ texture->render_target->used_in_frame = true;
+ }
- // 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);
+ texture->gl_set_filter(filter_from_uniform[int(texture_uniforms[ti].filter)]);
+ texture->gl_set_repeat(repeat_from_uniform[int(texture_uniforms[ti].repeat)]);
}
}
@@ -3288,7 +3247,7 @@ void SceneShaderData::set_code(const String &p_code) {
uses_alpha = false;
uses_alpha_clip = false;
uses_blend_alpha = false;
- uses_depth_pre_pass = false;
+ uses_depth_prepass_alpha = false;
uses_discard = false;
uses_roughness = false;
uses_normal = false;
@@ -3336,14 +3295,14 @@ void SceneShaderData::set_code(const String &p_code) {
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;
+ // Use alpha clip pipeline for alpha hash/dither.
+ // This prevents sorting issues inherent to alpha blending and allows such materials to cast shadows.
+ actions.usage_flag_pointers["ALPHA_HASH_SCALE"] = &uses_alpha_clip;
+ actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_prepass_alpha;
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;
@@ -3396,6 +3355,11 @@ void SceneShaderData::set_code(const String &p_code) {
vertex_input_mask |= uses_bones << 9;
vertex_input_mask |= uses_weights << 10;
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
+ uses_screen_texture = gen_code.uses_screen_texture;
+ uses_depth_texture = gen_code.uses_depth_texture;
+ uses_normal_texture = gen_code.uses_normal_roughness_texture;
+ uses_vertex_time = gen_code.uses_vertex_time;
+ uses_fragment_time = gen_code.uses_fragment_time;
#if 0
print_line("**compiling shader:");
@@ -3435,101 +3399,16 @@ void SceneShaderData::set_code(const String &p_code) {
valid = true;
}
-void SceneShaderData::set_default_texture_parameter(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 ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
- E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
- 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_parameter_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;
+ return (uses_fragment_time && uses_discard) || (uses_vertex_time && uses_vertex);
}
bool SceneShaderData::casts_shadows() const {
- return false;
-}
+ bool has_read_screen_alpha = uses_screen_texture || uses_depth_texture || uses_normal_texture;
+ bool has_base_alpha = (uses_alpha && !uses_alpha_clip) || has_read_screen_alpha;
+ bool has_alpha = has_base_alpha || uses_blend_alpha;
-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();
+ return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED));
}
RS::ShaderNativeSourceCode SceneShaderData::get_native_source_code() const {
@@ -3561,7 +3440,7 @@ void SceneMaterialData::set_next_pass(RID 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);
+ 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() {
@@ -3584,13 +3463,126 @@ void SceneMaterialData::bind_uniforms() {
Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
glActiveTexture(GL_TEXTURE0 + ti);
glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
+ if (texture->render_target) {
+ texture->render_target->used_in_frame = true;
+ }
+
+ texture->gl_set_filter(filter_from_uniform[int(texture_uniforms[ti].filter)]);
+ texture->gl_set_repeat(repeat_from_uniform[int(texture_uniforms[ti].repeat)]);
+ }
+}
+
+/* Particles SHADER */
+
+void ParticlesShaderData::set_code(const String &p_code) {
+ //compile
+
+ code = p_code;
+ valid = false;
+ ubo_size = 0;
+ uniforms.clear();
+ uses_collision = false;
+
+ if (code.is_empty()) {
+ return; //just invalid, but no error
+ }
+
+ ShaderCompiler::GeneratedCode gen_code;
+ ShaderCompiler::IdentifierActions actions;
+ actions.entry_point_stages["start"] = ShaderCompiler::STAGE_VERTEX;
+ actions.entry_point_stages["process"] = ShaderCompiler::STAGE_VERTEX;
+
+ actions.usage_flag_pointers["COLLIDED"] = &uses_collision;
+
+ userdata_count = 0;
+ for (uint32_t i = 0; i < PARTICLES_MAX_USERDATAS; i++) {
+ userdatas_used[i] = false;
+ actions.usage_flag_pointers["USERDATA" + itos(i + 1)] = &userdatas_used[i];
+ }
+
+ actions.uniforms = &uniforms;
+
+ Error err = MaterialStorage::get_singleton()->shaders.compiler_particles.compile(RS::SHADER_PARTICLES, code, &actions, path, gen_code);
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
+
+ if (version.is_null()) {
+ version = MaterialStorage::get_singleton()->shaders.particles_process_shader.version_create();
+ }
+
+ for (uint32_t i = 0; i < PARTICLES_MAX_USERDATAS; i++) {
+ if (userdatas_used[i]) {
+ userdata_count++;
+ }
+ }
+
+ 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.particles_process_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.particles_process_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;
+}
+
+bool ParticlesShaderData::is_animated() const {
+ return false;
+}
+
+bool ParticlesShaderData::casts_shadows() const {
+ return false;
+}
+
+RS::ShaderNativeSourceCode ParticlesShaderData::get_native_source_code() const {
+ return MaterialStorage::get_singleton()->shaders.particles_process_shader.version_get_native_source_code(version);
+}
+
+ParticlesShaderData::~ParticlesShaderData() {
+ if (version.is_valid()) {
+ MaterialStorage::get_singleton()->shaders.particles_process_shader.version_free(version);
+ }
+}
+
+GLES3::ShaderData *GLES3::_create_particles_shader_func() {
+ ParticlesShaderData *shader_data = memnew(ParticlesShaderData);
+ return shader_data;
+}
+
+void ParticleProcessMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+ 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);
+}
+
+ParticleProcessMaterialData::~ParticleProcessMaterialData() {
+}
+
+GLES3::MaterialData *GLES3::_create_particles_material_func(ShaderData *p_shader) {
+ ParticleProcessMaterialData *material_data = memnew(ParticleProcessMaterialData);
+ material_data->shader_data = static_cast<ParticlesShaderData *>(p_shader);
+ //update will happen later anyway so do nothing.
+ return material_data;
+}
+
+void ParticleProcessMaterialData::bind_uniforms() {
+ // Bind Material Uniforms
+ glBindBufferBase(GL_UNIFORM_BUFFER, GLES3::PARTICLES_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 reserved for the heightmap texture.
+ glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
+ if (texture->render_target) {
+ texture->render_target->used_in_frame = true;
+ }
- // 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);
+ texture->gl_set_filter(filter_from_uniform[int(texture_uniforms[ti].filter)]);
+ texture->gl_set_repeat(repeat_from_uniform[int(texture_uniforms[ti].repeat)]);
}
}
diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h
index 65c46631ed..4c5861b017 100644
--- a/drivers/gles3/storage/material_storage.h
+++ b/drivers/gles3/storage/material_storage.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* material_storage.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
@@ -44,6 +44,7 @@
#include "../shaders/canvas.glsl.gen.h"
#include "../shaders/cubemap_filter.glsl.gen.h"
+#include "../shaders/particles.glsl.gen.h"
#include "../shaders/scene.glsl.gen.h"
#include "../shaders/sky.glsl.gen.h"
@@ -52,15 +53,20 @@ namespace GLES3 {
/* Shader Structs */
struct ShaderData {
- virtual void set_code(const String &p_Code) = 0;
- virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index) = 0;
- virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const = 0;
+ String path;
+ HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ HashMap<StringName, HashMap<int, RID>> default_texture_params;
- virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const = 0;
- virtual bool is_parameter_texture(const StringName &p_param) const = 0;
+ virtual void set_path_hint(const String &p_hint);
+ virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ 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_parameter_texture(const StringName &p_param) const;
+
+ virtual void set_code(const String &p_Code) = 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() {}
@@ -147,17 +153,14 @@ struct CanvasShaderData : public ShaderData {
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_screen_texture_mipmaps = false;
@@ -165,14 +168,8 @@ struct CanvasShaderData : public ShaderData {
bool uses_time = false;
virtual void set_code(const String &p_Code);
- virtual void set_default_texture_parameter(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_parameter_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();
@@ -199,15 +196,12 @@ 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;
@@ -216,13 +210,8 @@ struct SkyShaderData : public ShaderData {
bool uses_light;
virtual void set_code(const String &p_Code);
- virtual void set_default_texture_parameter(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_parameter_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();
@@ -280,16 +269,12 @@ struct SceneShaderData : public ShaderData {
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;
@@ -301,7 +286,7 @@ struct SceneShaderData : public ShaderData {
bool uses_alpha;
bool uses_blend_alpha;
bool uses_alpha_clip;
- bool uses_depth_pre_pass;
+ bool uses_depth_prepass_alpha;
bool uses_discard;
bool uses_roughness;
bool uses_normal;
@@ -318,6 +303,8 @@ struct SceneShaderData : public ShaderData {
bool uses_depth_texture;
bool uses_normal_texture;
bool uses_time;
+ bool uses_vertex_time;
+ bool uses_fragment_time;
bool writes_modelview_or_projection;
bool uses_world_coordinates;
bool uses_tangent;
@@ -337,14 +324,8 @@ struct SceneShaderData : public ShaderData {
uint32_t index = 0;
virtual void set_code(const String &p_Code);
- virtual void set_default_texture_parameter(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_parameter_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();
@@ -368,6 +349,53 @@ struct SceneMaterialData : public MaterialData {
MaterialData *_create_scene_material_func(ShaderData *p_shader);
+/* Particle Shader */
+
+enum {
+ PARTICLES_MAX_USERDATAS = 6
+};
+
+struct ParticlesShaderData : public ShaderData {
+ bool valid = false;
+ RID version;
+ bool uses_collision = false;
+
+ Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
+
+ Vector<uint32_t> ubo_offsets;
+ uint32_t ubo_size = 0;
+
+ String code;
+
+ bool uses_time = false;
+
+ bool userdatas_used[PARTICLES_MAX_USERDATAS] = {};
+ uint32_t userdata_count = 0;
+
+ virtual void set_code(const String &p_Code);
+ virtual bool is_animated() const;
+ virtual bool casts_shadows() const;
+ virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+
+ ParticlesShaderData() {}
+ virtual ~ParticlesShaderData();
+};
+
+ShaderData *_create_particles_shader_func();
+
+struct ParticleProcessMaterialData : public MaterialData {
+ ParticlesShaderData *shader_data = nullptr;
+ RID uniform_set;
+
+ 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 ~ParticleProcessMaterialData();
+};
+
+MaterialData *_create_particles_material_func(ShaderData *p_shader);
+
/* Global shader uniform structs */
struct GlobalShaderUniforms {
enum {
@@ -494,7 +522,7 @@ public:
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];
+ p_array[i * 4 + j] = p_mtx.columns[i][j];
}
}
}
@@ -504,6 +532,7 @@ public:
SkyShaderGLES3 sky_shader;
SceneShaderGLES3 scene_shader;
CubemapFilterShaderGLES3 cubemap_filter_shader;
+ ParticlesShaderGLES3 particles_process_shader;
ShaderCompiler compiler_canvas;
ShaderCompiler compiler_scene;
@@ -530,7 +559,7 @@ public:
virtual int32_t global_shader_parameters_instance_allocate(RID p_instance) override;
virtual void global_shader_parameters_instance_free(RID p_instance) override;
- virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value) override;
+ virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value, int p_flags_count = 0) override;
GLuint global_shader_parameters_get_uniform_buffer() const;
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index ddf94af5b8..71f262af20 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* mesh_storage.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
@@ -44,10 +44,16 @@ MeshStorage *MeshStorage::get_singleton() {
MeshStorage::MeshStorage() {
singleton = this;
+
+ {
+ skeleton_shader.shader.initialize();
+ skeleton_shader.shader_version = skeleton_shader.shader.version_create();
+ }
}
MeshStorage::~MeshStorage() {
singleton = nullptr;
+ skeleton_shader.shader.version_free(skeleton_shader.shader_version);
}
/* MESH API */
@@ -87,7 +93,6 @@ void MeshStorage::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count
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;
}
@@ -111,7 +116,6 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
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) {
@@ -245,25 +249,82 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
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 (p_surface.skin_data.size() || mesh->blend_shape_count > 0) {
+ // Size must match the size of the vertex array.
+ int size = p_surface.vertex_data.size();
+ int vertex_size = 0;
+ int stride = 0;
+ int normal_offset = 0;
+ int tangent_offset = 0;
+ if ((p_surface.format & (1 << RS::ARRAY_VERTEX))) {
+ if (p_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
+ vertex_size = 2;
+ } else {
+ vertex_size = 3;
+ }
+ stride = sizeof(float) * vertex_size;
+ }
+ if ((p_surface.format & (1 << RS::ARRAY_NORMAL))) {
+ normal_offset = stride;
+ stride += sizeof(uint16_t) * 2;
+ }
+ if ((p_surface.format & (1 << RS::ARRAY_TANGENT))) {
+ tangent_offset = stride;
+ stride += sizeof(uint16_t) * 2;
+ }
+
+ if (mesh->blend_shape_count > 0) {
+ // Blend shapes are passed as one large array, for OpenGL, we need to split each of them into their own buffer
+ s->blend_shapes = memnew_arr(Mesh::Surface::BlendShape, mesh->blend_shape_count);
+
+ for (uint32_t i = 0; i < mesh->blend_shape_count; i++) {
+ glGenVertexArrays(1, &s->blend_shapes[i].vertex_array);
+ glBindVertexArray(s->blend_shapes[i].vertex_array);
+ glGenBuffers(1, &s->blend_shapes[i].vertex_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, s->blend_shapes[i].vertex_buffer);
+ glBufferData(GL_ARRAY_BUFFER, size, p_surface.blend_shape_data.ptr() + i * size, (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
+
+ if ((p_surface.format & (1 << RS::ARRAY_VERTEX))) {
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX + 3);
+ glVertexAttribPointer(RS::ARRAY_VERTEX + 3, vertex_size, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(0));
+ }
+ if ((p_surface.format & (1 << RS::ARRAY_NORMAL))) {
+ glEnableVertexAttribArray(RS::ARRAY_NORMAL + 3);
+ glVertexAttribPointer(RS::ARRAY_NORMAL + 3, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(normal_offset));
+ }
+ if ((p_surface.format & (1 << RS::ARRAY_TANGENT))) {
+ glEnableVertexAttribArray(RS::ARRAY_TANGENT + 3);
+ glVertexAttribPointer(RS::ARRAY_TANGENT + 3, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(tangent_offset));
+ }
+ }
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+
+ // Create a vertex array to use for skeleton/blend shapes.
+ glGenVertexArrays(1, &s->skeleton_vertex_array);
+ glBindVertexArray(s->skeleton_vertex_array);
+ glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer);
+
+ if ((p_surface.format & (1 << RS::ARRAY_VERTEX))) {
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, vertex_size, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(0));
+ }
+ if ((p_surface.format & (1 << RS::ARRAY_NORMAL))) {
+ glEnableVertexAttribArray(RS::ARRAY_NORMAL);
+ glVertexAttribPointer(RS::ARRAY_NORMAL, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(normal_offset));
+ }
+ if ((p_surface.format & (1 << RS::ARRAY_TANGENT))) {
+ glEnableVertexAttribArray(RS::ARRAY_TANGENT);
+ glVertexAttribPointer(RS::ARRAY_TANGENT, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(tangent_offset));
+ }
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
}
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++) {
- const AABB &bone = p_surface.bone_aabbs[i];
- if (!bone.has_no_volume()) {
- mesh->bone_aabbs.write[i].merge_with(bone);
- }
- }
mesh->aabb.merge_with(p_surface.aabb);
}
@@ -309,12 +370,48 @@ RS::BlendShapeMode MeshStorage::mesh_get_blend_shape_mode(RID p_mesh) const {
}
void MeshStorage::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+ ERR_FAIL_COND(p_data.size() == 0);
+
+ uint64_t data_size = p_data.size();
+ ERR_FAIL_COND(p_offset + data_size > mesh->surfaces[p_surface]->vertex_buffer_size);
+ const uint8_t *r = p_data.ptr();
+
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->surfaces[p_surface]->vertex_buffer);
+ glBufferSubData(GL_ARRAY_BUFFER, p_offset, data_size, r);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void MeshStorage::mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+ ERR_FAIL_COND(p_data.size() == 0);
+
+ uint64_t data_size = p_data.size();
+ ERR_FAIL_COND(p_offset + data_size > mesh->surfaces[p_surface]->attribute_buffer_size);
+ const uint8_t *r = p_data.ptr();
+
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->surfaces[p_surface]->attribute_buffer);
+ glBufferSubData(GL_ARRAY_BUFFER, p_offset, data_size, r);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void MeshStorage::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+ ERR_FAIL_COND(p_data.size() == 0);
+
+ uint64_t data_size = p_data.size();
+ ERR_FAIL_COND(p_offset + data_size > mesh->surfaces[p_surface]->skin_buffer_size);
+ const uint8_t *r = p_data.ptr();
+
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->surfaces[p_surface]->skin_buffer);
+ glBufferSubData(GL_ARRAY_BUFFER, p_offset, data_size, r);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void MeshStorage::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) {
@@ -352,6 +449,10 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
sd.attribute_data = Utilities::buffer_get_data(GL_ARRAY_BUFFER, s.attribute_buffer, s.attribute_buffer_size);
}
+ if (s.skin_buffer != 0) {
+ sd.skin_data = Utilities::buffer_get_data(GL_ARRAY_BUFFER, s.skin_buffer, s.skin_buffer_size);
+ }
+
sd.vertex_count = s.vertex_count;
sd.index_count = s.index_count;
sd.primitive = s.primitive;
@@ -369,7 +470,13 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
}
sd.bone_aabbs = s.bone_aabbs;
- glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ if (mesh->blend_shape_count) {
+ sd.blend_shape_data = Vector<uint8_t>();
+ for (uint32_t i = 0; i < mesh->blend_shape_count; i++) {
+ sd.blend_shape_data.append_array(Utilities::buffer_get_data(GL_ARRAY_BUFFER, s.blend_shapes[i].vertex_buffer, s.vertex_buffer_size));
+ }
+ }
return sd;
}
@@ -402,7 +509,7 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- if (!skeleton || skeleton->size == 0) {
+ if (!skeleton || skeleton->size == 0 || mesh->skeleton_aabb_version == skeleton->version) {
return mesh->aabb;
}
@@ -496,6 +603,8 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
}
}
+ mesh->aabb = aabb;
+ mesh->skeleton_aabb_version = skeleton->version;
return aabb;
}
@@ -550,6 +659,39 @@ void MeshStorage::mesh_clear(RID p_mesh) {
glDeleteBuffers(1, &s.index_buffer);
s.index_buffer = 0;
}
+
+ if (s.versions) {
+ memfree(s.versions); //reallocs, so free with memfree.
+ }
+
+ if (s.lod_count) {
+ for (uint32_t j = 0; j < s.lod_count; j++) {
+ if (s.lods[j].index_buffer != 0) {
+ glDeleteBuffers(1, &s.lods[j].index_buffer);
+ s.lods[j].index_buffer = 0;
+ }
+ }
+ memdelete_arr(s.lods);
+ }
+
+ if (mesh->blend_shape_count) {
+ for (uint32_t j = 0; j < mesh->blend_shape_count; j++) {
+ if (s.blend_shapes[j].vertex_buffer != 0) {
+ glDeleteBuffers(1, &s.blend_shapes[j].vertex_buffer);
+ s.blend_shapes[j].vertex_buffer = 0;
+ }
+ if (s.blend_shapes[j].vertex_array != 0) {
+ glDeleteVertexArrays(1, &s.blend_shapes[j].vertex_array);
+ s.blend_shapes[j].vertex_array = 0;
+ }
+ }
+ memdelete_arr(s.blend_shapes);
+ }
+ if (s.skeleton_vertex_array != 0) {
+ glDeleteVertexArrays(1, &s.skeleton_vertex_array);
+ s.skeleton_vertex_array = 0;
+ }
+
memdelete(mesh->surfaces[i]);
}
if (mesh->surfaces) {
@@ -605,15 +747,15 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
case RS::ARRAY_NORMAL: {
attribs[i].offset = vertex_stride;
attribs[i].size = 2;
- attribs[i].type = GL_UNSIGNED_SHORT;
- vertex_stride += sizeof(uint16_t) * 2;
+ attribs[i].type = (mis ? GL_FLOAT : GL_UNSIGNED_SHORT);
+ vertex_stride += sizeof(uint16_t) * 2 * (mis ? 2 : 1);
attribs[i].normalized = GL_TRUE;
} break;
case RS::ARRAY_TANGENT: {
attribs[i].offset = vertex_stride;
attribs[i].size = 2;
- attribs[i].type = GL_UNSIGNED_SHORT;
- vertex_stride += sizeof(uint16_t) * 2;
+ attribs[i].type = (mis ? GL_FLOAT : GL_UNSIGNED_SHORT);
+ vertex_stride += sizeof(uint16_t) * 2 * (mis ? 2 : 1);
attribs[i].normalized = GL_TRUE;
} break;
case RS::ARRAY_COLOR: {
@@ -658,7 +800,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
attribs[i].offset = skin_stride;
attribs[i].size = 4;
attribs[i].type = GL_UNSIGNED_SHORT;
- attributes_stride += 4 * sizeof(uint16_t);
+ skin_stride += 4 * sizeof(uint16_t);
attribs[i].normalized = GL_FALSE;
attribs[i].integer = true;
} break;
@@ -666,7 +808,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
attribs[i].offset = skin_stride;
attribs[i].size = 4;
attribs[i].type = GL_UNSIGNED_SHORT;
- attributes_stride += 4 * sizeof(uint16_t);
+ skin_stride += 4 * sizeof(uint16_t);
attribs[i].normalized = GL_TRUE;
} break;
}
@@ -757,7 +899,7 @@ void MeshStorage::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int
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;
+ mi->dirty = true;
}
void MeshStorage::_mesh_instance_clear(MeshInstance *mi) {
@@ -769,38 +911,65 @@ void MeshStorage::_mesh_instance_clear(MeshInstance *mi) {
}
memfree(mi->surfaces[i].versions);
}
+
+ if (mi->surfaces[i].vertex_buffers[0] != 0) {
+ glDeleteBuffers(2, mi->surfaces[i].vertex_buffers);
+ mi->surfaces[i].vertex_buffers[0] = 0;
+ mi->surfaces[i].vertex_buffers[1] = 0;
+ }
+
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) {
+ if (mesh->blend_shape_count > 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;
+ mi->blend_weights[i] = 0.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);
+ if ((mesh->blend_shape_count > 0 || (mesh->surfaces[p_surface]->format & RS::ARRAY_FORMAT_BONES)) && mesh->surfaces[p_surface]->vertex_buffer_size > 0) {
+ // Cache surface properties
+ s.format_cache = mesh->surfaces[p_surface]->format;
+ if ((s.format_cache & (1 << RS::ARRAY_VERTEX))) {
+ if (s.format_cache & RS::ARRAY_FLAG_USE_2D_VERTICES) {
+ s.vertex_size_cache = 2;
+ } else {
+ s.vertex_size_cache = 3;
+ }
+ s.vertex_stride_cache = sizeof(float) * s.vertex_size_cache;
+ }
+ if ((s.format_cache & (1 << RS::ARRAY_NORMAL))) {
+ s.vertex_normal_offset_cache = s.vertex_stride_cache;
+ s.vertex_stride_cache += sizeof(uint32_t) * 2;
+ }
+ if ((s.format_cache & (1 << RS::ARRAY_TANGENT))) {
+ s.vertex_tangent_offset_cache = s.vertex_stride_cache;
+ s.vertex_stride_cache += sizeof(uint32_t) * 2;
+ }
+
+ // Buffer to be used for rendering. Final output of skeleton and blend shapes.
+ glGenBuffers(1, &s.vertex_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, s.vertex_buffer);
+ glBufferData(GL_ARRAY_BUFFER, s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count, nullptr, GL_DYNAMIC_DRAW);
+ if (mesh->blend_shape_count > 0) {
+ // Ping-Pong buffers for processing blendshapes.
+ glGenBuffers(2, s.vertex_buffers);
+ for (uint32_t i = 0; i < 2; i++) {
+ glBindBuffer(GL_ARRAY_BUFFER, s.vertex_buffers[i]);
+ glBufferData(GL_ARRAY_BUFFER, s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count, nullptr, GL_DYNAMIC_DRAW);
+ }
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
}
mi->surfaces.push_back(s);
@@ -812,11 +981,6 @@ void MeshStorage::mesh_instance_check_for_update(RID 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;
}
@@ -833,22 +997,223 @@ void MeshStorage::mesh_instance_check_for_update(RID p_mesh_instance) {
}
}
-void MeshStorage::update_mesh_instances() {
- while (dirty_mesh_instance_weights.first()) {
- MeshInstance *mi = dirty_mesh_instance_weights.first()->self();
+void MeshStorage::_blend_shape_bind_mesh_instance_buffer(MeshInstance *p_mi, uint32_t p_surface) {
+ glBindBuffer(GL_ARRAY_BUFFER, p_mi->surfaces[p_surface].vertex_buffers[0]);
- 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 ((p_mi->surfaces[p_surface].format_cache & (1 << RS::ARRAY_VERTEX))) {
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, p_mi->surfaces[p_surface].vertex_size_cache, GL_FLOAT, GL_FALSE, p_mi->surfaces[p_surface].vertex_stride_cache, CAST_INT_TO_UCHAR_PTR(0));
+ } else {
+ glDisableVertexAttribArray(RS::ARRAY_VERTEX);
+ }
+ if ((p_mi->surfaces[p_surface].format_cache & (1 << RS::ARRAY_NORMAL))) {
+ glEnableVertexAttribArray(RS::ARRAY_NORMAL);
+ glVertexAttribIPointer(RS::ARRAY_NORMAL, 2, GL_UNSIGNED_INT, p_mi->surfaces[p_surface].vertex_stride_cache, CAST_INT_TO_UCHAR_PTR(p_mi->surfaces[p_surface].vertex_normal_offset_cache));
+ } else {
+ glDisableVertexAttribArray(RS::ARRAY_NORMAL);
+ }
+ if ((p_mi->surfaces[p_surface].format_cache & (1 << RS::ARRAY_TANGENT))) {
+ glEnableVertexAttribArray(RS::ARRAY_TANGENT);
+ glVertexAttribIPointer(RS::ARRAY_TANGENT, 2, GL_UNSIGNED_INT, p_mi->surfaces[p_surface].vertex_stride_cache, CAST_INT_TO_UCHAR_PTR(p_mi->surfaces[p_surface].vertex_tangent_offset_cache));
+ } else {
+ glDisableVertexAttribArray(RS::ARRAY_TANGENT);
+ }
+}
+
+void MeshStorage::_compute_skeleton(MeshInstance *p_mi, Skeleton *p_sk, uint32_t p_surface) {
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ // Add in the bones and weights.
+ glBindBuffer(GL_ARRAY_BUFFER, p_mi->mesh->surfaces[p_surface]->skin_buffer);
+
+ bool use_8_weights = p_mi->surfaces[p_surface].format_cache & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
+ int skin_stride = sizeof(int16_t) * (use_8_weights ? 16 : 8);
+ glEnableVertexAttribArray(RS::ARRAY_BONES);
+ glVertexAttribIPointer(RS::ARRAY_BONES, 4, GL_UNSIGNED_SHORT, skin_stride, CAST_INT_TO_UCHAR_PTR(0));
+ if (use_8_weights) {
+ glEnableVertexAttribArray(11);
+ glVertexAttribIPointer(11, 4, GL_UNSIGNED_SHORT, skin_stride, CAST_INT_TO_UCHAR_PTR(4 * sizeof(uint16_t)));
+ glEnableVertexAttribArray(12);
+ glVertexAttribPointer(12, 4, GL_UNSIGNED_SHORT, GL_TRUE, skin_stride, CAST_INT_TO_UCHAR_PTR(8 * sizeof(uint16_t)));
+ glEnableVertexAttribArray(13);
+ glVertexAttribPointer(13, 4, GL_UNSIGNED_SHORT, GL_TRUE, skin_stride, CAST_INT_TO_UCHAR_PTR(12 * sizeof(uint16_t)));
+ } else {
+ glEnableVertexAttribArray(RS::ARRAY_WEIGHTS);
+ glVertexAttribPointer(RS::ARRAY_WEIGHTS, 4, GL_UNSIGNED_SHORT, GL_TRUE, skin_stride, CAST_INT_TO_UCHAR_PTR(4 * sizeof(uint16_t)));
}
+
+ glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, p_mi->surfaces[p_surface].vertex_buffer);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, p_sk->transforms_texture);
+
+ glBeginTransformFeedback(GL_POINTS);
+ glDrawArrays(GL_POINTS, 0, p_mi->mesh->surfaces[p_surface]->vertex_count);
+ glEndTransformFeedback();
+
+ glDisableVertexAttribArray(RS::ARRAY_BONES);
+ glDisableVertexAttribArray(RS::ARRAY_WEIGHTS);
+ glDisableVertexAttribArray(RS::ARRAY_BONES + 2);
+ glDisableVertexAttribArray(RS::ARRAY_WEIGHTS + 2);
+ glBindVertexArray(0);
+ glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
+}
+
+void MeshStorage::update_mesh_instances() {
if (dirty_mesh_instance_arrays.first() == nullptr) {
return; //nothing to do
}
+ glEnable(GL_RASTERIZER_DISCARD);
// Process skeletons and blend shapes using transform feedback
- // TODO: Implement when working on skeletons and blend shapes
+ while (dirty_mesh_instance_arrays.first()) {
+ MeshInstance *mi = dirty_mesh_instance_arrays.first()->self();
+
+ Skeleton *sk = skeleton_owner.get_or_null(mi->skeleton);
+
+ // Precompute base weight if using blend shapes.
+ float base_weight = 1.0;
+ if (mi->mesh->blend_shape_count && mi->mesh->blend_shape_mode == RS::BLEND_SHAPE_MODE_NORMALIZED) {
+ for (uint32_t i = 0; i < mi->mesh->blend_shape_count; i++) {
+ base_weight -= mi->blend_weights[i];
+ }
+ }
+
+ for (uint32_t i = 0; i < mi->surfaces.size(); i++) {
+ if (mi->surfaces[i].vertex_buffer == 0 || mi->mesh->surfaces[i]->skeleton_vertex_array == 0) {
+ continue;
+ }
+
+ bool array_is_2d = mi->surfaces[i].format_cache & RS::ARRAY_FLAG_USE_2D_VERTICES;
+ bool can_use_skeleton = sk != nullptr && sk->use_2d == array_is_2d && (mi->surfaces[i].format_cache & RS::ARRAY_FORMAT_BONES);
+ bool use_8_weights = mi->surfaces[i].format_cache & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
+
+ // Always process blend shapes first.
+ if (mi->mesh->blend_shape_count) {
+ SkeletonShaderGLES3::ShaderVariant variant = SkeletonShaderGLES3::MODE_BASE_PASS;
+ uint64_t specialization = 0;
+ specialization |= array_is_2d ? SkeletonShaderGLES3::MODE_2D : 0;
+ specialization |= SkeletonShaderGLES3::USE_BLEND_SHAPES;
+ if (!array_is_2d) {
+ if ((mi->surfaces[i].format_cache & (1 << RS::ARRAY_NORMAL))) {
+ specialization |= SkeletonShaderGLES3::USE_NORMAL;
+ }
+ if ((mi->surfaces[i].format_cache & (1 << RS::ARRAY_TANGENT))) {
+ specialization |= SkeletonShaderGLES3::USE_TANGENT;
+ }
+ }
+
+ bool success = skeleton_shader.shader.version_bind_shader(skeleton_shader.shader_version, variant, specialization);
+ if (!success) {
+ continue;
+ }
+
+ skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::BLEND_WEIGHT, base_weight, skeleton_shader.shader_version, variant, specialization);
+ skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::BLEND_SHAPE_COUNT, float(mi->mesh->blend_shape_count), skeleton_shader.shader_version, variant, specialization);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindVertexArray(mi->mesh->surfaces[i]->skeleton_vertex_array);
+ glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mi->surfaces[i].vertex_buffers[0]);
+ glBeginTransformFeedback(GL_POINTS);
+ glDrawArrays(GL_POINTS, 0, mi->mesh->surfaces[i]->vertex_count);
+ glEndTransformFeedback();
+
+ variant = SkeletonShaderGLES3::MODE_BLEND_PASS;
+ success = skeleton_shader.shader.version_bind_shader(skeleton_shader.shader_version, variant, specialization);
+ if (!success) {
+ continue;
+ }
+
+ //Do the last blend shape separately, as it can be combined with the skeleton pass.
+ for (uint32_t bs = 0; bs < mi->mesh->blend_shape_count - 1; bs++) {
+ float weight = mi->blend_weights[bs];
+
+ if (Math::is_zero_approx(weight)) {
+ //not bother with this one
+ continue;
+ }
+ skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::BLEND_WEIGHT, weight, skeleton_shader.shader_version, variant, specialization);
+ skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::BLEND_SHAPE_COUNT, float(mi->mesh->blend_shape_count), skeleton_shader.shader_version, variant, specialization);
+
+ glBindVertexArray(mi->mesh->surfaces[i]->blend_shapes[bs].vertex_array);
+ _blend_shape_bind_mesh_instance_buffer(mi, i);
+ glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mi->surfaces[i].vertex_buffers[1]);
+
+ glBeginTransformFeedback(GL_POINTS);
+ glDrawArrays(GL_POINTS, 0, mi->mesh->surfaces[i]->vertex_count);
+ glEndTransformFeedback();
+
+ SWAP(mi->surfaces[i].vertex_buffers[0], mi->surfaces[i].vertex_buffers[1]);
+ }
+ uint32_t bs = mi->mesh->blend_shape_count - 1;
+
+ float weight = mi->blend_weights[bs];
+
+ glBindVertexArray(mi->mesh->surfaces[i]->blend_shapes[bs].vertex_array);
+ _blend_shape_bind_mesh_instance_buffer(mi, i);
+
+ specialization |= can_use_skeleton ? SkeletonShaderGLES3::USE_SKELETON : 0;
+ specialization |= (can_use_skeleton && use_8_weights) ? SkeletonShaderGLES3::USE_EIGHT_WEIGHTS : 0;
+ specialization |= SkeletonShaderGLES3::FINAL_PASS;
+ success = skeleton_shader.shader.version_bind_shader(skeleton_shader.shader_version, variant, specialization);
+ if (!success) {
+ continue;
+ }
+
+ skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::BLEND_WEIGHT, weight, skeleton_shader.shader_version, variant, specialization);
+ skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::BLEND_SHAPE_COUNT, float(mi->mesh->blend_shape_count), skeleton_shader.shader_version, variant, specialization);
+
+ if (can_use_skeleton) {
+ // Do last blendshape in the same pass as the Skeleton.
+ _compute_skeleton(mi, sk, i);
+ can_use_skeleton = false;
+ } else {
+ // Do last blendshape by itself and prepare vertex data for use by the renderer.
+ glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mi->surfaces[i].vertex_buffer);
+
+ glBeginTransformFeedback(GL_POINTS);
+ glDrawArrays(GL_POINTS, 0, mi->mesh->surfaces[i]->vertex_count);
+ glEndTransformFeedback();
+ }
+
+ glBindVertexArray(0);
+ glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
+ }
+
+ // This branch should only execute when Skeleton is run by itself.
+ if (can_use_skeleton) {
+ SkeletonShaderGLES3::ShaderVariant variant = SkeletonShaderGLES3::MODE_BASE_PASS;
+ uint64_t specialization = 0;
+ specialization |= array_is_2d ? SkeletonShaderGLES3::MODE_2D : 0;
+ specialization |= SkeletonShaderGLES3::USE_SKELETON;
+ specialization |= SkeletonShaderGLES3::FINAL_PASS;
+ specialization |= use_8_weights ? SkeletonShaderGLES3::USE_EIGHT_WEIGHTS : 0;
+ if (!array_is_2d) {
+ if ((mi->surfaces[i].format_cache & (1 << RS::ARRAY_NORMAL))) {
+ specialization |= SkeletonShaderGLES3::USE_NORMAL;
+ }
+ if ((mi->surfaces[i].format_cache & (1 << RS::ARRAY_TANGENT))) {
+ specialization |= SkeletonShaderGLES3::USE_TANGENT;
+ }
+ }
+
+ bool success = skeleton_shader.shader.version_bind_shader(skeleton_shader.shader_version, variant, specialization);
+ if (!success) {
+ continue;
+ }
+
+ glBindVertexArray(mi->mesh->surfaces[i]->skeleton_vertex_array);
+ _compute_skeleton(mi, sk, i);
+ }
+ }
+ mi->dirty = false;
+ if (sk) {
+ mi->skeleton_version = sk->version;
+ }
+ dirty_mesh_instance_arrays.remove(&mi->array_update_list);
+ }
+ glDisable(GL_RASTERIZER_DISCARD);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
}
/* MULTIMESH API */
@@ -949,7 +1314,7 @@ void MeshStorage::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
#define MULTIMESH_DIRTY_REGION_SIZE 512
void MeshStorage::_multimesh_make_local(MultiMesh *multimesh) const {
- if (multimesh->data_cache.size() > 0) {
+ if (multimesh->data_cache.size() > 0 || multimesh->instances == 0) {
return; //already local
}
ERR_FAIL_COND(multimesh->data_cache.size() > 0);
@@ -1366,7 +1731,7 @@ 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) {
+ if (multimesh->buffer == 0 || multimesh->instances == 0) {
return Vector<float>();
} else if (multimesh->data_cache.size()) {
ret = multimesh->data_cache;
@@ -1519,45 +1884,207 @@ void MeshStorage::_update_dirty_multimeshes() {
/* SKELETON API */
RID MeshStorage::skeleton_allocate() {
- return RID();
+ return skeleton_owner.allocate_rid();
}
void MeshStorage::skeleton_initialize(RID p_rid) {
+ skeleton_owner.initialize_rid(p_rid, Skeleton());
}
void MeshStorage::skeleton_free(RID p_rid) {
+ _update_dirty_skeletons();
+ skeleton_allocate_data(p_rid, 0);
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_rid);
+ skeleton->dependency.deleted_notify(p_rid);
+ skeleton_owner.free(p_rid);
+}
+
+void MeshStorage::_skeleton_make_dirty(Skeleton *skeleton) {
+ if (!skeleton->dirty) {
+ skeleton->dirty = true;
+ skeleton->dirty_list = skeleton_dirty_list;
+ skeleton_dirty_list = skeleton;
+ }
}
void MeshStorage::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton) {
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+ ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_COND(p_bones < 0);
+
+ if (skeleton->size == p_bones && skeleton->use_2d == p_2d_skeleton) {
+ return;
+ }
+
+ skeleton->size = p_bones;
+ skeleton->use_2d = p_2d_skeleton;
+ skeleton->height = (p_bones * (p_2d_skeleton ? 2 : 3)) / 256;
+ if ((p_bones * (p_2d_skeleton ? 2 : 3)) % 256) {
+ skeleton->height++;
+ }
+
+ if (skeleton->transforms_texture != 0) {
+ glDeleteTextures(1, &skeleton->transforms_texture);
+ skeleton->transforms_texture = 0;
+ skeleton->data.clear();
+ }
+
+ if (skeleton->size) {
+ skeleton->data.resize(256 * skeleton->height * 4);
+ glGenTextures(1, &skeleton->transforms_texture);
+ glBindTexture(GL_TEXTURE_2D, skeleton->transforms_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 256, skeleton->height, 0, GL_RGBA, GL_FLOAT, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ memset(skeleton->data.ptrw(), 0, skeleton->data.size() * sizeof(float));
+
+ _skeleton_make_dirty(skeleton);
+ }
+
+ skeleton->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_SKELETON_DATA);
}
void MeshStorage::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) {
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+
+ ERR_FAIL_NULL(skeleton);
+ ERR_FAIL_COND(!skeleton->use_2d);
+
+ skeleton->base_transform_2d = p_base_transform;
}
int MeshStorage::skeleton_get_bone_count(RID p_skeleton) const {
- return 0;
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+ ERR_FAIL_COND_V(!skeleton, 0);
+
+ return skeleton->size;
}
void MeshStorage::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) {
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+
+ ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_INDEX(p_bone, skeleton->size);
+ ERR_FAIL_COND(skeleton->use_2d);
+
+ float *dataptr = skeleton->data.ptrw() + p_bone * 12;
+
+ 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;
+
+ _skeleton_make_dirty(skeleton);
}
Transform3D MeshStorage::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const {
- return Transform3D();
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+
+ ERR_FAIL_COND_V(!skeleton, Transform3D());
+ ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform3D());
+ ERR_FAIL_COND_V(skeleton->use_2d, Transform3D());
+
+ const float *dataptr = skeleton->data.ptr() + p_bone * 12;
+
+ Transform3D t;
+
+ 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;
}
void MeshStorage::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) {
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+
+ ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_INDEX(p_bone, skeleton->size);
+ ERR_FAIL_COND(!skeleton->use_2d);
+
+ float *dataptr = skeleton->data.ptrw() + p_bone * 8;
+
+ 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];
+
+ _skeleton_make_dirty(skeleton);
}
Transform2D MeshStorage::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const {
- return Transform2D();
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+
+ ERR_FAIL_COND_V(!skeleton, Transform2D());
+ ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform2D());
+ ERR_FAIL_COND_V(!skeleton->use_2d, Transform2D());
+
+ const float *dataptr = skeleton->data.ptr() + p_bone * 8;
+
+ Transform2D t;
+ 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;
}
-void MeshStorage::skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) {
+void MeshStorage::_update_dirty_skeletons() {
+ while (skeleton_dirty_list) {
+ Skeleton *skeleton = skeleton_dirty_list;
+
+ if (skeleton->size) {
+ glBindTexture(GL_TEXTURE_2D, skeleton->transforms_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 256, skeleton->height, 0, GL_RGBA, GL_FLOAT, skeleton->data.ptr());
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ skeleton_dirty_list = skeleton->dirty_list;
+
+ skeleton->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_SKELETON_BONES);
+
+ skeleton->version++;
+
+ skeleton->dirty = false;
+ skeleton->dirty_list = nullptr;
+ }
+
+ skeleton_dirty_list = nullptr;
}
-/* OCCLUDER */
+void MeshStorage::skeleton_update_dependency(RID p_skeleton, DependencyTracker *p_instance) {
+ Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
+ ERR_FAIL_COND(!skeleton);
-void MeshStorage::occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) {
+ p_instance->update_dependency(&skeleton->dependency);
}
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h
index 74f5800795..2efc57462b 100644
--- a/drivers/gles3/storage/mesh_storage.h
+++ b/drivers/gles3/storage/mesh_storage.h
@@ -1,38 +1,39 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* mesh_storage.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 "../shaders/skeleton.glsl.gen.h"
#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
@@ -102,7 +103,13 @@ struct Mesh {
Vector<AABB> bone_aabbs;
- GLuint blend_shape_buffer = 0;
+ struct BlendShape {
+ GLuint vertex_buffer = 0;
+ GLuint vertex_array = 0;
+ };
+
+ BlendShape *blend_shapes = nullptr;
+ GLuint skeleton_vertex_array = 0;
RID material;
};
@@ -113,12 +120,11 @@ struct Mesh {
Surface **surfaces = nullptr;
uint32_t surface_count = 0;
- Vector<AABB> bone_aabbs;
-
bool has_bone_weights = false;
AABB aabb;
AABB custom_aabb;
+ uint64_t skeleton_aabb_version = 0;
Vector<RID> material_cache;
@@ -136,7 +142,14 @@ struct MeshInstance {
Mesh *mesh = nullptr;
RID skeleton;
struct Surface {
+ GLuint vertex_buffers[2] = { 0, 0 };
+ GLuint vertex_arrays[2] = { 0, 0 };
GLuint vertex_buffer = 0;
+ int vertex_stride_cache = 0;
+ int vertex_size_cache = 0;
+ int vertex_normal_offset_cache = 0;
+ int vertex_tangent_offset_cache = 0;
+ uint32_t format_cache = 0;
Mesh::Surface::Version *versions = nullptr; //allocated on demand
uint32_t version_count = 0;
@@ -144,7 +157,6 @@ struct MeshInstance {
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;
@@ -186,13 +198,15 @@ struct MultiMesh {
struct Skeleton {
bool use_2d = false;
int size = 0;
+ int height = 0;
Vector<float> data;
- GLuint buffer = 0;
bool dirty = false;
Skeleton *dirty_list = nullptr;
Transform2D base_transform_2d;
+ GLuint transforms_texture = 0;
+
uint64_t version = 1;
Dependency dependency;
@@ -202,6 +216,11 @@ class MeshStorage : public RendererMeshStorage {
private:
static MeshStorage *singleton;
+ struct {
+ SkeletonShaderGLES3 shader;
+ RID shader_version;
+ } skeleton_shader;
+
/* Mesh */
mutable RID_Owner<Mesh, true> mesh_owner;
@@ -214,6 +233,7 @@ private:
void _mesh_instance_clear(MeshInstance *mi);
void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface);
+ void _blend_shape_bind_mesh_instance_buffer(MeshInstance *p_mi, uint32_t p_surface);
SelfList<MeshInstance>::List dirty_mesh_instance_weights;
SelfList<MeshInstance>::List dirty_mesh_instance_arrays;
@@ -232,9 +252,10 @@ private:
mutable RID_Owner<Skeleton, true> skeleton_owner;
- Skeleton *skeleton_dirty_list = nullptr;
-
_FORCE_INLINE_ void _skeleton_make_dirty(Skeleton *skeleton);
+ void _compute_skeleton(MeshInstance *p_mi, Skeleton *p_sk, uint32_t p_surface);
+
+ Skeleton *skeleton_dirty_list = nullptr;
public:
static MeshStorage *get_singleton();
@@ -325,13 +346,13 @@ public:
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 {
+ _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) const {
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+ ERR_FAIL_COND_V(!s, 0);
int32_t current_lod = -1;
- if (r_index_count) {
- *r_index_count = s->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) {
@@ -342,9 +363,7 @@ public:
if (current_lod == -1) {
return 0;
} else {
- if (r_index_count) {
- *r_index_count = s->lods[current_lod].index_count;
- }
+ r_index_count = s->lods[current_lod].index_count;
return current_lod + 1;
}
}
@@ -406,6 +425,8 @@ public:
virtual void mesh_instance_check_for_update(RID p_mesh_instance) override;
virtual void update_mesh_instances() override;
+ // TODO: considering hashing versions with multimesh buffer RID.
+ // Doing so would allow us to avoid specifying multimesh buffer pointers every frame and may improve performance.
_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);
@@ -534,9 +555,11 @@ public:
virtual void skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) override;
- /* OCCLUDER */
+ void _update_dirty_skeletons();
- void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices);
+ _FORCE_INLINE_ bool skeleton_is_valid(RID p_skeleton) {
+ return skeleton_owner.get_or_null(p_skeleton) != nullptr;
+ }
};
} // namespace GLES3
diff --git a/drivers/gles3/storage/particles_storage.cpp b/drivers/gles3/storage/particles_storage.cpp
index 9ed9fedd5a..2b47271408 100644
--- a/drivers/gles3/storage/particles_storage.cpp
+++ b/drivers/gles3/storage/particles_storage.cpp
@@ -1,36 +1,42 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* particles_storage.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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"
+#include "material_storage.h"
+#include "mesh_storage.h"
+#include "texture_storage.h"
+#include "utilities.h"
+
+#include "servers/rendering/rendering_server_default.h"
using namespace GLES3;
@@ -42,213 +48,1347 @@ ParticlesStorage *ParticlesStorage::get_singleton() {
ParticlesStorage::ParticlesStorage() {
singleton = this;
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+
+ {
+ String global_defines;
+ global_defines += "#define MAX_GLOBAL_SHADER_UNIFORMS 256\n"; // TODO: this is arbitrary for now
+ material_storage->shaders.particles_process_shader.initialize(global_defines, 1);
+ }
+ {
+ // default material and shader for particles shader
+ particles_shader.default_shader = material_storage->shader_allocate();
+ material_storage->shader_initialize(particles_shader.default_shader);
+ material_storage->shader_set_code(particles_shader.default_shader, R"(
+// Default particles shader.
+
+shader_type particles;
+
+void process() {
+ COLOR = vec4(1.0);
+}
+)");
+ particles_shader.default_material = material_storage->material_allocate();
+ material_storage->material_initialize(particles_shader.default_material);
+ material_storage->material_set_shader(particles_shader.default_material, particles_shader.default_shader);
+ }
+ {
+ particles_shader.copy_shader.initialize();
+ particles_shader.copy_shader_version = particles_shader.copy_shader.version_create();
+ }
}
ParticlesStorage::~ParticlesStorage() {
singleton = nullptr;
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+
+ material_storage->material_free(particles_shader.default_material);
+ material_storage->shader_free(particles_shader.default_shader);
+ particles_shader.copy_shader.version_free(particles_shader.copy_shader_version);
}
/* PARTICLES */
RID ParticlesStorage::particles_allocate() {
- return RID();
+ return particles_owner.allocate_rid();
}
void ParticlesStorage::particles_initialize(RID p_rid) {
+ particles_owner.initialize_rid(p_rid, Particles());
}
void ParticlesStorage::particles_free(RID p_rid) {
+ update_particles();
+ Particles *particles = particles_owner.get_or_null(p_rid);
+ particles->dependency.deleted_notify(p_rid);
+ _particles_free_data(particles);
+ particles_owner.free(p_rid);
}
void ParticlesStorage::particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) {
-}
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+ if (particles->mode == p_mode) {
+ return;
+ }
-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) {
+ _particles_free_data(particles);
+
+ particles->mode = p_mode;
}
void ParticlesStorage::particles_set_emitting(RID p_particles, bool p_emitting) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->emitting = p_emitting;
+}
+
+bool ParticlesStorage::particles_get_emitting(RID p_particles) {
+ ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer.");
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND_V(!particles, false);
+
+ return particles->emitting;
+}
+
+void ParticlesStorage::_particles_free_data(Particles *particles) {
+ particles->userdata_count = 0;
+ particles->instance_buffer_size_cache = 0;
+ particles->instance_buffer_stride_cache = 0;
+ particles->num_attrib_arrays_cache = 0;
+ particles->process_buffer_stride_cache = 0;
+
+ if (particles->front_process_buffer != 0) {
+ glDeleteVertexArrays(1, &particles->front_vertex_array);
+ glDeleteBuffers(1, &particles->front_process_buffer);
+ glDeleteBuffers(1, &particles->front_instance_buffer);
+ particles->front_vertex_array = 0;
+ particles->front_process_buffer = 0;
+ particles->front_instance_buffer = 0;
+
+ glDeleteVertexArrays(1, &particles->back_vertex_array);
+ glDeleteBuffers(1, &particles->back_process_buffer);
+ glDeleteBuffers(1, &particles->back_instance_buffer);
+ particles->back_vertex_array = 0;
+ particles->back_process_buffer = 0;
+ particles->back_instance_buffer = 0;
+ }
+
+ if (particles->sort_buffer != 0) {
+ glDeleteBuffers(1, &particles->last_frame_buffer);
+ glDeleteBuffers(1, &particles->sort_buffer);
+ particles->last_frame_buffer = 0;
+ particles->sort_buffer = 0;
+ particles->sort_buffer_filled = false;
+ particles->last_frame_buffer_filled = false;
+ }
+
+ if (particles->frame_params_ubo != 0) {
+ glDeleteBuffers(1, &particles->frame_params_ubo);
+ particles->frame_params_ubo = 0;
+ }
}
void ParticlesStorage::particles_set_amount(RID p_particles, int p_amount) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ if (particles->amount == p_amount) {
+ return;
+ }
+
+ _particles_free_data(particles);
+
+ particles->amount = p_amount;
+
+ particles->prev_ticks = 0;
+ particles->phase = 0;
+ particles->prev_phase = 0;
+ particles->clear = true;
+
+ particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);
}
void ParticlesStorage::particles_set_lifetime(RID p_particles, double p_lifetime) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->lifetime = p_lifetime;
}
void ParticlesStorage::particles_set_one_shot(RID p_particles, bool p_one_shot) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->one_shot = p_one_shot;
}
void ParticlesStorage::particles_set_pre_process_time(RID p_particles, double p_time) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->pre_process_time = p_time;
}
-
void ParticlesStorage::particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->explosiveness = p_ratio;
}
-
void ParticlesStorage::particles_set_randomness_ratio(RID p_particles, real_t p_ratio) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->randomness = p_ratio;
}
void ParticlesStorage::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->custom_aabb = p_aabb;
+ particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_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) {
-}
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
-void ParticlesStorage::particles_set_process_material(RID p_particles, RID p_material) {
+ particles->speed_scale = p_scale;
}
+void ParticlesStorage::particles_set_use_local_coordinates(RID p_particles, bool p_enable) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
-RID ParticlesStorage::particles_get_process_material(RID p_particles) const {
- return RID();
+ particles->use_local_coords = p_enable;
+ particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);
}
void ParticlesStorage::particles_set_fixed_fps(RID p_particles, int p_fps) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->fixed_fps = p_fps;
+
+ _particles_free_data(particles);
+
+ particles->prev_ticks = 0;
+ particles->phase = 0;
+ particles->prev_phase = 0;
+ particles->clear = true;
+
+ particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);
}
void ParticlesStorage::particles_set_interpolate(RID p_particles, bool p_enable) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->interpolate = p_enable;
}
void ParticlesStorage::particles_set_fractional_delta(RID p_particles, bool p_enable) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->fractional_delta = p_enable;
}
-void ParticlesStorage::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) {
+void ParticlesStorage::particles_set_trails(RID p_particles, bool p_enable, double p_length) {
+ if (p_enable) {
+ WARN_PRINT_ONCE("The OpenGL 3 renderer does not support particle trails");
+ }
}
-void ParticlesStorage::particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) {
+void ParticlesStorage::particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) {
+ if (p_bind_poses.size() != 0) {
+ WARN_PRINT_ONCE("The OpenGL 3 renderer does not support particle trails");
+ }
}
void ParticlesStorage::particles_set_collision_base_size(RID p_particles, real_t p_size) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->collision_base_size = p_size;
}
void ParticlesStorage::particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) {
-}
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
-void ParticlesStorage::particles_set_trails(RID p_particles, bool p_enable, double p_length) {
+ particles->transform_align = p_transform_align;
}
-void ParticlesStorage::particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) {
+void ParticlesStorage::particles_set_process_material(RID p_particles, RID p_material) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->process_material = p_material;
+ particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES); //the instance buffer may have changed
}
-void ParticlesStorage::particles_restart(RID p_particles) {
+RID ParticlesStorage::particles_get_process_material(RID p_particles) const {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND_V(!particles, RID());
+
+ return particles->process_material;
}
void ParticlesStorage::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->draw_order = p_order;
}
-void ParticlesStorage::particles_set_draw_passes(RID p_particles, int p_count) {
+void ParticlesStorage::particles_set_draw_passes(RID p_particles, int p_passes) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->draw_passes.resize(p_passes);
}
void ParticlesStorage::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+ ERR_FAIL_INDEX(p_pass, particles->draw_passes.size());
+ particles->draw_passes.write[p_pass] = p_mesh;
+ particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);
+}
+
+void ParticlesStorage::particles_restart(RID p_particles) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->restart_request = true;
+}
+
+void ParticlesStorage::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) {
+ if (p_subemitter_particles.is_valid()) {
+ WARN_PRINT_ONCE("The OpenGL 3 renderer does not support particle sub emitters");
+ }
+}
+
+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) {
+ WARN_PRINT_ONCE("The OpenGL 3 renderer does not support manually emitting particles");
}
void ParticlesStorage::particles_request_process(RID p_particles) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ if (!particles->dirty) {
+ particles->dirty = true;
+ particles->update_list = particle_update_list;
+ particle_update_list = particles;
+ }
}
AABB ParticlesStorage::particles_get_current_aabb(RID p_particles) {
- return AABB();
+ if (RSG::threaded) {
+ WARN_PRINT_ONCE("Calling this function with threaded rendering enabled stalls the renderer, use with care.");
+ }
+
+ const Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND_V(!particles, AABB());
+
+ int total_amount = particles->amount;
+
+ // If available, read from the sort buffer which should be 2 frames out of date.
+ // This will help alleviate GPU stalls.
+ GLuint read_buffer = particles->sort_buffer_filled ? particles->sort_buffer : particles->back_instance_buffer;
+
+ Vector<uint8_t> buffer = Utilities::buffer_get_data(GL_ARRAY_BUFFER, read_buffer, total_amount * sizeof(ParticleInstanceData3D));
+ ERR_FAIL_COND_V(buffer.size() != (int)(total_amount * sizeof(ParticleInstanceData3D)), AABB());
+
+ Transform3D inv = particles->emission_transform.affine_inverse();
+
+ AABB aabb;
+ if (buffer.size()) {
+ bool first = true;
+
+ const uint8_t *data_ptr = (const uint8_t *)buffer.ptr();
+ uint32_t particle_data_size = sizeof(ParticleInstanceData3D) + sizeof(float) * particles->userdata_count;
+
+ for (int i = 0; i < total_amount; i++) {
+ const ParticleInstanceData3D &particle_data = *(const ParticleInstanceData3D *)&data_ptr[particle_data_size * i];
+ // If scale is 0.0, we assume the particle is inactive.
+ if (particle_data.xform[0] > 0.0) {
+ Vector3 pos = Vector3(particle_data.xform[3], particle_data.xform[7], particle_data.xform[11]);
+ if (!particles->use_local_coords) {
+ pos = inv.xform(pos);
+ }
+ if (first) {
+ aabb.position = pos;
+ first = false;
+ } else {
+ aabb.expand_to(pos);
+ }
+ }
+ }
+ }
+
+ float longest_axis_size = 0;
+ for (int i = 0; i < particles->draw_passes.size(); i++) {
+ if (particles->draw_passes[i].is_valid()) {
+ AABB maabb = MeshStorage::get_singleton()->mesh_get_aabb(particles->draw_passes[i], RID());
+ longest_axis_size = MAX(maabb.get_longest_axis_size(), longest_axis_size);
+ }
+ }
+
+ aabb.grow_by(longest_axis_size);
+
+ return aabb;
}
AABB ParticlesStorage::particles_get_aabb(RID p_particles) const {
- return AABB();
+ const Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND_V(!particles, AABB());
+
+ return particles->custom_aabb;
}
void ParticlesStorage::particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) {
-}
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
-bool ParticlesStorage::particles_get_emitting(RID p_particles) {
- return false;
+ particles->emission_transform = p_transform;
}
int ParticlesStorage::particles_get_draw_passes(RID p_particles) const {
- return 0;
-}
+ const Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND_V(!particles, 0);
-RID ParticlesStorage::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const {
- return RID();
+ return particles->draw_passes.size();
}
-void ParticlesStorage::particles_add_collision(RID p_particles, RID p_instance) {
+RID ParticlesStorage::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const {
+ const Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND_V(!particles, RID());
+ ERR_FAIL_INDEX_V(p_pass, particles->draw_passes.size(), RID());
+
+ return particles->draw_passes[p_pass];
}
-void ParticlesStorage::particles_remove_collision(RID p_particles, RID p_instance) {
+void ParticlesStorage::particles_add_collision(RID p_particles, RID p_particles_collision_instance) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->collisions.insert(p_particles_collision_instance);
+}
+
+void ParticlesStorage::particles_remove_collision(RID p_particles, RID p_particles_collision_instance) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->collisions.erase(p_particles_collision_instance);
+}
+
+void ParticlesStorage::particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, GLuint p_texture) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->has_sdf_collision = p_enable;
+ particles->sdf_collision_transform = p_xform;
+ particles->sdf_collision_to_screen = p_to_screen;
+ particles->sdf_collision_texture = p_texture;
+}
+
+// Does one step of processing particles by reading from back_process_buffer and writing to front_process_buffer.
+void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+
+ double new_phase = Math::fmod(p_particles->phase + (p_delta / p_particles->lifetime) * p_particles->speed_scale, 1.0);
+
+ //update current frame
+ ParticlesFrameParams frame_params;
+
+ if (p_particles->clear) {
+ p_particles->cycle_number = 0;
+ p_particles->random_seed = Math::rand();
+ } else if (new_phase < p_particles->phase) {
+ if (p_particles->one_shot) {
+ p_particles->emitting = false;
+ }
+ p_particles->cycle_number++;
+ }
+
+ frame_params.emitting = p_particles->emitting;
+ frame_params.system_phase = new_phase;
+ frame_params.prev_system_phase = p_particles->phase;
+
+ p_particles->phase = new_phase;
+
+ frame_params.time = RSG::rasterizer->get_total_time();
+ frame_params.delta = p_delta * p_particles->speed_scale;
+ frame_params.random_seed = p_particles->random_seed;
+ frame_params.explosiveness = p_particles->explosiveness;
+ frame_params.randomness = p_particles->randomness;
+
+ if (p_particles->use_local_coords) {
+ GLES3::MaterialStorage::store_transform(Transform3D(), frame_params.emission_transform);
+ } else {
+ GLES3::MaterialStorage::store_transform(p_particles->emission_transform, frame_params.emission_transform);
+ }
+
+ frame_params.cycle = p_particles->cycle_number;
+ frame_params.frame = p_particles->frame_counter++;
+ frame_params.pad0 = 0;
+ frame_params.pad1 = 0;
+ frame_params.pad2 = 0;
+
+ { //collision and attractors
+
+ frame_params.collider_count = 0;
+ frame_params.attractor_count = 0;
+ frame_params.particle_size = p_particles->collision_base_size;
+
+ GLuint collision_heightmap_texture = 0;
+
+ Transform3D to_particles;
+ if (p_particles->use_local_coords) {
+ to_particles = p_particles->emission_transform.affine_inverse();
+ }
+
+ if (p_particles->has_sdf_collision && p_particles->sdf_collision_texture != 0) {
+ //2D collision
+
+ Transform2D xform = p_particles->sdf_collision_transform; //will use dotproduct manually so invert beforehand
+
+ if (!p_particles->use_local_coords) {
+ Transform2D emission;
+ emission.columns[0] = Vector2(p_particles->emission_transform.basis.get_column(0).x, p_particles->emission_transform.basis.get_column(0).y);
+ emission.columns[1] = Vector2(p_particles->emission_transform.basis.get_column(1).x, p_particles->emission_transform.basis.get_column(1).y);
+ emission.set_origin(Vector2(p_particles->emission_transform.origin.x, p_particles->emission_transform.origin.y));
+ xform = xform * emission.affine_inverse();
+ }
+
+ Transform2D revert = xform.affine_inverse();
+ frame_params.collider_count = 1;
+ frame_params.colliders[0].transform[0] = xform.columns[0][0];
+ frame_params.colliders[0].transform[1] = xform.columns[0][1];
+ frame_params.colliders[0].transform[2] = 0;
+ frame_params.colliders[0].transform[3] = xform.columns[2][0];
+
+ frame_params.colliders[0].transform[4] = xform.columns[1][0];
+ frame_params.colliders[0].transform[5] = xform.columns[1][1];
+ frame_params.colliders[0].transform[6] = 0;
+ frame_params.colliders[0].transform[7] = xform.columns[2][1];
+
+ frame_params.colliders[0].transform[8] = revert.columns[0][0];
+ frame_params.colliders[0].transform[9] = revert.columns[0][1];
+ frame_params.colliders[0].transform[10] = 0;
+ frame_params.colliders[0].transform[11] = revert.columns[2][0];
+
+ frame_params.colliders[0].transform[12] = revert.columns[1][0];
+ frame_params.colliders[0].transform[13] = revert.columns[1][1];
+ frame_params.colliders[0].transform[14] = 0;
+ frame_params.colliders[0].transform[15] = revert.columns[2][1];
+
+ frame_params.colliders[0].extents[0] = p_particles->sdf_collision_to_screen.size.x;
+ frame_params.colliders[0].extents[1] = p_particles->sdf_collision_to_screen.size.y;
+ frame_params.colliders[0].extents[2] = p_particles->sdf_collision_to_screen.position.x;
+ frame_params.colliders[0].scale = p_particles->sdf_collision_to_screen.position.y;
+ frame_params.colliders[0].type = ParticlesFrameParams::COLLISION_TYPE_2D_SDF;
+
+ collision_heightmap_texture = p_particles->sdf_collision_texture;
+ }
+
+ for (const RID &E : p_particles->collisions) {
+ ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(E);
+ if (!pci || !pci->active) {
+ continue;
+ }
+ ParticlesCollision *pc = particles_collision_owner.get_or_null(pci->collision);
+ ERR_CONTINUE(!pc);
+
+ Transform3D to_collider = pci->transform;
+ if (p_particles->use_local_coords) {
+ to_collider = to_particles * to_collider;
+ }
+ Vector3 scale = to_collider.basis.get_scale();
+ to_collider.basis.orthonormalize();
+
+ if (pc->type <= RS::PARTICLES_COLLISION_TYPE_VECTOR_FIELD_ATTRACT) {
+ //attractor
+ if (frame_params.attractor_count >= ParticlesFrameParams::MAX_ATTRACTORS) {
+ continue;
+ }
+
+ ParticlesFrameParams::Attractor &attr = frame_params.attractors[frame_params.attractor_count];
+
+ GLES3::MaterialStorage::store_transform(to_collider, attr.transform);
+ attr.strength = pc->attractor_strength;
+ attr.attenuation = pc->attractor_attenuation;
+ attr.directionality = pc->attractor_directionality;
+
+ switch (pc->type) {
+ case RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT: {
+ attr.type = ParticlesFrameParams::ATTRACTOR_TYPE_SPHERE;
+ float radius = pc->radius;
+ radius *= (scale.x + scale.y + scale.z) / 3.0;
+ attr.extents[0] = radius;
+ attr.extents[1] = radius;
+ attr.extents[2] = radius;
+ } break;
+ case RS::PARTICLES_COLLISION_TYPE_BOX_ATTRACT: {
+ attr.type = ParticlesFrameParams::ATTRACTOR_TYPE_BOX;
+ Vector3 extents = pc->extents * scale;
+ attr.extents[0] = extents.x;
+ attr.extents[1] = extents.y;
+ attr.extents[2] = extents.z;
+ } break;
+ case RS::PARTICLES_COLLISION_TYPE_VECTOR_FIELD_ATTRACT: {
+ WARN_PRINT_ONCE("Vector field particle attractors are not available in the OpenGL2 renderer.");
+ } break;
+ default: {
+ }
+ }
+
+ frame_params.attractor_count++;
+ } else {
+ //collider
+ if (frame_params.collider_count >= ParticlesFrameParams::MAX_COLLIDERS) {
+ continue;
+ }
+
+ ParticlesFrameParams::Collider &col = frame_params.colliders[frame_params.collider_count];
+
+ GLES3::MaterialStorage::store_transform(to_collider, col.transform);
+ switch (pc->type) {
+ case RS::PARTICLES_COLLISION_TYPE_SPHERE_COLLIDE: {
+ col.type = ParticlesFrameParams::COLLISION_TYPE_SPHERE;
+ float radius = pc->radius;
+ radius *= (scale.x + scale.y + scale.z) / 3.0;
+ col.extents[0] = radius;
+ col.extents[1] = radius;
+ col.extents[2] = radius;
+ } break;
+ case RS::PARTICLES_COLLISION_TYPE_BOX_COLLIDE: {
+ col.type = ParticlesFrameParams::COLLISION_TYPE_BOX;
+ Vector3 extents = pc->extents * scale;
+ col.extents[0] = extents.x;
+ col.extents[1] = extents.y;
+ col.extents[2] = extents.z;
+ } break;
+ case RS::PARTICLES_COLLISION_TYPE_SDF_COLLIDE: {
+ WARN_PRINT_ONCE("SDF Particle Colliders are not available in the OpenGL 3 renderer.");
+ } break;
+ case RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE: {
+ if (collision_heightmap_texture != 0) { //already taken
+ continue;
+ }
+
+ col.type = ParticlesFrameParams::COLLISION_TYPE_HEIGHT_FIELD;
+ Vector3 extents = pc->extents * scale;
+ col.extents[0] = extents.x;
+ col.extents[1] = extents.y;
+ col.extents[2] = extents.z;
+ collision_heightmap_texture = pc->heightfield_texture;
+ } break;
+ default: {
+ }
+ }
+
+ frame_params.collider_count++;
+ }
+ }
+
+ // Bind heightmap or SDF texture.
+ GLuint heightmap = collision_heightmap_texture;
+ if (heightmap == 0) {
+ GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_BLACK));
+ heightmap = tex->tex_id;
+ }
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, heightmap);
+ }
+
+ if (p_particles->frame_params_ubo == 0) {
+ glGenBuffers(1, &p_particles->frame_params_ubo);
+ }
+ // Update per-frame UBO.
+ glBindBufferBase(GL_UNIFORM_BUFFER, PARTICLES_FRAME_UNIFORM_LOCATION, p_particles->frame_params_ubo);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(ParticlesFrameParams), &frame_params, GL_STREAM_DRAW);
+
+ // Get shader and set shader uniforms;
+ ParticleProcessMaterialData *m = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(p_particles->process_material, RS::SHADER_PARTICLES));
+ if (!m) {
+ m = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(particles_shader.default_material, RS::SHADER_PARTICLES));
+ }
+
+ ERR_FAIL_COND(!m);
+
+ ParticlesShaderGLES3::ShaderVariant variant = ParticlesShaderGLES3::MODE_DEFAULT;
+
+ uint32_t specialization = 0;
+ for (uint32_t i = 0; i < p_particles->userdata_count; i++) {
+ specialization |= (1 << i);
+ }
+
+ if (p_particles->mode == RS::ParticlesMode::PARTICLES_MODE_3D) {
+ specialization |= ParticlesShaderGLES3::MODE_3D;
+ }
+
+ RID version = particles_shader.default_shader_version;
+ if (m->shader_data->version.is_valid() && m->shader_data->valid) {
+ // Bind material uniform buffer and textures.
+ m->bind_uniforms();
+ version = m->shader_data->version;
+ }
+
+ bool success = material_storage->shaders.particles_process_shader.version_bind_shader(version, variant, specialization);
+ if (!success) {
+ return;
+ }
+
+ material_storage->shaders.particles_process_shader.version_set_uniform(ParticlesShaderGLES3::LIFETIME, p_particles->lifetime, version, variant, specialization);
+ material_storage->shaders.particles_process_shader.version_set_uniform(ParticlesShaderGLES3::CLEAR, p_particles->clear, version, variant, specialization);
+ material_storage->shaders.particles_process_shader.version_set_uniform(ParticlesShaderGLES3::TOTAL_PARTICLES, uint32_t(p_particles->amount), version, variant, specialization);
+ material_storage->shaders.particles_process_shader.version_set_uniform(ParticlesShaderGLES3::USE_FRACTIONAL_DELTA, p_particles->fractional_delta, version, variant, specialization);
+
+ p_particles->clear = false;
+
+ p_particles->has_collision_cache = m->shader_data->uses_collision;
+
+ glBindVertexArray(p_particles->back_vertex_array);
+
+ glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, p_particles->front_process_buffer);
+
+ glBeginTransformFeedback(GL_POINTS);
+ glDrawArrays(GL_POINTS, 0, p_particles->amount);
+ glEndTransformFeedback();
+
+ glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
+ glBindVertexArray(0);
+
+ SWAP(p_particles->front_process_buffer, p_particles->back_process_buffer);
+ SWAP(p_particles->front_vertex_array, p_particles->back_vertex_array);
}
-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::particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
+ return;
+ }
+
+ if (particles->front_process_buffer == 0) {
+ return; //particles have not processed yet
+ }
+
+ Vector3 axis = -p_axis; // cameras look to z negative
+
+ if (particles->use_local_coords) {
+ axis = particles->emission_transform.basis.xform_inv(axis).normalized();
+ }
+
+ // Sort will be done on CPU since we don't have compute shaders.
+ // If the sort_buffer has valid data
+ // Use a buffer that is 2 frames out of date to avoid stalls.
+ if (particles->draw_order == RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->sort_buffer_filled) {
+ glBindBuffer(GL_ARRAY_BUFFER, particles->sort_buffer);
+
+ ParticleInstanceData3D *particle_array;
+#ifndef __EMSCRIPTEN__
+ particle_array = static_cast<ParticleInstanceData3D *>(glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(ParticleInstanceData3D), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
+ ERR_FAIL_NULL(particle_array);
+#else
+ LocalVector<ParticleInstanceData3D> particle_vector;
+ particle_vector.resize(particles->amount);
+ particle_array = particle_vector.ptr();
+ glGetBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(ParticleInstanceData3D), particle_array);
+#endif
+ SortArray<ParticleInstanceData3D, ParticlesViewSort> sorter;
+ sorter.compare.z_dir = axis;
+ sorter.sort(particle_array, particles->amount);
+
+#ifndef __EMSCRIPTEN__
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+#else
+ glBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(ParticleInstanceData3D), particle_vector.ptr());
+#endif
+ }
+
+ glEnable(GL_RASTERIZER_DISCARD);
+ _particles_update_instance_buffer(particles, axis, p_up_axis);
+ glDisable(GL_RASTERIZER_DISCARD);
+}
+
+void ParticlesStorage::_particles_update_buffers(Particles *particles) {
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ uint32_t userdata_count = 0;
+
+ if (particles->process_material.is_valid()) {
+ GLES3::ParticleProcessMaterialData *material_data = static_cast<GLES3::ParticleProcessMaterialData *>(material_storage->material_get_data(particles->process_material, RS::SHADER_PARTICLES));
+ if (material_data && material_data->shader_data->version.is_valid() && material_data->shader_data->valid) {
+ userdata_count = material_data->shader_data->userdata_count;
+ }
+ }
+
+ if (userdata_count != particles->userdata_count) {
+ // Mismatch userdata, re-create buffers.
+ _particles_free_data(particles);
+ }
+
+ if (particles->amount > 0 && particles->front_process_buffer == 0) {
+ int total_amount = particles->amount;
+
+ particles->userdata_count = userdata_count;
+
+ uint32_t xform_size = particles->mode == RS::PARTICLES_MODE_2D ? 2 : 3;
+ particles->instance_buffer_stride_cache = sizeof(float) * 4 * (xform_size + 1);
+ particles->instance_buffer_size_cache = particles->instance_buffer_stride_cache * total_amount;
+ particles->num_attrib_arrays_cache = 5 + userdata_count + (xform_size - 2);
+ particles->process_buffer_stride_cache = sizeof(float) * 4 * particles->num_attrib_arrays_cache;
+
+ int process_data_amount = 4 * particles->num_attrib_arrays_cache * total_amount;
+ float *data = memnew_arr(float, process_data_amount);
+
+ for (int i = 0; i < process_data_amount; i++) {
+ data[i] = 0;
+ }
+
+ {
+ glGenVertexArrays(1, &particles->front_vertex_array);
+ glBindVertexArray(particles->front_vertex_array);
+ glGenBuffers(1, &particles->front_process_buffer);
+ glGenBuffers(1, &particles->front_instance_buffer);
+
+ glBindBuffer(GL_ARRAY_BUFFER, particles->front_process_buffer);
+ glBufferData(GL_ARRAY_BUFFER, particles->process_buffer_stride_cache * total_amount, data, GL_DYNAMIC_COPY);
+
+ for (uint32_t j = 0; j < particles->num_attrib_arrays_cache; j++) {
+ glEnableVertexAttribArray(j);
+ glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, particles->process_buffer_stride_cache, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * j));
+ }
+ glBindVertexArray(0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, particles->front_instance_buffer);
+ glBufferData(GL_ARRAY_BUFFER, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_COPY);
+ }
+
+ {
+ glGenVertexArrays(1, &particles->back_vertex_array);
+ glBindVertexArray(particles->back_vertex_array);
+ glGenBuffers(1, &particles->back_process_buffer);
+ glGenBuffers(1, &particles->back_instance_buffer);
+
+ glBindBuffer(GL_ARRAY_BUFFER, particles->back_process_buffer);
+ glBufferData(GL_ARRAY_BUFFER, particles->process_buffer_stride_cache * total_amount, data, GL_DYNAMIC_COPY);
+
+ for (uint32_t j = 0; j < particles->num_attrib_arrays_cache; j++) {
+ glEnableVertexAttribArray(j);
+ glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, particles->process_buffer_stride_cache, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * j));
+ }
+ glBindVertexArray(0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, particles->back_instance_buffer);
+ glBufferData(GL_ARRAY_BUFFER, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_COPY);
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ memdelete_arr(data);
+ }
+}
+
+void ParticlesStorage::_particles_allocate_history_buffers(Particles *particles) {
+ if (particles->sort_buffer == 0) {
+ glGenBuffers(1, &particles->last_frame_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, particles->last_frame_buffer);
+ glBufferData(GL_ARRAY_BUFFER, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_READ);
+
+ glGenBuffers(1, &particles->sort_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, particles->sort_buffer);
+ glBufferData(GL_ARRAY_BUFFER, particles->instance_buffer_size_cache, nullptr, GL_DYNAMIC_READ);
+ particles->sort_buffer_filled = false;
+ particles->last_frame_buffer_filled = false;
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+}
+void ParticlesStorage::_particles_update_instance_buffer(Particles *particles, const Vector3 &p_axis, const Vector3 &p_up_axis) {
+ ParticlesCopyShaderGLES3::ShaderVariant variant = ParticlesCopyShaderGLES3::MODE_DEFAULT;
+
+ uint64_t specialization = 0;
+ if (particles->mode == RS::ParticlesMode::PARTICLES_MODE_3D) {
+ specialization |= ParticlesCopyShaderGLES3::MODE_3D;
+ }
+
+ bool success = particles_shader.copy_shader.version_bind_shader(particles_shader.copy_shader_version, variant, specialization);
+ if (!success) {
+ return;
+ }
+
+ // Affect 2D only.
+ if (particles->use_local_coords) {
+ // In local mode, particle positions are calculated locally (relative to the node position)
+ // and they're also drawn locally.
+ // It works as expected, so we just pass an identity transform.
+ particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::INV_EMISSION_TRANSFORM, Transform3D(), particles_shader.copy_shader_version, variant, specialization);
+ } else {
+ // In global mode, particle positions are calculated globally (relative to the canvas origin)
+ // but they're drawn locally.
+ // So, we need to pass the inverse of the emission transform to bring the
+ // particles to local coordinates before drawing.
+ Transform3D inv = particles->emission_transform.affine_inverse();
+ particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::INV_EMISSION_TRANSFORM, inv, particles_shader.copy_shader_version, variant, specialization);
+ }
+
+ particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::FRAME_REMAINDER, particles->interpolate ? particles->frame_remainder : 0.0, particles_shader.copy_shader_version, variant, specialization);
+ particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::ALIGN_MODE, uint32_t(particles->transform_align), particles_shader.copy_shader_version, variant, specialization);
+ particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::ALIGN_UP, p_up_axis, particles_shader.copy_shader_version, variant, specialization);
+ particles_shader.copy_shader.version_set_uniform(ParticlesCopyShaderGLES3::SORT_DIRECTION, p_axis, particles_shader.copy_shader_version, variant, specialization);
+
+ glBindVertexArray(particles->back_vertex_array);
+ glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, particles->front_instance_buffer, 0, particles->instance_buffer_size_cache);
+ glBeginTransformFeedback(GL_POINTS);
+
+ if (particles->draw_order == RS::PARTICLES_DRAW_ORDER_LIFETIME) {
+ uint32_t lifetime_split = MIN(particles->amount * particles->phase, particles->amount - 1);
+ uint32_t stride = particles->process_buffer_stride_cache;
+
+ glBindBuffer(GL_ARRAY_BUFFER, particles->back_process_buffer);
+
+ // Offset VBO so you render starting at the newest particle.
+ if (particles->amount - lifetime_split > 0) {
+ glEnableVertexAttribArray(0); // Color.
+ glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 0));
+ glEnableVertexAttribArray(1); // .xyz: velocity. .z: flags.
+ glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 1));
+ glEnableVertexAttribArray(2); // Custom.
+ glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 2));
+ glEnableVertexAttribArray(3); // Xform1.
+ glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 3));
+ glEnableVertexAttribArray(4); // Xform2.
+ glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 4));
+ if (particles->mode == RS::PARTICLES_MODE_3D) {
+ glEnableVertexAttribArray(5); // Xform3.
+ glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * lifetime_split + sizeof(float) * 4 * 5));
+ }
+
+ uint32_t to_draw = particles->amount - lifetime_split;
+ glDrawArrays(GL_POINTS, 0, to_draw);
+ }
+
+ // Then render from index 0 up intil the newest particle.
+ if (lifetime_split > 0) {
+ glEndTransformFeedback();
+ // Now output to the second portion of the instance buffer.
+ glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, particles->front_instance_buffer, particles->instance_buffer_stride_cache * (particles->amount - lifetime_split), particles->instance_buffer_stride_cache * (lifetime_split));
+ glBeginTransformFeedback(GL_POINTS);
+ // Reset back to normal.
+ for (uint32_t j = 0; j < particles->num_attrib_arrays_cache; j++) {
+ glEnableVertexAttribArray(j);
+ glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * j));
+ }
+
+ glDrawArrays(GL_POINTS, 0, lifetime_split);
+ }
+ } else {
+ glDrawArrays(GL_POINTS, 0, particles->amount);
+ }
+
+ glEndTransformFeedback();
+ glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, 0, 0);
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void ParticlesStorage::update_particles() {
+ glEnable(GL_RASTERIZER_DISCARD);
+
+ GLuint global_buffer = GLES3::MaterialStorage::get_singleton()->global_shader_parameters_get_uniform_buffer();
+
+ glBindBufferBase(GL_UNIFORM_BUFFER, PARTICLES_GLOBALS_UNIFORM_LOCATION, global_buffer);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+ while (particle_update_list) {
+ // Use transform feedback to process particles.
+
+ Particles *particles = particle_update_list;
+
+ particle_update_list = particles->update_list;
+ particles->update_list = nullptr;
+ particles->dirty = false;
+
+ _particles_update_buffers(particles);
+
+ if (particles->restart_request) {
+ particles->prev_ticks = 0;
+ particles->phase = 0;
+ particles->prev_phase = 0;
+ particles->clear = true;
+ particles->restart_request = false;
+ }
+
+ if (particles->inactive && !particles->emitting) {
+ //go next
+ continue;
+ }
+
+ if (particles->emitting) {
+ if (particles->inactive) {
+ //restart system from scratch
+ particles->prev_ticks = 0;
+ particles->phase = 0;
+ particles->prev_phase = 0;
+ particles->clear = true;
+ }
+ particles->inactive = false;
+ particles->inactive_time = 0;
+ } else {
+ particles->inactive_time += particles->speed_scale * RSG::rasterizer->get_frame_delta_time();
+ if (particles->inactive_time > particles->lifetime * 1.2) {
+ particles->inactive = true;
+ continue;
+ }
+ }
+
+ // Copy the instance buffer that was last used into the last_frame buffer.
+ // sort_buffer should now be 2 frames out of date.
+ if (particles->draw_order == RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH || particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME) {
+ _particles_allocate_history_buffers(particles);
+ SWAP(particles->last_frame_buffer, particles->sort_buffer);
+
+ glBindBuffer(GL_COPY_READ_BUFFER, particles->back_instance_buffer);
+ glBindBuffer(GL_COPY_WRITE_BUFFER, particles->last_frame_buffer);
+ glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, particles->instance_buffer_size_cache);
+
+ // Last frame's last_frame turned into this frame's sort buffer.
+ particles->sort_buffer_filled = particles->last_frame_buffer_filled;
+ particles->sort_buffer_phase = particles->last_frame_phase;
+ particles->last_frame_buffer_filled = true;
+ particles->last_frame_phase = particles->phase;
+ glBindBuffer(GL_COPY_READ_BUFFER, 0);
+ glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
+ }
+
+ int fixed_fps = 0;
+ if (particles->fixed_fps > 0) {
+ fixed_fps = particles->fixed_fps;
+ }
+
+ bool zero_time_scale = Engine::get_singleton()->get_time_scale() <= 0.0;
+
+ if (particles->clear && particles->pre_process_time > 0.0) {
+ double frame_time;
+ if (fixed_fps > 0) {
+ frame_time = 1.0 / fixed_fps;
+ } else {
+ frame_time = 1.0 / 30.0;
+ }
+
+ double todo = particles->pre_process_time;
+
+ while (todo >= 0) {
+ _particles_process(particles, frame_time);
+ todo -= frame_time;
+ }
+ }
+
+ if (fixed_fps > 0) {
+ double frame_time;
+ double decr;
+ if (zero_time_scale) {
+ frame_time = 0.0;
+ decr = 1.0 / fixed_fps;
+ } else {
+ frame_time = 1.0 / fixed_fps;
+ decr = frame_time;
+ }
+ double delta = RSG::rasterizer->get_frame_delta_time();
+ if (delta > 0.1) { //avoid recursive stalls if fps goes below 10
+ delta = 0.1;
+ } else if (delta <= 0.0) { //unlikely but..
+ delta = 0.001;
+ }
+ double todo = particles->frame_remainder + delta;
+
+ while (todo >= frame_time) {
+ _particles_process(particles, frame_time);
+ todo -= decr;
+ }
+
+ particles->frame_remainder = todo;
+
+ } else {
+ if (zero_time_scale) {
+ _particles_process(particles, 0.0);
+ } else {
+ _particles_process(particles, RSG::rasterizer->get_frame_delta_time());
+ }
+ }
+
+ // Copy particles to instance buffer and pack Color/Custom.
+ // We don't have camera information here, so don't copy here if we need camera information for view depth or align mode.
+ if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
+ _particles_update_instance_buffer(particles, Vector3(0.0, 0.0, 0.0), Vector3(0.0, 0.0, 0.0));
+
+ if (particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME && particles->sort_buffer_filled) {
+ if (particles->mode == RS::ParticlesMode::PARTICLES_MODE_2D) {
+ _particles_reverse_lifetime_sort<ParticleInstanceData2D>(particles);
+ } else {
+ _particles_reverse_lifetime_sort<ParticleInstanceData3D>(particles);
+ }
+ }
+ }
+
+ SWAP(particles->front_instance_buffer, particles->back_instance_buffer);
+
+ // At the end of update, the back_buffer contains the most up-to-date-information to read from.
+
+ particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
+ }
+
+ glDisable(GL_RASTERIZER_DISCARD);
+}
+
+template <typename ParticleInstanceData>
+void ParticlesStorage::_particles_reverse_lifetime_sort(Particles *particles) {
+ glBindBuffer(GL_ARRAY_BUFFER, particles->sort_buffer);
+
+ ParticleInstanceData *particle_array;
+ uint32_t buffer_size = particles->amount * sizeof(ParticleInstanceData);
+#ifndef __EMSCRIPTEN__
+ particle_array = static_cast<ParticleInstanceData *>(glMapBufferRange(GL_ARRAY_BUFFER, 0, buffer_size, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
+
+ ERR_FAIL_NULL(particle_array);
+#else
+ LocalVector<ParticleInstanceData> particle_vector;
+ particle_vector.resize(particles->amount);
+ particle_array = particle_vector.ptr();
+ glGetBufferSubData(GL_ARRAY_BUFFER, 0, buffer_size, particle_array);
+#endif
+
+ uint32_t lifetime_split = MIN(particles->amount * particles->sort_buffer_phase, particles->amount - 1);
+
+ for (uint32_t i = 0; i < lifetime_split / 2; i++) {
+ SWAP(particle_array[i], particle_array[lifetime_split - i]);
+ }
+
+ for (uint32_t i = 0; i < (particles->amount - lifetime_split) / 2; i++) {
+ SWAP(particle_array[lifetime_split + i + 1], particle_array[particles->amount - 1 - i]);
+ }
+
+#ifndef __EMSCRIPTEN__
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+#else
+ glBufferSubData(GL_ARRAY_BUFFER, 0, buffer_size, particle_vector.ptr());
+#endif
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+Dependency *ParticlesStorage::particles_get_dependency(RID p_particles) const {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_NULL_V(particles, nullptr);
+
+ return &particles->dependency;
}
bool ParticlesStorage::particles_is_inactive(RID p_particles) const {
- return false;
+ ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer.");
+ const Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND_V(!particles, false);
+ return !particles->emitting && particles->inactive;
}
-/* PARTICLES COLLISION */
+/* PARTICLES COLLISION API */
RID ParticlesStorage::particles_collision_allocate() {
- return RID();
+ return particles_collision_owner.allocate_rid();
}
-
void ParticlesStorage::particles_collision_initialize(RID p_rid) {
+ particles_collision_owner.initialize_rid(p_rid, ParticlesCollision());
}
void ParticlesStorage::particles_collision_free(RID p_rid) {
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_rid);
+
+ if (particles_collision->heightfield_texture != 0) {
+ glDeleteTextures(1, &particles_collision->heightfield_texture);
+ particles_collision->heightfield_texture = 0;
+ glDeleteFramebuffers(1, &particles_collision->heightfield_fb);
+ particles_collision->heightfield_fb = 0;
+ }
+ particles_collision->dependency.deleted_notify(p_rid);
+ particles_collision_owner.free(p_rid);
+}
+
+GLuint ParticlesStorage::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const {
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
+ ERR_FAIL_COND_V(!particles_collision, 0);
+ ERR_FAIL_COND_V(particles_collision->type != RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE, 0);
+
+ if (particles_collision->heightfield_texture == 0) {
+ //create
+ const int resolutions[RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX] = { 256, 512, 1024, 2048, 4096, 8192 };
+ Size2i size;
+ if (particles_collision->extents.x > particles_collision->extents.z) {
+ size.x = resolutions[particles_collision->heightfield_resolution];
+ size.y = int32_t(particles_collision->extents.z / particles_collision->extents.x * size.x);
+ } else {
+ size.y = resolutions[particles_collision->heightfield_resolution];
+ size.x = int32_t(particles_collision->extents.x / particles_collision->extents.z * size.y);
+ }
+
+ glGenTextures(1, &particles_collision->heightfield_texture);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, particles_collision->heightfield_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, size.x, size.y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+
+ glGenFramebuffers(1, &particles_collision->heightfield_fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, particles_collision->heightfield_fb);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, particles_collision->heightfield_texture, 0);
+#ifdef DEBUG_ENABLED
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ WARN_PRINT("Could create heightmap texture status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
+ }
+#endif
+ particles_collision->heightfield_fb_size = size;
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ }
+
+ return particles_collision->heightfield_fb;
}
void ParticlesStorage::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) {
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
+ ERR_FAIL_COND(!particles_collision);
+
+ if (p_type == particles_collision->type) {
+ return;
+ }
+
+ if (particles_collision->heightfield_texture != 0) {
+ glDeleteTextures(1, &particles_collision->heightfield_texture);
+ particles_collision->heightfield_texture = 0;
+ glDeleteFramebuffers(1, &particles_collision->heightfield_fb);
+ particles_collision->heightfield_fb = 0;
+ }
+
+ particles_collision->type = p_type;
+ particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
void ParticlesStorage::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) {
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
+ ERR_FAIL_COND(!particles_collision);
+ particles_collision->cull_mask = p_cull_mask;
}
void ParticlesStorage::particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) {
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
+ ERR_FAIL_COND(!particles_collision);
+
+ particles_collision->radius = p_radius;
+ particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
void ParticlesStorage::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) {
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
+ ERR_FAIL_COND(!particles_collision);
+
+ particles_collision->extents = p_extents;
+ particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
void ParticlesStorage::particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) {
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
+ ERR_FAIL_COND(!particles_collision);
+
+ particles_collision->attractor_strength = p_strength;
}
void ParticlesStorage::particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) {
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
+ ERR_FAIL_COND(!particles_collision);
+
+ particles_collision->attractor_directionality = p_directionality;
}
void ParticlesStorage::particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) {
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
+ ERR_FAIL_COND(!particles_collision);
+
+ particles_collision->attractor_attenuation = p_curve;
}
void ParticlesStorage::particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) {
+ WARN_PRINT_ONCE("The OpenGL 3 renderer does not support SDF collisions in 3D particle shaders");
}
void ParticlesStorage::particles_collision_height_field_update(RID p_particles_collision) {
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
+ ERR_FAIL_COND(!particles_collision);
+ particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
void ParticlesStorage::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) {
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
+ ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_INDEX(p_resolution, RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX);
+
+ if (particles_collision->heightfield_resolution == p_resolution) {
+ return;
+ }
+
+ particles_collision->heightfield_resolution = p_resolution;
+
+ if (particles_collision->heightfield_texture != 0) {
+ glDeleteTextures(1, &particles_collision->heightfield_texture);
+ particles_collision->heightfield_texture = 0;
+ glDeleteFramebuffers(1, &particles_collision->heightfield_fb);
+ particles_collision->heightfield_fb = 0;
+ }
}
AABB ParticlesStorage::particles_collision_get_aabb(RID p_particles_collision) const {
- return AABB();
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
+ ERR_FAIL_COND_V(!particles_collision, AABB());
+
+ switch (particles_collision->type) {
+ case RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT:
+ case RS::PARTICLES_COLLISION_TYPE_SPHERE_COLLIDE: {
+ AABB aabb;
+ aabb.position = -Vector3(1, 1, 1) * particles_collision->radius;
+ aabb.size = Vector3(2, 2, 2) * particles_collision->radius;
+ return aabb;
+ }
+ default: {
+ AABB aabb;
+ aabb.position = -particles_collision->extents;
+ aabb.size = particles_collision->extents * 2;
+ return aabb;
+ }
+ }
+}
+
+Vector3 ParticlesStorage::particles_collision_get_extents(RID p_particles_collision) const {
+ const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
+ ERR_FAIL_COND_V(!particles_collision, Vector3());
+ return particles_collision->extents;
}
bool ParticlesStorage::particles_collision_is_heightfield(RID p_particles_collision) const {
- return false;
+ const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
+ ERR_FAIL_COND_V(!particles_collision, false);
+ return particles_collision->type == RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE;
}
-RID ParticlesStorage::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const {
- return RID();
+Dependency *ParticlesStorage::particles_collision_get_dependency(RID p_particles_collision) const {
+ ParticlesCollision *pc = particles_collision_owner.get_or_null(p_particles_collision);
+ ERR_FAIL_NULL_V(pc, nullptr);
+
+ return &pc->dependency;
}
+/* Particles collision instance */
+
RID ParticlesStorage::particles_collision_instance_create(RID p_collision) {
- return RID();
+ ParticlesCollisionInstance pci;
+ pci.collision = p_collision;
+ return particles_collision_instance_owner.make_rid(pci);
}
void ParticlesStorage::particles_collision_instance_free(RID p_rid) {
+ particles_collision_instance_owner.free(p_rid);
}
void ParticlesStorage::particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) {
+ ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(p_collision_instance);
+ ERR_FAIL_COND(!pci);
+ pci->transform = p_transform;
}
void ParticlesStorage::particles_collision_instance_set_active(RID p_collision_instance, bool p_active) {
+ ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(p_collision_instance);
+ ERR_FAIL_COND(!pci);
+ pci->active = p_active;
}
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/storage/particles_storage.h b/drivers/gles3/storage/particles_storage.h
index 84d1f94d8c..b220c48de9 100644
--- a/drivers/gles3/storage/particles_storage.h
+++ b/drivers/gles3/storage/particles_storage.h
@@ -1,57 +1,315 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* particles_storage.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 "../shaders/particles_copy.glsl.gen.h"
#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"
+#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 {
+enum ParticlesUniformLocation {
+ PARTICLES_FRAME_UNIFORM_LOCATION,
+ PARTICLES_GLOBALS_UNIFORM_LOCATION,
+ PARTICLES_MATERIAL_UNIFORM_LOCATION,
+};
+
class ParticlesStorage : public RendererParticlesStorage {
private:
static ParticlesStorage *singleton;
+ /* PARTICLES */
+
+ struct ParticleInstanceData3D {
+ float xform[12];
+ float color[2]; // Color and custom are packed together into one vec4;
+ float custom[2];
+ };
+
+ struct ParticleInstanceData2D {
+ float xform[8];
+ float color[2]; // Color and custom are packed together into one vec4;
+ float custom[2];
+ };
+
+ struct ParticlesViewSort {
+ Vector3 z_dir;
+ bool operator()(const ParticleInstanceData3D &p_a, const ParticleInstanceData3D &p_b) const {
+ return z_dir.dot(Vector3(p_a.xform[3], p_a.xform[7], p_a.xform[11])) < z_dir.dot(Vector3(p_b.xform[3], p_b.xform[7], p_b.xform[11]));
+ }
+ };
+
+ struct ParticlesFrameParams {
+ enum {
+ MAX_ATTRACTORS = 32,
+ MAX_COLLIDERS = 32,
+ MAX_3D_TEXTURES = 0 // GLES3 renderer doesn't support using 3D textures for flow field or collisions.
+ };
+
+ enum AttractorType {
+ ATTRACTOR_TYPE_SPHERE,
+ ATTRACTOR_TYPE_BOX,
+ ATTRACTOR_TYPE_VECTOR_FIELD,
+ };
+
+ struct Attractor {
+ float transform[16];
+ float extents[4]; // Extents or radius. w-channel is padding.
+
+ uint32_t type;
+ float strength;
+ float attenuation;
+ float directionality;
+ };
+
+ enum CollisionType {
+ COLLISION_TYPE_SPHERE,
+ COLLISION_TYPE_BOX,
+ COLLISION_TYPE_SDF,
+ COLLISION_TYPE_HEIGHT_FIELD,
+ COLLISION_TYPE_2D_SDF,
+
+ };
+
+ struct Collider {
+ float transform[16];
+ float extents[4]; // Extents or radius. w-channel is padding.
+
+ uint32_t type;
+ float scale;
+ float pad0;
+ float pad1;
+ };
+
+ uint32_t emitting;
+ uint32_t cycle;
+ float system_phase;
+ float prev_system_phase;
+
+ float explosiveness;
+ float randomness;
+ float time;
+ float delta;
+
+ float particle_size;
+ float pad0;
+ float pad1;
+ float pad2;
+
+ uint32_t random_seed;
+ uint32_t attractor_count;
+ uint32_t collider_count;
+ uint32_t frame;
+
+ float emission_transform[16];
+
+ Attractor attractors[MAX_ATTRACTORS];
+ Collider colliders[MAX_COLLIDERS];
+ };
+
+ struct Particles {
+ RS::ParticlesMode mode = RS::PARTICLES_MODE_3D;
+ bool inactive = true;
+ double inactive_time = 0.0;
+ bool emitting = false;
+ bool one_shot = false;
+ int amount = 0;
+ double lifetime = 1.0;
+ double pre_process_time = 0.0;
+ real_t explosiveness = 0.0;
+ real_t randomness = 0.0;
+ bool restart_request = false;
+ AABB custom_aabb = AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8));
+ bool use_local_coords = false;
+ bool has_collision_cache = false;
+
+ bool has_sdf_collision = false;
+ Transform2D sdf_collision_transform;
+ Rect2 sdf_collision_to_screen;
+ GLuint sdf_collision_texture = 0;
+
+ RID process_material;
+ uint32_t frame_counter = 0;
+ RS::ParticlesTransformAlign transform_align = RS::PARTICLES_TRANSFORM_ALIGN_DISABLED;
+
+ RS::ParticlesDrawOrder draw_order = RS::PARTICLES_DRAW_ORDER_INDEX;
+
+ Vector<RID> draw_passes;
+
+ GLuint frame_params_ubo = 0;
+
+ // We may process particles multiple times each frame (if they have a fixed FPS higher than the game FPS).
+ // Unfortunately, this means we can't just use a round-robin system of 3 buffers.
+ // To ensure the sort buffer is accurate, we copy the last frame instance buffer just before processing.
+
+ // Transform Feedback buffer and VAO for rendering.
+ // Each frame we render to this one.
+ GLuint front_vertex_array = 0; // Binds process buffer. Used for processing.
+ GLuint front_process_buffer = 0; // Transform + color + custom data + userdata + velocity + flags. Only needed for processing.
+ GLuint front_instance_buffer = 0; // Transform + color + custom data. In packed format needed for rendering.
+
+ // VAO for transform feedback, contains last frame's data.
+ // Read from this one for particles process and then copy to last frame buffer.
+ GLuint back_vertex_array = 0; // Binds process buffer. Used for processing.
+ GLuint back_process_buffer = 0; // Transform + color + custom data + userdata + velocity + flags. Only needed for processing.
+ GLuint back_instance_buffer = 0; // Transform + color + custom data. In packed format needed for rendering.
+
+ uint32_t instance_buffer_size_cache = 0;
+ uint32_t instance_buffer_stride_cache = 0;
+ uint32_t num_attrib_arrays_cache = 0;
+ uint32_t process_buffer_stride_cache = 0;
+
+ // Only ever copied to, holds last frame's instance data, then swaps with sort_buffer.
+ GLuint last_frame_buffer = 0;
+ bool last_frame_buffer_filled = false;
+ float last_frame_phase = 0.0;
+
+ // The frame-before-last's instance buffer.
+ // Use this to copy data back for sorting or computing AABB.
+ GLuint sort_buffer = 0;
+ bool sort_buffer_filled = false;
+ float sort_buffer_phase = 0.0;
+
+ uint32_t userdata_count = 0;
+
+ bool dirty = false;
+ Particles *update_list = nullptr;
+
+ double phase = 0.0;
+ double prev_phase = 0.0;
+ uint64_t prev_ticks = 0;
+ uint32_t random_seed = 0;
+
+ uint32_t cycle_number = 0;
+
+ double speed_scale = 1.0;
+
+ int fixed_fps = 30;
+ bool interpolate = true;
+ bool fractional_delta = false;
+ double frame_remainder = 0;
+ real_t collision_base_size = 0.01;
+
+ bool clear = true;
+
+ Transform3D emission_transform;
+
+ HashSet<RID> collisions;
+
+ Dependency dependency;
+
+ double trail_length = 1.0;
+ bool trails_enabled = false;
+
+ Particles() {
+ }
+ };
+
+ void _particles_process(Particles *p_particles, double p_delta);
+ void _particles_free_data(Particles *particles);
+ void _particles_update_buffers(Particles *particles);
+ void _particles_allocate_history_buffers(Particles *particles);
+ void _particles_update_instance_buffer(Particles *particles, const Vector3 &p_axis, const Vector3 &p_up_axis);
+
+ template <typename T>
+ void _particles_reverse_lifetime_sort(Particles *particles);
+
+ struct ParticlesShader {
+ RID default_shader;
+ RID default_material;
+ RID default_shader_version;
+
+ ParticlesCopyShaderGLES3 copy_shader;
+ RID copy_shader_version;
+ } particles_shader;
+
+ Particles *particle_update_list = nullptr;
+
+ mutable RID_Owner<Particles, true> particles_owner;
+
+ /* Particles Collision */
+
+ struct ParticlesCollision {
+ RS::ParticlesCollisionType type = RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT;
+ uint32_t cull_mask = 0xFFFFFFFF;
+ float radius = 1.0;
+ Vector3 extents = Vector3(1, 1, 1);
+ float attractor_strength = 1.0;
+ float attractor_attenuation = 1.0;
+ float attractor_directionality = 0.0;
+ GLuint field_texture = 0;
+ GLuint heightfield_texture = 0;
+ GLuint heightfield_fb = 0;
+ Size2i heightfield_fb_size;
+
+ RS::ParticlesCollisionHeightfieldResolution heightfield_resolution = RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_1024;
+
+ Dependency dependency;
+ };
+
+ struct ParticlesCollisionInstance {
+ RID collision;
+ Transform3D transform;
+ bool active = false;
+ };
+
+ mutable RID_Owner<ParticlesCollision, true> particles_collision_owner;
+
+ mutable RID_Owner<ParticlesCollisionInstance> particles_collision_instance_owner;
+
public:
static ParticlesStorage *get_singleton();
ParticlesStorage();
virtual ~ParticlesStorage();
+ bool free(RID p_rid);
+
/* PARTICLES */
+ bool owns_particles(RID p_rid) { return particles_owner.owns(p_rid); }
+
virtual RID particles_allocate() override;
virtual void particles_initialize(RID p_rid) override;
virtual void particles_free(RID p_rid) override;
@@ -102,12 +360,51 @@ public:
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;
+ void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, GLuint p_texture);
virtual void update_particles() override;
virtual bool particles_is_inactive(RID p_particles) const override;
+ _FORCE_INLINE_ RS::ParticlesMode particles_get_mode(RID p_particles) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND_V(!particles, RS::PARTICLES_MODE_2D);
+ return particles->mode;
+ }
+
+ _FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND_V(!particles, 0);
+
+ return particles->amount;
+ }
+
+ _FORCE_INLINE_ GLuint particles_get_gl_buffer(RID p_particles) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+
+ if ((particles->draw_order == RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH || particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME) && particles->sort_buffer_filled) {
+ return particles->sort_buffer;
+ }
+ return particles->back_instance_buffer;
+ }
+
+ _FORCE_INLINE_ bool particles_has_collision(RID p_particles) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND_V(!particles, 0);
+
+ return particles->has_collision_cache;
+ }
+
+ _FORCE_INLINE_ uint32_t particles_is_using_local_coords(RID p_particles) {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_COND_V(!particles, false);
+
+ return particles->use_local_coords;
+ }
+
+ Dependency *particles_get_dependency(RID p_particles) const;
+
/* PARTICLES COLLISION */
+ bool owns_particles_collision(RID p_rid) { return particles_collision_owner.owns(p_rid); }
virtual RID particles_collision_allocate() override;
virtual void particles_collision_initialize(RID p_rid) override;
@@ -124,8 +421,22 @@ public:
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;
+ Vector3 particles_collision_get_extents(RID p_particles_collision) const;
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;
+ GLuint particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const;
+
+ _FORCE_INLINE_ Size2i particles_collision_get_heightfield_size(RID p_particles_collision) const {
+ ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
+ ERR_FAIL_COND_V(!particles_collision, Size2i());
+ ERR_FAIL_COND_V(particles_collision->type != RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE, Size2i());
+
+ return particles_collision->heightfield_fb_size;
+ }
+
+ Dependency *particles_collision_get_dependency(RID p_particles) const;
+
+ /* PARTICLES COLLISION INSTANCE*/
+ bool owns_particles_collision_instance(RID p_rid) { return particles_collision_instance_owner.owns(p_rid); }
virtual RID particles_collision_instance_create(RID p_collision) override;
virtual void particles_collision_instance_free(RID p_rid) override;
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
index 5d121e2ef9..19bf57df94 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* render_scene_buffers_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. */
-/*************************************************************************/
+/**************************************************************************/
+/* render_scene_buffers_gles3.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
@@ -37,67 +37,30 @@ RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() {
free_render_buffer_data();
}
-void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
+void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::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();
//internal_size.x = p_internal_size.x; // ignore for now
//internal_size.y = p_internal_size.y;
width = p_target_size.x;
height = p_target_size.y;
+ //scaling_3d_mode = p_scaling_3d_mode
//fsr_sharpness = p_fsr_sharpness;
//texture_mipmap_bias = p_texture_mipmap_bias;
render_target = p_render_target;
//msaa = p_msaa;
//screen_space_aa = p_screen_space_aa;
//use_debanding = p_use_debanding;
- //view_count = p_view_count;
+ view_count = p_view_count;
free_render_buffer_data();
GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
is_transparent = rt->is_transparent;
-
- // framebuffer
- glGenFramebuffers(1, &framebuffer);
- glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
-
- glBindTexture(GL_TEXTURE_2D, rt->color);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
-
- glGenTextures(1, &depth_texture);
- glBindTexture(GL_TEXTURE_2D, depth_texture);
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 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, 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();
- WARN_PRINT("Could not create 3D renderbuffer, status: " + texture_storage->get_framebuffer_error(status));
- return;
- }
}
void RenderSceneBuffersGLES3::free_render_buffer_data() {
- if (depth_texture) {
- glDeleteTextures(1, &depth_texture);
- depth_texture = 0;
- }
- if (framebuffer) {
- glDeleteFramebuffers(1, &framebuffer);
- framebuffer = 0;
- }
}
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.h b/drivers/gles3/storage/render_scene_buffers_gles3.h
index ad0d2032b0..d07a0812f6 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.h
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* render_scene_buffers_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. */
-/*************************************************************************/
+/**************************************************************************/
+/* render_scene_buffers_gles3.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 RENDER_SCENE_BUFFERS_GLES3_H
#define RENDER_SCENE_BUFFERS_GLES3_H
@@ -56,14 +56,11 @@ public:
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;
+ 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 {
@@ -84,7 +81,7 @@ public:
private:
public:
virtual ~RenderSceneBuffersGLES3();
- virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
+ virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
virtual void set_fsr_sharpness(float p_fsr_sharpness) override{};
virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override{};
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index b8ab4d6839..67526bc003 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* texture_storage.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
@@ -34,6 +34,10 @@
#include "config.h"
#include "drivers/gles3/effects/copy_effects.h"
+#ifdef ANDROID_ENABLED
+#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
+#endif
+
using namespace GLES3;
TextureStorage *TextureStorage::singleton = nullptr;
@@ -59,9 +63,7 @@ TextureStorage::TextureStorage() {
{ //create default textures
{ // White Textures
- Ref<Image> image;
- image.instantiate();
- image->create(4, 4, true, Image::FORMAT_RGBA8);
+ Ref<Image> image = Image::create_empty(4, 4, true, Image::FORMAT_RGBA8);
image->fill(Color(1, 1, 1, 1));
image->generate_mipmaps();
@@ -90,9 +92,7 @@ TextureStorage::TextureStorage() {
}
{ // black
- Ref<Image> image;
- image.instantiate();
- image->create(4, 4, true, Image::FORMAT_RGBA8);
+ Ref<Image> image = Image::create_empty(4, 4, true, Image::FORMAT_RGBA8);
image->fill(Color(0, 0, 0, 1));
image->generate_mipmaps();
@@ -116,9 +116,7 @@ TextureStorage::TextureStorage() {
}
{ // transparent black
- Ref<Image> image;
- image.instantiate();
- image->create(4, 4, true, Image::FORMAT_RGBA8);
+ Ref<Image> image = Image::create_empty(4, 4, true, Image::FORMAT_RGBA8);
image->fill(Color(0, 0, 0, 0));
image->generate_mipmaps();
@@ -127,9 +125,7 @@ TextureStorage::TextureStorage() {
}
{
- Ref<Image> image;
- image.instantiate();
- image->create(4, 4, true, Image::FORMAT_RGBA8);
+ Ref<Image> image = Image::create_empty(4, 4, true, Image::FORMAT_RGBA8);
image->fill(Color(0.5, 0.5, 1, 1));
image->generate_mipmaps();
@@ -138,9 +134,7 @@ TextureStorage::TextureStorage() {
}
{
- Ref<Image> image;
- image.instantiate();
- image->create(4, 4, true, Image::FORMAT_RGBA8);
+ Ref<Image> image = Image::create_empty(4, 4, true, Image::FORMAT_RGBA8);
image->fill(Color(1.0, 0.5, 1, 1));
image->generate_mipmaps();
@@ -197,6 +191,27 @@ TextureStorage::TextureStorage() {
glBindTexture(GL_TEXTURE_2D, 0);
+ { // Atlas Texture initialize.
+ uint8_t 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] = 255;
+ }
+
+ glGenTextures(1, &texture_atlas.texture);
+ glBindTexture(GL_TEXTURE_2D, texture_atlas.texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ {
+ sdf_shader.shader.initialize();
+ sdf_shader.shader_version = sdf_shader.shader.version_create();
+ }
+
#ifdef GLES_OVER_GL
glEnable(GL_PROGRAM_POINT_SIZE);
#endif
@@ -207,6 +222,12 @@ TextureStorage::~TextureStorage() {
for (int i = 0; i < DEFAULT_GL_TEXTURE_MAX; i++) {
texture_free(default_gl_textures[i]);
}
+
+ glDeleteTextures(1, &texture_atlas.texture);
+ texture_atlas.texture = 0;
+ glDeleteFramebuffers(1, &texture_atlas.framebuffer);
+ texture_atlas.framebuffer = 0;
+ sdf_shader.shader.version_free(sdf_shader.shader_version);
}
//TODO, move back to storage
@@ -230,6 +251,8 @@ void TextureStorage::canvas_texture_free(RID 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);
+ ERR_FAIL_NULL(ct);
+
switch (p_channel) {
case RS::CANVAS_TEXTURE_CHANNEL_DIFFUSE: {
ct->diffuse = p_texture;
@@ -245,6 +268,8 @@ void TextureStorage::canvas_texture_set_channel(RID p_canvas_texture, RS::Canvas
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);
+ ERR_FAIL_NULL(ct);
+
ct->specular_color.r = p_specular_color.r;
ct->specular_color.g = p_specular_color.g;
ct->specular_color.b = p_specular_color.b;
@@ -253,61 +278,16 @@ void TextureStorage::canvas_texture_set_shading_parameters(RID p_canvas_texture,
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);
+ ERR_FAIL_NULL(ct);
+
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);
+ ERR_FAIL_NULL(ct);
- 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);
+ ct->texture_repeat = p_repeat;
}
/* Texture API */
@@ -320,6 +300,7 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
r_real_format = p_format;
bool need_decompress = false;
+ bool decompress_ra_to_rg = false;
switch (p_format) {
case Image::FORMAT_L8: {
@@ -585,6 +566,34 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
need_decompress = true;
}
} break;
+ case Image::FORMAT_ETC2_RA_AS_RG: {
+#ifndef WEB_ENABLED
+ 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
+#endif
+ {
+ need_decompress = true;
+ }
+ decompress_ra_to_rg = true;
+ } break;
+ case Image::FORMAT_DXT5_RA_AS_RG: {
+#ifndef WEB_ENABLED
+ 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
+#endif
+ {
+ need_decompress = true;
+ }
+ decompress_ra_to_rg = true;
+ } break;
default: {
ERR_FAIL_V_MSG(Ref<Image>(), "Image Format: " + itos(p_format) + " is not supported by the OpenGL3 Renderer");
}
@@ -595,7 +604,18 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
image = image->duplicate();
image->decompress();
ERR_FAIL_COND_V(image->is_compressed(), image);
+ if (decompress_ra_to_rg) {
+ image->convert_ra_rgba8_to_rg();
+ image->convert(Image::FORMAT_RG8);
+ }
switch (image->get_format()) {
+ case Image::FORMAT_RG8: {
+ r_gl_format = GL_RG;
+ r_gl_internal_format = GL_RG8;
+ r_gl_type = GL_UNSIGNED_BYTE;
+ r_real_format = Image::FORMAT_RG8;
+ r_compressed = false;
+ } break;
case Image::FORMAT_RGB8: {
r_gl_format = GL_RGB;
r_gl_internal_format = GL_RGB;
@@ -617,7 +637,6 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
r_gl_type = GL_UNSIGNED_BYTE;
r_real_format = Image::FORMAT_RGBA8;
r_compressed = false;
-
} break;
}
}
@@ -642,7 +661,9 @@ void TextureStorage::texture_free(RID p_texture) {
}
if (t->tex_id != 0) {
- glDeleteTextures(1, &t->tex_id);
+ if (!t->is_external) {
+ glDeleteTextures(1, &t->tex_id);
+ }
t->tex_id = 0;
}
@@ -653,7 +674,7 @@ void TextureStorage::texture_free(RID p_texture) {
}
}
- //decal_atlas_remove_texture(p_texture);
+ texture_atlas_remove_texture(p_texture);
for (int i = 0; i < t->proxies.size(); i++) {
Texture *p = texture_owner.get_or_null(t->proxies[i]);
@@ -666,12 +687,14 @@ void TextureStorage::texture_free(RID p_texture) {
}
void TextureStorage::texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) {
+ ERR_FAIL_COND(p_image.is_null());
+
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.mipmaps = p_image->get_mipmap_count() + 1;
texture.format = p_image->get_format();
texture.type = Texture::TYPE_2D;
texture.target = GL_TEXTURE_2D;
@@ -706,9 +729,37 @@ void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) {
texture_owner.initialize_rid(p_texture, proxy_tex);
}
+RID TextureStorage::texture_create_external(Texture::Type p_type, Image::Format p_format, unsigned int p_image, int p_width, int p_height, int p_depth, int p_layers, RS::TextureLayeredType p_layered_type) {
+ Texture texture;
+ texture.active = true;
+ texture.is_external = true;
+ texture.type = p_type;
+
+ switch (p_type) {
+ case Texture::TYPE_2D: {
+ texture.target = GL_TEXTURE_2D;
+ } break;
+ case Texture::TYPE_3D: {
+ texture.target = GL_TEXTURE_3D;
+ } break;
+ case Texture::TYPE_LAYERED: {
+ texture.target = GL_TEXTURE_2D_ARRAY;
+ } break;
+ }
+
+ texture.real_format = texture.format = p_format;
+ texture.tex_id = p_image;
+ texture.alloc_width = texture.width = p_width;
+ texture.alloc_height = texture.height = p_height;
+ texture.depth = p_depth;
+ texture.layers = p_layers;
+ texture.layered_type = p_layered_type;
+
+ return texture_owner.make_rid(texture);
+}
+
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);
+ texture_set_data(p_texture, p_image, p_layer);
#ifdef TOOLS_ENABLED
Texture *tex = texture_owner.get_or_null(p_texture);
@@ -717,14 +768,32 @@ void TextureStorage::texture_2d_update(RID p_texture, const Ref<Image> &p_image,
}
void TextureStorage::texture_proxy_update(RID p_texture, RID p_proxy_to) {
+ Texture *tex = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND(!tex);
+ ERR_FAIL_COND(!tex->is_proxy);
+ Texture *proxy_to = texture_owner.get_or_null(p_proxy_to);
+ ERR_FAIL_COND(!proxy_to);
+ ERR_FAIL_COND(proxy_to->is_proxy);
+
+ if (tex->proxy_to.is_valid()) {
+ Texture *prev_tex = texture_owner.get_or_null(tex->proxy_to);
+ ERR_FAIL_COND(!prev_tex);
+ prev_tex->proxies.erase(p_texture);
+ }
+
+ *tex = *proxy_to;
+
+ tex->proxy_to = p_proxy_to;
+ tex->is_render_target = false;
+ tex->is_proxy = true;
+ tex->proxies.clear();
+ proxy_to->proxies.push_back(p_texture);
}
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);
+ Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
image->fill(Color(1, 0, 1, 1));
texture_2d_initialize(p_texture, image);
@@ -733,9 +802,7 @@ void TextureStorage::texture_2d_placeholder_initialize(RID p_texture) {
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);
+ Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
image->fill(Color(1, 0, 1, 1));
Vector<Ref<Image>> images;
@@ -754,9 +821,7 @@ void TextureStorage::texture_2d_layered_placeholder_initialize(RID p_texture, Re
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);
+ Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
image->fill(Color(1, 0, 1, 1));
Vector<Ref<Image>> images;
@@ -780,6 +845,7 @@ Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
#ifdef GLES_OVER_GL
// OpenGL 3.3 supports glGetTexImage which is faster and simpler than glReadPixels.
+ // It also allows for reading compressed textures, mipmaps, and more formats.
Vector<uint8_t> data;
int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, texture->real_format, texture->mipmaps > 1);
@@ -810,16 +876,71 @@ Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
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);
+ Ref<Image> image = Image::create_from_data(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;
+
+ Vector<uint8_t> data;
+
+ // On web and mobile we always read an RGBA8 image with no mipmaps.
+ int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false);
+
+ data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers
+ uint8_t *w = data.ptrw();
+
+ GLuint temp_framebuffer;
+ glGenFramebuffers(1, &temp_framebuffer);
+
+ GLuint temp_color_texture;
+ glGenTextures(1, &temp_color_texture);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer);
+
+ glBindTexture(GL_TEXTURE_2D, temp_color_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 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);
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ CopyEffects::get_singleton()->copy_to_rect(Rect2i(0, 0, 1.0, 1.0));
+
+ glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &w[0]);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glDeleteTextures(1, &temp_color_texture);
+ glDeleteFramebuffers(1, &temp_framebuffer);
+
+ data.resize(data_size);
+
+ ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
+ Ref<Image> image = Image::create_from_data(texture->width, texture->height, false, Image::FORMAT_RGBA8, data);
+ ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
+
+ if (texture->format != Image::FORMAT_RGBA8) {
+ image->convert(texture->format);
+ }
+
+ if (texture->mipmaps > 1) {
+ image->generate_mipmaps();
+ }
+
#endif
#ifdef TOOLS_ENABLED
@@ -873,7 +994,7 @@ void TextureStorage::texture_replace(RID p_texture, RID p_by_texture) {
//delete last, so proxies can be updated
texture_owner.free(p_by_texture);
- //decal_atlas_mark_dirty_on_texture(p_texture);
+ texture_atlas_mark_dirty_on_texture(p_texture);
}
void TextureStorage::texture_set_size_override(RID p_texture, int p_width, int p_height) {
@@ -968,6 +1089,10 @@ Size2 TextureStorage::texture_size_with_proxy(RID p_texture) {
}
}
+RID TextureStorage::texture_get_rd_texture_rid(RID p_texture, bool p_srgb) const {
+ return RID();
+}
+
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);
@@ -1007,7 +1132,7 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
img->resize_to_po2(false);
}
- GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : GL_TEXTURE_2D;
+ GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : texture->target;
Vector<uint8_t> read = img->get_data();
@@ -1018,15 +1143,14 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
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
+#ifndef WEB_ENABLED
switch (texture->format) {
+#ifdef GLES_OVER_GL
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);
@@ -1034,15 +1158,29 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_RED);
glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_GREEN);
} break;
+#endif // GLES3_OVER_GL
+
+ case Image::FORMAT_ETC2_RA_AS_RG:
+ case Image::FORMAT_DXT5_RA_AS_RG: {
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED);
+ if (texture->format == real_format) {
+ // Swizzle RA from compressed texture into RG
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_ALPHA);
+ } else {
+ // Converted textures are already in RG, leave as-is
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
+ }
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_ZERO);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_ONE);
+ } 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
+#endif // WEB_ENABLED
int mipmaps = img->has_mipmaps() ? img->get_mipmap_count() + 1 : 1;
@@ -1064,7 +1202,11 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
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]);
+ if (texture->target == GL_TEXTURE_2D_ARRAY) {
+ glTexSubImage3D(GL_TEXTURE_2D_ARRAY, i, 0, 0, p_layer, w, h, 0, format, type, &read[ofs]);
+ } else {
+ glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]);
+ }
}
tsize += size;
@@ -1141,6 +1283,217 @@ RID TextureStorage::texture_create_radiance_cubemap(RID p_source, int p_resoluti
return RID();
}
+/* TEXTURE ATLAS API */
+
+void TextureStorage::texture_add_to_texture_atlas(RID p_texture) {
+ if (!texture_atlas.textures.has(p_texture)) {
+ TextureAtlas::Texture t;
+ t.users = 1;
+ texture_atlas.textures[p_texture] = t;
+ texture_atlas.dirty = true;
+ } else {
+ TextureAtlas::Texture *t = texture_atlas.textures.getptr(p_texture);
+ t->users++;
+ }
+}
+
+void TextureStorage::texture_remove_from_texture_atlas(RID p_texture) {
+ TextureAtlas::Texture *t = texture_atlas.textures.getptr(p_texture);
+ ERR_FAIL_COND(!t);
+ t->users--;
+ if (t->users == 0) {
+ texture_atlas.textures.erase(p_texture);
+ // Do not mark it dirty, there is no need to since it remains working.
+ }
+}
+
+void TextureStorage::texture_atlas_mark_dirty_on_texture(RID p_texture) {
+ if (texture_atlas.textures.has(p_texture)) {
+ texture_atlas.dirty = true; // Mark it dirty since it was most likely modified.
+ }
+}
+
+void TextureStorage::texture_atlas_remove_texture(RID p_texture) {
+ if (texture_atlas.textures.has(p_texture)) {
+ texture_atlas.textures.erase(p_texture);
+ // There is not much a point of making it dirty, texture can be removed next time the atlas is updated.
+ }
+}
+
+GLuint TextureStorage::texture_atlas_get_texture() const {
+ return texture_atlas.texture;
+}
+
+void TextureStorage::update_texture_atlas() {
+ CopyEffects *copy_effects = CopyEffects::get_singleton();
+ ERR_FAIL_NULL(copy_effects);
+
+ if (!texture_atlas.dirty) {
+ return; //nothing to do
+ }
+
+ texture_atlas.dirty = false;
+
+ if (texture_atlas.texture != 0) {
+ glDeleteTextures(1, &texture_atlas.texture);
+ texture_atlas.texture = 0;
+ glDeleteFramebuffers(1, &texture_atlas.framebuffer);
+ texture_atlas.framebuffer = 0;
+ }
+
+ const int border = 2;
+
+ if (texture_atlas.textures.size()) {
+ //generate atlas
+ Vector<TextureAtlas::SortItem> itemsv;
+ itemsv.resize(texture_atlas.textures.size());
+ int base_size = 8;
+
+ int idx = 0;
+
+ for (const KeyValue<RID, TextureAtlas::Texture> &E : texture_atlas.textures) {
+ TextureAtlas::SortItem &si = itemsv.write[idx];
+
+ Texture *src_tex = get_texture(E.key);
+
+ si.size.width = (src_tex->width / border) + 1;
+ si.size.height = (src_tex->height / border) + 1;
+ si.pixel_size = Size2i(src_tex->width, src_tex->height);
+
+ if (base_size < si.size.width) {
+ base_size = nearest_power_of_2_templated(si.size.width);
+ }
+
+ si.texture = E.key;
+ idx++;
+ }
+
+ //sort items by size
+ itemsv.sort();
+
+ //attempt to create atlas
+ int item_count = itemsv.size();
+ TextureAtlas::SortItem *items = itemsv.ptrw();
+
+ int atlas_height = 0;
+
+ while (true) {
+ Vector<int> v_offsetsv;
+ v_offsetsv.resize(base_size);
+
+ int *v_offsets = v_offsetsv.ptrw();
+ memset(v_offsets, 0, sizeof(int) * base_size);
+
+ int max_height = 0;
+
+ for (int i = 0; i < item_count; i++) {
+ //best fit
+ TextureAtlas::SortItem &si = items[i];
+ int best_idx = -1;
+ int best_height = 0x7FFFFFFF;
+ for (int j = 0; j <= base_size - si.size.width; j++) {
+ int height = 0;
+ for (int k = 0; k < si.size.width; k++) {
+ int h = v_offsets[k + j];
+ if (h > height) {
+ height = h;
+ if (height > best_height) {
+ break; //already bad
+ }
+ }
+ }
+
+ if (height < best_height) {
+ best_height = height;
+ best_idx = j;
+ }
+ }
+
+ //update
+ for (int k = 0; k < si.size.width; k++) {
+ v_offsets[k + best_idx] = best_height + si.size.height;
+ }
+
+ si.pos.x = best_idx;
+ si.pos.y = best_height;
+
+ if (si.pos.y + si.size.height > max_height) {
+ max_height = si.pos.y + si.size.height;
+ }
+ }
+
+ if (max_height <= base_size * 2) {
+ atlas_height = max_height;
+ break; //good ratio, break;
+ }
+
+ base_size *= 2;
+ }
+
+ texture_atlas.size.width = base_size * border;
+ texture_atlas.size.height = nearest_power_of_2_templated(atlas_height * border);
+
+ for (int i = 0; i < item_count; i++) {
+ TextureAtlas::Texture *t = texture_atlas.textures.getptr(items[i].texture);
+ t->uv_rect.position = items[i].pos * border + Vector2i(border / 2, border / 2);
+ t->uv_rect.size = items[i].pixel_size;
+
+ t->uv_rect.position /= Size2(texture_atlas.size);
+ t->uv_rect.size /= Size2(texture_atlas.size);
+ }
+ } else {
+ texture_atlas.size.width = 4;
+ texture_atlas.size.height = 4;
+ }
+
+ { // Atlas Texture initialize.
+ // TODO validate texture atlas size with maximum texture size
+ glGenTextures(1, &texture_atlas.texture);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture_atlas.texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texture_atlas.size.width, texture_atlas.size.height, 0, GL_RGBA, 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);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+
+ glGenFramebuffers(1, &texture_atlas.framebuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, texture_atlas.framebuffer);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_atlas.texture, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ glDeleteFramebuffers(1, &texture_atlas.framebuffer);
+ texture_atlas.framebuffer = 0;
+ glDeleteTextures(1, &texture_atlas.texture);
+ texture_atlas.texture = 0;
+ WARN_PRINT("Could not create texture atlas, status: " + get_framebuffer_error(status));
+ return;
+ }
+ glViewport(0, 0, texture_atlas.size.width, texture_atlas.size.height);
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ glDisable(GL_BLEND);
+
+ if (texture_atlas.textures.size()) {
+ for (const KeyValue<RID, TextureAtlas::Texture> &E : texture_atlas.textures) {
+ TextureAtlas::Texture *t = texture_atlas.textures.getptr(E.key);
+ Texture *src_tex = get_texture(E.key);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, src_tex->tex_id);
+ copy_effects->copy_to_rect(t->uv_rect);
+ }
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
/* DECAL API */
RID TextureStorage::decal_allocate() {
@@ -1197,9 +1550,11 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
return;
}
+ Config *config = Config::get_singleton();
+
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->color_type = rt->is_transparent ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
rt->image_format = Image::FORMAT_RGBA8;
glDisable(GL_SCISSOR_TEST);
@@ -1207,31 +1562,82 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
glDepthMask(GL_FALSE);
{
- /* Front FBO */
+ Texture *texture;
+ bool use_multiview = rt->view_count > 1 && config->multiview_supported;
+ GLenum texture_target = use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
- Texture *texture = get_texture(rt->texture);
- ERR_FAIL_COND(!texture);
+ /* Front FBO */
- // framebuffer
glGenFramebuffers(1, &rt->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
// color
- glGenTextures(1, &rt->color);
- glBindTexture(GL_TEXTURE_2D, rt->color);
+ if (rt->overridden.color.is_valid()) {
+ texture = get_texture(rt->overridden.color);
+ ERR_FAIL_COND(!texture);
- glTexImage2D(GL_TEXTURE_2D, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr);
+ rt->color = texture->tex_id;
+ rt->size = Size2i(texture->width, texture->height);
+ } else {
+ texture = get_texture(rt->texture);
+ ERR_FAIL_COND(!texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glGenTextures(1, &rt->color);
+ glBindTexture(texture_target, rt->color);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ if (use_multiview) {
+ glTexImage3D(texture_target, 0, rt->color_internal_format, rt->size.x, rt->size.y, rt->view_count, 0, rt->color_format, rt->color_type, nullptr);
+ } else {
+ glTexImage2D(texture_target, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr);
+ }
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
+ glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+#ifndef IOS_ENABLED
+ if (use_multiview) {
+ glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, rt->view_count);
+ } else {
+#else
+ {
+#endif
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
+ }
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ // depth
+ if (rt->overridden.depth.is_valid()) {
+ texture = get_texture(rt->overridden.depth);
+ ERR_FAIL_COND(!texture);
+
+ rt->depth = texture->tex_id;
+ } else {
+ glGenTextures(1, &rt->depth);
+ glBindTexture(texture_target, rt->depth);
+
+ if (use_multiview) {
+ glTexImage3D(texture_target, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, rt->view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+ } else {
+ glTexImage2D(texture_target, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+ }
+
+ glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+#ifndef IOS_ENABLED
+ if (use_multiview) {
+ glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, rt->depth, 0, 0, rt->view_count);
+ } else {
+#else
+ {
+#endif
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0);
+ }
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
glDeleteFramebuffers(1, &rt->fbo);
glDeleteTextures(1, &rt->color);
@@ -1239,25 +1645,38 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
rt->size.x = 0;
rt->size.y = 0;
rt->color = 0;
- texture->tex_id = 0;
- texture->active = false;
+ rt->depth = 0;
+ if (rt->overridden.color.is_null()) {
+ 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;
+ texture->is_render_target = true;
+ texture->render_target = rt;
+ if (rt->overridden.color.is_null()) {
+ texture->format = rt->image_format;
+ texture->real_format = rt->image_format;
+ texture->target = texture_target;
+ if (rt->view_count > 1 && config->multiview_supported) {
+ texture->type = Texture::TYPE_LAYERED;
+ texture->layers = rt->view_count;
+ } else {
+ texture->type = Texture::TYPE_2D;
+ texture->layers = 1;
+ }
+ 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);
@@ -1323,37 +1742,54 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
return;
}
+ // Dispose of the cached fbo's and the allocated textures
+ for (KeyValue<uint32_t, RenderTarget::RTOverridden::FBOCacheEntry> &E : rt->overridden.fbo_cache) {
+ glDeleteTextures(E.value.allocated_textures.size(), E.value.allocated_textures.ptr());
+ // Don't delete the current FBO, we'll do that a couple lines down.
+ if (E.value.fbo != rt->fbo) {
+ glDeleteFramebuffers(1, &E.value.fbo);
+ }
+ }
+ rt->overridden.fbo_cache.clear();
+
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->overridden.color.is_null()) {
+ if (rt->texture.is_valid()) {
+ Texture *tex = get_texture(rt->texture);
+ tex->alloc_height = 0;
+ tex->alloc_width = 0;
+ tex->width = 0;
+ tex->height = 0;
+ tex->active = false;
+ tex->render_target = nullptr;
+ tex->is_render_target = false;
+ }
+ } else {
+ Texture *tex = get_texture(rt->overridden.color);
+ tex->render_target = nullptr;
+ tex->is_render_target = false;
+ }
+
+ if (rt->overridden.color.is_valid()) {
+ rt->overridden.color = RID();
+ } else if (rt->color) {
+ glDeleteTextures(1, &rt->color);
+ }
+ rt->color = 0;
+
+ if (rt->overridden.depth.is_valid()) {
+ rt->overridden.depth = RID();
+ } else if (rt->depth) {
+ glDeleteTextures(1, &rt->depth);
+ }
+ rt->depth = 0;
+
+ rt->overridden.velocity = RID();
+ rt->overridden.is_overridden = false;
if (rt->backbuffer_fbo != 0) {
glDeleteFramebuffers(1, &rt->backbuffer_fbo);
@@ -1361,11 +1797,12 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
rt->backbuffer = 0;
rt->backbuffer_fbo = 0;
}
+ _render_target_clear_sdf(rt);
}
RID TextureStorage::render_target_create() {
RenderTarget render_target;
- //render_target.was_used = false;
+ render_target.used_in_frame = false;
render_target.clear_requested = false;
Texture t;
@@ -1385,7 +1822,9 @@ void TextureStorage::render_target_free(RID p_rid) {
Texture *t = get_texture(rt->texture);
if (t) {
t->is_render_target = false;
- texture_free(rt->texture);
+ if (rt->overridden.color.is_null()) {
+ texture_free(rt->texture);
+ }
//memdelete(t);
}
render_target_owner.free(p_rid);
@@ -1398,132 +1837,126 @@ void TextureStorage::render_target_set_position(RID p_render_target, int p_x, in
rt->position = Point2i(p_x, p_y);
}
+Point2i TextureStorage::render_target_get_position(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, Point2i());
+
+ return rt->position;
+};
+
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) {
+ if (p_width == rt->size.x && p_height == rt->size.y && p_view_count == rt->view_count) {
+ return;
+ }
+ if (rt->overridden.color.is_valid()) {
return;
}
_clear_render_target(rt);
rt->size = Size2i(p_width, p_height);
+ rt->view_count = p_view_count;
_update_render_target(rt);
}
// TODO: convert to Size2i internally
-Size2i TextureStorage::render_target_get_size(RID p_render_target) {
+Size2i TextureStorage::render_target_get_size(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, Size2());
+ ERR_FAIL_COND_V(!rt, Size2i());
return rt->size;
}
-RID TextureStorage::render_target_get_texture(RID p_render_target) {
+void TextureStorage::render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_COND(!rt);
+ ERR_FAIL_COND(rt->direct_to_screen);
- if (rt->external.fbo == 0) {
- return rt->texture;
- } else {
- return rt->external.texture;
+ rt->overridden.velocity = p_velocity_texture;
+
+ if (rt->overridden.color == p_color_texture && rt->overridden.depth == p_depth_texture) {
+ return;
}
-}
-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_color_texture.is_null() && p_depth_texture.is_null()) {
+ _clear_render_target(rt);
+ _update_render_target(rt);
+ return;
+ }
- if (p_texture_id == 0) {
- if (rt->external.fbo != 0) {
- // free this
- glDeleteFramebuffers(1, &rt->external.fbo);
+ if (!rt->overridden.is_overridden) {
+ _clear_render_target(rt);
+ }
- // and this
- if (rt->external.depth != 0) {
- glDeleteRenderbuffers(1, &rt->external.depth);
- }
+ rt->overridden.color = p_color_texture;
+ rt->overridden.depth = p_depth_texture;
+ rt->overridden.is_overridden = true;
+
+ uint32_t hash_key = hash_murmur3_one_64(p_color_texture.get_id());
+ hash_key = hash_murmur3_one_64(p_depth_texture.get_id(), hash_key);
+ hash_key = hash_fmix32(hash_key);
+
+ RBMap<uint32_t, RenderTarget::RTOverridden::FBOCacheEntry>::Element *cache;
+ if ((cache = rt->overridden.fbo_cache.find(hash_key)) != nullptr) {
+ rt->fbo = cache->get().fbo;
+ rt->color = cache->get().color;
+ rt->depth = cache->get().depth;
+ rt->size = cache->get().size;
+ rt->texture = p_color_texture;
+ return;
+ }
- // 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);
+ _update_render_target(rt);
- } else {
- // bind our frame buffer
- glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo);
+ RenderTarget::RTOverridden::FBOCacheEntry new_entry;
+ new_entry.fbo = rt->fbo;
+ new_entry.color = rt->color;
+ new_entry.depth = rt->depth;
+ new_entry.size = rt->size;
+ // Keep track of any textures we had to allocate because they weren't overridden.
+ if (p_color_texture.is_null()) {
+ new_entry.allocated_textures.push_back(rt->color);
+ }
+ if (p_depth_texture.is_null()) {
+ new_entry.allocated_textures.push_back(rt->depth);
+ }
+ rt->overridden.fbo_cache.insert(hash_key, new_entry);
+}
- // find our texture
- t = get_texture(rt->external.texture);
- }
+RID TextureStorage::render_target_get_override_color(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
- // set our texture
- t->tex_id = p_texture_id;
- rt->external.color = p_texture_id;
+ return rt->overridden.color;
+}
- // 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;
+RID TextureStorage::render_target_get_override_depth(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
- // 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);
- }
+ return rt->overridden.depth;
+}
- // check status and unbind
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
+RID TextureStorage::render_target_get_override_velocity(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
- if (status != GL_FRAMEBUFFER_COMPLETE) {
- WARN_PRINT("framebuffer fail, status: " + get_framebuffer_error(status));
- }
+ return rt->overridden.velocity;
+}
- ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
+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->overridden.color.is_valid()) {
+ return rt->overridden.color;
}
+
+ return rt->texture;
}
void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_transparent) {
@@ -1532,8 +1965,17 @@ void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_t
rt->is_transparent = p_transparent;
- _clear_render_target(rt);
- _update_render_target(rt);
+ if (rt->overridden.color.is_null()) {
+ _clear_render_target(rt);
+ _update_render_target(rt);
+ }
+}
+
+bool TextureStorage::render_target_get_transparent(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, false);
+
+ return rt->is_transparent;
}
void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) {
@@ -1547,10 +1989,22 @@ void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, boo
// 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;
+ if (rt->direct_to_screen) {
+ rt->overridden.color = RID();
+ rt->overridden.depth = RID();
+ rt->overridden.velocity = RID();
+ }
_update_render_target(rt);
}
-bool TextureStorage::render_target_was_used(RID p_render_target) {
+bool TextureStorage::render_target_get_direct_to_screen(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, false);
+
+ return rt->direct_to_screen;
+}
+
+bool TextureStorage::render_target_was_used(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, false);
@@ -1572,11 +2026,19 @@ void TextureStorage::render_target_set_msaa(RID p_render_target, RS::ViewportMSA
}
WARN_PRINT("2D MSAA is not yet supported for GLES3.");
+
_clear_render_target(rt);
rt->msaa = p_msaa;
_update_render_target(rt);
}
+RS::ViewportMSAA TextureStorage::render_target_get_msaa(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, RS::VIEWPORT_MSAA_DISABLED);
+
+ return rt->msaa;
+}
+
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);
@@ -1607,19 +2069,291 @@ void TextureStorage::render_target_do_clear_request(RID p_render_target) {
if (!rt->clear_requested) {
return;
}
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
glClearBufferfv(GL_COLOR, 0, rt->clear_color.components);
rt->clear_requested = false;
+ glBindFramebuffer(GL_FRAMEBUFFER, system_fbo);
}
void TextureStorage::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+ if (rt->sdf_oversize == p_size && rt->sdf_scale == p_scale) {
+ return;
+ }
+
+ rt->sdf_oversize = p_size;
+ rt->sdf_scale = p_scale;
+
+ _render_target_clear_sdf(rt);
+}
+
+Rect2i TextureStorage::_render_target_get_sdf_rect(const RenderTarget *rt) const {
+ Size2i margin;
+ int scale;
+ switch (rt->sdf_oversize) {
+ case RS::VIEWPORT_SDF_OVERSIZE_100_PERCENT: {
+ scale = 100;
+ } break;
+ case RS::VIEWPORT_SDF_OVERSIZE_120_PERCENT: {
+ scale = 120;
+ } break;
+ case RS::VIEWPORT_SDF_OVERSIZE_150_PERCENT: {
+ scale = 150;
+ } break;
+ case RS::VIEWPORT_SDF_OVERSIZE_200_PERCENT: {
+ scale = 200;
+ } break;
+ default: {
+ }
+ }
+
+ margin = (rt->size * scale / 100) - rt->size;
+
+ Rect2i r(Vector2i(), rt->size);
+ r.position -= margin;
+ r.size += margin * 2;
+
+ return r;
}
Rect2i TextureStorage::render_target_get_sdf_rect(RID p_render_target) const {
- return Rect2i();
+ const RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, Rect2i());
+
+ return _render_target_get_sdf_rect(rt);
}
void TextureStorage::render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ rt->sdf_enabled = p_enabled;
+}
+
+bool TextureStorage::render_target_is_sdf_enabled(RID p_render_target) const {
+ const RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, false);
+
+ return rt->sdf_enabled;
+}
+
+GLuint TextureStorage::render_target_get_sdf_texture(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, 0);
+ if (rt->sdf_texture_read == 0) {
+ Texture *texture = texture_owner.get_or_null(default_gl_textures[DEFAULT_GL_TEXTURE_BLACK]);
+ return texture->tex_id;
+ }
+
+ return rt->sdf_texture_read;
+}
+
+void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) {
+ ERR_FAIL_COND(rt->sdf_texture_write_fb != 0);
+
+ Size2i size = _render_target_get_sdf_rect(rt).size;
+
+ glGenTextures(1, &rt->sdf_texture_write);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_write);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, size.width, size.height, 0, GL_RED, GL_UNSIGNED_BYTE, 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_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ 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->sdf_texture_write_fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->sdf_texture_write_fb);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->sdf_texture_write, 0);
+
+ int scale;
+ switch (rt->sdf_scale) {
+ case RS::VIEWPORT_SDF_SCALE_100_PERCENT: {
+ scale = 100;
+ } break;
+ case RS::VIEWPORT_SDF_SCALE_50_PERCENT: {
+ scale = 50;
+ } break;
+ case RS::VIEWPORT_SDF_SCALE_25_PERCENT: {
+ scale = 25;
+ } break;
+ default: {
+ scale = 100;
+ } break;
+ }
+
+ rt->process_size = size * scale / 100;
+ rt->process_size.x = MAX(rt->process_size.x, 1);
+ rt->process_size.y = MAX(rt->process_size.y, 1);
+
+ glGenTextures(2, rt->sdf_texture_process);
+ glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_process[0]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16I, rt->process_size.width, rt->process_size.height, 0, GL_RG_INTEGER, GL_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_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_process[1]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16I, rt->process_size.width, rt->process_size.height, 0, GL_RG_INTEGER, GL_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_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glGenTextures(1, &rt->sdf_texture_read);
+ glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_read);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, rt->process_size.width, rt->process_size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ 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::_render_target_clear_sdf(RenderTarget *rt) {
+ if (rt->sdf_texture_write_fb != 0) {
+ glDeleteTextures(1, &rt->sdf_texture_read);
+ glDeleteTextures(1, &rt->sdf_texture_write);
+ glDeleteTextures(2, rt->sdf_texture_process);
+ glDeleteFramebuffers(1, &rt->sdf_texture_write_fb);
+ rt->sdf_texture_read = 0;
+ rt->sdf_texture_write = 0;
+ rt->sdf_texture_process[0] = 0;
+ rt->sdf_texture_process[1] = 0;
+ rt->sdf_texture_write_fb = 0;
+ }
+}
+
+GLuint TextureStorage::render_target_get_sdf_framebuffer(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, 0);
+
+ if (rt->sdf_texture_write_fb == 0) {
+ _render_target_allocate_sdf(rt);
+ }
+
+ return rt->sdf_texture_write_fb;
+}
+void TextureStorage::render_target_sdf_process(RID p_render_target) {
+ CopyEffects *copy_effects = CopyEffects::get_singleton();
+
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+ ERR_FAIL_COND(rt->sdf_texture_write_fb == 0);
+
+ Rect2i r = _render_target_get_sdf_rect(rt);
+
+ Size2i size = r.size;
+ int32_t shift = 0;
+
+ bool shrink = false;
+
+ switch (rt->sdf_scale) {
+ case RS::VIEWPORT_SDF_SCALE_50_PERCENT: {
+ size[0] >>= 1;
+ size[1] >>= 1;
+ shift = 1;
+ shrink = true;
+ } break;
+ case RS::VIEWPORT_SDF_SCALE_25_PERCENT: {
+ size[0] >>= 2;
+ size[1] >>= 2;
+ shift = 2;
+ shrink = true;
+ } break;
+ default: {
+ };
+ }
+
+ GLuint temp_fb;
+ glGenFramebuffers(1, &temp_fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, temp_fb);
+
+ // Load
+ CanvasSdfShaderGLES3::ShaderVariant variant = shrink ? CanvasSdfShaderGLES3::MODE_LOAD_SHRINK : CanvasSdfShaderGLES3::MODE_LOAD;
+ bool success = sdf_shader.shader.version_bind_shader(sdf_shader.shader_version, variant);
+ if (!success) {
+ return;
+ }
+
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::BASE_SIZE, r.size, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SIZE, size, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::STRIDE, 0, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SHIFT, shift, sdf_shader.shader_version, variant);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_write);
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->sdf_texture_process[0], 0);
+ glViewport(0, 0, size.width, size.height);
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(0, 0, size.width, size.height);
+
+ copy_effects->draw_screen_triangle();
+
+ // Process
+
+ int stride = nearest_power_of_2_templated(MAX(size.width, size.height) / 2);
+
+ variant = CanvasSdfShaderGLES3::MODE_PROCESS;
+ success = sdf_shader.shader.version_bind_shader(sdf_shader.shader_version, variant);
+ if (!success) {
+ return;
+ }
+
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::BASE_SIZE, r.size, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SIZE, size, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::STRIDE, stride, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SHIFT, shift, sdf_shader.shader_version, variant);
+
+ bool swap = false;
+
+ //jumpflood
+ while (stride > 0) {
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->sdf_texture_process[swap ? 0 : 1], 0);
+ glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_process[swap ? 1 : 0]);
+
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::STRIDE, stride, sdf_shader.shader_version, variant);
+
+ copy_effects->draw_screen_triangle();
+
+ stride /= 2;
+ swap = !swap;
+ }
+
+ // Store
+ variant = shrink ? CanvasSdfShaderGLES3::MODE_STORE_SHRINK : CanvasSdfShaderGLES3::MODE_STORE;
+ success = sdf_shader.shader.version_bind_shader(sdf_shader.shader_version, variant);
+ if (!success) {
+ return;
+ }
+
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::BASE_SIZE, r.size, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SIZE, size, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::STRIDE, stride, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SHIFT, shift, sdf_shader.shader_version, variant);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->sdf_texture_read, 0);
+ glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_process[swap ? 1 : 0]);
+
+ copy_effects->draw_screen_triangle();
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, system_fbo);
+ glDeleteFramebuffers(1, &temp_fb);
+ glDisable(GL_SCISSOR_TEST);
}
void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) {
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index 4f4032723b..9d3f407226 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* texture_storage.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
@@ -39,6 +39,8 @@
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/storage/texture_storage.h"
+#include "../shaders/canvas_sdf.glsl.gen.h"
+
// This must come first to avoid windows.h mess
#include "platform_config.h"
#ifndef OPENGL_INCLUDE_H
@@ -84,18 +86,8 @@ namespace GLES3 {
#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
@@ -126,22 +118,6 @@ struct CanvasTexture {
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;
@@ -150,9 +126,10 @@ struct Texture {
RID self;
bool is_proxy = false;
+ bool is_external = false;
bool is_render_target = false;
- RID proxy_to = RID();
+ RID proxy_to;
Vector<RID> proxies;
String path;
@@ -211,6 +188,7 @@ struct Texture {
void copy_from(const Texture &o) {
proxy_to = o.proxy_to;
is_proxy = o.is_proxy;
+ is_external = o.is_external;
width = o.width;
height = o.height;
alloc_width = o.alloc_width;
@@ -327,22 +305,14 @@ private:
};
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);
+ uint32_t view_count = 1;
int mipmap_count = 1;
RID self;
GLuint fbo = 0;
GLuint color = 0;
+ GLuint depth = 0;
GLuint backbuffer_fbo = 0;
GLuint backbuffer = 0;
@@ -351,12 +321,37 @@ struct RenderTarget {
GLuint color_type = GL_UNSIGNED_BYTE;
Image::Format image_format = Image::FORMAT_RGBA8;
+ GLuint sdf_texture_write = 0;
+ GLuint sdf_texture_write_fb = 0;
+ GLuint sdf_texture_process[2] = { 0, 0 };
+ GLuint sdf_texture_read = 0;
+ RS::ViewportSDFOversize sdf_oversize = RS::VIEWPORT_SDF_OVERSIZE_120_PERCENT;
+ RS::ViewportSDFScale sdf_scale = RS::VIEWPORT_SDF_SCALE_50_PERCENT;
+ Size2i process_size;
+ bool sdf_enabled = false;
+
bool is_transparent = false;
bool direct_to_screen = false;
bool used_in_frame = false;
RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
+ struct RTOverridden {
+ bool is_overridden = false;
+ RID color;
+ RID depth;
+ RID velocity;
+
+ struct FBOCacheEntry {
+ GLuint fbo;
+ GLuint color;
+ GLuint depth;
+ Size2i size;
+ Vector<GLuint> allocated_textures;
+ };
+ RBMap<uint32_t, FBOCacheEntry> fbo_cache;
+ } overridden;
+
RID texture;
Color clear_color = Color(1, 1, 1, 1);
@@ -376,16 +371,44 @@ private:
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;
+ /* TEXTURE ATLAS API */
+
+ struct TextureAtlas {
+ struct Texture {
+ int users;
+ Rect2 uv_rect;
+ };
+
+ struct SortItem {
+ RID texture;
+ Size2i pixel_size;
+ Size2i size;
+ Point2i pos;
+
+ bool operator<(const SortItem &p_item) const {
+ //sort larger to smaller
+ if (size.height == p_item.size.height) {
+ return size.width > p_item.size.width;
+ } else {
+ return size.height > p_item.size.height;
+ }
+ }
+ };
+
+ HashMap<RID, Texture> textures;
+ bool dirty = true;
+
+ GLuint texture = 0;
+ GLuint framebuffer = 0;
+ Size2i size;
+ } texture_atlas;
+
/* Render Target API */
mutable RID_Owner<RenderTarget> render_target_owner;
@@ -393,6 +416,14 @@ private:
void _clear_render_target(RenderTarget *rt);
void _update_render_target(RenderTarget *rt);
void _create_render_target_backbuffer(RenderTarget *rt);
+ void _render_target_allocate_sdf(RenderTarget *rt);
+ void _render_target_clear_sdf(RenderTarget *rt);
+ Rect2i _render_target_get_sdf_rect(const RenderTarget *rt) const;
+
+ struct RenderTargetSDF {
+ CanvasSdfShaderGLES3 shader;
+ RID shader_version;
+ } sdf_shader;
public:
static TextureStorage *get_singleton();
@@ -419,10 +450,6 @@ public:
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) {
@@ -446,6 +473,8 @@ public:
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
+ RID texture_create_external(Texture::Type p_type, Image::Format p_format, unsigned int p_image, int p_width, int p_height, int p_depth, int p_layers, RS::TextureLayeredType p_layered_type = RS::TEXTURE_LAYERED_2D_ARRAY);
+
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;
@@ -476,6 +505,8 @@ public:
virtual Size2 texture_size_with_proxy(RID p_proxy) override;
+ virtual RID texture_get_rd_texture_rid(RID p_texture, bool p_srgb = false) const 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;
@@ -488,6 +519,25 @@ public:
void texture_bind(RID p_texture, uint32_t p_texture_no);
RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const;
+ /* TEXTURE ATLAS API */
+
+ void update_texture_atlas();
+
+ GLuint texture_atlas_get_texture() const;
+ _FORCE_INLINE_ Rect2 texture_atlas_get_texture_rect(RID p_texture) {
+ TextureAtlas::Texture *t = texture_atlas.textures.getptr(p_texture);
+ if (!t) {
+ return Rect2();
+ }
+
+ return t->uv_rect;
+ }
+
+ void texture_add_to_texture_atlas(RID p_texture);
+ void texture_remove_from_texture_atlas(RID p_texture);
+ void texture_atlas_mark_dirty_on_texture(RID p_texture);
+ void texture_atlas_remove_texture(RID p_texture);
+
/* DECAL API */
virtual RID decal_allocate() override;
@@ -509,6 +559,13 @@ public:
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 {}
+ /* DECAL INSTANCE */
+
+ virtual RID decal_instance_create(RID p_decal) override { return RID(); }
+ virtual void decal_instance_free(RID p_decal_instance) override {}
+ virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override {}
+ virtual void decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) override {}
+
/* RENDER TARGET API */
static GLuint system_fbo;
@@ -518,17 +575,19 @@ public:
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 Point2i render_target_get_position(RID p_render_target) const 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 Size2i render_target_get_size(RID p_render_target) const override;
virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override;
+ virtual bool render_target_get_transparent(RID p_render_target) const 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;
+ virtual bool render_target_get_direct_to_screen(RID p_render_target) const override;
+ virtual bool render_target_was_used(RID p_render_target) const override;
void render_target_clear_used(RID p_render_target);
virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) override;
+ virtual RS::ViewportMSAA render_target_get_msaa(RID p_render_target) const override;
// new
void render_target_set_as_unused(RID p_render_target) override {
@@ -541,15 +600,29 @@ public:
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;
+ virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override;
+ virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const override;
+ GLuint render_target_get_sdf_texture(RID p_render_target);
+ GLuint render_target_get_sdf_framebuffer(RID p_render_target);
+ void render_target_sdf_process(RID p_render_target);
+ virtual void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override;
+ bool render_target_is_sdf_enabled(RID p_render_target) const;
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{};
+
+ virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override {}
+ virtual RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const override { return RS::VIEWPORT_VRS_DISABLED; }
+ virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override {}
+ virtual RID render_target_get_vrs_texture(RID p_render_target) const override { return RID(); }
+
+ virtual void render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) override;
+ virtual RID render_target_get_override_color(RID p_render_target) const override;
+ virtual RID render_target_get_override_depth(RID p_render_target) const override;
+ virtual RID render_target_get_override_velocity(RID p_render_target) const override;
+
+ virtual RID render_target_get_texture(RID p_render_target) override;
void bind_framebuffer(GLuint framebuffer) {
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
diff --git a/drivers/gles3/storage/utilities.cpp b/drivers/gles3/storage/utilities.cpp
index 16bacf1829..e72240c69b 100644
--- a/drivers/gles3/storage/utilities.cpp
+++ b/drivers/gles3/storage/utilities.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* utilities.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
@@ -38,20 +38,44 @@
#include "particles_storage.h"
#include "texture_storage.h"
+#include "servers/rendering/rendering_server_globals.h"
+
using namespace GLES3;
Utilities *Utilities::singleton = nullptr;
Utilities::Utilities() {
singleton = this;
+ frame = 0;
+ for (int i = 0; i < FRAME_COUNT; i++) {
+ frames[i].index = 0;
+ glGenQueries(max_timestamp_query_elements, frames[i].queries);
+
+ 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.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;
+ }
}
Utilities::~Utilities() {
singleton = nullptr;
+ for (int i = 0; i < FRAME_COUNT; i++) {
+ glDeleteQueries(max_timestamp_query_elements, frames[i].queries);
+ }
}
Vector<uint8_t> Utilities::buffer_get_data(GLenum p_target, GLuint p_buffer, uint32_t p_buffer_size) {
Vector<uint8_t> ret;
+
+ if (p_buffer_size == 0) {
+ return ret;
+ }
+
ret.resize(p_buffer_size);
glBindBuffer(p_target, p_buffer);
@@ -84,6 +108,10 @@ RS::InstanceType Utilities::get_base_type(RID p_rid) const {
return RS::INSTANCE_LIGHT;
} else if (GLES3::LightStorage::get_singleton()->owns_lightmap(p_rid)) {
return RS::INSTANCE_LIGHTMAP;
+ } else if (GLES3::ParticlesStorage::get_singleton()->owns_particles(p_rid)) {
+ return RS::INSTANCE_PARTICLES;
+ } else if (GLES3::ParticlesStorage::get_singleton()->owns_particles_collision(p_rid)) {
+ return RS::INSTANCE_PARTICLES_COLLISION;
}
return RS::INSTANCE_NONE;
}
@@ -119,53 +147,21 @@ bool Utilities::free(RID p_rid) {
} else if (GLES3::LightStorage::get_singleton()->owns_lightmap(p_rid)) {
GLES3::LightStorage::get_singleton()->lightmap_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);
-
+ } else if (GLES3::ParticlesStorage::get_singleton()->owns_particles(p_rid)) {
+ GLES3::ParticlesStorage::get_singleton()->particles_free(p_rid);
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);
+ } else if (GLES3::ParticlesStorage::get_singleton()->owns_particles_collision(p_rid)) {
+ GLES3::ParticlesStorage::get_singleton()->particles_collision_free(p_rid);
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);
-
+ } else if (GLES3::ParticlesStorage::get_singleton()->owns_particles_collision_instance(p_rid)) {
+ GLES3::ParticlesStorage::get_singleton()->particles_collision_instance_free(p_rid);
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);
-
+ } else if (GLES3::MeshStorage::get_singleton()->owns_skeleton(p_rid)) {
+ GLES3::MeshStorage::get_singleton()->skeleton_free(p_rid);
return true;
+ } else {
+ return false;
}
- */
}
/* DEPENDENCIES */
@@ -183,6 +179,12 @@ void Utilities::base_update_dependency(RID p_base, DependencyTracker *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);
+ } else if (ParticlesStorage::get_singleton()->owns_particles(p_base)) {
+ Dependency *dependency = ParticlesStorage::get_singleton()->particles_get_dependency(p_base);
+ p_instance->update_dependency(dependency);
+ } else if (ParticlesStorage::get_singleton()->owns_particles_collision(p_base)) {
+ Dependency *dependency = ParticlesStorage::get_singleton()->particles_collision_get_dependency(p_base);
+ p_instance->update_dependency(dependency);
}
}
@@ -213,95 +215,78 @@ void Utilities::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_de
/* 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
-// }
-//}
+void Utilities::capture_timestamps_begin() {
+ capture_timestamp("Frame Begin");
+}
+
+void Utilities::capture_timestamp(const String &p_name) {
+ ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements);
+
+#ifdef GLES_OVER_GL
+ glQueryCounter(frames[frame].queries[frames[frame].timestamp_count], GL_TIMESTAMP);
+#endif
+
+ frames[frame].timestamp_names[frames[frame].timestamp_count] = p_name;
+ frames[frame].timestamp_cpu_values[frames[frame].timestamp_count] = OS::get_singleton()->get_ticks_usec();
+ frames[frame].timestamp_count++;
+}
+
+void Utilities::_capture_timestamps_begin() {
+ // frame is incremented at the end of the frame so this gives us the queries for frame - 2. By then they should be ready.
+ if (frames[frame].timestamp_count) {
+#ifdef GLES_OVER_GL
+ for (uint32_t i = 0; i < frames[frame].timestamp_count; i++) {
+ uint64_t temp = 0;
+ glGetQueryObjectui64v(frames[frame].queries[i], GL_QUERY_RESULT, &temp);
+ frames[frame].timestamp_result_values[i] = temp;
+ }
+#endif
+ SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names);
+ SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values);
+ }
+
+ frames[frame].timestamp_result_count = frames[frame].timestamp_count;
+ frames[frame].timestamp_count = 0;
+ frames[frame].index = Engine::get_singleton()->get_frames_drawn();
+ capture_timestamp("Internal Begin");
+}
+
+void Utilities::capture_timestamps_end() {
+ capture_timestamp("Internal End");
+ frame = (frame + 1) % FRAME_COUNT;
+}
+
+uint32_t Utilities::get_captured_timestamps_count() const {
+ return frames[frame].timestamp_result_count;
+}
+
+uint64_t Utilities::get_captured_timestamps_frame() const {
+ return frames[frame].index;
+}
+
+uint64_t Utilities::get_captured_timestamp_gpu_time(uint32_t p_index) const {
+ ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
+ return frames[frame].timestamp_result_values[p_index];
+}
+
+uint64_t Utilities::get_captured_timestamp_cpu_time(uint32_t p_index) const {
+ ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
+ return frames[frame].timestamp_cpu_result_values[p_index];
+}
+
+String Utilities::get_captured_timestamp_name(uint32_t p_index) const {
+ ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, String());
+ return frames[frame].timestamp_result_names[p_index];
+}
/* 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_skeletons();
MeshStorage::get_singleton()->_update_dirty_multimeshes();
+ TextureStorage::get_singleton()->update_texture_atlas();
}
void Utilities::set_debug_generate_wireframes(bool p_generate) {
@@ -355,4 +340,13 @@ String Utilities::get_video_adapter_api_version() const {
return (const char *)glGetString(GL_VERSION);
}
+Size2i Utilities::get_maximum_viewport_size() const {
+ Config *config = Config::get_singleton();
+ if (!config) {
+ return Size2i();
+ }
+
+ return Size2i(config->max_viewport_size[0], config->max_viewport_size[1]);
+}
+
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/storage/utilities.h b/drivers/gles3/storage/utilities.h
index e054f2f816..92131aff8c 100644
--- a/drivers/gles3/storage/utilities.h
+++ b/drivers/gles3/storage/utilities.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* utilities.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
@@ -79,62 +79,35 @@ public:
/* 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;
+#define MAX_QUERIES 256
+#define FRAME_COUNT 3
+
+ struct Frame {
+ GLuint queries[MAX_QUERIES];
+ TightLocalVector<String> timestamp_names;
+ TightLocalVector<uint64_t> timestamp_cpu_values;
+ uint32_t timestamp_count = 0;
+ 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;
+ };
+
+ const uint32_t max_timestamp_query_elements = MAX_QUERIES;
+
+ Frame frames[FRAME_COUNT]; // Frames for capturing timestamps. We use 3 so we don't need to wait for commands to complete
+ uint32_t frame = 0;
+
+ virtual void capture_timestamps_begin() override;
+ virtual void capture_timestamp(const String &p_name) override;
+ virtual uint32_t get_captured_timestamps_count() const override;
+ virtual uint64_t get_captured_timestamps_frame() const override;
+ virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const override;
+ virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const override;
+ virtual String get_captured_timestamp_name(uint32_t p_index) const override;
+ void _capture_timestamps_begin();
+ void capture_timestamps_end();
/* MISC */
@@ -150,6 +123,8 @@ public:
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;
+
+ virtual Size2i get_maximum_viewport_size() const override;
};
} // namespace GLES3
diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp
index 8d2f8a7ed6..cbcb54bc11 100644
--- a/drivers/png/image_loader_png.cpp
+++ b/drivers/png/image_loader_png.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* image_loader_png.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* image_loader_png.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 "image_loader_png.h"
@@ -36,7 +36,7 @@
#include <string.h>
-Error ImageLoaderPNG::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
+Error ImageLoaderPNG::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
const uint64_t buffer_size = f->get_length();
Vector<uint8_t> file_buffer;
Error err = file_buffer.resize(buffer_size);
diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h
index 91c3c8925f..d587672dd1 100644
--- a/drivers/png/image_loader_png.h
+++ b/drivers/png/image_loader_png.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* image_loader_png.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* image_loader_png.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 IMAGE_LOADER_PNG_H
#define IMAGE_LOADER_PNG_H
@@ -40,7 +40,7 @@ private:
static Ref<Image> load_mem_png(const uint8_t *p_png, int p_size);
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderPNG();
};
diff --git a/drivers/png/png_driver_common.cpp b/drivers/png/png_driver_common.cpp
index bc4bb3782b..a789d5c5b3 100644
--- a/drivers/png/png_driver_common.cpp
+++ b/drivers/png/png_driver_common.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* png_driver_common.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* png_driver_common.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 "png_driver_common.h"
@@ -119,7 +119,7 @@ Error png_to_image(const uint8_t *p_source, size_t p_size, bool p_force_linear,
ERR_FAIL_COND_V(!success, ERR_FILE_CORRUPT);
//print_line("png width: "+itos(png_img.width)+" height: "+itos(png_img.height));
- p_image->create(png_img.width, png_img.height, false, dest_format, buffer);
+ p_image->set_data(png_img.width, png_img.height, false, dest_format, buffer);
return OK;
}
diff --git a/drivers/png/png_driver_common.h b/drivers/png/png_driver_common.h
index 24546d4402..423a3b5b02 100644
--- a/drivers/png/png_driver_common.h
+++ b/drivers/png/png_driver_common.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* png_driver_common.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* png_driver_common.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 PNG_DRIVER_COMMON_H
#define PNG_DRIVER_COMMON_H
diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp
index 275f3240d7..ab0ff32514 100644
--- a/drivers/png/resource_saver_png.cpp
+++ b/drivers/png/resource_saver_png.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* resource_saver_png.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* resource_saver_png.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 "resource_saver_png.h"
diff --git a/drivers/png/resource_saver_png.h b/drivers/png/resource_saver_png.h
index 260a643a1b..2193b4a39b 100644
--- a/drivers/png/resource_saver_png.h
+++ b/drivers/png/resource_saver_png.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* resource_saver_png.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* resource_saver_png.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 RESOURCE_SAVER_PNG_H
#define RESOURCE_SAVER_PNG_H
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index b25cf1d5b4..e14c3c7f7a 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* audio_driver_pulseaudio.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* audio_driver_pulseaudio.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#include "audio_driver_pulseaudio.h"
@@ -264,7 +264,7 @@ Error AudioDriverPulseAudio::init_device() {
samples_in.resize(buffer_frames * channels);
samples_out.resize(pa_buffer_size);
- // Reset audio input to keep synchronisation.
+ // Reset audio input to keep synchronization.
input_position = 0;
input_size = 0;
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h
index 85e328b49f..16398e67eb 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.h
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* audio_driver_pulseaudio.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* audio_driver_pulseaudio.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef AUDIO_DRIVER_PULSEAUDIO_H
#define AUDIO_DRIVER_PULSEAUDIO_H
@@ -48,8 +48,8 @@ class AudioDriverPulseAudio : public AudioDriver {
pa_context *pa_ctx = nullptr;
pa_stream *pa_str = nullptr;
pa_stream *pa_rec_str = nullptr;
- pa_channel_map pa_map;
- pa_channel_map pa_rec_map;
+ pa_channel_map pa_map = {};
+ pa_channel_map pa_rec_map = {};
String device_name = "Default";
String new_device = "Default";
diff --git a/drivers/pulseaudio/pulse-so_wrap.c b/drivers/pulseaudio/pulse-so_wrap.c
index 12bdcc704e..1765d7e7e6 100644
--- a/drivers/pulseaudio/pulse-so_wrap.c
+++ b/drivers/pulseaudio/pulse-so_wrap.c
@@ -1,7 +1,7 @@
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by /home/hp/Projects/godot/pulse/generate-wrapper.py 0.3 on 2021-02-20 00:08:31
-// flags: /home/hp/Projects/godot/pulse/generate-wrapper.py --include /usr/include/pulse/pulseaudio.h --sys-include <pulse/pulseaudio.h> --soname libpulse.so.0 --omit-prefix _pa_ --init-name pulse --output-header pulse-so_wrap.h --output-implementation pulse-so_wrap.c
+// generated by ../dynload-wrapper/generate-wrapper.py 0.3 on 2023-01-12 10:26:29
+// flags: ../dynload-wrapper/generate-wrapper.py --include ./thirdparty/linuxbsd_headers/pulse/pulseaudio.h --sys-include "thirdparty/linuxbsd_headers/pulse/pulseaudio.h" --soname libpulse.so.0 --omit-prefix _pa_ --init-name pulse --output-header ./drivers/pulseaudio/pulse-so_wrap.h --output-implementation ./drivers/pulseaudio/pulse-so_wrap.c
//
#include <stdint.h>
@@ -89,10 +89,6 @@
#define pa_format_info_get_prop_string pa_format_info_get_prop_string_dylibloader_orig_pulse
#define pa_format_info_get_prop_string_array pa_format_info_get_prop_string_array_dylibloader_orig_pulse
#define pa_format_info_free_string_array pa_format_info_free_string_array_dylibloader_orig_pulse
-#define pa_format_info_get_sample_format pa_format_info_get_sample_format_dylibloader_orig_pulse
-#define pa_format_info_get_rate pa_format_info_get_rate_dylibloader_orig_pulse
-#define pa_format_info_get_channels pa_format_info_get_channels_dylibloader_orig_pulse
-#define pa_format_info_get_channel_map pa_format_info_get_channel_map_dylibloader_orig_pulse
#define pa_format_info_set_prop_int pa_format_info_set_prop_int_dylibloader_orig_pulse
#define pa_format_info_set_prop_int_array pa_format_info_set_prop_int_array_dylibloader_orig_pulse
#define pa_format_info_set_prop_int_range pa_format_info_set_prop_int_range_dylibloader_orig_pulse
@@ -327,7 +323,6 @@
#define pa_threaded_mainloop_get_api pa_threaded_mainloop_get_api_dylibloader_orig_pulse
#define pa_threaded_mainloop_in_thread pa_threaded_mainloop_in_thread_dylibloader_orig_pulse
#define pa_threaded_mainloop_set_name pa_threaded_mainloop_set_name_dylibloader_orig_pulse
-#define pa_threaded_mainloop_once_unlocked pa_threaded_mainloop_once_unlocked_dylibloader_orig_pulse
#define pa_mainloop_new pa_mainloop_new_dylibloader_orig_pulse
#define pa_mainloop_free pa_mainloop_free_dylibloader_orig_pulse
#define pa_mainloop_prepare pa_mainloop_prepare_dylibloader_orig_pulse
@@ -352,7 +347,6 @@
#define pa_get_binary_name pa_get_binary_name_dylibloader_orig_pulse
#define pa_path_get_filename pa_path_get_filename_dylibloader_orig_pulse
#define pa_msleep pa_msleep_dylibloader_orig_pulse
-#define pa_thread_make_realtime pa_thread_make_realtime_dylibloader_orig_pulse
#define pa_gettimeofday pa_gettimeofday_dylibloader_orig_pulse
#define pa_timeval_diff pa_timeval_diff_dylibloader_orig_pulse
#define pa_timeval_cmp pa_timeval_cmp_dylibloader_orig_pulse
@@ -362,7 +356,7 @@
#define pa_timeval_store pa_timeval_store_dylibloader_orig_pulse
#define pa_timeval_load pa_timeval_load_dylibloader_orig_pulse
#define pa_rtclock_now pa_rtclock_now_dylibloader_orig_pulse
-#include <pulse/pulseaudio.h>
+#include "thirdparty/linuxbsd_headers/pulse/pulseaudio.h"
#undef pa_get_library_version
#undef pa_bytes_per_second
#undef pa_frame_size
@@ -447,10 +441,6 @@
#undef pa_format_info_get_prop_string
#undef pa_format_info_get_prop_string_array
#undef pa_format_info_free_string_array
-#undef pa_format_info_get_sample_format
-#undef pa_format_info_get_rate
-#undef pa_format_info_get_channels
-#undef pa_format_info_get_channel_map
#undef pa_format_info_set_prop_int
#undef pa_format_info_set_prop_int_array
#undef pa_format_info_set_prop_int_range
@@ -685,7 +675,6 @@
#undef pa_threaded_mainloop_get_api
#undef pa_threaded_mainloop_in_thread
#undef pa_threaded_mainloop_set_name
-#undef pa_threaded_mainloop_once_unlocked
#undef pa_mainloop_new
#undef pa_mainloop_free
#undef pa_mainloop_prepare
@@ -710,7 +699,6 @@
#undef pa_get_binary_name
#undef pa_path_get_filename
#undef pa_msleep
-#undef pa_thread_make_realtime
#undef pa_gettimeofday
#undef pa_timeval_diff
#undef pa_timeval_cmp
@@ -751,21 +739,21 @@ int (*pa_proplist_sets_dylibloader_wrapper_pulse)( pa_proplist*,const char*,cons
int (*pa_proplist_setp_dylibloader_wrapper_pulse)( pa_proplist*,const char*);
int (*pa_proplist_setf_dylibloader_wrapper_pulse)( pa_proplist*,const char*,const char*,...);
int (*pa_proplist_set_dylibloader_wrapper_pulse)( pa_proplist*,const char*,const void*, size_t);
-const char* (*pa_proplist_gets_dylibloader_wrapper_pulse)(const pa_proplist*,const char*);
-int (*pa_proplist_get_dylibloader_wrapper_pulse)(const pa_proplist*,const char*,const void**, size_t*);
+const char* (*pa_proplist_gets_dylibloader_wrapper_pulse)( pa_proplist*,const char*);
+int (*pa_proplist_get_dylibloader_wrapper_pulse)( pa_proplist*,const char*,const void**, size_t*);
void (*pa_proplist_update_dylibloader_wrapper_pulse)( pa_proplist*, pa_update_mode_t,const pa_proplist*);
int (*pa_proplist_unset_dylibloader_wrapper_pulse)( pa_proplist*,const char*);
int (*pa_proplist_unset_many_dylibloader_wrapper_pulse)( pa_proplist*,const char* []);
-const char* (*pa_proplist_iterate_dylibloader_wrapper_pulse)(const pa_proplist*, void**);
-char* (*pa_proplist_to_string_dylibloader_wrapper_pulse)(const pa_proplist*);
-char* (*pa_proplist_to_string_sep_dylibloader_wrapper_pulse)(const pa_proplist*,const char*);
+const char* (*pa_proplist_iterate_dylibloader_wrapper_pulse)( pa_proplist*, void**);
+char* (*pa_proplist_to_string_dylibloader_wrapper_pulse)( pa_proplist*);
+char* (*pa_proplist_to_string_sep_dylibloader_wrapper_pulse)( pa_proplist*,const char*);
pa_proplist* (*pa_proplist_from_string_dylibloader_wrapper_pulse)(const char*);
-int (*pa_proplist_contains_dylibloader_wrapper_pulse)(const pa_proplist*,const char*);
+int (*pa_proplist_contains_dylibloader_wrapper_pulse)( pa_proplist*,const char*);
void (*pa_proplist_clear_dylibloader_wrapper_pulse)( pa_proplist*);
pa_proplist* (*pa_proplist_copy_dylibloader_wrapper_pulse)(const pa_proplist*);
-unsigned (*pa_proplist_size_dylibloader_wrapper_pulse)(const pa_proplist*);
-int (*pa_proplist_isempty_dylibloader_wrapper_pulse)(const pa_proplist*);
-int (*pa_proplist_equal_dylibloader_wrapper_pulse)(const pa_proplist*,const pa_proplist*);
+unsigned (*pa_proplist_size_dylibloader_wrapper_pulse)( pa_proplist*);
+int (*pa_proplist_isempty_dylibloader_wrapper_pulse)( pa_proplist*);
+int (*pa_proplist_equal_dylibloader_wrapper_pulse)( pa_proplist*, pa_proplist*);
pa_channel_map* (*pa_channel_map_init_dylibloader_wrapper_pulse)( pa_channel_map*);
pa_channel_map* (*pa_channel_map_init_mono_dylibloader_wrapper_pulse)( pa_channel_map*);
pa_channel_map* (*pa_channel_map_init_stereo_dylibloader_wrapper_pulse)( pa_channel_map*);
@@ -806,10 +794,6 @@ int (*pa_format_info_get_prop_int_array_dylibloader_wrapper_pulse)(const pa_form
int (*pa_format_info_get_prop_string_dylibloader_wrapper_pulse)(const pa_format_info*,const char*, char**);
int (*pa_format_info_get_prop_string_array_dylibloader_wrapper_pulse)(const pa_format_info*,const char*, char***, int*);
void (*pa_format_info_free_string_array_dylibloader_wrapper_pulse)( char**, int);
-int (*pa_format_info_get_sample_format_dylibloader_wrapper_pulse)(const pa_format_info*, pa_sample_format_t*);
-int (*pa_format_info_get_rate_dylibloader_wrapper_pulse)(const pa_format_info*, uint32_t*);
-int (*pa_format_info_get_channels_dylibloader_wrapper_pulse)(const pa_format_info*, uint8_t*);
-int (*pa_format_info_get_channel_map_dylibloader_wrapper_pulse)(const pa_format_info*, pa_channel_map*);
void (*pa_format_info_set_prop_int_dylibloader_wrapper_pulse)( pa_format_info*,const char*, int);
void (*pa_format_info_set_prop_int_array_dylibloader_wrapper_pulse)( pa_format_info*,const char*,const int*, int);
void (*pa_format_info_set_prop_int_range_dylibloader_wrapper_pulse)( pa_format_info*,const char*, int, int);
@@ -822,34 +806,34 @@ void (*pa_format_info_set_channel_map_dylibloader_wrapper_pulse)( pa_format_info
pa_operation* (*pa_operation_ref_dylibloader_wrapper_pulse)( pa_operation*);
void (*pa_operation_unref_dylibloader_wrapper_pulse)( pa_operation*);
void (*pa_operation_cancel_dylibloader_wrapper_pulse)( pa_operation*);
-pa_operation_state_t (*pa_operation_get_state_dylibloader_wrapper_pulse)(const pa_operation*);
+pa_operation_state_t (*pa_operation_get_state_dylibloader_wrapper_pulse)( pa_operation*);
void (*pa_operation_set_state_callback_dylibloader_wrapper_pulse)( pa_operation*, pa_operation_notify_cb_t, void*);
pa_context* (*pa_context_new_dylibloader_wrapper_pulse)( pa_mainloop_api*,const char*);
-pa_context* (*pa_context_new_with_proplist_dylibloader_wrapper_pulse)( pa_mainloop_api*,const char*,const pa_proplist*);
+pa_context* (*pa_context_new_with_proplist_dylibloader_wrapper_pulse)( pa_mainloop_api*,const char*, pa_proplist*);
void (*pa_context_unref_dylibloader_wrapper_pulse)( pa_context*);
pa_context* (*pa_context_ref_dylibloader_wrapper_pulse)( pa_context*);
void (*pa_context_set_state_callback_dylibloader_wrapper_pulse)( pa_context*, pa_context_notify_cb_t, void*);
void (*pa_context_set_event_callback_dylibloader_wrapper_pulse)( pa_context*, pa_context_event_cb_t, void*);
-int (*pa_context_errno_dylibloader_wrapper_pulse)(const pa_context*);
-int (*pa_context_is_pending_dylibloader_wrapper_pulse)(const pa_context*);
-pa_context_state_t (*pa_context_get_state_dylibloader_wrapper_pulse)(const pa_context*);
+int (*pa_context_errno_dylibloader_wrapper_pulse)( pa_context*);
+int (*pa_context_is_pending_dylibloader_wrapper_pulse)( pa_context*);
+pa_context_state_t (*pa_context_get_state_dylibloader_wrapper_pulse)( pa_context*);
int (*pa_context_connect_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_flags_t,const pa_spawn_api*);
void (*pa_context_disconnect_dylibloader_wrapper_pulse)( pa_context*);
pa_operation* (*pa_context_drain_dylibloader_wrapper_pulse)( pa_context*, pa_context_notify_cb_t, void*);
pa_operation* (*pa_context_exit_daemon_dylibloader_wrapper_pulse)( pa_context*, pa_context_success_cb_t, void*);
pa_operation* (*pa_context_set_default_sink_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_success_cb_t, void*);
pa_operation* (*pa_context_set_default_source_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_success_cb_t, void*);
-int (*pa_context_is_local_dylibloader_wrapper_pulse)(const pa_context*);
+int (*pa_context_is_local_dylibloader_wrapper_pulse)( pa_context*);
pa_operation* (*pa_context_set_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_success_cb_t, void*);
-const char* (*pa_context_get_server_dylibloader_wrapper_pulse)(const pa_context*);
-uint32_t (*pa_context_get_protocol_version_dylibloader_wrapper_pulse)(const pa_context*);
-uint32_t (*pa_context_get_server_protocol_version_dylibloader_wrapper_pulse)(const pa_context*);
-pa_operation* (*pa_context_proplist_update_dylibloader_wrapper_pulse)( pa_context*, pa_update_mode_t,const pa_proplist*, pa_context_success_cb_t, void*);
+const char* (*pa_context_get_server_dylibloader_wrapper_pulse)( pa_context*);
+uint32_t (*pa_context_get_protocol_version_dylibloader_wrapper_pulse)( pa_context*);
+uint32_t (*pa_context_get_server_protocol_version_dylibloader_wrapper_pulse)( pa_context*);
+pa_operation* (*pa_context_proplist_update_dylibloader_wrapper_pulse)( pa_context*, pa_update_mode_t, pa_proplist*, pa_context_success_cb_t, void*);
pa_operation* (*pa_context_proplist_remove_dylibloader_wrapper_pulse)( pa_context*,const char* [], pa_context_success_cb_t, void*);
-uint32_t (*pa_context_get_index_dylibloader_wrapper_pulse)(const pa_context*);
-pa_time_event* (*pa_context_rttime_new_dylibloader_wrapper_pulse)(const pa_context*, pa_usec_t, pa_time_event_cb_t, void*);
-void (*pa_context_rttime_restart_dylibloader_wrapper_pulse)(const pa_context*, pa_time_event*, pa_usec_t);
-size_t (*pa_context_get_tile_size_dylibloader_wrapper_pulse)(const pa_context*,const pa_sample_spec*);
+uint32_t (*pa_context_get_index_dylibloader_wrapper_pulse)( pa_context*);
+pa_time_event* (*pa_context_rttime_new_dylibloader_wrapper_pulse)( pa_context*, pa_usec_t, pa_time_event_cb_t, void*);
+void (*pa_context_rttime_restart_dylibloader_wrapper_pulse)( pa_context*, pa_time_event*, pa_usec_t);
+size_t (*pa_context_get_tile_size_dylibloader_wrapper_pulse)( pa_context*,const pa_sample_spec*);
int (*pa_context_load_cookie_from_file_dylibloader_wrapper_pulse)( pa_context*,const char*);
int (*pa_cvolume_equal_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_cvolume*);
pa_cvolume* (*pa_cvolume_init_dylibloader_wrapper_pulse)( pa_cvolume*);
@@ -888,9 +872,9 @@ pa_cvolume* (*pa_cvolume_set_fade_dylibloader_wrapper_pulse)( pa_cvolume*,const
float (*pa_cvolume_get_lfe_balance_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*);
pa_cvolume* (*pa_cvolume_set_lfe_balance_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_channel_map*, float);
pa_cvolume* (*pa_cvolume_scale_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t);
-pa_cvolume* (*pa_cvolume_scale_mask_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t,const pa_channel_map*, pa_channel_position_mask_t);
+pa_cvolume* (*pa_cvolume_scale_mask_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t, pa_channel_map*, pa_channel_position_mask_t);
pa_cvolume* (*pa_cvolume_set_position_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_channel_map*, pa_channel_position_t, pa_volume_t);
-pa_volume_t (*pa_cvolume_get_position_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*, pa_channel_position_t);
+pa_volume_t (*pa_cvolume_get_position_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_channel_map*, pa_channel_position_t);
pa_cvolume* (*pa_cvolume_merge_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_cvolume*,const pa_cvolume*);
pa_cvolume* (*pa_cvolume_inc_clamp_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t, pa_volume_t);
pa_cvolume* (*pa_cvolume_inc_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t);
@@ -900,13 +884,13 @@ pa_stream* (*pa_stream_new_with_proplist_dylibloader_wrapper_pulse)( pa_context*
pa_stream* (*pa_stream_new_extended_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_format_info**, unsigned int, pa_proplist*);
void (*pa_stream_unref_dylibloader_wrapper_pulse)( pa_stream*);
pa_stream* (*pa_stream_ref_dylibloader_wrapper_pulse)( pa_stream*);
-pa_stream_state_t (*pa_stream_get_state_dylibloader_wrapper_pulse)(const pa_stream*);
-pa_context* (*pa_stream_get_context_dylibloader_wrapper_pulse)(const pa_stream*);
-uint32_t (*pa_stream_get_index_dylibloader_wrapper_pulse)(const pa_stream*);
-uint32_t (*pa_stream_get_device_index_dylibloader_wrapper_pulse)(const pa_stream*);
-const char* (*pa_stream_get_device_name_dylibloader_wrapper_pulse)(const pa_stream*);
-int (*pa_stream_is_suspended_dylibloader_wrapper_pulse)(const pa_stream*);
-int (*pa_stream_is_corked_dylibloader_wrapper_pulse)(const pa_stream*);
+pa_stream_state_t (*pa_stream_get_state_dylibloader_wrapper_pulse)( pa_stream*);
+pa_context* (*pa_stream_get_context_dylibloader_wrapper_pulse)( pa_stream*);
+uint32_t (*pa_stream_get_index_dylibloader_wrapper_pulse)( pa_stream*);
+uint32_t (*pa_stream_get_device_index_dylibloader_wrapper_pulse)( pa_stream*);
+const char* (*pa_stream_get_device_name_dylibloader_wrapper_pulse)( pa_stream*);
+int (*pa_stream_is_suspended_dylibloader_wrapper_pulse)( pa_stream*);
+int (*pa_stream_is_corked_dylibloader_wrapper_pulse)( pa_stream*);
int (*pa_stream_connect_playback_dylibloader_wrapper_pulse)( pa_stream*,const char*,const pa_buffer_attr*, pa_stream_flags_t,const pa_cvolume*, pa_stream*);
int (*pa_stream_connect_record_dylibloader_wrapper_pulse)( pa_stream*,const char*,const pa_buffer_attr*, pa_stream_flags_t);
int (*pa_stream_disconnect_dylibloader_wrapper_pulse)( pa_stream*);
@@ -916,15 +900,15 @@ int (*pa_stream_write_dylibloader_wrapper_pulse)( pa_stream*,const void*, size_t
int (*pa_stream_write_ext_free_dylibloader_wrapper_pulse)( pa_stream*,const void*, size_t, pa_free_cb_t, void*, int64_t, pa_seek_mode_t);
int (*pa_stream_peek_dylibloader_wrapper_pulse)( pa_stream*,const void**, size_t*);
int (*pa_stream_drop_dylibloader_wrapper_pulse)( pa_stream*);
-size_t (*pa_stream_writable_size_dylibloader_wrapper_pulse)(const pa_stream*);
-size_t (*pa_stream_readable_size_dylibloader_wrapper_pulse)(const pa_stream*);
+size_t (*pa_stream_writable_size_dylibloader_wrapper_pulse)( pa_stream*);
+size_t (*pa_stream_readable_size_dylibloader_wrapper_pulse)( pa_stream*);
pa_operation* (*pa_stream_drain_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_success_cb_t, void*);
pa_operation* (*pa_stream_update_timing_info_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_success_cb_t, void*);
void (*pa_stream_set_state_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
void (*pa_stream_set_write_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_request_cb_t, void*);
void (*pa_stream_set_read_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_request_cb_t, void*);
void (*pa_stream_set_overflow_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
-int64_t (*pa_stream_get_underflow_index_dylibloader_wrapper_pulse)(const pa_stream*);
+int64_t (*pa_stream_get_underflow_index_dylibloader_wrapper_pulse)( pa_stream*);
void (*pa_stream_set_underflow_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
void (*pa_stream_set_started_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
void (*pa_stream_set_latency_update_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
@@ -942,14 +926,14 @@ int (*pa_stream_get_latency_dylibloader_wrapper_pulse)( pa_stream*, pa_usec_t*,
const pa_timing_info* (*pa_stream_get_timing_info_dylibloader_wrapper_pulse)( pa_stream*);
const pa_sample_spec* (*pa_stream_get_sample_spec_dylibloader_wrapper_pulse)( pa_stream*);
const pa_channel_map* (*pa_stream_get_channel_map_dylibloader_wrapper_pulse)( pa_stream*);
-const pa_format_info* (*pa_stream_get_format_info_dylibloader_wrapper_pulse)(const pa_stream*);
+const pa_format_info* (*pa_stream_get_format_info_dylibloader_wrapper_pulse)( pa_stream*);
const pa_buffer_attr* (*pa_stream_get_buffer_attr_dylibloader_wrapper_pulse)( pa_stream*);
pa_operation* (*pa_stream_set_buffer_attr_dylibloader_wrapper_pulse)( pa_stream*,const pa_buffer_attr*, pa_stream_success_cb_t, void*);
pa_operation* (*pa_stream_update_sample_rate_dylibloader_wrapper_pulse)( pa_stream*, uint32_t, pa_stream_success_cb_t, void*);
pa_operation* (*pa_stream_proplist_update_dylibloader_wrapper_pulse)( pa_stream*, pa_update_mode_t, pa_proplist*, pa_stream_success_cb_t, void*);
pa_operation* (*pa_stream_proplist_remove_dylibloader_wrapper_pulse)( pa_stream*,const char* [], pa_stream_success_cb_t, void*);
int (*pa_stream_set_monitor_stream_dylibloader_wrapper_pulse)( pa_stream*, uint32_t);
-uint32_t (*pa_stream_get_monitor_stream_dylibloader_wrapper_pulse)(const pa_stream*);
+uint32_t (*pa_stream_get_monitor_stream_dylibloader_wrapper_pulse)( pa_stream*);
pa_operation* (*pa_context_get_sink_info_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_sink_info_cb_t, void*);
pa_operation* (*pa_context_get_sink_info_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_sink_info_cb_t, void*);
pa_operation* (*pa_context_get_sink_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_sink_info_cb_t, void*);
@@ -1016,7 +1000,7 @@ int (*pa_stream_connect_upload_dylibloader_wrapper_pulse)( pa_stream*, size_t);
int (*pa_stream_finish_upload_dylibloader_wrapper_pulse)( pa_stream*);
pa_operation* (*pa_context_remove_sample_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_success_cb_t, void*);
pa_operation* (*pa_context_play_sample_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_volume_t, pa_context_success_cb_t, void*);
-pa_operation* (*pa_context_play_sample_with_proplist_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_volume_t,const pa_proplist*, pa_context_play_sample_cb_t, void*);
+pa_operation* (*pa_context_play_sample_with_proplist_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_volume_t, pa_proplist*, pa_context_play_sample_cb_t, void*);
const char* (*pa_strerror_dylibloader_wrapper_pulse)( int);
void* (*pa_xmalloc_dylibloader_wrapper_pulse)( size_t);
void* (*pa_xmalloc0_dylibloader_wrapper_pulse)( size_t);
@@ -1040,17 +1024,16 @@ void (*pa_threaded_mainloop_unlock_dylibloader_wrapper_pulse)( pa_threaded_mainl
void (*pa_threaded_mainloop_wait_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
void (*pa_threaded_mainloop_signal_dylibloader_wrapper_pulse)( pa_threaded_mainloop*, int);
void (*pa_threaded_mainloop_accept_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
-int (*pa_threaded_mainloop_get_retval_dylibloader_wrapper_pulse)(const pa_threaded_mainloop*);
+int (*pa_threaded_mainloop_get_retval_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
pa_mainloop_api* (*pa_threaded_mainloop_get_api_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
int (*pa_threaded_mainloop_in_thread_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
void (*pa_threaded_mainloop_set_name_dylibloader_wrapper_pulse)( pa_threaded_mainloop*,const char*);
-void (*pa_threaded_mainloop_once_unlocked_dylibloader_wrapper_pulse)( pa_threaded_mainloop*, void*, void*);
pa_mainloop* (*pa_mainloop_new_dylibloader_wrapper_pulse)( void);
void (*pa_mainloop_free_dylibloader_wrapper_pulse)( pa_mainloop*);
int (*pa_mainloop_prepare_dylibloader_wrapper_pulse)( pa_mainloop*, int);
int (*pa_mainloop_poll_dylibloader_wrapper_pulse)( pa_mainloop*);
int (*pa_mainloop_dispatch_dylibloader_wrapper_pulse)( pa_mainloop*);
-int (*pa_mainloop_get_retval_dylibloader_wrapper_pulse)(const pa_mainloop*);
+int (*pa_mainloop_get_retval_dylibloader_wrapper_pulse)( pa_mainloop*);
int (*pa_mainloop_iterate_dylibloader_wrapper_pulse)( pa_mainloop*, int, int*);
int (*pa_mainloop_run_dylibloader_wrapper_pulse)( pa_mainloop*, int*);
pa_mainloop_api* (*pa_mainloop_get_api_dylibloader_wrapper_pulse)( pa_mainloop*);
@@ -1069,7 +1052,6 @@ char* (*pa_get_home_dir_dylibloader_wrapper_pulse)( char*, size_t);
char* (*pa_get_binary_name_dylibloader_wrapper_pulse)( char*, size_t);
char* (*pa_path_get_filename_dylibloader_wrapper_pulse)(const char*);
int (*pa_msleep_dylibloader_wrapper_pulse)( unsigned long);
-int (*pa_thread_make_realtime_dylibloader_wrapper_pulse)( int);
struct timeval* (*pa_gettimeofday_dylibloader_wrapper_pulse)(struct timeval*);
pa_usec_t (*pa_timeval_diff_dylibloader_wrapper_pulse)(struct timeval*,struct timeval*);
int (*pa_timeval_cmp_dylibloader_wrapper_pulse)(struct timeval*,struct timeval*);
@@ -1762,38 +1744,6 @@ int initialize_pulse(int verbose) {
fprintf(stderr, "%s\n", error);
}
}
-// pa_format_info_get_sample_format
- *(void **) (&pa_format_info_get_sample_format_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_get_sample_format");
- if (verbose) {
- error = dlerror();
- if (error != NULL) {
- fprintf(stderr, "%s\n", error);
- }
- }
-// pa_format_info_get_rate
- *(void **) (&pa_format_info_get_rate_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_get_rate");
- if (verbose) {
- error = dlerror();
- if (error != NULL) {
- fprintf(stderr, "%s\n", error);
- }
- }
-// pa_format_info_get_channels
- *(void **) (&pa_format_info_get_channels_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_get_channels");
- if (verbose) {
- error = dlerror();
- if (error != NULL) {
- fprintf(stderr, "%s\n", error);
- }
- }
-// pa_format_info_get_channel_map
- *(void **) (&pa_format_info_get_channel_map_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_get_channel_map");
- if (verbose) {
- error = dlerror();
- if (error != NULL) {
- fprintf(stderr, "%s\n", error);
- }
- }
// pa_format_info_set_prop_int
*(void **) (&pa_format_info_set_prop_int_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_set_prop_int");
if (verbose) {
@@ -3666,14 +3616,6 @@ int initialize_pulse(int verbose) {
fprintf(stderr, "%s\n", error);
}
}
-// pa_threaded_mainloop_once_unlocked
- *(void **) (&pa_threaded_mainloop_once_unlocked_dylibloader_wrapper_pulse) = dlsym(handle, "pa_threaded_mainloop_once_unlocked");
- if (verbose) {
- error = dlerror();
- if (error != NULL) {
- fprintf(stderr, "%s\n", error);
- }
- }
// pa_mainloop_new
*(void **) (&pa_mainloop_new_dylibloader_wrapper_pulse) = dlsym(handle, "pa_mainloop_new");
if (verbose) {
@@ -3866,14 +3808,6 @@ int initialize_pulse(int verbose) {
fprintf(stderr, "%s\n", error);
}
}
-// pa_thread_make_realtime
- *(void **) (&pa_thread_make_realtime_dylibloader_wrapper_pulse) = dlsym(handle, "pa_thread_make_realtime");
- if (verbose) {
- error = dlerror();
- if (error != NULL) {
- fprintf(stderr, "%s\n", error);
- }
- }
// pa_gettimeofday
*(void **) (&pa_gettimeofday_dylibloader_wrapper_pulse) = dlsym(handle, "pa_gettimeofday");
if (verbose) {
diff --git a/drivers/pulseaudio/pulse-so_wrap.h b/drivers/pulseaudio/pulse-so_wrap.h
index 7f9a70fae1..b3baf4c81a 100644
--- a/drivers/pulseaudio/pulse-so_wrap.h
+++ b/drivers/pulseaudio/pulse-so_wrap.h
@@ -2,8 +2,8 @@
#define DYLIBLOAD_WRAPPER_PULSE
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by /home/hp/Projects/godot/pulse/generate-wrapper.py 0.3 on 2021-02-20 00:08:31
-// flags: /home/hp/Projects/godot/pulse/generate-wrapper.py --include /usr/include/pulse/pulseaudio.h --sys-include <pulse/pulseaudio.h> --soname libpulse.so.0 --omit-prefix _pa_ --init-name pulse --output-header pulse-so_wrap.h --output-implementation pulse-so_wrap.c
+// generated by ../dynload-wrapper/generate-wrapper.py 0.3 on 2023-01-12 10:26:29
+// flags: ../dynload-wrapper/generate-wrapper.py --include ./thirdparty/linuxbsd_headers/pulse/pulseaudio.h --sys-include "thirdparty/linuxbsd_headers/pulse/pulseaudio.h" --soname libpulse.so.0 --omit-prefix _pa_ --init-name pulse --output-header ./drivers/pulseaudio/pulse-so_wrap.h --output-implementation ./drivers/pulseaudio/pulse-so_wrap.c
//
#include <stdint.h>
@@ -91,10 +91,6 @@
#define pa_format_info_get_prop_string pa_format_info_get_prop_string_dylibloader_orig_pulse
#define pa_format_info_get_prop_string_array pa_format_info_get_prop_string_array_dylibloader_orig_pulse
#define pa_format_info_free_string_array pa_format_info_free_string_array_dylibloader_orig_pulse
-#define pa_format_info_get_sample_format pa_format_info_get_sample_format_dylibloader_orig_pulse
-#define pa_format_info_get_rate pa_format_info_get_rate_dylibloader_orig_pulse
-#define pa_format_info_get_channels pa_format_info_get_channels_dylibloader_orig_pulse
-#define pa_format_info_get_channel_map pa_format_info_get_channel_map_dylibloader_orig_pulse
#define pa_format_info_set_prop_int pa_format_info_set_prop_int_dylibloader_orig_pulse
#define pa_format_info_set_prop_int_array pa_format_info_set_prop_int_array_dylibloader_orig_pulse
#define pa_format_info_set_prop_int_range pa_format_info_set_prop_int_range_dylibloader_orig_pulse
@@ -329,7 +325,6 @@
#define pa_threaded_mainloop_get_api pa_threaded_mainloop_get_api_dylibloader_orig_pulse
#define pa_threaded_mainloop_in_thread pa_threaded_mainloop_in_thread_dylibloader_orig_pulse
#define pa_threaded_mainloop_set_name pa_threaded_mainloop_set_name_dylibloader_orig_pulse
-#define pa_threaded_mainloop_once_unlocked pa_threaded_mainloop_once_unlocked_dylibloader_orig_pulse
#define pa_mainloop_new pa_mainloop_new_dylibloader_orig_pulse
#define pa_mainloop_free pa_mainloop_free_dylibloader_orig_pulse
#define pa_mainloop_prepare pa_mainloop_prepare_dylibloader_orig_pulse
@@ -354,7 +349,6 @@
#define pa_get_binary_name pa_get_binary_name_dylibloader_orig_pulse
#define pa_path_get_filename pa_path_get_filename_dylibloader_orig_pulse
#define pa_msleep pa_msleep_dylibloader_orig_pulse
-#define pa_thread_make_realtime pa_thread_make_realtime_dylibloader_orig_pulse
#define pa_gettimeofday pa_gettimeofday_dylibloader_orig_pulse
#define pa_timeval_diff pa_timeval_diff_dylibloader_orig_pulse
#define pa_timeval_cmp pa_timeval_cmp_dylibloader_orig_pulse
@@ -364,7 +358,7 @@
#define pa_timeval_store pa_timeval_store_dylibloader_orig_pulse
#define pa_timeval_load pa_timeval_load_dylibloader_orig_pulse
#define pa_rtclock_now pa_rtclock_now_dylibloader_orig_pulse
-#include <pulse/pulseaudio.h>
+#include "thirdparty/linuxbsd_headers/pulse/pulseaudio.h"
#undef pa_get_library_version
#undef pa_bytes_per_second
#undef pa_frame_size
@@ -449,10 +443,6 @@
#undef pa_format_info_get_prop_string
#undef pa_format_info_get_prop_string_array
#undef pa_format_info_free_string_array
-#undef pa_format_info_get_sample_format
-#undef pa_format_info_get_rate
-#undef pa_format_info_get_channels
-#undef pa_format_info_get_channel_map
#undef pa_format_info_set_prop_int
#undef pa_format_info_set_prop_int_array
#undef pa_format_info_set_prop_int_range
@@ -687,7 +677,6 @@
#undef pa_threaded_mainloop_get_api
#undef pa_threaded_mainloop_in_thread
#undef pa_threaded_mainloop_set_name
-#undef pa_threaded_mainloop_once_unlocked
#undef pa_mainloop_new
#undef pa_mainloop_free
#undef pa_mainloop_prepare
@@ -712,7 +701,6 @@
#undef pa_get_binary_name
#undef pa_path_get_filename
#undef pa_msleep
-#undef pa_thread_make_realtime
#undef pa_gettimeofday
#undef pa_timeval_diff
#undef pa_timeval_cmp
@@ -809,10 +797,6 @@ extern "C" {
#define pa_format_info_get_prop_string pa_format_info_get_prop_string_dylibloader_wrapper_pulse
#define pa_format_info_get_prop_string_array pa_format_info_get_prop_string_array_dylibloader_wrapper_pulse
#define pa_format_info_free_string_array pa_format_info_free_string_array_dylibloader_wrapper_pulse
-#define pa_format_info_get_sample_format pa_format_info_get_sample_format_dylibloader_wrapper_pulse
-#define pa_format_info_get_rate pa_format_info_get_rate_dylibloader_wrapper_pulse
-#define pa_format_info_get_channels pa_format_info_get_channels_dylibloader_wrapper_pulse
-#define pa_format_info_get_channel_map pa_format_info_get_channel_map_dylibloader_wrapper_pulse
#define pa_format_info_set_prop_int pa_format_info_set_prop_int_dylibloader_wrapper_pulse
#define pa_format_info_set_prop_int_array pa_format_info_set_prop_int_array_dylibloader_wrapper_pulse
#define pa_format_info_set_prop_int_range pa_format_info_set_prop_int_range_dylibloader_wrapper_pulse
@@ -1047,7 +1031,6 @@ extern "C" {
#define pa_threaded_mainloop_get_api pa_threaded_mainloop_get_api_dylibloader_wrapper_pulse
#define pa_threaded_mainloop_in_thread pa_threaded_mainloop_in_thread_dylibloader_wrapper_pulse
#define pa_threaded_mainloop_set_name pa_threaded_mainloop_set_name_dylibloader_wrapper_pulse
-#define pa_threaded_mainloop_once_unlocked pa_threaded_mainloop_once_unlocked_dylibloader_wrapper_pulse
#define pa_mainloop_new pa_mainloop_new_dylibloader_wrapper_pulse
#define pa_mainloop_free pa_mainloop_free_dylibloader_wrapper_pulse
#define pa_mainloop_prepare pa_mainloop_prepare_dylibloader_wrapper_pulse
@@ -1072,7 +1055,6 @@ extern "C" {
#define pa_get_binary_name pa_get_binary_name_dylibloader_wrapper_pulse
#define pa_path_get_filename pa_path_get_filename_dylibloader_wrapper_pulse
#define pa_msleep pa_msleep_dylibloader_wrapper_pulse
-#define pa_thread_make_realtime pa_thread_make_realtime_dylibloader_wrapper_pulse
#define pa_gettimeofday pa_gettimeofday_dylibloader_wrapper_pulse
#define pa_timeval_diff pa_timeval_diff_dylibloader_wrapper_pulse
#define pa_timeval_cmp pa_timeval_cmp_dylibloader_wrapper_pulse
@@ -1111,21 +1093,21 @@ extern int (*pa_proplist_sets_dylibloader_wrapper_pulse)( pa_proplist*,const cha
extern int (*pa_proplist_setp_dylibloader_wrapper_pulse)( pa_proplist*,const char*);
extern int (*pa_proplist_setf_dylibloader_wrapper_pulse)( pa_proplist*,const char*,const char*,...);
extern int (*pa_proplist_set_dylibloader_wrapper_pulse)( pa_proplist*,const char*,const void*, size_t);
-extern const char* (*pa_proplist_gets_dylibloader_wrapper_pulse)(const pa_proplist*,const char*);
-extern int (*pa_proplist_get_dylibloader_wrapper_pulse)(const pa_proplist*,const char*,const void**, size_t*);
+extern const char* (*pa_proplist_gets_dylibloader_wrapper_pulse)( pa_proplist*,const char*);
+extern int (*pa_proplist_get_dylibloader_wrapper_pulse)( pa_proplist*,const char*,const void**, size_t*);
extern void (*pa_proplist_update_dylibloader_wrapper_pulse)( pa_proplist*, pa_update_mode_t,const pa_proplist*);
extern int (*pa_proplist_unset_dylibloader_wrapper_pulse)( pa_proplist*,const char*);
extern int (*pa_proplist_unset_many_dylibloader_wrapper_pulse)( pa_proplist*,const char* []);
-extern const char* (*pa_proplist_iterate_dylibloader_wrapper_pulse)(const pa_proplist*, void**);
-extern char* (*pa_proplist_to_string_dylibloader_wrapper_pulse)(const pa_proplist*);
-extern char* (*pa_proplist_to_string_sep_dylibloader_wrapper_pulse)(const pa_proplist*,const char*);
+extern const char* (*pa_proplist_iterate_dylibloader_wrapper_pulse)( pa_proplist*, void**);
+extern char* (*pa_proplist_to_string_dylibloader_wrapper_pulse)( pa_proplist*);
+extern char* (*pa_proplist_to_string_sep_dylibloader_wrapper_pulse)( pa_proplist*,const char*);
extern pa_proplist* (*pa_proplist_from_string_dylibloader_wrapper_pulse)(const char*);
-extern int (*pa_proplist_contains_dylibloader_wrapper_pulse)(const pa_proplist*,const char*);
+extern int (*pa_proplist_contains_dylibloader_wrapper_pulse)( pa_proplist*,const char*);
extern void (*pa_proplist_clear_dylibloader_wrapper_pulse)( pa_proplist*);
extern pa_proplist* (*pa_proplist_copy_dylibloader_wrapper_pulse)(const pa_proplist*);
-extern unsigned (*pa_proplist_size_dylibloader_wrapper_pulse)(const pa_proplist*);
-extern int (*pa_proplist_isempty_dylibloader_wrapper_pulse)(const pa_proplist*);
-extern int (*pa_proplist_equal_dylibloader_wrapper_pulse)(const pa_proplist*,const pa_proplist*);
+extern unsigned (*pa_proplist_size_dylibloader_wrapper_pulse)( pa_proplist*);
+extern int (*pa_proplist_isempty_dylibloader_wrapper_pulse)( pa_proplist*);
+extern int (*pa_proplist_equal_dylibloader_wrapper_pulse)( pa_proplist*, pa_proplist*);
extern pa_channel_map* (*pa_channel_map_init_dylibloader_wrapper_pulse)( pa_channel_map*);
extern pa_channel_map* (*pa_channel_map_init_mono_dylibloader_wrapper_pulse)( pa_channel_map*);
extern pa_channel_map* (*pa_channel_map_init_stereo_dylibloader_wrapper_pulse)( pa_channel_map*);
@@ -1166,10 +1148,6 @@ extern int (*pa_format_info_get_prop_int_array_dylibloader_wrapper_pulse)(const
extern int (*pa_format_info_get_prop_string_dylibloader_wrapper_pulse)(const pa_format_info*,const char*, char**);
extern int (*pa_format_info_get_prop_string_array_dylibloader_wrapper_pulse)(const pa_format_info*,const char*, char***, int*);
extern void (*pa_format_info_free_string_array_dylibloader_wrapper_pulse)( char**, int);
-extern int (*pa_format_info_get_sample_format_dylibloader_wrapper_pulse)(const pa_format_info*, pa_sample_format_t*);
-extern int (*pa_format_info_get_rate_dylibloader_wrapper_pulse)(const pa_format_info*, uint32_t*);
-extern int (*pa_format_info_get_channels_dylibloader_wrapper_pulse)(const pa_format_info*, uint8_t*);
-extern int (*pa_format_info_get_channel_map_dylibloader_wrapper_pulse)(const pa_format_info*, pa_channel_map*);
extern void (*pa_format_info_set_prop_int_dylibloader_wrapper_pulse)( pa_format_info*,const char*, int);
extern void (*pa_format_info_set_prop_int_array_dylibloader_wrapper_pulse)( pa_format_info*,const char*,const int*, int);
extern void (*pa_format_info_set_prop_int_range_dylibloader_wrapper_pulse)( pa_format_info*,const char*, int, int);
@@ -1182,34 +1160,34 @@ extern void (*pa_format_info_set_channel_map_dylibloader_wrapper_pulse)( pa_form
extern pa_operation* (*pa_operation_ref_dylibloader_wrapper_pulse)( pa_operation*);
extern void (*pa_operation_unref_dylibloader_wrapper_pulse)( pa_operation*);
extern void (*pa_operation_cancel_dylibloader_wrapper_pulse)( pa_operation*);
-extern pa_operation_state_t (*pa_operation_get_state_dylibloader_wrapper_pulse)(const pa_operation*);
+extern pa_operation_state_t (*pa_operation_get_state_dylibloader_wrapper_pulse)( pa_operation*);
extern void (*pa_operation_set_state_callback_dylibloader_wrapper_pulse)( pa_operation*, pa_operation_notify_cb_t, void*);
extern pa_context* (*pa_context_new_dylibloader_wrapper_pulse)( pa_mainloop_api*,const char*);
-extern pa_context* (*pa_context_new_with_proplist_dylibloader_wrapper_pulse)( pa_mainloop_api*,const char*,const pa_proplist*);
+extern pa_context* (*pa_context_new_with_proplist_dylibloader_wrapper_pulse)( pa_mainloop_api*,const char*, pa_proplist*);
extern void (*pa_context_unref_dylibloader_wrapper_pulse)( pa_context*);
extern pa_context* (*pa_context_ref_dylibloader_wrapper_pulse)( pa_context*);
extern void (*pa_context_set_state_callback_dylibloader_wrapper_pulse)( pa_context*, pa_context_notify_cb_t, void*);
extern void (*pa_context_set_event_callback_dylibloader_wrapper_pulse)( pa_context*, pa_context_event_cb_t, void*);
-extern int (*pa_context_errno_dylibloader_wrapper_pulse)(const pa_context*);
-extern int (*pa_context_is_pending_dylibloader_wrapper_pulse)(const pa_context*);
-extern pa_context_state_t (*pa_context_get_state_dylibloader_wrapper_pulse)(const pa_context*);
+extern int (*pa_context_errno_dylibloader_wrapper_pulse)( pa_context*);
+extern int (*pa_context_is_pending_dylibloader_wrapper_pulse)( pa_context*);
+extern pa_context_state_t (*pa_context_get_state_dylibloader_wrapper_pulse)( pa_context*);
extern int (*pa_context_connect_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_flags_t,const pa_spawn_api*);
extern void (*pa_context_disconnect_dylibloader_wrapper_pulse)( pa_context*);
extern pa_operation* (*pa_context_drain_dylibloader_wrapper_pulse)( pa_context*, pa_context_notify_cb_t, void*);
extern pa_operation* (*pa_context_exit_daemon_dylibloader_wrapper_pulse)( pa_context*, pa_context_success_cb_t, void*);
extern pa_operation* (*pa_context_set_default_sink_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_success_cb_t, void*);
extern pa_operation* (*pa_context_set_default_source_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_success_cb_t, void*);
-extern int (*pa_context_is_local_dylibloader_wrapper_pulse)(const pa_context*);
+extern int (*pa_context_is_local_dylibloader_wrapper_pulse)( pa_context*);
extern pa_operation* (*pa_context_set_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_success_cb_t, void*);
-extern const char* (*pa_context_get_server_dylibloader_wrapper_pulse)(const pa_context*);
-extern uint32_t (*pa_context_get_protocol_version_dylibloader_wrapper_pulse)(const pa_context*);
-extern uint32_t (*pa_context_get_server_protocol_version_dylibloader_wrapper_pulse)(const pa_context*);
-extern pa_operation* (*pa_context_proplist_update_dylibloader_wrapper_pulse)( pa_context*, pa_update_mode_t,const pa_proplist*, pa_context_success_cb_t, void*);
+extern const char* (*pa_context_get_server_dylibloader_wrapper_pulse)( pa_context*);
+extern uint32_t (*pa_context_get_protocol_version_dylibloader_wrapper_pulse)( pa_context*);
+extern uint32_t (*pa_context_get_server_protocol_version_dylibloader_wrapper_pulse)( pa_context*);
+extern pa_operation* (*pa_context_proplist_update_dylibloader_wrapper_pulse)( pa_context*, pa_update_mode_t, pa_proplist*, pa_context_success_cb_t, void*);
extern pa_operation* (*pa_context_proplist_remove_dylibloader_wrapper_pulse)( pa_context*,const char* [], pa_context_success_cb_t, void*);
-extern uint32_t (*pa_context_get_index_dylibloader_wrapper_pulse)(const pa_context*);
-extern pa_time_event* (*pa_context_rttime_new_dylibloader_wrapper_pulse)(const pa_context*, pa_usec_t, pa_time_event_cb_t, void*);
-extern void (*pa_context_rttime_restart_dylibloader_wrapper_pulse)(const pa_context*, pa_time_event*, pa_usec_t);
-extern size_t (*pa_context_get_tile_size_dylibloader_wrapper_pulse)(const pa_context*,const pa_sample_spec*);
+extern uint32_t (*pa_context_get_index_dylibloader_wrapper_pulse)( pa_context*);
+extern pa_time_event* (*pa_context_rttime_new_dylibloader_wrapper_pulse)( pa_context*, pa_usec_t, pa_time_event_cb_t, void*);
+extern void (*pa_context_rttime_restart_dylibloader_wrapper_pulse)( pa_context*, pa_time_event*, pa_usec_t);
+extern size_t (*pa_context_get_tile_size_dylibloader_wrapper_pulse)( pa_context*,const pa_sample_spec*);
extern int (*pa_context_load_cookie_from_file_dylibloader_wrapper_pulse)( pa_context*,const char*);
extern int (*pa_cvolume_equal_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_cvolume*);
extern pa_cvolume* (*pa_cvolume_init_dylibloader_wrapper_pulse)( pa_cvolume*);
@@ -1248,9 +1226,9 @@ extern pa_cvolume* (*pa_cvolume_set_fade_dylibloader_wrapper_pulse)( pa_cvolume*
extern float (*pa_cvolume_get_lfe_balance_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*);
extern pa_cvolume* (*pa_cvolume_set_lfe_balance_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_channel_map*, float);
extern pa_cvolume* (*pa_cvolume_scale_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t);
-extern pa_cvolume* (*pa_cvolume_scale_mask_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t,const pa_channel_map*, pa_channel_position_mask_t);
+extern pa_cvolume* (*pa_cvolume_scale_mask_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t, pa_channel_map*, pa_channel_position_mask_t);
extern pa_cvolume* (*pa_cvolume_set_position_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_channel_map*, pa_channel_position_t, pa_volume_t);
-extern pa_volume_t (*pa_cvolume_get_position_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*, pa_channel_position_t);
+extern pa_volume_t (*pa_cvolume_get_position_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_channel_map*, pa_channel_position_t);
extern pa_cvolume* (*pa_cvolume_merge_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_cvolume*,const pa_cvolume*);
extern pa_cvolume* (*pa_cvolume_inc_clamp_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t, pa_volume_t);
extern pa_cvolume* (*pa_cvolume_inc_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t);
@@ -1260,13 +1238,13 @@ extern pa_stream* (*pa_stream_new_with_proplist_dylibloader_wrapper_pulse)( pa_c
extern pa_stream* (*pa_stream_new_extended_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_format_info**, unsigned int, pa_proplist*);
extern void (*pa_stream_unref_dylibloader_wrapper_pulse)( pa_stream*);
extern pa_stream* (*pa_stream_ref_dylibloader_wrapper_pulse)( pa_stream*);
-extern pa_stream_state_t (*pa_stream_get_state_dylibloader_wrapper_pulse)(const pa_stream*);
-extern pa_context* (*pa_stream_get_context_dylibloader_wrapper_pulse)(const pa_stream*);
-extern uint32_t (*pa_stream_get_index_dylibloader_wrapper_pulse)(const pa_stream*);
-extern uint32_t (*pa_stream_get_device_index_dylibloader_wrapper_pulse)(const pa_stream*);
-extern const char* (*pa_stream_get_device_name_dylibloader_wrapper_pulse)(const pa_stream*);
-extern int (*pa_stream_is_suspended_dylibloader_wrapper_pulse)(const pa_stream*);
-extern int (*pa_stream_is_corked_dylibloader_wrapper_pulse)(const pa_stream*);
+extern pa_stream_state_t (*pa_stream_get_state_dylibloader_wrapper_pulse)( pa_stream*);
+extern pa_context* (*pa_stream_get_context_dylibloader_wrapper_pulse)( pa_stream*);
+extern uint32_t (*pa_stream_get_index_dylibloader_wrapper_pulse)( pa_stream*);
+extern uint32_t (*pa_stream_get_device_index_dylibloader_wrapper_pulse)( pa_stream*);
+extern const char* (*pa_stream_get_device_name_dylibloader_wrapper_pulse)( pa_stream*);
+extern int (*pa_stream_is_suspended_dylibloader_wrapper_pulse)( pa_stream*);
+extern int (*pa_stream_is_corked_dylibloader_wrapper_pulse)( pa_stream*);
extern int (*pa_stream_connect_playback_dylibloader_wrapper_pulse)( pa_stream*,const char*,const pa_buffer_attr*, pa_stream_flags_t,const pa_cvolume*, pa_stream*);
extern int (*pa_stream_connect_record_dylibloader_wrapper_pulse)( pa_stream*,const char*,const pa_buffer_attr*, pa_stream_flags_t);
extern int (*pa_stream_disconnect_dylibloader_wrapper_pulse)( pa_stream*);
@@ -1276,15 +1254,15 @@ extern int (*pa_stream_write_dylibloader_wrapper_pulse)( pa_stream*,const void*,
extern int (*pa_stream_write_ext_free_dylibloader_wrapper_pulse)( pa_stream*,const void*, size_t, pa_free_cb_t, void*, int64_t, pa_seek_mode_t);
extern int (*pa_stream_peek_dylibloader_wrapper_pulse)( pa_stream*,const void**, size_t*);
extern int (*pa_stream_drop_dylibloader_wrapper_pulse)( pa_stream*);
-extern size_t (*pa_stream_writable_size_dylibloader_wrapper_pulse)(const pa_stream*);
-extern size_t (*pa_stream_readable_size_dylibloader_wrapper_pulse)(const pa_stream*);
+extern size_t (*pa_stream_writable_size_dylibloader_wrapper_pulse)( pa_stream*);
+extern size_t (*pa_stream_readable_size_dylibloader_wrapper_pulse)( pa_stream*);
extern pa_operation* (*pa_stream_drain_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_success_cb_t, void*);
extern pa_operation* (*pa_stream_update_timing_info_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_success_cb_t, void*);
extern void (*pa_stream_set_state_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
extern void (*pa_stream_set_write_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_request_cb_t, void*);
extern void (*pa_stream_set_read_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_request_cb_t, void*);
extern void (*pa_stream_set_overflow_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
-extern int64_t (*pa_stream_get_underflow_index_dylibloader_wrapper_pulse)(const pa_stream*);
+extern int64_t (*pa_stream_get_underflow_index_dylibloader_wrapper_pulse)( pa_stream*);
extern void (*pa_stream_set_underflow_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
extern void (*pa_stream_set_started_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
extern void (*pa_stream_set_latency_update_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
@@ -1302,14 +1280,14 @@ extern int (*pa_stream_get_latency_dylibloader_wrapper_pulse)( pa_stream*, pa_us
extern const pa_timing_info* (*pa_stream_get_timing_info_dylibloader_wrapper_pulse)( pa_stream*);
extern const pa_sample_spec* (*pa_stream_get_sample_spec_dylibloader_wrapper_pulse)( pa_stream*);
extern const pa_channel_map* (*pa_stream_get_channel_map_dylibloader_wrapper_pulse)( pa_stream*);
-extern const pa_format_info* (*pa_stream_get_format_info_dylibloader_wrapper_pulse)(const pa_stream*);
+extern const pa_format_info* (*pa_stream_get_format_info_dylibloader_wrapper_pulse)( pa_stream*);
extern const pa_buffer_attr* (*pa_stream_get_buffer_attr_dylibloader_wrapper_pulse)( pa_stream*);
extern pa_operation* (*pa_stream_set_buffer_attr_dylibloader_wrapper_pulse)( pa_stream*,const pa_buffer_attr*, pa_stream_success_cb_t, void*);
extern pa_operation* (*pa_stream_update_sample_rate_dylibloader_wrapper_pulse)( pa_stream*, uint32_t, pa_stream_success_cb_t, void*);
extern pa_operation* (*pa_stream_proplist_update_dylibloader_wrapper_pulse)( pa_stream*, pa_update_mode_t, pa_proplist*, pa_stream_success_cb_t, void*);
extern pa_operation* (*pa_stream_proplist_remove_dylibloader_wrapper_pulse)( pa_stream*,const char* [], pa_stream_success_cb_t, void*);
extern int (*pa_stream_set_monitor_stream_dylibloader_wrapper_pulse)( pa_stream*, uint32_t);
-extern uint32_t (*pa_stream_get_monitor_stream_dylibloader_wrapper_pulse)(const pa_stream*);
+extern uint32_t (*pa_stream_get_monitor_stream_dylibloader_wrapper_pulse)( pa_stream*);
extern pa_operation* (*pa_context_get_sink_info_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_sink_info_cb_t, void*);
extern pa_operation* (*pa_context_get_sink_info_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_sink_info_cb_t, void*);
extern pa_operation* (*pa_context_get_sink_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_sink_info_cb_t, void*);
@@ -1376,7 +1354,7 @@ extern int (*pa_stream_connect_upload_dylibloader_wrapper_pulse)( pa_stream*, si
extern int (*pa_stream_finish_upload_dylibloader_wrapper_pulse)( pa_stream*);
extern pa_operation* (*pa_context_remove_sample_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_success_cb_t, void*);
extern pa_operation* (*pa_context_play_sample_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_volume_t, pa_context_success_cb_t, void*);
-extern pa_operation* (*pa_context_play_sample_with_proplist_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_volume_t,const pa_proplist*, pa_context_play_sample_cb_t, void*);
+extern pa_operation* (*pa_context_play_sample_with_proplist_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_volume_t, pa_proplist*, pa_context_play_sample_cb_t, void*);
extern const char* (*pa_strerror_dylibloader_wrapper_pulse)( int);
extern void* (*pa_xmalloc_dylibloader_wrapper_pulse)( size_t);
extern void* (*pa_xmalloc0_dylibloader_wrapper_pulse)( size_t);
@@ -1400,17 +1378,16 @@ extern void (*pa_threaded_mainloop_unlock_dylibloader_wrapper_pulse)( pa_threade
extern void (*pa_threaded_mainloop_wait_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
extern void (*pa_threaded_mainloop_signal_dylibloader_wrapper_pulse)( pa_threaded_mainloop*, int);
extern void (*pa_threaded_mainloop_accept_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
-extern int (*pa_threaded_mainloop_get_retval_dylibloader_wrapper_pulse)(const pa_threaded_mainloop*);
+extern int (*pa_threaded_mainloop_get_retval_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
extern pa_mainloop_api* (*pa_threaded_mainloop_get_api_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
extern int (*pa_threaded_mainloop_in_thread_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
extern void (*pa_threaded_mainloop_set_name_dylibloader_wrapper_pulse)( pa_threaded_mainloop*,const char*);
-extern void (*pa_threaded_mainloop_once_unlocked_dylibloader_wrapper_pulse)( pa_threaded_mainloop*, void*, void*);
extern pa_mainloop* (*pa_mainloop_new_dylibloader_wrapper_pulse)( void);
extern void (*pa_mainloop_free_dylibloader_wrapper_pulse)( pa_mainloop*);
extern int (*pa_mainloop_prepare_dylibloader_wrapper_pulse)( pa_mainloop*, int);
extern int (*pa_mainloop_poll_dylibloader_wrapper_pulse)( pa_mainloop*);
extern int (*pa_mainloop_dispatch_dylibloader_wrapper_pulse)( pa_mainloop*);
-extern int (*pa_mainloop_get_retval_dylibloader_wrapper_pulse)(const pa_mainloop*);
+extern int (*pa_mainloop_get_retval_dylibloader_wrapper_pulse)( pa_mainloop*);
extern int (*pa_mainloop_iterate_dylibloader_wrapper_pulse)( pa_mainloop*, int, int*);
extern int (*pa_mainloop_run_dylibloader_wrapper_pulse)( pa_mainloop*, int*);
extern pa_mainloop_api* (*pa_mainloop_get_api_dylibloader_wrapper_pulse)( pa_mainloop*);
@@ -1429,7 +1406,6 @@ extern char* (*pa_get_home_dir_dylibloader_wrapper_pulse)( char*, size_t);
extern char* (*pa_get_binary_name_dylibloader_wrapper_pulse)( char*, size_t);
extern char* (*pa_path_get_filename_dylibloader_wrapper_pulse)(const char*);
extern int (*pa_msleep_dylibloader_wrapper_pulse)( unsigned long);
-extern int (*pa_thread_make_realtime_dylibloader_wrapper_pulse)( int);
extern struct timeval* (*pa_gettimeofday_dylibloader_wrapper_pulse)(struct timeval*);
extern pa_usec_t (*pa_timeval_diff_dylibloader_wrapper_pulse)(struct timeval*,struct timeval*);
extern int (*pa_timeval_cmp_dylibloader_wrapper_pulse)(struct timeval*,struct timeval*);
diff --git a/drivers/register_driver_types.cpp b/drivers/register_driver_types.cpp
index 504ef9843a..d5524fcc2f 100644
--- a/drivers/register_driver_types.cpp
+++ b/drivers/register_driver_types.cpp
@@ -1,44 +1,44 @@
-/*************************************************************************/
-/* register_driver_types.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* register_driver_types.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 "register_driver_types.h"
-#include "core/extension/native_extension_manager.h"
+#include "core/extension/gdextension_manager.h"
#include "drivers/png/image_loader_png.h"
#include "drivers/png/resource_saver_png.h"
-static ImageLoaderPNG *image_loader_png;
+static Ref<ImageLoaderPNG> image_loader_png;
static Ref<ResourceSaverPNG> resource_saver_png;
void register_core_driver_types() {
- image_loader_png = memnew(ImageLoaderPNG);
+ image_loader_png.instantiate();
ImageLoader::add_image_format_loader(image_loader_png);
resource_saver_png.instantiate();
@@ -46,9 +46,8 @@ void register_core_driver_types() {
}
void unregister_core_driver_types() {
- if (image_loader_png) {
- memdelete(image_loader_png);
- }
+ ImageLoader::remove_image_format_loader(image_loader_png);
+ image_loader_png.unref();
ResourceSaver::remove_resource_format_saver(resource_saver_png);
resource_saver_png.unref();
diff --git a/drivers/register_driver_types.h b/drivers/register_driver_types.h
index 41f95b57e7..32c020df22 100644
--- a/drivers/register_driver_types.h
+++ b/drivers/register_driver_types.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* register_driver_types.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* register_driver_types.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 REGISTER_DRIVER_TYPES_H
#define REGISTER_DRIVER_TYPES_H
diff --git a/drivers/spirv-reflect/SCsub b/drivers/spirv-reflect/SCsub
deleted file mode 100644
index 1e7b3de0e6..0000000000
--- a/drivers/spirv-reflect/SCsub
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-
-# Thirdparty source files
-
-thirdparty_dir = "#thirdparty/spirv-reflect/"
-thirdparty_sources = [
- "spirv_reflect.c",
-]
-
-thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
-
-env_thirdparty = env.Clone()
-env_thirdparty.disable_warnings()
-
-env_thirdparty.add_source_files(env.drivers_sources, thirdparty_sources)
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp
index 55ea952696..a162f46103 100644
--- a/drivers/unix/dir_access_unix.cpp
+++ b/drivers/unix/dir_access_unix.cpp
@@ -1,36 +1,36 @@
-/*************************************************************************/
-/* dir_access_unix.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* dir_access_unix.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 "dir_access_unix.h"
-#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)
+#if defined(UNIX_ENABLED)
#include "core/os/memory.h"
#include "core/os/os.h"
@@ -41,10 +41,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-
-#ifndef ANDROID_ENABLED
#include <sys/statvfs.h>
-#endif
#ifdef HAVE_MNTENT
#include <mntent.h>
@@ -74,7 +71,7 @@ bool DirAccessUnix::file_exists(String p_file) {
p_file = fix_path(p_file);
- struct stat flags;
+ struct stat flags = {};
bool success = (stat(p_file.utf8().get_data(), &flags) == 0);
if (success && S_ISDIR(flags.st_mode)) {
@@ -93,7 +90,7 @@ bool DirAccessUnix::dir_exists(String p_dir) {
p_dir = fix_path(p_dir);
- struct stat flags;
+ struct stat flags = {};
bool success = (stat(p_dir.utf8().get_data(), &flags) == 0);
return (success && S_ISDIR(flags.st_mode));
@@ -128,7 +125,7 @@ uint64_t DirAccessUnix::get_modified_time(String p_file) {
p_file = fix_path(p_file);
- struct stat flags;
+ struct stat flags = {};
bool success = (stat(p_file.utf8().get_data(), &flags) == 0);
if (success) {
@@ -161,7 +158,7 @@ String DirAccessUnix::get_next() {
if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK) {
String f = current_dir.path_join(fname);
- struct stat flags;
+ struct stat flags = {};
if (stat(f.utf8().get_data(), &flags) == 0) {
_cisdir = S_ISDIR(flags.st_mode);
} else {
@@ -192,7 +189,7 @@ void DirAccessUnix::list_dir_end() {
_cisdir = false;
}
-#if defined(HAVE_MNTENT) && defined(X11_ENABLED)
+#if defined(HAVE_MNTENT) && defined(LINUXBSD_ENABLED)
static bool _filter_drive(struct mntent *mnt) {
// Ignore devices that don't point to /dev
if (strncmp(mnt->mnt_fsname, "/dev", 4) != 0) {
@@ -216,7 +213,7 @@ static void _get_drives(List<String> *list) {
// Add root.
list->push_back("/");
-#if defined(HAVE_MNTENT) && defined(X11_ENABLED)
+#if defined(HAVE_MNTENT) && defined(LINUXBSD_ENABLED)
// Check /etc/mtab for the list of mounted partitions.
FILE *mtab = setmntent("/etc/mtab", "r");
if (mtab) {
@@ -415,7 +412,7 @@ Error DirAccessUnix::remove(String p_path) {
p_path = fix_path(p_path);
- struct stat flags;
+ struct stat flags = {};
if ((stat(p_path.utf8().get_data(), &flags) != 0)) {
return FAILED;
}
@@ -434,7 +431,7 @@ bool DirAccessUnix::is_link(String p_file) {
p_file = fix_path(p_file);
- struct stat flags;
+ struct stat flags = {};
if ((lstat(p_file.utf8().get_data(), &flags) != 0)) {
return FAILED;
}
@@ -475,17 +472,12 @@ Error DirAccessUnix::create_link(String p_source, String p_target) {
}
uint64_t DirAccessUnix::get_space_left() {
-#ifndef NO_STATVFS
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 {
@@ -516,4 +508,4 @@ DirAccessUnix::~DirAccessUnix() {
list_dir_end();
}
-#endif // UNIX_ENABLED || LIBC_FILEIO_ENABLED
+#endif // UNIX_ENABLED
diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h
index f5dca7c282..68ad869003 100644
--- a/drivers/unix/dir_access_unix.h
+++ b/drivers/unix/dir_access_unix.h
@@ -1,37 +1,37 @@
-/*************************************************************************/
-/* dir_access_unix.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* dir_access_unix.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 DIR_ACCESS_UNIX_H
#define DIR_ACCESS_UNIX_H
-#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)
+#if defined(UNIX_ENABLED)
#include "core/io/dir_access.h"
@@ -90,6 +90,6 @@ public:
~DirAccessUnix();
};
-#endif // UNIX_ENABLED || LIBC_FILEIO_ENABLED
+#endif // UNIX_ENABLED
#endif // DIR_ACCESS_UNIX_H
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index 388ad479b9..43d3f53904 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -1,53 +1,49 @@
-/*************************************************************************/
-/* file_access_unix.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* file_access_unix.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 "file_access_unix.h"
-#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)
+#if defined(UNIX_ENABLED)
#include "core/os/os.h"
#include "core/string/print_string.h"
+#include <errno.h>
+#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <errno.h>
-
#if defined(UNIX_ENABLED)
#include <unistd.h>
#endif
-#ifndef ANDROID_ENABLED
-#include <sys/statvfs.h>
-#endif
-
#ifdef MSVC
#define S_ISREG(m) ((m)&_S_IFREG)
#include <io.h>
@@ -56,12 +52,6 @@
#define S_ISREG(m) ((m)&S_IFREG)
#endif
-#ifndef NO_FCNTL
-#include <fcntl.h>
-#else
-#include <sys/ioctl.h>
-#endif
-
void FileAccessUnix::check_errors() const {
ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
@@ -70,7 +60,7 @@ void FileAccessUnix::check_errors() const {
}
}
-Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessUnix::open_internal(const String &p_path, int p_mode_flags) {
_close();
path_src = p_path;
@@ -96,7 +86,7 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) {
backend (unix-compatible mostly) supports utf8 encoding */
//printf("opening %s as %s\n", p_path.utf8().get_data(), path.utf8().get_data());
- struct stat st;
+ struct stat st = {};
int err = stat(path.utf8().get_data(), &st);
if (!err) {
switch (st.st_mode & S_IFMT) {
@@ -131,13 +121,8 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) {
int fd = fileno(f);
if (fd != -1) {
-#if defined(NO_FCNTL)
- unsigned long par = 0;
- ioctl(fd, FIOCLEX, &par);
-#else
int opts = fcntl(fd, F_GETFD);
fcntl(fd, F_SETFD, opts | FD_CLOEXEC);
-#endif
}
last_error = OK;
@@ -267,7 +252,7 @@ void FileAccessUnix::store_buffer(const uint8_t *p_src, uint64_t p_length) {
bool FileAccessUnix::file_exists(const String &p_path) {
int err;
- struct stat st;
+ struct stat st = {};
String filename = fix_path(p_path);
// Does the name exist at all?
@@ -299,7 +284,7 @@ bool FileAccessUnix::file_exists(const String &p_path) {
uint64_t FileAccessUnix::_get_modified_time(const String &p_file) {
String file = fix_path(p_file);
- struct stat flags;
+ struct stat flags = {};
int err = stat(file.utf8().get_data(), &flags);
if (!err) {
@@ -312,7 +297,7 @@ uint64_t FileAccessUnix::_get_modified_time(const String &p_file) {
uint32_t FileAccessUnix::_get_unix_permissions(const String &p_file) {
String file = fix_path(p_file);
- struct stat flags;
+ struct stat flags = {};
int err = stat(file.utf8().get_data(), &flags);
if (!err) {
@@ -339,4 +324,4 @@ FileAccessUnix::~FileAccessUnix() {
_close();
}
-#endif // UNIX_ENABLED || LIBC_FILEIO_ENABLED
+#endif // UNIX_ENABLED
diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h
index 297c34e454..884fb9567f 100644
--- a/drivers/unix/file_access_unix.h
+++ b/drivers/unix/file_access_unix.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* file_access_unix.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* file_access_unix.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 FILE_ACCESS_UNIX_H
#define FILE_ACCESS_UNIX_H
@@ -36,7 +36,7 @@
#include <stdio.h>
-#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)
+#if defined(UNIX_ENABLED)
typedef void (*CloseNotificationFunc)(const String &p_file, int p_flags);
@@ -54,7 +54,7 @@ class FileAccessUnix : public FileAccess {
public:
static CloseNotificationFunc close_notification_func;
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(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 override; /// returns the path for the current open file
@@ -86,6 +86,6 @@ public:
virtual ~FileAccessUnix();
};
-#endif // UNIX_ENABLED || LIBC_FILEIO_ENABLED
+#endif // UNIX_ENABLED
#endif // FILE_ACCESS_UNIX_H
diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp
index 0dc2efedc1..ec60d9e91a 100644
--- a/drivers/unix/ip_unix.cpp
+++ b/drivers/unix/ip_unix.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* ip_unix.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* ip_unix.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 "ip_unix.h"
diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h
index 798d02095c..274b7c561e 100644
--- a/drivers/unix/ip_unix.h
+++ b/drivers/unix/ip_unix.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* ip_unix.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* ip_unix.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 IP_UNIX_H
#define IP_UNIX_H
diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp
index 86adf33d62..b46af012f1 100644
--- a/drivers/unix/net_socket_posix.cpp
+++ b/drivers/unix/net_socket_posix.cpp
@@ -1,61 +1,59 @@
-/*************************************************************************/
-/* net_socket_posix.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* net_socket_posix.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 "net_socket_posix.h"
+// Some proprietary Unix-derived platforms don't expose Unix sockets
+// so this allows skipping this file to reimplement this API differently.
#ifndef UNIX_SOCKET_UNAVAILABLE
+
#if defined(UNIX_ENABLED)
#include <errno.h>
+#include <fcntl.h>
#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
+#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
-#ifndef NO_FCNTL
-#include <fcntl.h>
-#else
-#include <sys/ioctl.h>
-#endif
-#include <netinet/in.h>
-#include <sys/socket.h>
#ifdef WEB_ENABLED
#include <arpa/inet.h>
#endif
-#include <netinet/tcp.h>
-
// BSD calls this flag IPV6_JOIN_GROUP
#if !defined(IPV6_ADD_MEMBERSHIP) && defined(IPV6_JOIN_GROUP)
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
@@ -93,7 +91,7 @@
#define SIO_UDP_NETRESET _WSAIOW(IOC_VENDOR, 15)
#endif
-#endif
+#endif // UNIX_ENABLED
size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type) {
memset(p_addr, 0, sizeof(struct sockaddr_storage));
@@ -181,8 +179,8 @@ NetSocketPosix::~NetSocketPosix() {
close();
}
-// Silent a warning reported in #27594
-
+// Silence a warning reported in GH-27594.
+// EAGAIN and EWOULDBLOCK have the same value on most platforms, but it's not guaranteed.
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
@@ -309,14 +307,9 @@ void NetSocketPosix::_set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_
void NetSocketPosix::_set_close_exec_enabled(bool p_enabled) {
#ifndef WINDOWS_ENABLED
// Enable close on exec to avoid sharing with subprocesses. Off by default on Windows.
-#if defined(NO_FCNTL)
- unsigned long par = p_enabled ? 1 : 0;
- SOCK_IOCTL(_sock, FIOCLEX, &par);
-#else
int opts = fcntl(_sock, F_GETFD);
fcntl(_sock, F_SETFD, opts | FD_CLOEXEC);
#endif
-#endif
}
Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) {
@@ -658,7 +651,7 @@ void NetSocketPosix::set_blocking_enabled(bool p_enabled) {
ERR_FAIL_COND(!is_open());
int ret = 0;
-#if defined(WINDOWS_ENABLED) || defined(NO_FCNTL)
+#if defined(WINDOWS_ENABLED)
unsigned long par = p_enabled ? 0 : 1;
ret = SOCK_IOCTL(_sock, FIONBIO, &par);
#else
@@ -781,4 +774,5 @@ Error NetSocketPosix::join_multicast_group(const IPAddress &p_multi_address, Str
Error NetSocketPosix::leave_multicast_group(const IPAddress &p_multi_address, String p_if_name) {
return _change_multicast_group(p_multi_address, p_if_name, false);
}
-#endif
+
+#endif // UNIX_SOCKET_UNAVAILABLE
diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h
index 5558114cb1..bd2088b4f9 100644
--- a/drivers/unix/net_socket_posix.h
+++ b/drivers/unix/net_socket_posix.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* net_socket_posix.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* net_socket_posix.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 NET_SOCKET_POSIX_H
#define NET_SOCKET_POSIX_H
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index 384f46c8df..178f01b185 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* os_unix.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* os_unix.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 "os_unix.h"
@@ -51,7 +51,6 @@
#include <sys/sysctl.h>
#endif
-#include <assert.h>
#include <dlfcn.h>
#include <errno.h>
#include <poll.h>
@@ -104,10 +103,6 @@ static void _setup_clock() {
}
#endif
-void OS_Unix::debug_break() {
- assert(false);
-}
-
static void handle_interrupt(int sig) {
if (!EngineDebugger::is_active()) {
return;
@@ -131,9 +126,7 @@ int OS_Unix::unix_initialize_audio(int p_audio_driver) {
}
void OS_Unix::initialize_core() {
-#if !defined(NO_THREADS)
init_thread_posix();
-#endif
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES);
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA);
@@ -142,10 +135,8 @@ void OS_Unix::initialize_core() {
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA);
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM);
-#ifndef NO_NETWORK
NetSocketPosix::make_default();
IPUnix::make_default();
-#endif
_setup_clock();
}
@@ -154,15 +145,13 @@ void OS_Unix::finalize_core() {
NetSocketPosix::cleanup();
}
-String OS_Unix::get_stdin_string(bool p_block) {
- if (p_block) {
- char buff[1024];
- String ret = stdin_buf + fgets(buff, 1024, stdin);
- stdin_buf = "";
- return ret;
- }
+Vector<String> OS_Unix::get_video_adapter_driver_info() const {
+ return Vector<String>();
+}
- return "";
+String OS_Unix::get_stdin_string() {
+ char buff[1024];
+ return String::utf8(fgets(buff, 1024, stdin));
}
Error OS_Unix::get_entropy(uint8_t *r_buffer, int p_bytes) {
@@ -175,6 +164,7 @@ Error OS_Unix::get_entropy(uint8_t *r_buffer, int p_bytes) {
left -= chunk;
ofs += chunk;
} while (left > 0);
+// Define this yourself if you don't want to fall back to /dev/urandom.
#elif !defined(NO_URANDOM)
int r = open("/dev/urandom", O_RDONLY);
ERR_FAIL_COND_V(r < 0, FAILED);
@@ -194,13 +184,21 @@ String OS_Unix::get_name() const {
return "Unix";
}
+String OS_Unix::get_distribution_name() const {
+ return "";
+}
+
+String OS_Unix::get_version() const {
+ return "";
+}
+
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 {
+OS::DateTime OS_Unix::get_datetime(bool p_utc) const {
time_t t = time(nullptr);
struct tm lt;
if (p_utc) {
@@ -208,7 +206,7 @@ OS::Date OS_Unix::get_date(bool p_utc) const {
} else {
localtime_r(&t, &lt);
}
- Date ret;
+ DateTime ret;
ret.year = 1900 + lt.tm_year;
// Index starting at 1 to match OS_Unix::get_date
// and Windows SYSTEMTIME and tm_mon follows the typical structure
@@ -216,24 +214,11 @@ OS::Date OS_Unix::get_date(bool p_utc) const {
ret.month = (Month)(lt.tm_mon + 1);
ret.day = lt.tm_mday;
ret.weekday = (Weekday)lt.tm_wday;
- ret.dst = lt.tm_isdst;
-
- return ret;
-}
-
-OS::Time OS_Unix::get_time(bool p_utc) const {
- time_t t = time(nullptr);
- struct tm lt;
- if (p_utc) {
- gmtime_r(&t, &lt);
- } else {
- localtime_r(&t, &lt);
- }
- Time ret;
ret.hour = lt.tm_hour;
ret.minute = lt.tm_min;
ret.second = lt.tm_sec;
- get_time_zone_info();
+ ret.dst = lt.tm_isdst;
+
return ret;
}
@@ -426,10 +411,6 @@ bool OS_Unix::is_process_running(const ProcessID &p_pid) const {
return true;
}
-bool OS_Unix::has_environment(const String &p_var) const {
- return getenv(p_var.utf8().get_data()) != nullptr;
-}
-
String OS_Unix::get_locale() const {
if (!has_environment("LANG")) {
return "en";
@@ -502,6 +483,10 @@ Error OS_Unix::set_cwd(const String &p_cwd) {
return OK;
}
+bool OS_Unix::has_environment(const String &p_var) const {
+ return getenv(p_var.utf8().get_data()) != nullptr;
+}
+
String OS_Unix::get_environment(const String &p_var) const {
if (getenv(p_var.utf8().get_data())) {
return getenv(p_var.utf8().get_data());
@@ -509,20 +494,23 @@ String OS_Unix::get_environment(const String &p_var) const {
return "";
}
-bool OS_Unix::set_environment(const String &p_var, const String &p_value) const {
- return setenv(p_var.utf8().get_data(), p_value.utf8().get_data(), /* overwrite: */ true) == 0;
+void OS_Unix::set_environment(const String &p_var, const String &p_value) const {
+ ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var));
+ int err = setenv(p_var.utf8().get_data(), p_value.utf8().get_data(), /* overwrite: */ 1);
+ ERR_FAIL_COND_MSG(err != 0, vformat("Failed setting environment variable '%s', the system is out of memory.", p_var));
}
-int OS_Unix::get_processor_count() const {
- return sysconf(_SC_NPROCESSORS_CONF);
+void OS_Unix::unset_environment(const String &p_var) const {
+ ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var));
+ unsetenv(p_var.utf8().get_data());
}
String OS_Unix::get_user_data_dir() const {
- String appname = get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/name"));
+ String appname = get_safe_dir_name(GLOBAL_GET("application/config/name"));
if (!appname.is_empty()) {
- bool use_custom_dir = ProjectSettings::get_singleton()->get("application/config/use_custom_user_dir");
+ bool use_custom_dir = GLOBAL_GET("application/config/use_custom_user_dir");
if (use_custom_dir) {
- String custom_dir = get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/custom_user_dir_name"), true);
+ String custom_dir = get_safe_dir_name(GLOBAL_GET("application/config/custom_user_dir_name"), true);
if (custom_dir.is_empty()) {
custom_dir = appname;
}
@@ -578,7 +566,7 @@ String OS_Unix::get_executable_path() const {
WARN_PRINT("MAXPATHLEN is too small");
}
- String path(resolved_path);
+ String path = String::utf8(resolved_path);
delete[] resolved_path;
return path;
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index f4609a565b..03429622ae 100644
--- a/drivers/unix/os_unix.h
+++ b/drivers/unix/os_unix.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* os_unix.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* os_unix.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 OS_UNIX_H
#define OS_UNIX_H
@@ -46,14 +46,14 @@ protected:
virtual void finalize_core() override;
- String stdin_buf;
-
public:
OS_Unix();
- virtual String get_stdin_string(bool p_block) override;
+ virtual Vector<String> get_video_adapter_driver_info() const override;
+
+ virtual String get_stdin_string() override;
- virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) override; // Should return cryptographycally-safe random bytes.
+ virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) 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;
@@ -62,9 +62,10 @@ public:
virtual Error set_cwd(const String &p_cwd) override;
virtual String get_name() const override;
+ virtual String get_distribution_name() const override;
+ virtual String get_version() const override;
- virtual Date get_date(bool p_utc) const override;
- virtual Time get_time(bool p_utc) const override;
+ virtual DateTime get_datetime(bool p_utc) const override;
virtual TimeZoneInfo get_time_zone_info() const override;
virtual double get_unix_time() const override;
@@ -80,12 +81,11 @@ public:
virtual bool has_environment(const String &p_var) const override;
virtual String get_environment(const String &p_var) const override;
- virtual bool set_environment(const String &p_var, const String &p_value) const override;
- virtual String get_locale() const override;
+ virtual void set_environment(const String &p_var, const String &p_value) const override;
+ virtual void unset_environment(const String &p_var) const override;
- virtual int get_processor_count() const override;
+ virtual String get_locale() const override;
- virtual void debug_break() override;
virtual void initialize_debugging() override;
virtual String get_executable_path() const override;
diff --git a/drivers/unix/syslog_logger.cpp b/drivers/unix/syslog_logger.cpp
index 6189d645c6..60ade043e0 100644
--- a/drivers/unix/syslog_logger.cpp
+++ b/drivers/unix/syslog_logger.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* syslog_logger.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* syslog_logger.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 UNIX_ENABLED
diff --git a/drivers/unix/syslog_logger.h b/drivers/unix/syslog_logger.h
index cc6617eb25..f91d539ae7 100644
--- a/drivers/unix/syslog_logger.h
+++ b/drivers/unix/syslog_logger.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* syslog_logger.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* syslog_logger.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 SYSLOG_LOGGER_H
#define SYSLOG_LOGGER_H
diff --git a/drivers/unix/thread_posix.cpp b/drivers/unix/thread_posix.cpp
index cb5f261e6e..7f3b9e9761 100644
--- a/drivers/unix/thread_posix.cpp
+++ b/drivers/unix/thread_posix.cpp
@@ -1,34 +1,34 @@
-/*************************************************************************/
-/* thread_posix.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* thread_posix.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/**************************************************************************/
-#if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(NO_THREADS)
+#if defined(UNIX_ENABLED)
#include "thread_posix.h"
@@ -70,7 +70,7 @@ static Error set_name(const String &p_name) {
}
void init_thread_posix() {
- Thread::_set_platform_funcs(&set_name, nullptr);
+ Thread::_set_platform_functions({ .set_name = set_name });
}
-#endif
+#endif // UNIX_ENABLED
diff --git a/drivers/unix/thread_posix.h b/drivers/unix/thread_posix.h
index 672adcba72..acd9a0e965 100644
--- a/drivers/unix/thread_posix.h
+++ b/drivers/unix/thread_posix.h
@@ -1,38 +1,36 @@
-/*************************************************************************/
-/* thread_posix.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* thread_posix.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 THREAD_POSIX_H
#define THREAD_POSIX_H
-#if !defined(NO_THREADS)
void init_thread_posix();
-#endif
#endif // THREAD_POSIX_H
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 6a88f2c442..42146cd7ec 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* rendering_device_vulkan.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* rendering_device_vulkan.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#include "rendering_device_vulkan.h"
@@ -36,18 +36,16 @@
#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"
-#include "thirdparty/spirv-reflect/spirv_reflect.h"
//#define FORCE_FULL_BARRIER
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) {
+RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID p_buffer, VkPipelineStageFlags &r_stage_mask, VkAccessFlags &r_access_mask, BitField<BarrierMask> p_post_barrier) {
Buffer *buffer = nullptr;
if (vertex_buffer_owner.owns(p_buffer)) {
buffer = vertex_buffer_owner.get_or_null(p_buffer);
@@ -55,11 +53,11 @@ RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID
r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
r_access_mask |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
if (buffer->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) {
- if (p_post_barrier & BARRIER_MASK_RASTER) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
- if (p_post_barrier & BARRIER_MASK_COMPUTE) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
}
@@ -69,20 +67,20 @@ RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID
r_access_mask |= VK_ACCESS_INDEX_READ_BIT;
buffer = index_buffer_owner.get_or_null(p_buffer);
} else if (uniform_buffer_owner.owns(p_buffer)) {
- if (p_post_barrier & BARRIER_MASK_RASTER) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
- if (p_post_barrier & BARRIER_MASK_COMPUTE) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
}
r_access_mask |= VK_ACCESS_UNIFORM_READ_BIT;
buffer = uniform_buffer_owner.get_or_null(p_buffer);
} else if (texture_buffer_owner.owns(p_buffer)) {
- if (p_post_barrier & BARRIER_MASK_RASTER) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
r_access_mask |= VK_ACCESS_SHADER_READ_BIT;
}
- if (p_post_barrier & BARRIER_MASK_COMPUTE) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
r_access_mask |= VK_ACCESS_SHADER_READ_BIT;
}
@@ -90,11 +88,11 @@ RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID
buffer = &texture_buffer_owner.get_or_null(p_buffer)->buffer;
} else if (storage_buffer_owner.owns(p_buffer)) {
buffer = storage_buffer_owner.get_or_null(p_buffer);
- if (p_post_barrier & BARRIER_MASK_RASTER) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
r_stage_mask |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier & BARRIER_MASK_COMPUTE) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
r_stage_mask |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
r_access_mask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
@@ -996,8 +994,11 @@ void RenderingDeviceVulkan::get_compressed_image_format_block_dimensions(DataFor
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_SRGB_BLOCK:
- case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK:
+ case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: {
+ r_w = 4;
+ r_h = 4;
+ } break;
+ case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: // Unsupported
case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK:
case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK:
case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK:
@@ -1008,10 +1009,16 @@ void RenderingDeviceVulkan::get_compressed_image_format_block_dimensions(DataFor
case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK:
case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK:
case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK:
- case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK:
+ case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK: {
+ r_w = 4;
+ r_h = 4;
+ } break;
case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK:
- case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK:
- case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK:
+ case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: {
+ r_w = 8;
+ r_h = 8;
+ } break;
+ case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK: // Unsupported
case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK:
case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK:
case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK:
@@ -1101,7 +1108,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 16;
default: {
}
}
@@ -1123,6 +1130,10 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFor
case DATA_FORMAT_EAC_R11_UNORM_BLOCK:
case DATA_FORMAT_EAC_R11_SNORM_BLOCK:
return 1;
+ case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK:
+ case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: {
+ return 2;
+ }
default: {
}
}
@@ -1579,12 +1590,12 @@ Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, c
return OK;
}
-void RenderingDeviceVulkan::_memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw) {
+void RenderingDeviceVulkan::_memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_access, bool p_sync_with_draw) {
VkMemoryBarrier mem_barrier;
mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
mem_barrier.pNext = nullptr;
mem_barrier.srcAccessMask = p_src_access;
- mem_barrier.dstAccessMask = p_dst_sccess;
+ mem_barrier.dstAccessMask = p_dst_access;
if (p_src_stage_mask == 0 || p_dst_stage_mask == 0) {
return; // No barrier, since this is invalid.
@@ -1628,14 +1639,14 @@ void RenderingDeviceVulkan::_full_barrier(bool p_sync_with_draw) {
p_sync_with_draw);
}
-void RenderingDeviceVulkan::_buffer_memory_barrier(VkBuffer buffer, uint64_t p_from, uint64_t p_size, VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw) {
+void RenderingDeviceVulkan::_buffer_memory_barrier(VkBuffer buffer, uint64_t p_from, uint64_t p_size, VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_access, bool p_sync_with_draw) {
VkBufferMemoryBarrier buffer_mem_barrier;
buffer_mem_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
buffer_mem_barrier.pNext = nullptr;
buffer_mem_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
buffer_mem_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
buffer_mem_barrier.srcAccessMask = p_src_access;
- buffer_mem_barrier.dstAccessMask = p_dst_sccess;
+ buffer_mem_barrier.dstAccessMask = p_dst_access;
buffer_mem_barrier.buffer = buffer;
buffer_mem_barrier.offset = p_from;
buffer_mem_barrier.size = p_size;
@@ -1655,36 +1666,27 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
image_create_info.pNext = nullptr;
image_create_info.flags = 0;
-#ifndef _MSC_VER
-#warning TODO check for support via RenderingDevice to enable on mobile when possible
-#endif
-
-#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.
-#endif
if (p_format.shareable_formats.size()) {
image_create_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
-#ifndef ANDROID_ENABLED
-
- for (int i = 0; i < p_format.shareable_formats.size(); i++) {
- allowed_formats.push_back(vulkan_formats[p_format.shareable_formats[i]]);
- }
+ if (context->is_device_extension_enabled(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME)) {
+ for (int i = 0; i < p_format.shareable_formats.size(); i++) {
+ allowed_formats.push_back(vulkan_formats[p_format.shareable_formats[i]]);
+ }
- format_list_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
- format_list_create_info.pNext = nullptr;
- format_list_create_info.viewFormatCount = allowed_formats.size();
- format_list_create_info.pViewFormats = allowed_formats.ptr();
- image_create_info.pNext = &format_list_create_info;
+ format_list_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
+ format_list_create_info.pNext = nullptr;
+ format_list_create_info.viewFormatCount = allowed_formats.size();
+ format_list_create_info.pViewFormats = allowed_formats.ptr();
+ image_create_info.pNext = &format_list_create_info;
- ERR_FAIL_COND_V_MSG(p_format.shareable_formats.find(p_format.format) == -1, RID(),
- "If supplied a list of shareable formats, the current format must be present in the list");
- ERR_FAIL_COND_V_MSG(p_view.format_override != DATA_FORMAT_MAX && p_format.shareable_formats.find(p_view.format_override) == -1, RID(),
- "If supplied a list of shareable formats, the current view format override must be present in the list");
-#endif
+ ERR_FAIL_COND_V_MSG(p_format.shareable_formats.find(p_format.format) == -1, RID(),
+ "If supplied a list of shareable formats, the current format must be present in the list");
+ ERR_FAIL_COND_V_MSG(p_view.format_override != DATA_FORMAT_MAX && p_format.shareable_formats.find(p_view.format_override) == -1, RID(),
+ "If supplied a list of shareable formats, the current view format override must be present in the list");
+ }
}
if (p_format.texture_type == TEXTURE_TYPE_CUBE || p_format.texture_type == TEXTURE_TYPE_CUBE_ARRAY) {
@@ -2011,7 +2013,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
if (p_data.size()) {
for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) {
- _texture_update(id, i, p_data[i], RD::BARRIER_MASK_ALL, true);
+ _texture_update(id, i, p_data[i], RD::BARRIER_MASK_ALL_BARRIERS, true);
}
}
return id;
@@ -2087,49 +2089,54 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID
}
VkImageViewUsageCreateInfo usage_info;
- 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.
+ if (context->is_device_extension_enabled(VK_KHR_MAINTENANCE_2_EXTENSION_NAME)) {
+ // May need to make VK_KHR_maintenance2 manditory and thus has Vulkan 1.1 be our minimum supported version
+ // if we require setting this information. Vulkan 1.0 may simply not care..
- usage_info.usage = 0;
+ 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.
- if (texture.usage_flags & TEXTURE_USAGE_SAMPLING_BIT) {
- usage_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
- }
+ usage_info.usage = 0;
- if (texture.usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
- if (texture_is_format_supported_for_usage(p_view.format_override, TEXTURE_USAGE_STORAGE_BIT)) {
- usage_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
+ if (texture.usage_flags & TEXTURE_USAGE_SAMPLING_BIT) {
+ usage_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
}
- }
- if (texture.usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
- if (texture_is_format_supported_for_usage(p_view.format_override, TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
- usage_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ if (texture.usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
+ if (texture_is_format_supported_for_usage(p_view.format_override, TEXTURE_USAGE_STORAGE_BIT)) {
+ usage_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
+ }
}
- }
- if (texture.usage_flags & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT) {
- usage_info.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
- }
+ if (texture.usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
+ if (texture_is_format_supported_for_usage(p_view.format_override, TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
+ usage_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ }
+ }
- if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
- usage_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
- }
+ if (texture.usage_flags & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT) {
+ usage_info.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
+ }
- if (texture.usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT) {
- usage_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
- }
- if (texture.usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT) {
- usage_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
- }
+ if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
+ usage_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ }
- if (texture.usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT) {
- usage_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
- }
+ if (texture.usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT) {
+ usage_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ }
+ if (texture.usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT) {
+ usage_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+ }
- image_view_create_info.pNext = &usage_info;
+ if (texture.usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT) {
+ usage_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ }
+
+ image_view_create_info.pNext = &usage_info;
+ }
}
VkResult err = vkCreateImageView(device, &image_view_create_info, nullptr, &texture.view);
@@ -2162,14 +2169,35 @@ RID RenderingDeviceVulkan::texture_create_from_extension(TextureType p_type, Dat
texture.height = p_height;
texture.depth = p_depth;
texture.layers = p_layers;
- texture.mipmaps = 0; // Maybe make this settable too?
+ texture.mipmaps = 1;
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?
+ // Set base layout based on usage priority.
+
+ if (texture.usage_flags & TEXTURE_USAGE_SAMPLING_BIT) {
+ // First priority, readable.
+ texture.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+ } else if (texture.usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
+ // Second priority, storage.
+
+ texture.layout = VK_IMAGE_LAYOUT_GENERAL;
+
+ } else if (texture.usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
+ // Third priority, color or depth.
+
+ texture.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ } else if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
+ texture.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+ } else {
+ texture.layout = VK_IMAGE_LAYOUT_GENERAL;
+ }
if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
texture.read_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT;
@@ -2395,7 +2423,7 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p
return id;
}
-Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier) {
+Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier) {
return _texture_update(p_texture, p_layer, p_data, p_post_barrier, false);
}
@@ -2415,7 +2443,7 @@ static _ALWAYS_INLINE_ void _copy_region(uint8_t const *__restrict p_src, uint8_
}
}
-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) {
+Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier, bool p_use_setup_queue) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V_MSG((draw_list || compute_list) && !p_use_setup_queue, ERR_INVALID_PARAMETER,
@@ -2589,15 +2617,15 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
{
uint32_t barrier_flags = 0;
uint32_t access_flags = 0;
- if (p_post_barrier & BARRIER_MASK_COMPUTE) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier & BARRIER_MASK_RASTER) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier & BARRIER_MASK_TRANSFER) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT;
}
@@ -2850,7 +2878,7 @@ Size2i RenderingDeviceVulkan::texture_size(RID p_texture) {
return Size2i(tex->width, tex->height);
}
-Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, uint32_t p_post_barrier) {
+Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier) {
_THREAD_SAFE_METHOD_
Texture *src_tex = texture_owner.get_or_null(p_from_texture);
@@ -2975,15 +3003,15 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
uint32_t barrier_flags = 0;
uint32_t access_flags = 0;
- if (p_post_barrier & BARRIER_MASK_COMPUTE) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier & BARRIER_MASK_RASTER) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier & BARRIER_MASK_TRANSFER) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT;
}
@@ -3045,7 +3073,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
return OK;
}
-Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID p_to_texture, uint32_t p_post_barrier) {
+Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier) {
_THREAD_SAFE_METHOD_
Texture *src_tex = texture_owner.get_or_null(p_from_texture);
@@ -3153,15 +3181,15 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
uint32_t barrier_flags = 0;
uint32_t access_flags = 0;
- if (p_post_barrier & BARRIER_MASK_COMPUTE) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier & BARRIER_MASK_RASTER) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier & BARRIER_MASK_TRANSFER) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT;
}
@@ -3216,7 +3244,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
return OK;
}
-Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, uint32_t p_post_barrier) {
+Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier) {
_THREAD_SAFE_METHOD_
Texture *src_tex = texture_owner.get_or_null(p_texture);
@@ -3289,15 +3317,15 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,
uint32_t barrier_flags = 0;
uint32_t access_flags = 0;
- if (p_post_barrier & BARRIER_MASK_COMPUTE) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier & BARRIER_MASK_RASTER) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier & BARRIER_MASK_TRANSFER) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT;
}
@@ -3336,7 +3364,7 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,
return OK;
}
-bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const {
+bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_format, BitField<RenderingDevice::TextureUsageBits> p_usage) const {
ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false);
_THREAD_SAFE_METHOD_
@@ -3346,34 +3374,34 @@ bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_f
vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), vulkan_formats[p_format], &properties);
VkFormatFeatureFlags flags;
- if (p_usage & TEXTURE_USAGE_CPU_READ_BIT) {
+ if (p_usage.has_flag(TEXTURE_USAGE_CPU_READ_BIT)) {
flags = properties.linearTilingFeatures;
} else {
flags = properties.optimalTilingFeatures;
}
- if (p_usage & TEXTURE_USAGE_SAMPLING_BIT && !(flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
+ if (p_usage.has_flag(TEXTURE_USAGE_SAMPLING_BIT) && !(flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
return false;
}
- if (p_usage & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
+ if (p_usage.has_flag(TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) && !(flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
return false;
}
- if (p_usage & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ if (p_usage.has_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !(flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
return false;
}
- if (p_usage & TEXTURE_USAGE_STORAGE_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
+ if (p_usage.has_flag(TEXTURE_USAGE_STORAGE_BIT) && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
return false;
}
- if (p_usage & TEXTURE_USAGE_STORAGE_ATOMIC_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)) {
+ if (p_usage.has_flag(TEXTURE_USAGE_STORAGE_ATOMIC_BIT) && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)) {
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) {
+ if (p_usage.has_flag(TEXTURE_USAGE_VRS_ATTACHMENT_BIT) && p_format != DATA_FORMAT_R8_UINT) {
return false;
}
@@ -3403,6 +3431,16 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
LocalVector<int32_t> attachment_last_pass;
attachment_last_pass.resize(p_attachments.size());
+ if (p_view_count > 1) {
+ const VulkanContext::MultiviewCapabilities capabilities = context->get_multiview_capabilities();
+
+ // This only works with multiview!
+ ERR_FAIL_COND_V_MSG(!capabilities.is_supported, VK_NULL_HANDLE, "Multiview not supported");
+
+ // 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");
+ }
+
// 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;
@@ -3703,7 +3741,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachment_last_pass[attachment] = i;
}
- reference.aspectMask = 0;
+ reference.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
color_references.push_back(reference);
}
@@ -3725,7 +3763,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
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?
+ reference.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
input_references.push_back(reference);
}
@@ -3754,7 +3792,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
attachment_last_pass[attachment] = i;
}
- reference.aspectMask = 0;
+ reference.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
resolve_references.push_back(reference);
}
@@ -3769,7 +3807,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
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_remap[attachment];
depth_stencil_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- depth_stencil_reference.aspectMask = 0;
+ depth_stencil_reference.aspectMask = VK_IMAGE_ASPECT_NONE;
attachment_last_pass[attachment] = i;
if (is_multisample_first) {
@@ -3795,9 +3833,9 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
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;
+ vrs_reference.aspectMask = VK_IMAGE_ASPECT_NONE;
- Size2i texel_size = context->get_vrs_capabilities().max_texel_size;
+ Size2i texel_size = context->get_vrs_capabilities().texel_size;
VkFragmentShadingRateAttachmentInfoKHR &vrs_attachment_info = vrs_attachment_info_array[i];
vrs_attachment_info.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
@@ -3936,16 +3974,9 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
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!
- ERR_FAIL_COND_V_MSG(!capabilities.is_supported, VK_NULL_HANDLE, "Multiview not supported");
-
- // 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");
+ if ((p_view_count > 1) && !context->supports_renderpass2()) {
+ // This is only required when using vkCreateRenderPass, we add it if vkCreateRenderPass2KHR is not supported
+ // resulting this in being passed to our vkCreateRenderPass fallback.
// Set view masks for each subpass.
for (uint32_t i = 0; i < subpasses.size(); i++) {
@@ -4152,8 +4183,8 @@ RID RenderingDeviceVulkan::framebuffer_create_multipass(const Vector<RID> &p_tex
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.
+ // If this is not the first attachment we assume this is used as the VRS attachment.
+ // In this case this texture will be 1/16th the size of the color attachment.
// 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(),
@@ -4245,7 +4276,7 @@ RID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) {
sampler_create_info.addressModeW = address_modes[p_state.repeat_w];
sampler_create_info.mipLodBias = p_state.lod_bias;
- sampler_create_info.anisotropyEnable = p_state.use_anisotropy;
+ sampler_create_info.anisotropyEnable = p_state.use_anisotropy && context->get_physical_device_features().samplerAnisotropy;
sampler_create_info.maxAnisotropy = p_state.anisotropy_max;
sampler_create_info.compareEnable = p_state.enable_compare;
@@ -4356,7 +4387,7 @@ RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(cons
return id;
}
-RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers) {
+RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers, const Vector<uint64_t> &p_offsets) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID());
@@ -4370,6 +4401,13 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo
VertexArray vertex_array;
+ if (p_offsets.is_empty()) {
+ vertex_array.offsets.resize_zeroed(p_src_buffers.size());
+ } else {
+ ERR_FAIL_COND_V(p_offsets.size() != p_src_buffers.size(), RID());
+ vertex_array.offsets = p_offsets;
+ }
+
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.
@@ -4401,7 +4439,6 @@ 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.
}
RID id = vertex_array_owner.make_rid(vertex_array);
@@ -4496,14 +4533,6 @@ RID RenderingDeviceVulkan::index_array_create(RID p_index_buffer, uint32_t p_ind
/**** SHADER ****/
/****************/
-static const char *shader_stage_names[RenderingDevice::SHADER_STAGE_MAX] = {
- "Vertex",
- "Fragment",
- "TesselationControl",
- "TesselationEvaluation",
- "Compute"
-};
-
static const char *shader_uniform_names[RenderingDevice::UNIFORM_TYPE_MAX] = {
"Sampler", "CombinedSampler", "Texture", "Image", "TextureBuffer", "SamplerTextureBuffer", "ImageBuffer", "UniformBuffer", "StorageBuffer", "InputAttachment"
};
@@ -4534,198 +4563,6 @@ String RenderingDeviceVulkan::_shader_uniform_debug(RID p_shader, int p_set) {
}
return ret;
}
-#if 0
-bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLayoutBinding> > &bindings, Vector<Vector<UniformInfo> > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, Shader::PushConstant &push_constant, String *r_error) {
- VkDescriptorSetLayoutBinding layout_binding;
- UniformInfo info;
-
- switch (reflection.getType()->getBasicType()) {
- case glslang::EbtSampler: {
- //print_line("DEBUG: IsSampler");
- if (reflection.getType()->getSampler().dim == glslang::EsdBuffer) {
- // Texture buffers.
- if (reflection.getType()->getSampler().isCombined()) {
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
- info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER;
- //print_line("DEBUG: SAMPLER: texel combined");
- } else if (reflection.getType()->getSampler().isTexture()) {
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
- info.type = UNIFORM_TYPE_TEXTURE_BUFFER;
- //print_line("DEBUG: SAMPLER: texel alone");
- } else if (reflection.getType()->getSampler().isImage()) {
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
- info.type = UNIFORM_TYPE_IMAGE_BUFFER;
- //print_line("DEBUG: SAMPLER: texel buffer");
- } else {
- if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' is of unsupported buffer type.";
- }
- return false;
- }
- } else if (reflection.getType()->getSampler().isCombined()) {
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
- //print_line("DEBUG: SAMPLER: combined");
- } else if (reflection.getType()->getSampler().isPureSampler()) {
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
- info.type = UNIFORM_TYPE_SAMPLER;
- //print_line("DEBUG: SAMPLER: sampler");
- } else if (reflection.getType()->getSampler().isTexture()) {
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
- info.type = UNIFORM_TYPE_TEXTURE;
- //print_line("DEBUG: SAMPLER: image");
- } else if (reflection.getType()->getSampler().isImage()) {
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
- info.type = UNIFORM_TYPE_IMAGE;
- //print_line("DEBUG: SAMPLER: storage image");
- } else {
- //print_line("DEBUG: sampler unknown");
- if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' is of unsupported sampler type.";
- }
- return false;
- }
-
- if (reflection.getType()->isArray()) {
- layout_binding.descriptorCount = reflection.getType()->getArraySizes()->getCumulativeSize();
- //print_line("DEBUG: array of size: " + itos(layout_binding.descriptorCount));
- } else {
- layout_binding.descriptorCount = 1;
- }
-
- info.length = layout_binding.descriptorCount;
-
- } break;
- /*case glslang::EbtStruct: {
- print_line("DEBUG: Struct");
-
- } break;*/
- case glslang::EbtBlock: {
- //print_line("DEBUG: Block");
- if (reflection.getType()->getQualifier().storage == glslang::EvqUniform) {
- if (reflection.getType()->getQualifier().layoutPushConstant) {
- uint32_t len = reflection.size;
- if (push_constant.push_constant_size != 0 && push_constant.push_constant_size != len) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' push constants for different stages should all be the same size.";
- return false;
- }
- push_constant.push_constant_size = len;
- push_constant.push_constants_vk_stage |= shader_stage_masks[p_stage];
- return true;
- }
- //print_line("DEBUG: Uniform buffer");
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- info.type = UNIFORM_TYPE_UNIFORM_BUFFER;
- } else if (reflection.getType()->getQualifier().storage == glslang::EvqBuffer) {
- layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- info.type = UNIFORM_TYPE_STORAGE_BUFFER;
- //print_line("DEBUG: Storage buffer");
- } else {
- if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' is of unsupported block type: (" + itos(reflection.getType()->getQualifier().storage) + ").";
- }
- return false;
- }
-
- if (reflection.getType()->isArray()) {
- layout_binding.descriptorCount = reflection.getType()->getArraySizes()->getCumulativeSize();
- //print_line("DEBUG: array of size: " + itos(layout_binding.descriptorCount));
- } else {
- layout_binding.descriptorCount = 1;
- }
-
- info.length = reflection.size;
-
- } break;
- /*case glslang::EbtReference: {
- } break;*/
- /*case glslang::EbtAtomicUint: {
- } break;*/
- default: {
- if (reflection.getType()->getQualifier().hasOffset() || reflection.name.find(".") != std::string::npos) {
- // Member of uniform block?
- return true;
- }
-
- if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' unsupported uniform type.";
- }
- return false;
- }
- }
-
- if (!reflection.getType()->getQualifier().hasBinding()) {
- if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' lacks a binding number.";
- }
- return false;
- }
-
- uint32_t set = reflection.getType()->getQualifier().hasSet() ? reflection.getType()->getQualifier().layoutSet : 0;
-
- if (set >= MAX_UNIFORM_SETS) {
- if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ").";
- }
- return false;
- }
-
- if (set >= limits.maxBoundDescriptorSets) {
- if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ").";
- }
- return false;
- }
-
- uint32_t binding = reflection.getType()->getQualifier().layoutBinding;
-
- if (set < (uint32_t)bindings.size()) {
- // 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.
- 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.";
- }
- return false;
- }
-
- // 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.";
- }
- return false;
- }
-
- // 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;
- }
- }
- }
- layout_binding.binding = binding;
- layout_binding.stageFlags = shader_stage_masks[p_stage];
- layout_binding.pImmutableSamplers = nullptr; // No support for this yet.
-
- info.stages = 1 << p_stage;
- info.binding = binding;
-
- if (set >= (uint32_t)bindings.size()) {
- bindings.resize(set + 1);
- uniform_infos.resize(set + 1);
- }
-#if 0
- print_line("stage: " + String(shader_stage_names[p_stage]) + " set: " + itos(set) + " binding: " + itos(info.binding) + " type:" + shader_uniform_names[info.type] + " length: " + itos(info.length));
-#endif
- bindings.write[set].push_back(layout_binding);
- uniform_infos.write[set].push_back(info);
-
- return true;
-}
-#endif
// Version 1: initial.
// Version 2: Added shader name.
@@ -4734,7 +4571,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
#define SHADER_BINARY_VERSION 3
String RenderingDeviceVulkan::shader_get_binary_cache_key() const {
- return "Vulkan-SV" + itos(SHADER_BINARY_VERSION) + "-" + String(VERSION_NUMBER) + "-" + String(VERSION_HASH);
+ return "Vulkan-SV" + itos(SHADER_BINARY_VERSION);
}
struct RenderingDeviceVulkanShaderBinaryDataBinding {
@@ -4758,346 +4595,68 @@ struct RenderingDeviceVulkanShaderBinarySpecializationConstant {
struct RenderingDeviceVulkanShaderBinaryData {
uint32_t vertex_input_mask;
- uint32_t fragment_outputs;
- uint32_t specialization_constant_count;
+ uint32_t fragment_output_mask;
+ uint32_t specialization_constants_count;
uint32_t is_compute;
uint32_t compute_local_size[3];
uint32_t set_count;
uint32_t push_constant_size;
- uint32_t push_constants_vk_stage;
+ uint32_t push_constant_vk_stages_mask;
uint32_t stage_count;
uint32_t shader_name_len;
};
Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name) {
- RenderingDeviceVulkanShaderBinaryData binary_data;
- binary_data.vertex_input_mask = 0;
- binary_data.fragment_outputs = 0;
- binary_data.specialization_constant_count = 0;
- binary_data.is_compute = 0;
- binary_data.compute_local_size[0] = 0;
- binary_data.compute_local_size[1] = 0;
- binary_data.compute_local_size[2] = 0;
- binary_data.set_count = 0;
- binary_data.push_constant_size = 0;
- binary_data.push_constants_vk_stage = 0;
+ SpirvReflectionData spirv_data;
+ if (_reflect_spirv(p_spirv, spirv_data) != OK) {
+ return Vector<uint8_t>();
+ }
+ ERR_FAIL_COND_V_MSG((uint32_t)spirv_data.uniforms.size() > limits.maxBoundDescriptorSets, Vector<uint8_t>(),
+ "Number of uniform sets is larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ").");
+
+ // Collect reflection data into binary data.
+ RenderingDeviceVulkanShaderBinaryData binary_data;
Vector<Vector<RenderingDeviceVulkanShaderBinaryDataBinding>> uniform_info; // Set bindings.
Vector<RenderingDeviceVulkanShaderBinarySpecializationConstant> specialization_constants;
-
- uint32_t stages_processed = 0;
-
- for (int i = 0; i < p_spirv.size(); i++) {
- if (p_spirv[i].shader_stage == SHADER_STAGE_COMPUTE) {
- binary_data.is_compute = true;
- ERR_FAIL_COND_V_MSG(p_spirv.size() != 1, Vector<uint8_t>(),
- "Compute shaders can only receive one stage, dedicated to compute.");
- }
- ERR_FAIL_COND_V_MSG(stages_processed & (1 << p_spirv[i].shader_stage), Vector<uint8_t>(),
- "Stage " + String(shader_stage_names[p_spirv[i].shader_stage]) + " submitted more than once.");
-
- {
- SpvReflectShaderModule module;
- const uint8_t *spirv = p_spirv[i].spir_v.ptr();
- SpvReflectResult result = spvReflectCreateShaderModule(p_spirv[i].spir_v.size(), spirv, &module);
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed parsing shader.");
-
- if (binary_data.is_compute) {
- binary_data.compute_local_size[0] = module.entry_points->local_size.x;
- binary_data.compute_local_size[1] = module.entry_points->local_size.y;
- binary_data.compute_local_size[2] = module.entry_points->local_size.z;
- }
- uint32_t binding_count = 0;
- result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, nullptr);
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating descriptor bindings.");
-
- uint32_t stage = p_spirv[i].shader_stage;
-
- if (binding_count > 0) {
- // Parse bindings.
-
- Vector<SpvReflectDescriptorBinding *> bindings;
- bindings.resize(binding_count);
- result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, bindings.ptrw());
-
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed getting descriptor bindings.");
-
- for (uint32_t j = 0; j < binding_count; j++) {
- const SpvReflectDescriptorBinding &binding = *bindings[j];
-
- RenderingDeviceVulkanShaderBinaryDataBinding info;
-
- 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: {
- info.type = UNIFORM_TYPE_SAMPLER;
- need_array_dimensions = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
- info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
- need_array_dimensions = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE: {
- info.type = UNIFORM_TYPE_TEXTURE;
- need_array_dimensions = true;
- } break;
- 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;
- need_array_dimensions = true;
- } break;
- 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;
- need_block_size = true;
- } break;
- 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.");
- continue;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
- ERR_PRINT("Dynamic storage buffer not supported.");
- continue;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
- info.type = UNIFORM_TYPE_INPUT_ATTACHMENT;
- need_array_dimensions = true;
- } break;
- case SPV_REFLECT_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: {
- ERR_PRINT("Acceleration structure not supported.");
- continue;
- } break;
- }
-
- if (need_array_dimensions) {
- if (binding.array.dims_count == 0) {
- info.length = 1;
- } else {
- for (uint32_t k = 0; k < binding.array.dims_count; k++) {
- if (k == 0) {
- info.length = binding.array.dims[0];
- } else {
- info.length *= binding.array.dims[k];
- }
- }
- }
-
- } else if (need_block_size) {
- info.length = binding.block.size;
- } else {
- 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;
-
- ERR_FAIL_COND_V_MSG(set >= MAX_UNIFORM_SETS, Vector<uint8_t>(),
- "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ").");
-
- ERR_FAIL_COND_V_MSG(set >= limits.maxBoundDescriptorSets, Vector<uint8_t>(),
- "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.
- 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.
- 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.
- 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.");
-
- // 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.
- }
- }
-
- info.stages = 1 << stage;
-
- if (set >= (uint32_t)uniform_info.size()) {
- uniform_info.resize(set + 1);
- }
-
- uniform_info.write[set].push_back(info);
- }
- }
-
- {
- // Specialization constants.
-
- uint32_t sc_count = 0;
- result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, nullptr);
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating specialization constants.");
-
- if (sc_count) {
- Vector<SpvReflectSpecializationConstant *> spec_constants;
- spec_constants.resize(sc_count);
-
- result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, spec_constants.ptrw());
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining specialization constants.");
-
- for (uint32_t j = 0; j < sc_count; j++) {
- int32_t existing = -1;
- RenderingDeviceVulkanShaderBinarySpecializationConstant sconst;
- 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 = spc->default_value.int_bool_value != 0;
- } break;
- case SPV_REFLECT_SPECIALIZATION_CONSTANT_INT: {
- sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
- 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 = spc->default_value.float_value;
- } break;
- }
- sconst.stage_flags = 1 << p_spirv[i].shader_stage;
-
- for (int k = 0; k < specialization_constants.size(); k++) {
- if (specialization_constants[k].constant_id == sconst.constant_id) {
- ERR_FAIL_COND_V_MSG(specialization_constants[k].type != sconst.type, Vector<uint8_t>(), "More than one specialization constant used for id (" + itos(sconst.constant_id) + "), but their types differ.");
- ERR_FAIL_COND_V_MSG(specialization_constants[k].int_value != sconst.int_value, Vector<uint8_t>(), "More than one specialization constant used for id (" + itos(sconst.constant_id) + "), but their default values differ.");
- existing = k;
- break;
- }
- }
-
- if (existing > 0) {
- specialization_constants.write[existing].stage_flags |= sconst.stage_flags;
- } else {
- specialization_constants.push_back(sconst);
- }
- }
- }
- }
-
- if (stage == SHADER_STAGE_VERTEX) {
- uint32_t iv_count = 0;
- result = spvReflectEnumerateInputVariables(&module, &iv_count, nullptr);
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating input variables.");
-
- if (iv_count) {
- Vector<SpvReflectInterfaceVariable *> input_vars;
- input_vars.resize(iv_count);
-
- result = spvReflectEnumerateInputVariables(&module, &iv_count, input_vars.ptrw());
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "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.
- binary_data.vertex_input_mask |= (1 << uint32_t(input_vars[j]->location));
- }
- }
- }
- }
-
- if (stage == SHADER_STAGE_FRAGMENT) {
- uint32_t ov_count = 0;
- result = spvReflectEnumerateOutputVariables(&module, &ov_count, nullptr);
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating output variables.");
-
- if (ov_count) {
- Vector<SpvReflectInterfaceVariable *> output_vars;
- output_vars.resize(ov_count);
-
- result = spvReflectEnumerateOutputVariables(&module, &ov_count, output_vars.ptrw());
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining output variables.");
-
- for (uint32_t j = 0; j < ov_count; j++) {
- const SpvReflectInterfaceVariable *refvar = output_vars[j];
- if (refvar != nullptr && refvar->built_in != SpvBuiltInFragDepth) {
- binary_data.fragment_outputs |= 1 << refvar->location;
- }
- }
- }
+ {
+ binary_data.vertex_input_mask = spirv_data.vertex_input_mask;
+ binary_data.fragment_output_mask = spirv_data.fragment_output_mask;
+ binary_data.specialization_constants_count = spirv_data.specialization_constants.size();
+ binary_data.is_compute = spirv_data.is_compute;
+ binary_data.compute_local_size[0] = spirv_data.compute_local_size[0];
+ binary_data.compute_local_size[1] = spirv_data.compute_local_size[1];
+ binary_data.compute_local_size[2] = spirv_data.compute_local_size[2];
+ binary_data.set_count = spirv_data.uniforms.size();
+ binary_data.push_constant_size = spirv_data.push_constant_size;
+ for (uint32_t i = 0; i < SHADER_STAGE_MAX; i++) {
+ if (spirv_data.push_constant_stages_mask.has_flag((ShaderStage)(1 << i))) {
+ binary_data.push_constant_vk_stages_mask |= shader_stage_masks[i];
}
+ }
- uint32_t pc_count = 0;
- result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, nullptr);
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating push constants.");
-
- if (pc_count) {
- ERR_FAIL_COND_V_MSG(pc_count > 1, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "': Only one push constant is supported, which should be the same across shader stages.");
-
- Vector<SpvReflectBlockVariable *> pconstants;
- pconstants.resize(pc_count);
- result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, pconstants.ptrw());
- ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(),
- "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) {
- Ref<FileAccess> f = FileAccess::open("res://popo.spv", FileAccess::WRITE);
- f->store_buffer((const uint8_t *)&SpirV[0], SpirV.size() * sizeof(uint32_t));
- }
-#endif
-
- ERR_FAIL_COND_V_MSG(binary_data.push_constant_size && binary_data.push_constant_size != pconstants[0]->size, Vector<uint8_t>(),
- "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "': Push constant block must be the same across shader stages.");
-
- binary_data.push_constant_size = pconstants[0]->size;
- binary_data.push_constants_vk_stage |= shader_stage_masks[stage];
-
- //print_line("Stage: " + String(shader_stage_names[stage]) + " push constant of size=" + itos(push_constant.push_constant_size));
+ for (const Vector<SpirvReflectionData::Uniform> &spirv_set : spirv_data.uniforms) {
+ Vector<RenderingDeviceVulkanShaderBinaryDataBinding> set_bindings;
+ for (const SpirvReflectionData::Uniform &spirv_uniform : spirv_set) {
+ RenderingDeviceVulkanShaderBinaryDataBinding binding{};
+ binding.type = (uint32_t)spirv_uniform.type;
+ binding.binding = spirv_uniform.binding;
+ binding.stages = (uint32_t)spirv_uniform.stages_mask;
+ binding.length = spirv_uniform.length;
+ binding.writable = (uint32_t)spirv_uniform.writable;
+ set_bindings.push_back(binding);
}
-
- // Destroy the reflection data when no longer required.
- spvReflectDestroyShaderModule(&module);
+ uniform_info.push_back(set_bindings);
}
- stages_processed |= (1 << p_spirv[i].shader_stage);
+ for (const SpirvReflectionData::SpecializationConstant &spirv_sc : spirv_data.specialization_constants) {
+ RenderingDeviceVulkanShaderBinarySpecializationConstant spec_constant{};
+ spec_constant.type = (uint32_t)spirv_sc.type;
+ spec_constant.constant_id = spirv_sc.constant_id;
+ spec_constant.int_value = spirv_sc.int_value;
+ spec_constant.stage_flags = (uint32_t)spirv_sc.stages_mask;
+ specialization_constants.push_back(spec_constant);
+ }
}
Vector<Vector<uint8_t>> compressed_stages;
@@ -5139,7 +4698,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
stages_binary_size += s;
}
- binary_data.specialization_constant_count = specialization_constants.size();
+ binary_data.specialization_constants_count = specialization_constants.size();
binary_data.set_count = uniform_info.size();
binary_data.stage_count = p_spirv.size();
@@ -5172,9 +4731,9 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
uint32_t offset = 0;
uint8_t *binptr = ret.ptrw();
binptr[0] = 'G';
- binptr[1] = 'V';
+ binptr[1] = 'S';
binptr[2] = 'B';
- binptr[3] = 'D'; // Godot vulkan binary data.
+ binptr[3] = 'D'; // Godot Shader Binary Data.
offset += 4;
encode_uint32(SHADER_BINARY_VERSION, binptr + offset);
offset += sizeof(uint32_t);
@@ -5235,7 +4794,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
uint32_t read_offset = 0;
// 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());
+ ERR_FAIL_COND_V(binptr[0] != 'G' || binptr[1] != 'S' || 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());
@@ -5245,12 +4804,12 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
const RenderingDeviceVulkanShaderBinaryData &binary_data = *(reinterpret_cast<const RenderingDeviceVulkanShaderBinaryData *>(binptr + 12));
Shader::PushConstant push_constant;
- push_constant.push_constant_size = binary_data.push_constant_size;
- push_constant.push_constants_vk_stage = binary_data.push_constants_vk_stage;
+ push_constant.size = binary_data.push_constant_size;
+ push_constant.vk_stages_mask = binary_data.push_constant_vk_stages_mask;
uint32_t vertex_input_mask = binary_data.vertex_input_mask;
- uint32_t fragment_outputs = binary_data.fragment_outputs;
+ uint32_t fragment_output_mask = binary_data.fragment_output_mask;
bool is_compute = binary_data.is_compute;
@@ -5346,11 +4905,11 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
read_offset += set_size;
}
- ERR_FAIL_COND_V(read_offset + binary_data.specialization_constant_count * sizeof(RenderingDeviceVulkanShaderBinarySpecializationConstant) >= binsize, RID());
+ ERR_FAIL_COND_V(read_offset + binary_data.specialization_constants_count * sizeof(RenderingDeviceVulkanShaderBinarySpecializationConstant) >= binsize, RID());
Vector<Shader::SpecializationConstant> specialization_constants;
- for (uint32_t i = 0; i < binary_data.specialization_constant_count; i++) {
+ for (uint32_t i = 0; i < binary_data.specialization_constants_count; i++) {
const RenderingDeviceVulkanShaderBinarySpecializationConstant &src_sc = *(reinterpret_cast<const RenderingDeviceVulkanShaderBinarySpecializationConstant *>(binptr + read_offset));
Shader::SpecializationConstant sc;
sc.constant.int_value = src_sc.int_value;
@@ -5416,7 +4975,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
Shader shader;
shader.vertex_input_mask = vertex_input_mask;
- shader.fragment_output_mask = fragment_outputs;
+ shader.fragment_output_mask = fragment_output_mask;
shader.push_constant = push_constant;
shader.is_compute = is_compute;
shader.compute_local_size[0] = compute_local_size[0];
@@ -5446,19 +5005,11 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
break;
}
- const VkShaderStageFlagBits shader_stage_bits[SHADER_STAGE_MAX] = {
- VK_SHADER_STAGE_VERTEX_BIT,
- VK_SHADER_STAGE_FRAGMENT_BIT,
- VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
- VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
- VK_SHADER_STAGE_COMPUTE_BIT,
- };
-
VkPipelineShaderStageCreateInfo shader_stage;
shader_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shader_stage.pNext = nullptr;
shader_stage.flags = 0;
- shader_stage.stage = shader_stage_bits[stage_type[i]];
+ shader_stage.stage = shader_stage_masks[stage_type[i]];
shader_stage.module = module;
shader_stage.pName = "main";
shader_stage.pSpecializationInfo = nullptr;
@@ -5530,10 +5081,10 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
// Needs to be declared in this outer scope, otherwise it may not outlive its assignment
// to pipeline_layout_create_info.
VkPushConstantRange push_constant_range;
- if (push_constant.push_constant_size) {
- push_constant_range.stageFlags = push_constant.push_constants_vk_stage;
+ if (push_constant.size) {
+ push_constant_range.stageFlags = push_constant.vk_stages_mask;
push_constant_range.offset = 0;
- push_constant_range.size = push_constant.push_constant_size;
+ push_constant_range.size = push_constant.size;
pipeline_layout_create_info.pushConstantRangeCount = 1;
pipeline_layout_create_info.pPushConstantRanges = &push_constant_range;
@@ -5607,7 +5158,7 @@ RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Ve
return id;
}
-RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data, uint32_t p_usage) {
+RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data, BitField<StorageBufferUsage> p_usage) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V_MSG(draw_list != nullptr && p_data.size(), RID(),
"Creating buffers with data is forbidden during creation of a draw list");
@@ -5618,7 +5169,7 @@ RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Ve
Buffer buffer;
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) {
+ if (p_usage.has_flag(STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT)) {
flags |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
}
Error err = _buffer_allocate(&buffer, p_size_bytes, flags, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0);
@@ -5928,10 +5479,8 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
// 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.
- }
+
+ DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@@ -5982,10 +5531,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
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.
- }
+ DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@@ -6030,10 +5576,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
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.
- }
+ DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
img_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
@@ -6195,10 +5738,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
img_info.sampler = VK_NULL_HANDLE;
img_info.imageView = texture->view;
- if (texture->owner.is_valid()) {
- texture = texture_owner.get_or_null(texture->owner);
- ERR_FAIL_COND_V(!texture, RID()); // Bug, should never happen.
- }
+ DEV_ASSERT(!texture->owner.is_valid() || texture_owner.get_or_null(texture->owner));
img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@@ -6293,7 +5833,7 @@ void RenderingDeviceVulkan::uniform_set_set_invalidation_callback(RID p_uniform_
us->invalidated_callback_userdata = p_userdata;
}
-Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier) {
+Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V_MSG(draw_list, ERR_INVALID_PARAMETER,
@@ -6303,7 +5843,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) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
// Protect subsequent updates.
dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
dst_access = VK_ACCESS_TRANSFER_WRITE_BIT;
@@ -6339,7 +5879,7 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint
return err;
}
-Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier) {
+Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V_MSG((p_size % 4) != 0, ERR_INVALID_PARAMETER,
@@ -6351,7 +5891,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) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
// Protect subsequent updates.
dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
dst_access = VK_ACCESS_TRANSFER_WRITE_BIT;
@@ -6390,13 +5930,13 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) {
VkPipelineShaderStageCreateFlags src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
VkAccessFlags src_access_mask = VK_ACCESS_TRANSFER_WRITE_BIT;
// Get the vulkan buffer and the potential stage/access possible.
- Buffer *buffer = _get_buffer_from_owner(p_buffer, src_stage_mask, src_access_mask, BARRIER_MASK_ALL);
+ Buffer *buffer = _get_buffer_from_owner(p_buffer, src_stage_mask, src_access_mask, BARRIER_MASK_ALL_BARRIERS);
if (!buffer) {
ERR_FAIL_V_MSG(Vector<uint8_t>(), "Buffer is either invalid or this type of buffer can't be retrieved. Only Index and Vertex buffers allow retrieving.");
}
// Make sure no one is using the buffer -- the "false" gets us to the same command buffer as below.
- _buffer_memory_barrier(buffer->buffer, 0, buffer->size, src_stage_mask, src_access_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, false);
+ _buffer_memory_barrier(buffer->buffer, 0, buffer->size, src_stage_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, src_access_mask, VK_ACCESS_TRANSFER_READ_BIT, false);
VkCommandBuffer command_buffer = frames[frame].setup_command_buffer;
@@ -6432,7 +5972,7 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) {
/**** RENDER PIPELINE ****/
/*************************/
-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) {
+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, BitField<PipelineDynamicStateFlags> p_dynamic_state_flags, uint32_t p_for_render_pass, const Vector<PipelineSpecializationConstant> &p_specialization_constants) {
_THREAD_SAFE_METHOD_
// Needs a shader.
@@ -6561,7 +6101,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
ERR_FAIL_INDEX_V(p_rasterization_state.cull_mode, 3, RID());
rasterization_state_create_info.cullMode = cull_mode[p_rasterization_state.cull_mode];
rasterization_state_create_info.frontFace = (p_rasterization_state.front_face == POLYGON_FRONT_FACE_CLOCKWISE ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE);
- rasterization_state_create_info.depthBiasEnable = p_rasterization_state.depth_bias_enable;
+ rasterization_state_create_info.depthBiasEnable = p_rasterization_state.depth_bias_enabled;
rasterization_state_create_info.depthBiasConstantFactor = p_rasterization_state.depth_bias_constant_factor;
rasterization_state_create_info.depthBiasClamp = p_rasterization_state.depth_bias_clamp;
rasterization_state_create_info.depthBiasSlopeFactor = p_rasterization_state.depth_bias_slope_factor;
@@ -6718,31 +6258,31 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
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) {
+ if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_LINE_WIDTH)) {
dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_WIDTH);
}
- if (p_dynamic_state_flags & DYNAMIC_STATE_DEPTH_BIAS) {
+ if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_DEPTH_BIAS)) {
dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BIAS);
}
- if (p_dynamic_state_flags & DYNAMIC_STATE_BLEND_CONSTANTS) {
+ if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_BLEND_CONSTANTS)) {
dynamic_states.push_back(VK_DYNAMIC_STATE_BLEND_CONSTANTS);
}
- if (p_dynamic_state_flags & DYNAMIC_STATE_DEPTH_BOUNDS) {
+ if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_DEPTH_BOUNDS)) {
dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BOUNDS);
}
- if (p_dynamic_state_flags & DYNAMIC_STATE_STENCIL_COMPARE_MASK) {
+ if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_STENCIL_COMPARE_MASK)) {
dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK);
}
- if (p_dynamic_state_flags & DYNAMIC_STATE_STENCIL_WRITE_MASK) {
+ if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_STENCIL_WRITE_MASK)) {
dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK);
}
- if (p_dynamic_state_flags & DYNAMIC_STATE_STENCIL_REFERENCE) {
+ if (p_dynamic_state_flags.has_flag(DYNAMIC_STATE_STENCIL_REFERENCE)) {
dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_REFERENCE);
}
@@ -6850,10 +6390,10 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateGraphicsPipelines failed with error " + itos(err) + " for shader '" + shader->name + "'.");
pipeline.set_formats = shader->set_formats;
- pipeline.push_constant_stages = shader->push_constant.push_constants_vk_stage;
+ pipeline.push_constant_stages_mask = shader->push_constant.vk_stages_mask;
pipeline.pipeline_layout = shader->pipeline_layout;
pipeline.shader = p_shader;
- pipeline.push_constant_size = shader->push_constant.push_constant_size;
+ pipeline.push_constant_size = shader->push_constant.size;
#ifdef DEBUG_ENABLED
pipeline.validation.dynamic_state = p_dynamic_state_flags;
@@ -6965,10 +6505,10 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<Pi
ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateComputePipelines failed with error " + itos(err) + ".");
pipeline.set_formats = shader->set_formats;
- pipeline.push_constant_stages = shader->push_constant.push_constants_vk_stage;
+ pipeline.push_constant_stages_mask = shader->push_constant.vk_stages_mask;
pipeline.pipeline_layout = shader->pipeline_layout;
pipeline.shader = p_shader;
- pipeline.push_constant_size = shader->push_constant.push_constant_size;
+ pipeline.push_constant_size = shader->push_constant.size;
pipeline.local_group_size[0] = shader->compute_local_size[0];
pipeline.local_group_size[1] = shader->compute_local_size[1];
pipeline.local_group_size[2] = shader->compute_local_size[2];
@@ -7262,12 +6802,12 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
return OK;
}
-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) {
+void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *p_draw_list, Framebuffer *p_framebuffer, Point2i p_viewport_offset, Point2i p_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]);
+ for (int i = 0; i < p_framebuffer->texture_ids.size(); i++) {
+ Texture *texture = texture_owner.get_or_null(p_framebuffer->texture_ids[i]);
if (!texture) {
texture_index++;
@@ -7300,12 +6840,12 @@ void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list,
VkClearRect cr;
cr.baseArrayLayer = 0;
cr.layerCount = 1;
- cr.rect.offset.x = viewport_offset.x;
- cr.rect.offset.y = viewport_offset.y;
- cr.rect.extent.width = viewport_size.width;
- cr.rect.extent.height = viewport_size.height;
+ cr.rect.offset.x = p_viewport_offset.x;
+ cr.rect.offset.y = p_viewport_offset.y;
+ cr.rect.extent.width = p_viewport_size.width;
+ cr.rect.extent.height = p_viewport_size.height;
- vkCmdClearAttachments(draw_list->command_buffer, clear_attachments.size(), clear_attachments.ptr(), 1, &cr);
+ vkCmdClearAttachments(p_draw_list->command_buffer, clear_attachments.size(), clear_attachments.ptr(), 1, &cr);
}
RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
@@ -7610,7 +7150,7 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI
dl->state.set_count = pcount; // Update set count.
if (pipeline->push_constant_size) {
- dl->state.pipeline_push_constant_stages = pipeline->push_constant_stages;
+ dl->state.pipeline_push_constant_stages = pipeline->push_constant_stages_mask;
#ifdef DEBUG_ENABLED
dl->validation.pipeline_push_constant_supplied = false;
#endif
@@ -7729,7 +7269,7 @@ void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_
dl->validation.index_array_size = index_array->indices;
dl->validation.index_array_offset = index_array->offset;
- vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, index_array->offset, index_array->index_type);
+ vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, 0, index_array->index_type);
}
void RenderingDeviceVulkan::draw_list_set_line_width(DrawListID p_list, float p_width) {
@@ -8062,7 +7602,7 @@ void RenderingDeviceVulkan::_draw_list_free(Rect2i *r_last_viewport) {
_THREAD_SAFE_UNLOCK_
}
-void RenderingDeviceVulkan::draw_list_end(uint32_t p_post_barrier) {
+void RenderingDeviceVulkan::draw_list_end(BitField<BarrierMask> p_post_barrier) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_MSG(!draw_list, "Immediate draw list is already inactive.");
@@ -8084,15 +7624,15 @@ void RenderingDeviceVulkan::draw_list_end(uint32_t p_post_barrier) {
uint32_t barrier_flags = 0;
uint32_t access_flags = 0;
- if (p_post_barrier & BARRIER_MASK_COMPUTE) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier & BARRIER_MASK_RASTER) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT /*| VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT*/;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT /*| VK_ACCESS_INDIRECT_COMMAND_READ_BIT*/;
}
- if (p_post_barrier & BARRIER_MASK_TRANSFER) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
}
@@ -8226,7 +7766,7 @@ void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_l
cl->state.set_count = pcount; // Update set count.
if (pipeline->push_constant_size) {
- cl->state.pipeline_push_constant_stages = pipeline->push_constant_stages;
+ cl->state.pipeline_push_constant_stages = pipeline->push_constant_stages_mask;
#ifdef DEBUG_ENABLED
cl->validation.pipeline_push_constant_supplied = false;
#endif
@@ -8570,20 +8110,20 @@ void RenderingDeviceVulkan::compute_list_add_barrier(ComputeListID p_list) {
#endif
}
-void RenderingDeviceVulkan::compute_list_end(uint32_t p_post_barrier) {
+void RenderingDeviceVulkan::compute_list_end(BitField<BarrierMask> p_post_barrier) {
ERR_FAIL_COND(!compute_list);
uint32_t barrier_flags = 0;
uint32_t access_flags = 0;
- if (p_post_barrier & BARRIER_MASK_COMPUTE) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_COMPUTE)) {
barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
}
- if (p_post_barrier & BARRIER_MASK_RASTER) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_RASTER)) {
barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
}
- if (p_post_barrier & BARRIER_MASK_TRANSFER) {
+ if (p_post_barrier.has_flag(BARRIER_MASK_TRANSFER)) {
barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
}
@@ -8651,43 +8191,45 @@ void RenderingDeviceVulkan::compute_list_end(uint32_t p_post_barrier) {
_THREAD_SAFE_UNLOCK_
}
-void RenderingDeviceVulkan::barrier(uint32_t p_from, uint32_t p_to) {
+void RenderingDeviceVulkan::barrier(BitField<BarrierMask> p_from, BitField<BarrierMask> p_to) {
uint32_t src_barrier_flags = 0;
uint32_t src_access_flags = 0;
- if (p_from & BARRIER_MASK_COMPUTE) {
- src_barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
- src_access_flags |= VK_ACCESS_SHADER_WRITE_BIT;
- }
- if (p_from & BARRIER_MASK_RASTER) {
- src_barrier_flags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
- src_access_flags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
- }
- if (p_from & BARRIER_MASK_TRANSFER) {
- src_barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
- src_access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT;
- }
if (p_from == 0) {
src_barrier_flags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+ } else {
+ if (p_from.has_flag(BARRIER_MASK_COMPUTE)) {
+ src_barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ src_access_flags |= VK_ACCESS_SHADER_WRITE_BIT;
+ }
+ if (p_from.has_flag(BARRIER_MASK_RASTER)) {
+ src_barrier_flags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+ src_access_flags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ }
+ if (p_from.has_flag(BARRIER_MASK_TRANSFER)) {
+ src_barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
+ src_access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT;
+ }
}
uint32_t dst_barrier_flags = 0;
uint32_t dst_access_flags = 0;
- if (p_to & BARRIER_MASK_COMPUTE) {
- dst_barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
- dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
- }
- if (p_to & BARRIER_MASK_RASTER) {
- dst_barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
- dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
- }
- if (p_to & BARRIER_MASK_TRANSFER) {
- dst_barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
- dst_access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
- }
if (p_to == 0) {
dst_barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+ } else {
+ if (p_to.has_flag(BARRIER_MASK_COMPUTE)) {
+ dst_barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
+ }
+ if (p_to.has_flag(BARRIER_MASK_RASTER)) {
+ dst_barrier_flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
+ dst_access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
+ }
+ if (p_to.has_flag(BARRIER_MASK_TRANSFER)) {
+ dst_barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
+ dst_access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
+ }
}
_memory_barrier(src_barrier_flags, dst_barrier_flags, src_access_flags, dst_access_flags, true);
@@ -9011,7 +8553,7 @@ VkSampleCountFlagBits RenderingDeviceVulkan::_ensure_supported_sample_count(Text
// Find the closest lower supported sample count.
VkSampleCountFlagBits sample_count = rasterization_sample_count[p_requested_sample_count];
while (sample_count > VK_SAMPLE_COUNT_1_BIT) {
- if (sample_count_flags & rasterization_sample_count[sample_count]) {
+ if (sample_count_flags & sample_count) {
return sample_count;
}
sample_count = (VkSampleCountFlagBits)(sample_count >> 1);
@@ -9164,7 +8706,7 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
Texture *texture = &frames[p_frame].textures_to_dispose_of.front()->get();
if (texture->bound) {
- WARN_PRINT("Deleted a texture while it was bound..");
+ WARN_PRINT("Deleted a texture while it was bound.");
}
vkDestroyImageView(device, texture->view, nullptr);
if (texture->owner.is_null()) {
@@ -9365,12 +8907,10 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
}
}
- // 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 = GLOBAL_GET("rendering/rendering_device/staging_buffer/block_size_kb");
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 = GLOBAL_GET("rendering/rendering_device/staging_buffer/max_size_mb");
staging_buffer_max_size = MAX(1u, staging_buffer_max_size);
staging_buffer_max_size *= 1024 * 1024;
@@ -9378,7 +8918,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
// 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 = GLOBAL_GET("rendering/rendering_device/staging_buffer/texture_upload_region_size_px");
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.
@@ -9393,7 +8933,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
ERR_CONTINUE(err != OK);
}
- max_descriptors_per_pool = GLOBAL_DEF("rendering/vulkan/descriptor_pools/max_descriptors_per_pool", 64);
+ max_descriptors_per_pool = GLOBAL_GET("rendering/rendering_device/vulkan/max_descriptors_per_pool");
// Check to make sure DescriptorPoolKey is good.
static_assert(sizeof(uint64_t) * 3 >= UNIFORM_TYPE_MAX * sizeof(uint16_t));
@@ -9688,6 +9228,10 @@ uint64_t RenderingDeviceVulkan::limit_get(Limit p_limit) const {
return limits.maxComputeWorkGroupSize[1];
case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z:
return limits.maxComputeWorkGroupSize[2];
+ case LIMIT_MAX_VIEWPORT_DIMENSIONS_X:
+ return limits.maxViewportDimensions[0];
+ case LIMIT_MAX_VIEWPORT_DIMENSIONS_Y:
+ return limits.maxViewportDimensions[1];
case LIMIT_SUBGROUP_SIZE: {
VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
return subgroup_capabilities.size;
@@ -9700,6 +9244,12 @@ uint64_t RenderingDeviceVulkan::limit_get(Limit p_limit) const {
VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
return subgroup_capabilities.supported_operations_flags_rd();
}
+ case LIMIT_VRS_TEXEL_WIDTH: {
+ return context->get_vrs_capabilities().texel_size.x;
+ }
+ case LIMIT_VRS_TEXEL_HEIGHT: {
+ return context->get_vrs_capabilities().texel_size.y;
+ }
default:
ERR_FAIL_V(0);
}
@@ -9816,11 +9366,11 @@ bool RenderingDeviceVulkan::has_feature(const Features p_feature) const {
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;
+ return context->get_shader_capabilities().shader_float16_is_supported && context->get_physical_device_features().shaderInt16 && 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;
+ return vrs_capabilities.attachment_vrs_supported && context->get_physical_device_features().shaderStorageImageExtendedFormats;
} break;
default: {
return false;
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
index abec1b0e1b..b2c2a03a87 100644
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ b/drivers/vulkan/rendering_device_vulkan.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* rendering_device_vulkan.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* rendering_device_vulkan.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef RENDERING_DEVICE_VULKAN_H
#define RENDERING_DEVICE_VULKAN_H
@@ -162,7 +162,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t texture_upload_region_size_px = 0;
Vector<uint8_t> _texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer, bool p_2d = false);
- Error _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);
+ Error _texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier, bool p_use_setup_queue);
/*****************/
/**** SAMPLER ****/
@@ -226,8 +226,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
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);
void _full_barrier(bool p_sync_with_draw);
- void _memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw);
- void _buffer_memory_barrier(VkBuffer buffer, uint64_t p_from, uint64_t p_size, VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw);
+ void _memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_access, bool p_sync_with_draw);
+ void _buffer_memory_barrier(VkBuffer buffer, uint64_t p_from, uint64_t p_size, VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_access, bool p_sync_with_draw);
/*********************/
/**** FRAMEBUFFER ****/
@@ -543,10 +543,6 @@ class RenderingDeviceVulkan : public RenderingDevice {
// As a result, we need to figure out quickly when something is no longer "compatible".
// in order to avoid costly rebinds.
- enum {
- MAX_UNIFORM_SETS = 16
- };
-
struct UniformInfo {
UniformType type = UniformType::UNIFORM_TYPE_MAX;
bool writable = false;
@@ -628,8 +624,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t fragment_output_mask = 0;
struct PushConstant {
- uint32_t push_constant_size = 0;
- uint32_t push_constants_vk_stage = 0;
+ uint32_t size = 0;
+ uint32_t vk_stages_mask = 0;
};
PushConstant push_constant;
@@ -791,7 +787,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
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;
+ uint32_t push_constant_stages_mask = 0;
};
RID_Owner<RenderPipeline, true> render_pipeline_owner;
@@ -802,7 +798,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
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;
+ uint32_t push_constant_stages_mask = 0;
uint32_t local_group_size[3] = { 0, 0, 0 };
};
@@ -905,11 +901,11 @@ class RenderingDeviceVulkan : public RenderingDevice {
bool draw_list_unbind_color_textures = false;
bool draw_list_unbind_depth_textures = false;
- void _draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil);
+ void _draw_list_insert_clear_region(DrawList *p_draw_list, Framebuffer *p_framebuffer, Point2i p_viewport_offset, Point2i p_viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil);
Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass, uint32_t *r_subpass_count);
Error _draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents, const Vector<RID> &p_storage_textures);
_FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id);
- Buffer *_get_buffer_from_owner(RID p_buffer, VkPipelineStageFlags &dst_stage_mask, VkAccessFlags &dst_access, uint32_t p_post_barrier);
+ Buffer *_get_buffer_from_owner(RID p_buffer, VkPipelineStageFlags &dst_stage_mask, VkAccessFlags &dst_access, BitField<BarrierMask> p_post_barrier);
Error _draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass);
void _draw_list_free(Rect2i *r_last_viewport = nullptr);
@@ -1052,17 +1048,17 @@ public:
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);
+ virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
virtual Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer);
- virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const;
+ virtual bool texture_is_format_supported_for_usage(DataFormat p_format, BitField<RenderingDevice::TextureUsageBits> p_usage) const;
virtual bool texture_is_shared(RID p_texture);
virtual bool texture_is_valid(RID p_texture);
virtual Size2i texture_size(RID p_texture);
- virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, uint32_t p_post_barrier = BARRIER_MASK_ALL);
- virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, uint32_t p_post_barrier = BARRIER_MASK_ALL);
- virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, uint32_t p_post_barrier = BARRIER_MASK_ALL);
+ virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
+ virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
+ virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
/*********************/
/**** FRAMEBUFFER ****/
@@ -1095,7 +1091,7 @@ public:
// 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);
+ virtual RID vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers, const Vector<uint64_t> &p_offsets = Vector<uint64_t>());
virtual RID index_buffer_create(uint32_t p_size_indices, IndexBufferFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>(), bool p_use_restart_indices = false);
@@ -1117,22 +1113,22 @@ public:
/*****************/
virtual RID uniform_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>());
- virtual RID storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), uint32_t p_usage = 0);
+ virtual RID storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), BitField<StorageBufferUsage> p_usage = 0);
virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>());
virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set);
virtual bool uniform_set_is_valid(RID p_uniform_set);
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_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL);
+ virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS); // Works for any buffer.
+ virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
virtual Vector<uint8_t> buffer_get_data(RID p_buffer);
/*************************/
/**** RENDER PIPELINE ****/
/*************************/
- virtual RID 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 = 0, uint32_t p_for_render_pass = 0, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>());
+ virtual RID 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, BitField<PipelineDynamicStateFlags> p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>());
virtual bool render_pipeline_is_valid(RID p_pipeline);
/**************************/
@@ -1176,7 +1172,7 @@ public:
virtual DrawListID draw_list_switch_to_next_pass();
virtual Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids);
- virtual void draw_list_end(uint32_t p_post_barrier = BARRIER_MASK_ALL);
+ virtual void draw_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
/***********************/
/**** COMPUTE LISTS ****/
@@ -1191,9 +1187,9 @@ public:
virtual void compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups);
virtual void compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads);
virtual void compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset);
- virtual void compute_list_end(uint32_t p_post_barrier = BARRIER_MASK_ALL);
+ virtual void compute_list_end(BitField<BarrierMask> p_post_barrier = BARRIER_MASK_ALL_BARRIERS);
- virtual void barrier(uint32_t p_from = BARRIER_MASK_ALL, uint32_t p_to = BARRIER_MASK_ALL);
+ virtual void barrier(BitField<BarrierMask> p_from = BARRIER_MASK_ALL_BARRIERS, BitField<BarrierMask> p_to = BARRIER_MASK_ALL_BARRIERS);
virtual void full_barrier();
/**************/
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index 99ef57abae..d1391cb53e 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* vulkan_context.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* vulkan_context.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 "vulkan_context.h"
@@ -48,15 +48,119 @@
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");
+Vector<VkAttachmentReference> VulkanContext::_convert_VkAttachmentReference2(uint32_t p_count, const VkAttachmentReference2 *p_refs) {
+ Vector<VkAttachmentReference> att_refs;
+
+ if (p_refs != nullptr) {
+ for (uint32_t i = 0; i < p_count; i++) {
+ // We lose aspectMask in this conversion but we don't use it currently.
+
+ VkAttachmentReference ref = {
+ p_refs[i].attachment, /* attachment */
+ p_refs[i].layout /* layout */
+ };
+
+ att_refs.push_back(ref);
+ }
}
- if (fpCreateRenderPass2KHR == nullptr) {
- return VK_ERROR_EXTENSION_NOT_PRESENT;
+ return att_refs;
+}
+
+VkResult VulkanContext::vkCreateRenderPass2KHR(VkDevice p_device, const VkRenderPassCreateInfo2 *p_create_info, const VkAllocationCallbacks *p_allocator, VkRenderPass *p_render_pass) {
+ if (is_device_extension_enabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
+ if (fpCreateRenderPass2KHR == nullptr) {
+ fpCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(p_device, "vkCreateRenderPass2KHR");
+ }
+
+ if (fpCreateRenderPass2KHR == nullptr) {
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
+ } else {
+ return (fpCreateRenderPass2KHR)(p_device, p_create_info, p_allocator, p_render_pass);
+ }
} else {
- return (fpCreateRenderPass2KHR)(device, pCreateInfo, pAllocator, pRenderPass);
+ // need to fall back on vkCreateRenderPass
+
+ const void *next = p_create_info->pNext; // ATM we only support multiview which should work if supported.
+
+ Vector<VkAttachmentDescription> attachments;
+ for (uint32_t i = 0; i < p_create_info->attachmentCount; i++) {
+ // Basically the old layout just misses type and next.
+ VkAttachmentDescription att = {
+ p_create_info->pAttachments[i].flags, /* flags */
+ p_create_info->pAttachments[i].format, /* format */
+ p_create_info->pAttachments[i].samples, /* samples */
+ p_create_info->pAttachments[i].loadOp, /* loadOp */
+ p_create_info->pAttachments[i].storeOp, /* storeOp */
+ p_create_info->pAttachments[i].stencilLoadOp, /* stencilLoadOp */
+ p_create_info->pAttachments[i].stencilStoreOp, /* stencilStoreOp */
+ p_create_info->pAttachments[i].initialLayout, /* initialLayout */
+ p_create_info->pAttachments[i].finalLayout /* finalLayout */
+ };
+
+ attachments.push_back(att);
+ }
+
+ Vector<VkSubpassDescription> subpasses;
+ for (uint32_t i = 0; i < p_create_info->subpassCount; i++) {
+ // Here we need to do more, again it's just stripping out type and next
+ // but we have VkAttachmentReference2 to convert to VkAttachmentReference.
+ // Also viewmask is not supported but we don't use it outside of multiview.
+
+ Vector<VkAttachmentReference> input_attachments = _convert_VkAttachmentReference2(p_create_info->pSubpasses[i].inputAttachmentCount, p_create_info->pSubpasses[i].pInputAttachments);
+ Vector<VkAttachmentReference> color_attachments = _convert_VkAttachmentReference2(p_create_info->pSubpasses[i].colorAttachmentCount, p_create_info->pSubpasses[i].pColorAttachments);
+ Vector<VkAttachmentReference> resolve_attachments = _convert_VkAttachmentReference2(p_create_info->pSubpasses[i].colorAttachmentCount, p_create_info->pSubpasses[i].pResolveAttachments);
+ Vector<VkAttachmentReference> depth_attachments = _convert_VkAttachmentReference2(p_create_info->pSubpasses[i].colorAttachmentCount, p_create_info->pSubpasses[i].pDepthStencilAttachment);
+
+ VkSubpassDescription subpass = {
+ p_create_info->pSubpasses[i].flags, /* flags */
+ p_create_info->pSubpasses[i].pipelineBindPoint, /* pipelineBindPoint */
+ p_create_info->pSubpasses[i].inputAttachmentCount, /* inputAttachmentCount */
+ input_attachments.size() == 0 ? nullptr : input_attachments.ptr(), /* pInputAttachments */
+ p_create_info->pSubpasses[i].colorAttachmentCount, /* colorAttachmentCount */
+ color_attachments.size() == 0 ? nullptr : color_attachments.ptr(), /* pColorAttachments */
+ resolve_attachments.size() == 0 ? nullptr : resolve_attachments.ptr(), /* pResolveAttachments */
+ depth_attachments.size() == 0 ? nullptr : depth_attachments.ptr(), /* pDepthStencilAttachment */
+ p_create_info->pSubpasses[i].preserveAttachmentCount, /* preserveAttachmentCount */
+ p_create_info->pSubpasses[i].pPreserveAttachments /* pPreserveAttachments */
+ };
+
+ subpasses.push_back(subpass);
+ }
+
+ Vector<VkSubpassDependency> dependencies;
+ for (uint32_t i = 0; i < p_create_info->dependencyCount; i++) {
+ // We lose viewOffset here but again I don't believe we use this anywhere.
+ VkSubpassDependency dep = {
+ p_create_info->pDependencies[i].srcSubpass, /* srcSubpass */
+ p_create_info->pDependencies[i].dstSubpass, /* dstSubpass */
+ p_create_info->pDependencies[i].srcStageMask, /* srcStageMask */
+ p_create_info->pDependencies[i].dstStageMask, /* dstStageMask */
+ p_create_info->pDependencies[i].srcAccessMask, /* srcAccessMask */
+ p_create_info->pDependencies[i].dstAccessMask, /* dstAccessMask */
+ p_create_info->pDependencies[i].dependencyFlags, /* dependencyFlags */
+ };
+
+ dependencies.push_back(dep);
+ }
+
+ // CorrelatedViewMask is not supported in vkCreateRenderPass but we
+ // currently only use this for multiview.
+ // We'll need to look into this.
+
+ VkRenderPassCreateInfo create_info = {
+ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, /* sType */
+ next, /* pNext*/
+ p_create_info->flags, /* flags */
+ (uint32_t)attachments.size(), /* attachmentCount */
+ attachments.ptr(), /* pAttachments */
+ (uint32_t)subpasses.size(), /* subpassCount */
+ subpasses.ptr(), /* pSubpasses */
+ (uint32_t)dependencies.size(), /* */
+ dependencies.ptr(), /* */
+ };
+
+ return vkCreateRenderPass(device, &create_info, p_allocator, p_render_pass);
}
}
@@ -85,19 +189,6 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(
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;
}
@@ -262,11 +353,11 @@ Error VulkanContext::_get_preferred_validation_layers(uint32_t *count, const cha
ERR_FAIL_V(ERR_CANT_CREATE);
}
- for (uint32_t i = 0; i < instance_validation_layers_alt.size(); i++) {
- if (_check_layers(instance_validation_layers_alt[i].size(), instance_validation_layers_alt[i].ptr(), instance_layer_count, instance_layers)) {
- *count = instance_validation_layers_alt[i].size();
+ for (const LocalVector<const char *> &layer : instance_validation_layers_alt) {
+ if (_check_layers(layer.size(), layer.ptr(), instance_layer_count, instance_layers)) {
+ *count = layer.size();
if (names != nullptr) {
- *names = instance_validation_layers_alt[i].ptr();
+ *names = layer.ptr();
}
break;
}
@@ -287,9 +378,7 @@ Error VulkanContext::_obtain_vulkan_version() {
uint32_t api_version;
VkResult res = func(&api_version);
if (res == VK_SUCCESS) {
- vulkan_major = VK_API_VERSION_MAJOR(api_version);
- vulkan_minor = VK_API_VERSION_MINOR(api_version);
- vulkan_patch = VK_API_VERSION_PATCH(api_version);
+ instance_api_version = 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.
@@ -297,74 +386,183 @@ Error VulkanContext::_obtain_vulkan_version() {
}
} else {
print_line("vkEnumerateInstanceVersion not available, assuming Vulkan 1.0.");
- }
-
- // We don't go above 1.2.
- if ((vulkan_major > 1) || (vulkan_major == 1 && vulkan_minor > 2)) {
- vulkan_major = 1;
- vulkan_minor = 2;
- vulkan_patch = 0;
+ instance_api_version = VK_API_VERSION_1_0;
}
return OK;
}
-Error VulkanContext::_initialize_extensions() {
- uint32_t instance_extension_count = 0;
+bool VulkanContext::instance_extensions_initialized = false;
+HashMap<CharString, bool> VulkanContext::requested_instance_extensions;
+
+void VulkanContext::register_requested_instance_extension(const CharString &extension_name, bool p_required) {
+ ERR_FAIL_COND_MSG(instance_extensions_initialized, "You can only registered extensions before the Vulkan instance is created");
+ ERR_FAIL_COND(requested_instance_extensions.has(extension_name));
+
+ requested_instance_extensions[extension_name] = p_required;
+}
+
+Error VulkanContext::_initialize_instance_extensions() {
+ enabled_instance_extension_names.clear();
+
+ // Make sure our core extensions are here
+ register_requested_instance_extension(VK_KHR_SURFACE_EXTENSION_NAME, true);
+ register_requested_instance_extension(_get_platform_surface_extension(), true);
+
+ if (_use_validation_layers()) {
+ register_requested_instance_extension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, false);
+ }
- enabled_extension_count = 0;
- enabled_debug_utils = false;
- enabled_debug_report = false;
- // Look for instance extensions.
- VkBool32 surfaceExtFound = 0;
- VkBool32 platformSurfaceExtFound = 0;
- memset(extension_names, 0, sizeof(extension_names));
+ // This extension allows us to use the properties2 features to query additional device capabilities
+ register_requested_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, false);
+ // Only enable debug utils in verbose mode or DEV_ENABLED.
+ // End users would get spammed with messages of varying verbosity due to the
+ // mess that thirdparty layers/extensions and drivers seem to leave in their
+ // wake, making the Windows registry a bottomless pit of broken layer JSON.
+#ifdef DEV_ENABLED
+ bool want_debug_utils = true;
+#else
+ bool want_debug_utils = OS::get_singleton()->is_stdout_verbose();
+#endif
+ if (want_debug_utils) {
+ register_requested_instance_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, false);
+ }
+
+ // Load instance extensions that are available...
+ uint32_t instance_extension_count = 0;
VkResult err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr);
ERR_FAIL_COND_V(err != VK_SUCCESS && err != VK_INCOMPLETE, ERR_CANT_CREATE);
+ ERR_FAIL_COND_V_MSG(instance_extension_count == 0, ERR_CANT_CREATE, "No instance extensions found, is a driver installed?");
- if (instance_extension_count > 0) {
- VkExtensionProperties *instance_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * instance_extension_count);
- err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, instance_extensions);
- if (err != VK_SUCCESS && err != VK_INCOMPLETE) {
- free(instance_extensions);
- ERR_FAIL_V(ERR_CANT_CREATE);
+ VkExtensionProperties *instance_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * instance_extension_count);
+ err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, instance_extensions);
+ if (err != VK_SUCCESS && err != VK_INCOMPLETE) {
+ free(instance_extensions);
+ ERR_FAIL_V(ERR_CANT_CREATE);
+ }
+#ifdef DEV_ENABLED
+ for (uint32_t i = 0; i < instance_extension_count; i++) {
+ print_verbose(String("VULKAN: Found instance extension ") + String(instance_extensions[i].extensionName));
+ }
+#endif
+
+ // Enable all extensions that are supported and requested
+ for (uint32_t i = 0; i < instance_extension_count; i++) {
+ CharString extension_name(instance_extensions[i].extensionName);
+ if (requested_instance_extensions.has(extension_name)) {
+ enabled_instance_extension_names.insert(extension_name);
}
- for (uint32_t i = 0; i < instance_extension_count; i++) {
- if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) {
- surfaceExtFound = 1;
- extension_names[enabled_extension_count++] = VK_KHR_SURFACE_EXTENSION_NAME;
- }
+ }
- if (!strcmp(_get_platform_surface_extension(), instance_extensions[i].extensionName)) {
- platformSurfaceExtFound = 1;
- extension_names[enabled_extension_count++] = _get_platform_surface_extension();
- }
- if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, instance_extensions[i].extensionName)) {
- if (_use_validation_layers()) {
- extension_names[enabled_extension_count++] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
- enabled_debug_report = true;
- }
- }
- if (!strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, instance_extensions[i].extensionName)) {
- extension_names[enabled_extension_count++] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
- enabled_debug_utils = true;
- }
- if (!strcmp(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, instance_extensions[i].extensionName)) {
- extension_names[enabled_extension_count++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME;
- }
- if (enabled_extension_count >= MAX_EXTENSIONS) {
+ // Now check our requested extensions
+ for (KeyValue<CharString, bool> &requested_extension : requested_instance_extensions) {
+ if (!enabled_instance_extension_names.has(requested_extension.key)) {
+ if (requested_extension.value) {
free(instance_extensions);
- ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG");
+ ERR_FAIL_V_MSG(ERR_BUG, String("Required extension ") + String(requested_extension.key) + String(" not found, is a driver installed?"));
+ } else {
+ print_verbose(String("Optional extension ") + String(requested_extension.key) + String(" not found"));
}
}
+ }
- free(instance_extensions);
+ free(instance_extensions);
+
+ instance_extensions_initialized = true;
+ return OK;
+}
+
+bool VulkanContext::device_extensions_initialized = false;
+HashMap<CharString, bool> VulkanContext::requested_device_extensions;
+
+void VulkanContext::register_requested_device_extension(const CharString &extension_name, bool p_required) {
+ ERR_FAIL_COND_MSG(device_extensions_initialized, "You can only registered extensions before the Vulkan instance is created");
+ ERR_FAIL_COND(requested_device_extensions.has(extension_name));
+
+ requested_device_extensions[extension_name] = p_required;
+}
+
+Error VulkanContext::_initialize_device_extensions() {
+ // Look for device extensions.
+ enabled_device_extension_names.clear();
+
+ // Make sure our core extensions are here
+ register_requested_device_extension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true);
+
+ register_requested_device_extension(VK_KHR_MULTIVIEW_EXTENSION_NAME, false);
+ register_requested_device_extension(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME, false);
+ register_requested_device_extension(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, false);
+ register_requested_device_extension(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false);
+ register_requested_device_extension(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME, false);
+ register_requested_device_extension(VK_KHR_16BIT_STORAGE_EXTENSION_NAME, false);
+ register_requested_device_extension(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, false);
+ register_requested_device_extension(VK_KHR_MAINTENANCE_2_EXTENSION_NAME, false);
+
+ // TODO consider the following extensions:
+ // - VK_KHR_spirv_1_4
+ // - VK_KHR_swapchain_mutable_format
+ // - VK_EXT_full_screen_exclusive
+ // - VK_EXT_hdr_metadata
+ // - VK_KHR_depth_stencil_resolve
+
+ // Even though the user "enabled" the extension via the command
+ // line, we must make sure that it's enumerated for use with the
+ // device. Therefore, disable it here, and re-enable it again if
+ // enumerated.
+ if (VK_KHR_incremental_present_enabled) {
+ register_requested_device_extension(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, false);
+ }
+ if (VK_GOOGLE_display_timing_enabled) {
+ register_requested_device_extension(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME, false);
+ }
+
+ // obtain available device extensions
+ uint32_t device_extension_count = 0;
+ VkResult err = vkEnumerateDeviceExtensionProperties(gpu, nullptr, &device_extension_count, nullptr);
+ ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
+ ERR_FAIL_COND_V_MSG(device_extension_count == 0, ERR_CANT_CREATE,
+ "vkEnumerateDeviceExtensionProperties failed to find any extensions\n\n"
+ "Do you have a compatible Vulkan installable client driver (ICD) installed?\n"
+ "vkCreateInstance Failure");
+
+ VkExtensionProperties *device_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * device_extension_count);
+ err = vkEnumerateDeviceExtensionProperties(gpu, nullptr, &device_extension_count, device_extensions);
+ if (err) {
+ free(device_extensions);
+ ERR_FAIL_V(ERR_CANT_CREATE);
+ }
+
+#ifdef DEV_ENABLED
+ for (uint32_t i = 0; i < device_extension_count; i++) {
+ print_verbose(String("VULKAN: Found device extension ") + String(device_extensions[i].extensionName));
+ }
+#endif
+
+ // Enable all extensions that are supported and requested
+ for (uint32_t i = 0; i < device_extension_count; i++) {
+ CharString extension_name(device_extensions[i].extensionName);
+ if (requested_device_extensions.has(extension_name)) {
+ enabled_device_extension_names.insert(extension_name);
+ }
+ }
+
+ // Now check our requested extensions
+ for (KeyValue<CharString, bool> &requested_extension : requested_device_extensions) {
+ if (!enabled_device_extension_names.has(requested_extension.key)) {
+ if (requested_extension.value) {
+ free(device_extensions);
+ ERR_FAIL_V_MSG(ERR_BUG,
+ String("vkEnumerateDeviceExtensionProperties failed to find the ") + String(requested_extension.key) + String(" extension.\n\nDo you have a compatible Vulkan installable client driver (ICD) installed?\nvkCreateInstance Failure"));
+ } else {
+ print_verbose(String("Optional extension ") + String(requested_extension.key) + String(" not found"));
+ }
+ }
}
- ERR_FAIL_COND_V_MSG(!surfaceExtFound, ERR_CANT_CREATE, "No surface extension found, is a driver installed?");
- ERR_FAIL_COND_V_MSG(!platformSurfaceExtFound, ERR_CANT_CREATE, "No platform surface extension found, is a driver installed?");
+ free(device_extensions);
+ device_extensions_initialized = true;
return OK;
}
@@ -522,6 +720,9 @@ Error VulkanContext::_check_capabilities() {
vrs_capabilities.pipeline_vrs_supported = false;
vrs_capabilities.primitive_vrs_supported = false;
vrs_capabilities.attachment_vrs_supported = false;
+ vrs_capabilities.min_texel_size = Size2i();
+ vrs_capabilities.max_texel_size = Size2i();
+ vrs_capabilities.texel_size = Size2i();
multiview_capabilities.is_supported = false;
multiview_capabilities.geometry_shader_is_supported = false;
multiview_capabilities.tessellation_shader_is_supported = false;
@@ -538,155 +739,213 @@ Error VulkanContext::_check_capabilities() {
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,
- };
+ if (is_instance_extension_enabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+ // 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.
+ void *next = nullptr;
+
+ // We must check that the relative extension is present before assuming a
+ // feature as enabled.
+ // See also: https://github.com/godotengine/godot/issues/65409
+
+ VkPhysicalDeviceVulkan12Features device_features_vk12 = {};
+ VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features = {};
+ VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features = {};
+ VkPhysicalDevice16BitStorageFeaturesKHR storage_feature = {};
+ VkPhysicalDeviceMultiviewFeatures multiview_features = {};
+
+ if (device_api_version >= VK_API_VERSION_1_2) {
+ device_features_vk12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
+ device_features_vk12.pNext = next;
+ next = &device_features_vk12;
+ } else {
+ if (is_device_extension_enabled(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME)) {
+ shader_features = {
+ /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR,
+ /*pNext*/ next,
+ /*shaderFloat16*/ false,
+ /*shaderInt8*/ false,
+ };
+ next = &shader_features;
+ }
+ }
- VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features = {
- /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR,
- /*pNext*/ &vrs_features,
- /*shaderFloat16*/ false,
- /*shaderInt8*/ false,
- };
+ if (is_device_extension_enabled(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME)) {
+ vrs_features = {
+ /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR,
+ /*pNext*/ next,
+ /*pipelineFragmentShadingRate*/ false,
+ /*primitiveFragmentShadingRate*/ false,
+ /*attachmentFragmentShadingRate*/ false,
+ };
+ next = &vrs_features;
+ }
- VkPhysicalDevice16BitStorageFeaturesKHR storage_feature = {
- /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR,
- /*pNext*/ &shader_features,
- /*storageBuffer16BitAccess*/ false,
- /*uniformAndStorageBuffer16BitAccess*/ false,
- /*storagePushConstant16*/ false,
- /*storageInputOutput16*/ false,
- };
+ if (is_device_extension_enabled(VK_KHR_16BIT_STORAGE_EXTENSION_NAME)) {
+ storage_feature = {
+ /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR,
+ /*pNext*/ next,
+ /*storageBuffer16BitAccess*/ false,
+ /*uniformAndStorageBuffer16BitAccess*/ false,
+ /*storagePushConstant16*/ false,
+ /*storageInputOutput16*/ false,
+ };
+ next = &storage_feature;
+ }
- VkPhysicalDeviceMultiviewFeatures multiview_features = {
- /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES,
- /*pNext*/ &storage_feature,
- /*multiview*/ false,
- /*multiviewGeometryShader*/ false,
- /*multiviewTessellationShader*/ false,
- };
+ if (is_device_extension_enabled(VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
+ multiview_features = {
+ /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES,
+ /*pNext*/ next,
+ /*multiview*/ false,
+ /*multiviewGeometryShader*/ false,
+ /*multiviewTessellationShader*/ false,
+ };
+ next = &multiview_features;
+ }
- VkPhysicalDeviceFeatures2 device_features;
- device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
- device_features.pNext = &multiview_features;
+ VkPhysicalDeviceFeatures2 device_features;
+ device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ device_features.pNext = next;
- vkGetPhysicalDeviceFeatures2_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;
+ if (device_api_version >= VK_API_VERSION_1_2) {
+#ifdef MACOS_ENABLED
+ ERR_FAIL_COND_V_MSG(!device_features_vk12.shaderSampledImageArrayNonUniformIndexing, ERR_CANT_CREATE, "Your GPU doesn't support shaderSampledImageArrayNonUniformIndexing which is required to use the Vulkan-based renderers in Godot.");
+#endif
- 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;
+ if (is_device_extension_enabled(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME)) {
+ shader_capabilities.shader_float16_is_supported = device_features_vk12.shaderFloat16;
+ shader_capabilities.shader_int8_is_supported = device_features_vk12.shaderInt8;
+ }
+ } else {
+ if (is_device_extension_enabled(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME)) {
+ shader_capabilities.shader_float16_is_supported = shader_features.shaderFloat16;
+ shader_capabilities.shader_int8_is_supported = shader_features.shaderInt8;
+ }
+ }
- shader_capabilities.shader_float16_is_supported = shader_features.shaderFloat16;
- shader_capabilities.shader_int8_is_supported = shader_features.shaderInt8;
+ if (is_device_extension_enabled(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME)) {
+ vrs_capabilities.pipeline_vrs_supported = vrs_features.pipelineFragmentShadingRate;
+ vrs_capabilities.primitive_vrs_supported = vrs_features.primitiveFragmentShadingRate;
+ vrs_capabilities.attachment_vrs_supported = vrs_features.attachmentFragmentShadingRate;
+ }
- 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;
- }
+ if (is_device_extension_enabled(VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
+ 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;
+ }
- // 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.
- device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2KHR");
- }
- if (device_properties_func != nullptr) {
- VkPhysicalDeviceFragmentShadingRatePropertiesKHR vrsProperties;
- VkPhysicalDeviceMultiviewProperties multiviewProperties;
- VkPhysicalDeviceSubgroupProperties subgroupProperties;
- VkPhysicalDeviceProperties2 physicalDeviceProperties;
- void *nextptr = nullptr;
+ if (is_device_extension_enabled(VK_KHR_16BIT_STORAGE_EXTENSION_NAME)) {
+ 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;
+ }
+ }
- subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
- subgroupProperties.pNext = nextptr;
- nextptr = &subgroupProperties;
+ // 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.
+ device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2KHR");
+ }
+ if (device_properties_func != nullptr) {
+ VkPhysicalDeviceFragmentShadingRatePropertiesKHR vrsProperties{};
+ VkPhysicalDeviceMultiviewProperties multiviewProperties{};
+ VkPhysicalDeviceSubgroupProperties subgroupProperties{};
+ VkPhysicalDeviceProperties2 physicalDeviceProperties{};
+ void *nextptr = nullptr;
+
+ if (device_api_version >= VK_API_VERSION_1_1) { // Vulkan 1.1 or higher
+ subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
+ subgroupProperties.pNext = nextptr;
+
+ nextptr = &subgroupProperties;
+ }
- if (multiview_capabilities.is_supported) {
- multiviewProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
- multiviewProperties.pNext = nextptr;
+ if (multiview_capabilities.is_supported) {
+ multiviewProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
+ multiviewProperties.pNext = nextptr;
- nextptr = &multiviewProperties;
- }
+ nextptr = &multiviewProperties;
+ }
- if (vrs_capabilities.attachment_vrs_supported) {
- vrsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
- vrsProperties.pNext = nextptr;
+ if (vrs_capabilities.attachment_vrs_supported) {
+ vrsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
+ vrsProperties.pNext = nextptr;
- nextptr = &vrsProperties;
- }
+ nextptr = &vrsProperties;
+ }
- physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
- physicalDeviceProperties.pNext = nextptr;
+ physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+ physicalDeviceProperties.pNext = nextptr;
- device_properties_func(gpu, &physicalDeviceProperties);
+ 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.
- subgroup_capabilities.quadOperationsInAllStages = subgroupProperties.quadOperationsInAllStages;
+ 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.
+ 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;
+ 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;
+
+ // We'll attempt to default to a texel size of 16x16
+ vrs_capabilities.texel_size.x = CLAMP(16, vrs_capabilities.min_texel_size.x, vrs_capabilities.max_texel_size.x);
+ vrs_capabilities.texel_size.y = CLAMP(16, vrs_capabilities.min_texel_size.y, vrs_capabilities.max_texel_size.y);
+
+ 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(")"));
+ }
- 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");
}
- } 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;
- if (multiview_capabilities.is_supported) {
- multiview_capabilities.max_view_count = multiviewProperties.maxMultiviewViewCount;
- multiview_capabilities.max_instance_count = multiviewProperties.maxMultiviewInstanceIndex;
+ print_verbose("- Vulkan multiview supported:");
+ print_verbose(" max view count: " + itos(multiview_capabilities.max_view_count));
+ print_verbose(" max instances: " + itos(multiview_capabilities.max_instance_count));
+ } else {
+ print_verbose("- Vulkan multiview not supported");
+ }
- print_verbose("- Vulkan multiview supported:");
- print_verbose(" max view count: " + itos(multiview_capabilities.max_view_count));
- print_verbose(" max instances: " + itos(multiview_capabilities.max_instance_count));
+ print_verbose("- Vulkan subgroup:");
+ print_verbose(" size: " + itos(subgroup_capabilities.size));
+ print_verbose(" stages: " + subgroup_capabilities.supported_stages_desc());
+ print_verbose(" supported ops: " + subgroup_capabilities.supported_operations_desc());
+ if (subgroup_capabilities.quadOperationsInAllStages) {
+ print_verbose(" quad operations in all stages");
+ }
} else {
- print_verbose("- Vulkan multiview not supported");
- }
-
- print_verbose("- Vulkan subgroup:");
- print_verbose(" size: " + itos(subgroup_capabilities.size));
- print_verbose(" stages: " + subgroup_capabilities.supported_stages_desc());
- print_verbose(" supported ops: " + subgroup_capabilities.supported_operations_desc());
- if (subgroup_capabilities.quadOperationsInAllStages) {
- print_verbose(" quad operations in all stages");
+ print_verbose("- Couldn't call vkGetPhysicalDeviceProperties2");
}
- } else {
- print_verbose("- Couldn't call vkGetPhysicalDeviceProperties2");
}
return OK;
@@ -698,27 +957,40 @@ Error VulkanContext::_create_instance() {
// Initialize extensions.
{
- Error err = _initialize_extensions();
+ Error err = _initialize_instance_extensions();
if (err != OK) {
return err;
}
}
- CharString cs = ProjectSettings::get_singleton()->get("application/config/name").operator String().utf8();
+ int enabled_extension_count = 0;
+ const char *enabled_extension_names[MAX_EXTENSIONS];
+ ERR_FAIL_COND_V(enabled_instance_extension_names.size() > MAX_EXTENSIONS, ERR_CANT_CREATE);
+ for (const CharString &extension_name : enabled_instance_extension_names) {
+ enabled_extension_names[enabled_extension_count++] = extension_name.ptr();
+ }
+
+ // We'll set application version to the Vulkan version we're developing against, even if our instance is based on
+ // an older Vulkan version, devices can still support newer versions of Vulkan.
+ // The exception is when we're on Vulkan 1.0, we should not set this to anything but 1.0.
+ // Note that this value is only used by validation layers to warn us about version issues.
+ uint32_t application_api_version = instance_api_version == VK_API_VERSION_1_0 ? VK_API_VERSION_1_0 : VK_API_VERSION_1_2;
+
+ CharString cs = GLOBAL_GET("application/config/name").operator String().utf8();
const VkApplicationInfo app = {
/*sType*/ VK_STRUCTURE_TYPE_APPLICATION_INFO,
/*pNext*/ nullptr,
/*pApplicationName*/ cs.get_data(),
- /*applicationVersion*/ 0,
+ /*applicationVersion*/ 0, // It would be really nice if we store a version number in project settings, say "application/config/version"
/*pEngineName*/ VERSION_NAME,
/*engineVersion*/ VK_MAKE_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH),
- /*apiVersion*/ VK_MAKE_VERSION(vulkan_major, vulkan_minor, 0)
+ /*apiVersion*/ application_api_version
};
VkInstanceCreateInfo inst_info{};
inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
inst_info.pApplicationInfo = &app;
inst_info.enabledExtensionCount = enabled_extension_count;
- inst_info.ppEnabledExtensionNames = (const char *const *)extension_names;
+ inst_info.ppEnabledExtensionNames = (const char *const *)enabled_extension_names;
if (_use_validation_layers()) {
_get_preferred_validation_layers(&inst_info.enabledLayerCount, &inst_info.ppEnabledLayerNames);
}
@@ -728,9 +1000,9 @@ Error VulkanContext::_create_instance() {
* After the instance is created, we use the instance-based
* function to register the final callback.
*/
- VkDebugUtilsMessengerCreateInfoEXT dbg_messenger_create_info;
- VkDebugReportCallbackCreateInfoEXT dbg_report_callback_create_info{};
- if (enabled_debug_utils) {
+ VkDebugUtilsMessengerCreateInfoEXT dbg_messenger_create_info = {};
+ VkDebugReportCallbackCreateInfoEXT dbg_report_callback_create_info = {};
+ if (is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
// 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;
@@ -743,7 +1015,7 @@ Error VulkanContext::_create_instance() {
dbg_messenger_create_info.pfnUserCallback = _debug_messenger_callback;
dbg_messenger_create_info.pUserData = this;
inst_info.pNext = &dbg_messenger_create_info;
- } else if (enabled_debug_report) {
+ } else if (is_instance_extension_enabled(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
dbg_report_callback_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
dbg_report_callback_create_info.flags = VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
VK_DEBUG_REPORT_WARNING_BIT_EXT |
@@ -783,7 +1055,7 @@ Error VulkanContext::_create_instance() {
volkLoadInstance(inst);
#endif
- if (enabled_debug_utils) {
+ if (is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
// Setup VK_EXT_debug_utils function pointers always (we use them for debug labels and names).
CreateDebugUtilsMessengerEXT =
(PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugUtilsMessengerEXT");
@@ -824,7 +1096,7 @@ Error VulkanContext::_create_instance() {
ERR_FAIL_V(ERR_CANT_CREATE);
break;
}
- } else if (enabled_debug_report) {
+ } else if (is_instance_extension_enabled(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
CreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugReportCallbackEXT");
DebugReportMessageEXT = (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(inst, "vkDebugReportMessageEXT");
DestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(inst, "vkDestroyDebugReportCallbackEXT");
@@ -1005,12 +1277,6 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
free(physical_devices);
- // 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.
vkGetPhysicalDeviceProperties(gpu, &gpu_props);
@@ -1030,89 +1296,19 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
}
}
- print_line(
- "Vulkan API " + itos(vulkan_major) + "." + itos(vulkan_minor) + "." + itos(vulkan_patch) +
- " - " + "Using Vulkan Device #" + itos(device_index) + ": " + device_vendor + " - " + device_name);
-
+ // Get device version
device_api_version = gpu_props.apiVersion;
- err = vkEnumerateDeviceExtensionProperties(gpu, nullptr, &device_extension_count, nullptr);
- ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-
- if (device_extension_count > 0) {
- VkExtensionProperties *device_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * device_extension_count);
- err = vkEnumerateDeviceExtensionProperties(gpu, nullptr, &device_extension_count, device_extensions);
- if (err) {
- free(device_extensions);
- ERR_FAIL_V(ERR_CANT_CREATE);
- }
-
- for (uint32_t i = 0; i < device_extension_count; i++) {
- if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME, device_extensions[i].extensionName)) {
- swapchainExtFound = 1;
- 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.
- 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");
- }
- }
-
- if (VK_KHR_incremental_present_enabled) {
- // Even though the user "enabled" the extension via the command
- // line, we must make sure that it's enumerated for use with the
- // device. Therefore, disable it here, and re-enable it again if
- // enumerated.
- VK_KHR_incremental_present_enabled = false;
- for (uint32_t i = 0; i < device_extension_count; i++) {
- if (!strcmp(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, device_extensions[i].extensionName)) {
- extension_names[enabled_extension_count++] = VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME;
- VK_KHR_incremental_present_enabled = true;
- }
- if (enabled_extension_count >= MAX_EXTENSIONS) {
- free(device_extensions);
- ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG");
- }
- }
- }
+ // Output our device version
+ print_line("Vulkan API " + get_device_api_version() + " - " + "Using Vulkan Device #" + itos(device_index) + ": " + device_vendor + " - " + device_name);
- if (VK_GOOGLE_display_timing_enabled) {
- // Even though the user "enabled" the extension via the command
- // line, we must make sure that it's enumerated for use with the
- // device. Therefore, disable it here, and re-enable it again if
- // enumerated.
- VK_GOOGLE_display_timing_enabled = false;
- for (uint32_t i = 0; i < device_extension_count; i++) {
- if (!strcmp(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME, device_extensions[i].extensionName)) {
- extension_names[enabled_extension_count++] = VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME;
- VK_GOOGLE_display_timing_enabled = true;
- }
- if (enabled_extension_count >= MAX_EXTENSIONS) {
- free(device_extensions);
- ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG");
- }
- }
+ {
+ Error _err = _initialize_device_extensions();
+ if (_err != OK) {
+ return _err;
}
-
- free(device_extensions);
}
- ERR_FAIL_COND_V_MSG(!swapchainExtFound, ERR_CANT_CREATE,
- "vkEnumerateDeviceExtensionProperties failed to find the " VK_KHR_SWAPCHAIN_EXTENSION_NAME
- " extension.\n\nDo you have a compatible Vulkan installable client driver (ICD) installed?\n"
- "vkCreateInstance Failure");
-
// Call with nullptr data to get count.
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, nullptr);
ERR_FAIL_COND_V(queue_family_count == 0, ERR_CANT_CREATE);
@@ -1124,6 +1320,10 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
// features based on this query
vkGetPhysicalDeviceFeatures(gpu, &physical_device_features);
+ // Check required features
+ ERR_FAIL_COND_V_MSG(!physical_device_features.imageCubeArray, ERR_CANT_CREATE, "Your GPU doesn't support image cube arrays which are required to use the Vulkan-based renderers in Godot.");
+ ERR_FAIL_COND_V_MSG(!physical_device_features.independentBlend, ERR_CANT_CREATE, "Your GPU doesn't support independentBlend which is required to use the Vulkan-based renderers in Godot.");
+
physical_device_features.robustBufferAccess = false; // Turn off robust buffer access, which can hamper performance on some hardware.
#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
@@ -1173,7 +1373,7 @@ Error VulkanContext::_create_device() {
};
nextptr = &shader_features;
- VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_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;
@@ -1185,10 +1385,10 @@ Error VulkanContext::_create_device() {
nextptr = &vrs_features;
}
- VkPhysicalDeviceVulkan11Features vulkan11features;
- VkPhysicalDevice16BitStorageFeaturesKHR storage_feature;
- VkPhysicalDeviceMultiviewFeatures multiview_features;
- if (vulkan_major > 1 || vulkan_minor >= 2) {
+ VkPhysicalDeviceVulkan11Features vulkan11features = {};
+ VkPhysicalDevice16BitStorageFeaturesKHR storage_feature = {};
+ VkPhysicalDeviceMultiviewFeatures multiview_features = {};
+ if (device_api_version >= VK_API_VERSION_1_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;
@@ -1207,7 +1407,7 @@ Error VulkanContext::_create_device() {
vulkan11features.shaderDrawParameters = 0;
nextptr = &vulkan11features;
} else {
- // On Vulkan 1.0 and 1.1 we use our older structs to initialise these features.
+ // On Vulkan 1.0 and 1.1 we use our older structs to initialize 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;
@@ -1216,7 +1416,7 @@ Error VulkanContext::_create_device() {
storage_feature.storageInputOutput16 = storage_buffer_capabilities.storage_input_output_16;
nextptr = &storage_feature;
- if (vulkan_major == 1 && vulkan_minor == 1) {
+ if (device_api_version >= VK_API_VERSION_1_1) { // any Vulkan 1.1.x version
multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
multiview_features.pNext = nextptr;
multiview_features.multiview = multiview_capabilities.is_supported;
@@ -1226,6 +1426,13 @@ Error VulkanContext::_create_device() {
}
}
+ uint32_t enabled_extension_count = 0;
+ const char *enabled_extension_names[MAX_EXTENSIONS];
+ ERR_FAIL_COND_V(enabled_device_extension_names.size() > MAX_EXTENSIONS, ERR_CANT_CREATE);
+ for (const CharString &extension_name : enabled_device_extension_names) {
+ enabled_extension_names[enabled_extension_count++] = extension_name.ptr();
+ }
+
VkDeviceCreateInfo sdevice = {
/*sType*/ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
/*pNext*/ nextptr,
@@ -1235,7 +1442,7 @@ Error VulkanContext::_create_device() {
/*enabledLayerCount*/ 0,
/*ppEnabledLayerNames*/ nullptr,
/*enabledExtensionCount*/ enabled_extension_count,
- /*ppEnabledExtensionNames*/ (const char *const *)extension_names,
+ /*ppEnabledExtensionNames*/ (const char *const *)enabled_extension_names,
/*pEnabledFeatures*/ &physical_device_features, // If specific features are required, pass them in here.
};
if (separate_present_queue) {
@@ -1323,7 +1530,7 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) {
GET_DEVICE_PROC_ADDR(device, GetSwapchainImagesKHR);
GET_DEVICE_PROC_ADDR(device, AcquireNextImageKHR);
GET_DEVICE_PROC_ADDR(device, QueuePresentKHR);
- if (VK_GOOGLE_display_timing_enabled) {
+ if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) {
GET_DEVICE_PROC_ADDR(device, GetRefreshCycleDurationGOOGLE);
GET_DEVICE_PROC_ADDR(device, GetPastPresentationTimingGOOGLE);
}
@@ -1354,7 +1561,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 a 32bit RGBA unsigned normalised buffer or similar.
+ // we want a 32bit RGBA unsigned normalized buffer or similar.
const VkFormat allowed_formats[] = {
VK_FORMAT_B8G8R8A8_UNORM,
VK_FORMAT_R8G8B8A8_UNORM
@@ -1703,18 +1910,22 @@ Error VulkanContext::_update_swap_chain(Window *window) {
preTransform = surfCapabilities.currentTransform;
}
- // 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_PRE_MULTIPLIED_BIT_KHR,
- VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
- VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
- VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
- };
- for (uint32_t i = 0; i < ARRAY_SIZE(compositeAlphaFlags); i++) {
- if (surfCapabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) {
- compositeAlpha = compositeAlphaFlags[i];
- break;
+
+ if (OS::get_singleton()->is_layered_allowed() || !(surfCapabilities.supportedCompositeAlpha & compositeAlpha)) {
+ // Find a supported composite alpha mode - one of these is guaranteed to be set.
+ VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = {
+ VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
+ VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
+ VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
+ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+ };
+
+ for (uint32_t i = 0; i < ARRAY_SIZE(compositeAlphaFlags); i++) {
+ if (surfCapabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) {
+ compositeAlpha = compositeAlphaFlags[i];
+ break;
+ }
}
}
@@ -2074,7 +2285,7 @@ Error VulkanContext::swap_buffers() {
VkResult err;
#if 0
- if (VK_GOOGLE_display_timing_enabled) {
+ if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) {
// Look at what happened to previous presents, and make appropriate
// adjustments in timing.
DemoUpdateTargetIPD(demo);
@@ -2086,7 +2297,7 @@ Error VulkanContext::swap_buffers() {
// simple that it doesn't do either of those.
}
#endif
- // Wait for the image acquired semaphore to be signalled to ensure
+ // Wait for the image acquired semaphore to be signaled to ensure
// that the image won't be rendered to until the presentation
// engine has fully released ownership to the application, and it is
// okay to render to the image.
@@ -2138,7 +2349,7 @@ 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 signaling the ownership released semaphore when finished.
VkFence nullFence = VK_NULL_HANDLE;
pipe_stage_flags[0] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
submit_info.waitSemaphoreCount = 1;
@@ -2195,7 +2406,7 @@ Error VulkanContext::swap_buffers() {
}
#if 0
- if (VK_KHR_incremental_present_enabled) {
+ if (is_device_extension_enabled(VK_KHR_incremental_present_enabled)) {
// If using VK_KHR_incremental_present, we provide a hint of the region
// that contains changed content relative to the previously-presented
// image. The implementation can use this hint in order to save
@@ -2226,7 +2437,7 @@ Error VulkanContext::swap_buffers() {
#endif
#if 0
- if (VK_GOOGLE_display_timing_enabled) {
+ if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) {
VkPresentTimeGOOGLE ptime;
if (prev_desired_present_time == 0) {
// This must be the first present for this swapchain.
@@ -2256,13 +2467,11 @@ Error VulkanContext::swap_buffers() {
/*swapchainCount*/ present.swapchainCount,
/*pTimes*/ &ptime,
};
- if (VK_GOOGLE_display_timing_enabled) {
+ if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) {
present.pNext = &present_time;
}
}
#endif
- static int total_frames = 0;
- total_frames++;
// print_line("current buffer: " + itos(current_buffer));
err = fpQueuePresentKHR(present_queue, &present);
@@ -2331,6 +2540,13 @@ RID VulkanContext::local_device_create() {
queues[0].pQueuePriorities = queue_priorities;
queues[0].flags = 0;
+ uint32_t enabled_extension_count = 0;
+ const char *enabled_extension_names[MAX_EXTENSIONS];
+ ERR_FAIL_COND_V(enabled_device_extension_names.size() > MAX_EXTENSIONS, RID());
+ for (const CharString &extension_name : enabled_device_extension_names) {
+ enabled_extension_names[enabled_extension_count++] = extension_name.ptr();
+ }
+
VkDeviceCreateInfo sdevice = {
/*sType =*/VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
/*pNext */ nullptr,
@@ -2340,7 +2556,7 @@ RID VulkanContext::local_device_create() {
/*enabledLayerCount */ 0,
/*ppEnabledLayerNames */ nullptr,
/*enabledExtensionCount */ enabled_extension_count,
- /*ppEnabledExtensionNames */ (const char *const *)extension_names,
+ /*ppEnabledExtensionNames */ (const char *const *)enabled_extension_names,
/*pEnabledFeatures */ &physical_device_features, // If specific features are required, pass them in here.
};
err = vkCreateDevice(gpu, &sdevice, nullptr, &ld.device);
@@ -2405,7 +2621,7 @@ void VulkanContext::local_device_free(RID p_local_device) {
}
void VulkanContext::command_begin_label(VkCommandBuffer p_command_buffer, String p_label_name, const Color p_color) {
- if (!enabled_debug_utils) {
+ if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
return;
}
@@ -2422,7 +2638,7 @@ void VulkanContext::command_begin_label(VkCommandBuffer p_command_buffer, String
}
void VulkanContext::command_insert_label(VkCommandBuffer p_command_buffer, String p_label_name, const Color p_color) {
- if (!enabled_debug_utils) {
+ if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
return;
}
CharString cs = p_label_name.utf8();
@@ -2438,14 +2654,14 @@ void VulkanContext::command_insert_label(VkCommandBuffer p_command_buffer, Strin
}
void VulkanContext::command_end_label(VkCommandBuffer p_command_buffer) {
- if (!enabled_debug_utils) {
+ if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
return;
}
CmdEndDebugUtilsLabelEXT(p_command_buffer);
}
void VulkanContext::set_object_name(VkObjectType p_object_type, uint64_t p_object_handle, String p_object_name) {
- if (!enabled_debug_utils) {
+ if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
return;
}
CharString obj_data = p_object_name.utf8();
@@ -2471,7 +2687,7 @@ RenderingDevice::DeviceType VulkanContext::get_device_type() const {
}
String VulkanContext::get_device_api_version() const {
- return vformat("%d.%d.%d", vulkan_major, vulkan_minor, vulkan_patch);
+ return vformat("%d.%d.%d", VK_API_VERSION_MAJOR(device_api_version), VK_API_VERSION_MINOR(device_api_version), VK_API_VERSION_PATCH(device_api_version));
}
String VulkanContext::get_device_pipeline_cache_uuid() const {
@@ -2506,7 +2722,7 @@ VulkanContext::~VulkanContext() {
vkDestroySemaphore(device, image_ownership_semaphores[i], nullptr);
}
}
- if (inst_initialized && enabled_debug_utils) {
+ if (inst_initialized && is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
DestroyDebugUtilsMessengerEXT(inst, dbg_messenger, nullptr);
}
if (inst_initialized && dbg_debug_report != VK_NULL_HANDLE) {
diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h
index 9889cf336b..9fd2c40a06 100644
--- a/drivers/vulkan/vulkan_context.h
+++ b/drivers/vulkan/vulkan_context.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* vulkan_context.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* vulkan_context.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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_CONTEXT_H
#define VULKAN_CONTEXT_H
@@ -34,6 +34,7 @@
#include "core/error/error_list.h"
#include "core/os/mutex.h"
#include "core/string/ustring.h"
+#include "core/templates/hash_map.h"
#include "core/templates/rb_map.h"
#include "core/templates/rid_owner.h"
#include "servers/display_server.h"
@@ -76,6 +77,8 @@ public:
Size2i min_texel_size;
Size2i max_texel_size;
+
+ Size2i texel_size; // The texel size we'll use
};
struct ShaderCapabilities {
@@ -107,10 +110,7 @@ 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.
- uint32_t vulkan_major = 1;
- uint32_t vulkan_minor = 0;
- uint32_t vulkan_patch = 0;
+ uint32_t instance_api_version = VK_API_VERSION_1_0;
SubgroupCapabilities subgroup_capabilities;
MultiviewCapabilities multiview_capabilities;
VRSCapabilities vrs_capabilities;
@@ -182,18 +182,15 @@ private:
int command_buffer_count = 1;
// Extensions.
+ static bool instance_extensions_initialized;
+ static HashMap<CharString, bool> requested_instance_extensions;
+ HashSet<CharString> enabled_instance_extension_names;
+ static bool device_extensions_initialized;
+ static HashMap<CharString, bool> requested_device_extensions;
+ HashSet<CharString> enabled_device_extension_names;
bool VK_KHR_incremental_present_enabled = true;
bool VK_GOOGLE_display_timing_enabled = true;
- uint32_t enabled_extension_count = 0;
- const char *extension_names[MAX_EXTENSIONS];
- bool enabled_debug_utils = false;
-
- /**
- * True if VK_EXT_debug_report extension is used. VK_EXT_debug_report is deprecated but it is
- * still used if VK_EXT_debug_utils is not available.
- */
- bool enabled_debug_report = false;
PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT = nullptr;
PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT = nullptr;
@@ -222,7 +219,8 @@ private:
VkDebugReportCallbackEXT dbg_debug_report = VK_NULL_HANDLE;
Error _obtain_vulkan_version();
- Error _initialize_extensions();
+ Error _initialize_instance_extensions();
+ Error _initialize_device_extensions();
Error _check_capabilities();
VkBool32 _check_layers(uint32_t check_count, const char *const *check_names, uint32_t layer_count, VkLayerProperties *layers);
@@ -257,6 +255,8 @@ private:
Error _create_swap_chain();
Error _create_semaphores();
+ Vector<VkAttachmentReference> _convert_VkAttachmentReference2(uint32_t p_count, const VkAttachmentReference2 *p_refs);
+
protected:
virtual const char *_get_platform_surface_extension() const = 0;
@@ -270,15 +270,17 @@ protected:
public:
// Extension calls.
- VkResult vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);
+ bool supports_renderpass2() const { return is_device_extension_enabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); }
+ VkResult vkCreateRenderPass2KHR(VkDevice p_device, const VkRenderPassCreateInfo2 *p_create_info, const VkAllocationCallbacks *p_allocator, VkRenderPass *p_render_pass);
- uint32_t get_vulkan_major() const { return vulkan_major; };
- uint32_t get_vulkan_minor() const { return vulkan_minor; };
+ uint32_t get_vulkan_major() const { return VK_API_VERSION_MAJOR(device_api_version); };
+ uint32_t get_vulkan_minor() const { return VK_API_VERSION_MINOR(device_api_version); };
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; };
+ const VkPhysicalDeviceFeatures &get_physical_device_features() const { return physical_device_features; };
VkDevice get_device();
VkPhysicalDevice get_physical_device();
@@ -289,6 +291,16 @@ public:
static void set_vulkan_hooks(VulkanHooks *p_vulkan_hooks) { vulkan_hooks = p_vulkan_hooks; };
+ static void register_requested_instance_extension(const CharString &extension_name, bool p_required);
+ bool is_instance_extension_enabled(const CharString &extension_name) const {
+ return enabled_instance_extension_names.has(extension_name);
+ }
+
+ static void register_requested_device_extension(const CharString &extension_name, bool p_required);
+ bool is_device_extension_enabled(const CharString &extension_name) const {
+ return enabled_device_extension_names.has(extension_name);
+ }
+
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);
diff --git a/drivers/vulkan/vulkan_hooks.h b/drivers/vulkan/vulkan_hooks.h
index dec2042d0d..eaa52658e4 100644
--- a/drivers/vulkan/vulkan_hooks.h
+++ b/drivers/vulkan/vulkan_hooks.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
+/**************************************************************************/
+/* vulkan_hooks.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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
diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp
index fb90b776cf..b2745b1e86 100644
--- a/drivers/wasapi/audio_driver_wasapi.cpp
+++ b/drivers/wasapi/audio_driver_wasapi.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* audio_driver_wasapi.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* audio_driver_wasapi.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 WASAPI_ENABLED
@@ -201,7 +201,7 @@ public:
static CMMNotificationClient notif_client;
-Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool reinit) {
+Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool p_reinit, bool p_no_audio_client_3) {
WAVEFORMATEX *pwfex;
IMMDeviceEnumerator *enumerator = nullptr;
IMMDevice *device = nullptr;
@@ -267,7 +267,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
}
}
- if (reinit) {
+ if (p_reinit) {
// In case we're trying to re-initialize the device prevent throwing this error on the console,
// otherwise if there is currently no device available this will spam the console.
if (hr != S_OK) {
@@ -285,6 +285,11 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
}
using_audio_client_3 = !p_capture; // IID_IAudioClient3 is only used for adjustable output latency (not input)
+
+ if (p_no_audio_client_3) {
+ using_audio_client_3 = false;
+ }
+
if (using_audio_client_3) {
hr = device->Activate(IID_IAudioClient3, CLSCTX_ALL, nullptr, (void **)&p_device->audio_client);
if (hr != S_OK) {
@@ -302,7 +307,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
SAFE_RELEASE(device)
- if (reinit) {
+ if (p_reinit) {
if (hr != S_OK) {
return ERR_CANT_OPEN;
}
@@ -413,7 +418,12 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
&fundamental_period_frames,
&min_period_frames,
&max_period_frames);
- ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_CANT_OPEN, "WASAPI: GetSharedModeEnginePeriod failed with error 0x" + String::num_uint64(hr, 16) + ".");
+ if (hr != S_OK) {
+ print_verbose("WASAPI: GetSharedModeEnginePeriod failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient.");
+ CoTaskMemFree(pwfex);
+ SAFE_RELEASE(device)
+ return audio_device_init(p_device, p_capture, p_reinit, true);
+ }
// Period frames must be an integral multiple of fundamental_period_frames or IAudioClient3 initialization will fail,
// so we need to select the closest multiple to the user-specified latency.
@@ -430,12 +440,25 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
buffer_frames = period_frames;
hr = device_audio_client_3->InitializeSharedAudioStream(0, period_frames, pwfex, nullptr);
- ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_CANT_OPEN, "WASAPI: InitializeSharedAudioStream failed with error 0x" + String::num_uint64(hr, 16) + ".");
- uint32_t output_latency_in_frames;
- WAVEFORMATEX *current_pwfex;
- device_audio_client_3->GetCurrentSharedModeEnginePeriod(&current_pwfex, &output_latency_in_frames);
- real_latency = (float)output_latency_in_frames / (float)current_pwfex->nSamplesPerSec;
- CoTaskMemFree(current_pwfex);
+ if (hr != S_OK) {
+ print_verbose("WASAPI: InitializeSharedAudioStream failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient.");
+ CoTaskMemFree(pwfex);
+ SAFE_RELEASE(device);
+ return audio_device_init(p_device, p_capture, p_reinit, true);
+ } else {
+ uint32_t output_latency_in_frames;
+ WAVEFORMATEX *current_pwfex;
+ hr = device_audio_client_3->GetCurrentSharedModeEnginePeriod(&current_pwfex, &output_latency_in_frames);
+ if (hr == OK) {
+ real_latency = (float)output_latency_in_frames / (float)current_pwfex->nSamplesPerSec;
+ CoTaskMemFree(current_pwfex);
+ } else {
+ print_verbose("WASAPI: GetCurrentSharedModeEnginePeriod failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient.");
+ CoTaskMemFree(pwfex);
+ SAFE_RELEASE(device);
+ return audio_device_init(p_device, p_capture, p_reinit, true);
+ }
+ }
}
if (p_capture) {
@@ -452,8 +475,8 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
return OK;
}
-Error AudioDriverWASAPI::init_render_device(bool reinit) {
- Error err = audio_device_init(&audio_output, false, reinit);
+Error AudioDriverWASAPI::init_render_device(bool p_reinit) {
+ Error err = audio_device_init(&audio_output, false, p_reinit);
if (err != OK) {
return err;
}
@@ -484,8 +507,8 @@ Error AudioDriverWASAPI::init_render_device(bool reinit) {
return OK;
}
-Error AudioDriverWASAPI::init_capture_device(bool reinit) {
- Error err = audio_device_init(&audio_input, true, reinit);
+Error AudioDriverWASAPI::init_capture_device(bool p_reinit) {
+ Error err = audio_device_init(&audio_input, true, p_reinit);
if (err != OK) {
return err;
}
diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h
index c30a54c042..6eea24f78a 100644
--- a/drivers/wasapi/audio_driver_wasapi.h
+++ b/drivers/wasapi/audio_driver_wasapi.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* audio_driver_wasapi.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* audio_driver_wasapi.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef AUDIO_DRIVER_WASAPI_H
#define AUDIO_DRIVER_WASAPI_H
@@ -83,13 +83,13 @@ class AudioDriverWASAPI : public AudioDriver {
static _FORCE_INLINE_ int32_t read_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i);
static void thread_func(void *p_udata);
- Error init_render_device(bool reinit = false);
- Error init_capture_device(bool reinit = false);
+ Error init_render_device(bool p_reinit = false);
+ Error init_capture_device(bool p_reinit = false);
Error finish_render_device();
Error finish_capture_device();
- Error audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool reinit);
+ Error audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool p_reinit, bool p_no_audio_client_3 = false);
Error audio_device_finish(AudioDeviceWASAPI *p_device);
PackedStringArray audio_device_get_list(bool p_capture);
diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp
index 11fd29c8f5..7b88bd8a95 100644
--- a/drivers/windows/dir_access_windows.cpp
+++ b/drivers/windows/dir_access_windows.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* dir_access_windows.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* dir_access_windows.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/**************************************************************************/
#if defined(WINDOWS_ENABLED)
@@ -160,7 +160,7 @@ Error DirAccessWindows::make_dir(String p_dir) {
p_dir = current_dir.path_join(p_dir);
}
- p_dir = p_dir.replace("/", "\\");
+ p_dir = p_dir.simplify_path().replace("/", "\\");
bool success;
int err;
@@ -200,9 +200,9 @@ String DirAccessWindows::get_current_dir(bool p_include_drive) const {
return current_dir;
} else {
if (_get_root_string().is_empty()) {
- int p = current_dir.find(":");
- if (p != -1) {
- return current_dir.substr(p + 1);
+ int pos = current_dir.find(":");
+ if (pos != -1) {
+ return current_dir.substr(pos + 1);
}
}
return current_dir;
@@ -309,39 +309,13 @@ Error DirAccessWindows::remove(String p_path) {
}
}
-/*
-
-FileType DirAccessWindows::get_file_type(const String& p_file) const {
- WCHAR real_current_dir_name[2048];
- GetCurrentDirectoryW(2048, real_current_dir_name);
- String prev_dir = Strong::utf16((const char16_t *)real_current_dir_name);
-
- bool worked = SetCurrentDirectoryW((LPCWSTR)(current_dir.utf16().get_data()));
-
- DWORD attr;
- if (worked) {
- WIN32_FILE_ATTRIBUTE_DATA fileInfo;
- attr = GetFileAttributesExW((LPCWSTR)(p_file.utf16().get_data()), GetFileExInfoStandard, &fileInfo);
- }
-
- SetCurrentDirectoryW((LPCWSTR)(prev_dir.utf16().get_data()));
-
- if (!worked) {
- return FILE_TYPE_NONE;
- }
-
- return (attr & FILE_ATTRIBUTE_DIRECTORY) ? FILE_TYPE_
-}
-
-*/
-
uint64_t DirAccessWindows::get_space_left() {
uint64_t bytes = 0;
if (!GetDiskFreeSpaceEx(nullptr, (PULARGE_INTEGER)&bytes, nullptr, nullptr)) {
return 0;
}
- //this is either 0 or a value in bytes.
+ // This is either 0 or a value in bytes.
return bytes;
}
diff --git a/drivers/windows/dir_access_windows.h b/drivers/windows/dir_access_windows.h
index c2835b3347..9d91c22f7e 100644
--- a/drivers/windows/dir_access_windows.h
+++ b/drivers/windows/dir_access_windows.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* dir_access_windows.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* dir_access_windows.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 DIR_ACCESS_WINDOWS_H
#define DIR_ACCESS_WINDOWS_H
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index 1a66d19373..ea40622afc 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* file_access_windows.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* file_access_windows.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 WINDOWS_ENABLED
@@ -34,7 +34,6 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
-
#include <share.h> // _SH_DENYNO
#include <shlwapi.h>
#define WIN32_LEAN_AND_MEAN
@@ -58,7 +57,27 @@ void FileAccessWindows::check_errors() const {
}
}
-Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
+bool FileAccessWindows::is_path_invalid(const String &p_path) {
+ // Check for invalid operating system file.
+ String fname = p_path;
+ int dot = fname.find(".");
+ if (dot != -1) {
+ fname = fname.substr(0, dot);
+ }
+ fname = fname.to_lower();
+ return invalid_files.has(fname);
+}
+
+Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) {
+ if (is_path_invalid(p_path)) {
+#ifdef DEBUG_ENABLED
+ if (p_mode_flags != READ) {
+ WARN_PRINT("The path :" + p_path + " is a reserved Windows system pipe, so it can't be used for creating files.");
+ }
+#endif
+ return ERR_INVALID_PARAMETER;
+ }
+
_close();
path_src = p_path;
@@ -95,8 +114,8 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
// platforms).
if (p_mode_flags == READ) {
WIN32_FIND_DATAW d;
- HANDLE f = FindFirstFileW((LPCWSTR)(path.utf16().get_data()), &d);
- if (f != INVALID_HANDLE_VALUE) {
+ HANDLE fnd = FindFirstFileW((LPCWSTR)(path.utf16().get_data()), &d);
+ if (fnd != INVALID_HANDLE_VALUE) {
String fname = String::utf16((const char16_t *)(d.cFileName));
if (!fname.is_empty()) {
String base_file = path.get_file();
@@ -104,7 +123,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
WARN_PRINT("Case mismatch opening requested file '" + base_file + "', stored as '" + fname + "' in the filesystem. This file will not open when exported to other case-sensitive platforms.");
}
}
- FindClose(f);
+ FindClose(fnd);
}
}
#endif
@@ -313,6 +332,10 @@ void FileAccessWindows::store_buffer(const uint8_t *p_src, uint64_t p_length) {
}
bool FileAccessWindows::file_exists(const String &p_name) {
+ if (is_path_invalid(p_name)) {
+ return false;
+ }
+
String filename = fix_path(p_name);
FILE *g = _wfsopen((LPCWSTR)(filename.utf16().get_data()), L"rb", _SH_DENYNO);
if (g == nullptr) {
@@ -324,6 +347,10 @@ bool FileAccessWindows::file_exists(const String &p_name) {
}
uint64_t FileAccessWindows::_get_modified_time(const String &p_file) {
+ if (is_path_invalid(p_file)) {
+ return 0;
+ }
+
String file = fix_path(p_file);
if (file.ends_with("/") && file != "/") {
file = file.substr(0, file.length() - 1);
@@ -352,4 +379,20 @@ FileAccessWindows::~FileAccessWindows() {
_close();
}
+HashSet<String> FileAccessWindows::invalid_files;
+
+void FileAccessWindows::initialize() {
+ static const char *reserved_files[]{
+ "con", "prn", "aux", "nul", "com0", "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9", "lpt0", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", nullptr
+ };
+ int reserved_file_index = 0;
+ while (reserved_files[reserved_file_index] != nullptr) {
+ invalid_files.insert(reserved_files[reserved_file_index]);
+ reserved_file_index++;
+ }
+}
+void FileAccessWindows::finalize() {
+ invalid_files.clear();
+}
+
#endif // WINDOWS_ENABLED
diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h
index 8629bb936b..2b9960d494 100644
--- a/drivers/windows/file_access_windows.h
+++ b/drivers/windows/file_access_windows.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* file_access_windows.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* file_access_windows.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 FILE_ACCESS_WINDOWS_H
#define FILE_ACCESS_WINDOWS_H
@@ -50,8 +50,11 @@ class FileAccessWindows : public FileAccess {
void _close();
+ static bool is_path_invalid(const String &p_path);
+ static HashSet<String> invalid_files;
+
public:
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(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 override; /// returns the path for the current open file
@@ -79,6 +82,9 @@ public:
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;
+ static void initialize();
+ static void finalize();
+
FileAccessWindows() {}
virtual ~FileAccessWindows();
};
diff --git a/drivers/winmidi/midi_driver_winmidi.cpp b/drivers/winmidi/midi_driver_winmidi.cpp
index 64912dc3af..cdbab489c4 100644
--- a/drivers/winmidi/midi_driver_winmidi.cpp
+++ b/drivers/winmidi/midi_driver_winmidi.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* midi_driver_winmidi.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* midi_driver_winmidi.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 WINMIDI_ENABLED
diff --git a/drivers/winmidi/midi_driver_winmidi.h b/drivers/winmidi/midi_driver_winmidi.h
index e42f3df4cf..f3e016f378 100644
--- a/drivers/winmidi/midi_driver_winmidi.h
+++ b/drivers/winmidi/midi_driver_winmidi.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* midi_driver_winmidi.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* midi_driver_winmidi.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 MIDI_DRIVER_WINMIDI_H
#define MIDI_DRIVER_WINMIDI_H
diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp
index 6c48c1a844..cd1b29e17d 100644
--- a/drivers/xaudio2/audio_driver_xaudio2.cpp
+++ b/drivers/xaudio2/audio_driver_xaudio2.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* audio_driver_xaudio2.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* audio_driver_xaudio2.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#include "audio_driver_xaudio2.h"
diff --git a/drivers/xaudio2/audio_driver_xaudio2.h b/drivers/xaudio2/audio_driver_xaudio2.h
index 0f64d54a1f..df5ef52e88 100644
--- a/drivers/xaudio2/audio_driver_xaudio2.h
+++ b/drivers/xaudio2/audio_driver_xaudio2.h
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* audio_driver_xaudio2.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. */
-/*************************************************************************/
+/**************************************************************************/
+/* audio_driver_xaudio2.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#ifndef AUDIO_DRIVER_XAUDIO2_H
#define AUDIO_DRIVER_XAUDIO2_H