summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/alsa/audio_driver_alsa.cpp19
-rw-r--r--drivers/alsamidi/midi_driver_alsamidi.cpp4
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.cpp4
-rw-r--r--drivers/gl_context/SCsub6
-rw-r--r--drivers/gles3/effects/copy_effects.h2
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp7
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.h4
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp38
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp34
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h4
-rw-r--r--drivers/gles3/shader_gles3.cpp206
-rw-r--r--drivers/gles3/shader_gles3.h3
-rw-r--r--drivers/gles3/shaders/canvas.glsl2
-rw-r--r--drivers/gles3/shaders/particles.glsl153
-rw-r--r--drivers/gles3/shaders/particles_copy.glsl9
-rw-r--r--drivers/gles3/shaders/scene.glsl10
-rw-r--r--drivers/gles3/storage/light_storage.cpp1
-rw-r--r--drivers/gles3/storage/material_storage.cpp7
-rw-r--r--drivers/gles3/storage/material_storage.h10
-rw-r--r--drivers/gles3/storage/mesh_storage.h2
-rw-r--r--drivers/gles3/storage/particles_storage.cpp9
-rw-r--r--drivers/gles3/storage/particles_storage.h2
-rw-r--r--drivers/gles3/storage/texture_storage.cpp68
-rw-r--r--drivers/gles3/storage/texture_storage.h6
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp22
-rw-r--r--drivers/unix/file_access_unix.cpp12
-rw-r--r--drivers/unix/os_unix.cpp205
-rw-r--r--drivers/unix/os_unix.h2
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp180
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h4
-rw-r--r--drivers/vulkan/vulkan_context.cpp4
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp36
-rw-r--r--drivers/windows/dir_access_windows.cpp15
-rw-r--r--drivers/windows/dir_access_windows.h3
-rw-r--r--drivers/windows/file_access_windows.cpp8
-rw-r--r--drivers/windows/file_access_windows.h1
-rw-r--r--drivers/xaudio2/audio_driver_xaudio2.cpp7
37 files changed, 784 insertions, 325 deletions
diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp
index 689f76389b..966137920a 100644
--- a/drivers/alsa/audio_driver_alsa.cpp
+++ b/drivers/alsa/audio_driver_alsa.cpp
@@ -44,7 +44,8 @@ extern int initialize_pulse(int verbose);
#endif
Error AudioDriverALSA::init_output_device() {
- mix_rate = GLOBAL_GET("audio/driver/mix_rate");
+ mix_rate = _get_configured_mix_rate();
+
speaker_mode = SPEAKER_MODE_STEREO;
channels = 2;
@@ -169,6 +170,18 @@ Error AudioDriverALSA::init() {
return ERR_CANT_OPEN;
}
#endif
+ bool ver_ok = false;
+ String version = String::utf8(snd_asoundlib_version());
+ Vector<String> ver_parts = version.split(".");
+ if (ver_parts.size() >= 2) {
+ ver_ok = ((ver_parts[0].to_int() == 1 && ver_parts[1].to_int() >= 1)) || (ver_parts[0].to_int() > 1); // 1.1.0
+ }
+ print_verbose(vformat("ALSA %s detected.", version));
+ if (!ver_ok) {
+ print_verbose("Unsupported ALSA library version!");
+ return ERR_CANT_OPEN;
+ }
+
active.clear();
exit_thread.clear();
@@ -326,7 +339,9 @@ void AudioDriverALSA::finish_output_device() {
void AudioDriverALSA::finish() {
exit_thread.set();
- thread.wait_to_finish();
+ if (thread.is_started()) {
+ thread.wait_to_finish();
+ }
finish_output_device();
}
diff --git a/drivers/alsamidi/midi_driver_alsamidi.cpp b/drivers/alsamidi/midi_driver_alsamidi.cpp
index 81472fe70c..6b35987f70 100644
--- a/drivers/alsamidi/midi_driver_alsamidi.cpp
+++ b/drivers/alsamidi/midi_driver_alsamidi.cpp
@@ -207,7 +207,9 @@ Error MIDIDriverALSAMidi::open() {
void MIDIDriverALSAMidi::close() {
exit_thread.set();
- thread.wait_to_finish();
+ if (thread.is_started()) {
+ thread.wait_to_finish();
+ }
for (int i = 0; i < connected_inputs.size(); i++) {
snd_rawmidi_t *midi_in = connected_inputs[i].rawmidi_ptr;
diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp
index 2c959bb07b..4011727433 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.cpp
+++ b/drivers/coreaudio/audio_driver_coreaudio.cpp
@@ -116,7 +116,7 @@ Error AudioDriverCoreAudio::init() {
break;
}
- mix_rate = GLOBAL_GET("audio/driver/mix_rate");
+ mix_rate = _get_configured_mix_rate();
memset(&strdesc, 0, sizeof(strdesc));
strdesc.mFormatID = kAudioFormatLinearPCM;
@@ -405,7 +405,7 @@ Error AudioDriverCoreAudio::init_input_device() {
break;
}
- mix_rate = GLOBAL_GET("audio/driver/mix_rate");
+ mix_rate = _get_configured_mix_rate();
memset(&strdesc, 0, sizeof(strdesc));
strdesc.mFormatID = kAudioFormatLinearPCM;
diff --git a/drivers/gl_context/SCsub b/drivers/gl_context/SCsub
index 2204c486c6..91240ce3e3 100644
--- a/drivers/gl_context/SCsub
+++ b/drivers/gl_context/SCsub
@@ -10,7 +10,11 @@ if env["platform"] in ["haiku", "macos", "windows", "linuxbsd"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
- env.Prepend(CPPPATH=[thirdparty_dir])
+ # Treat glad headers as system headers to avoid raising warnings. Not supported on MSVC.
+ if not env.msvc:
+ env.Append(CPPFLAGS=["-isystem", Dir(thirdparty_dir).path])
+ else:
+ env.Prepend(CPPPATH=[thirdparty_dir])
env.Append(CPPDEFINES=["GLAD_ENABLED"])
env.Append(CPPDEFINES=["GLES_OVER_GL"])
diff --git a/drivers/gles3/effects/copy_effects.h b/drivers/gles3/effects/copy_effects.h
index 38f79b96a6..105fbcfe98 100644
--- a/drivers/gles3/effects/copy_effects.h
+++ b/drivers/gles3/effects/copy_effects.h
@@ -33,7 +33,7 @@
#ifdef GLES3_ENABLED
-#include "../shaders/copy.glsl.gen.h"
+#include "drivers/gles3/shaders/copy.glsl.gen.h"
namespace GLES3 {
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 522685bf87..19f2cfd47d 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -1310,6 +1310,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
uint32_t instance_color_offset = 0;
bool instance_uses_color = false;
bool instance_uses_custom_data = false;
+ bool use_instancing = 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);
@@ -1336,6 +1337,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
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);
+ use_instancing = true;
} 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);
@@ -1362,6 +1364,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
instance_color_offset = 8; // 8 bytes for instance transform.
instance_uses_color = true;
instance_uses_custom_data = true;
+ use_instancing = true;
}
ERR_FAIL_COND(mesh.is_null());
@@ -1397,7 +1400,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
use_index_buffer = true;
}
- if (instance_count > 1) {
+ if (use_instancing) {
if (instance_buffer == 0) {
break;
}
@@ -1426,7 +1429,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- if (instance_count > 1) {
+ if (use_instancing) {
glDisableVertexAttribArray(5);
glDisableVertexAttribArray(6);
glDisableVertexAttribArray(7);
diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h
index 1c14d0b466..2eac5f57e1 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.h
+++ b/drivers/gles3/rasterizer_canvas_gles3.h
@@ -39,8 +39,8 @@
#include "storage/material_storage.h"
#include "storage/texture_storage.h"
-#include "shaders/canvas.glsl.gen.h"
-#include "shaders/canvas_occlusion.glsl.gen.h"
+#include "drivers/gles3/shaders/canvas.glsl.gen.h"
+#include "drivers/gles3/shaders/canvas_occlusion.glsl.gen.h"
class RasterizerSceneGLES3;
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 7cbce428cb..6748e93383 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -34,6 +34,7 @@
#ifdef GLES3_ENABLED
#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
#include "core/os/os.h"
#include "storage/texture_storage.h"
@@ -257,6 +258,36 @@ RasterizerGLES3::RasterizerGLES3() {
#endif // GLES_OVER_GL
#endif // CAN_DEBUG
+ {
+ String shader_cache_dir = Engine::get_singleton()->get_shader_cache_path();
+ if (shader_cache_dir.is_empty()) {
+ shader_cache_dir = "user://";
+ }
+ Ref<DirAccess> da = DirAccess::open(shader_cache_dir);
+ if (da.is_null()) {
+ ERR_PRINT("Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir);
+ } else {
+ Error err = da->change_dir("shader_cache");
+ if (err != OK) {
+ err = da->make_dir("shader_cache");
+ }
+ if (err != OK) {
+ ERR_PRINT("Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir);
+ } else {
+ shader_cache_dir = shader_cache_dir.path_join("shader_cache");
+
+ bool shader_cache_enabled = GLOBAL_GET("rendering/shader_compiler/shader_cache/enabled");
+ if (!Engine::get_singleton()->is_editor_hint() && !shader_cache_enabled) {
+ shader_cache_dir = String(); //disable only if not editor
+ }
+
+ if (!shader_cache_dir.is_empty()) {
+ ShaderGLES3::set_shader_cache_dir(shader_cache_dir);
+ }
+ }
+ }
+ }
+
// OpenGL needs to be initialized before initializing the Rasterizers
config = memnew(GLES3::Config);
utilities = memnew(GLES3::Utilities);
@@ -300,12 +331,13 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
}
GLuint read_fbo = 0;
+ glGenFramebuffers(1, &read_fbo);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, read_fbo);
+
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);
+ glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
}
glReadBuffer(GL_COLOR_ATTACHMENT0);
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 9a4deefdc8..3d8f7924a7 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1948,7 +1948,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE);
scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
- scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_OPAQUE;
+ scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_ALWAYS;
if (!fb_cleared) {
glClearDepth(1.0f);
@@ -1976,24 +1976,44 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
_render_list_template<PASS_MODE_COLOR>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_OPAQUE].elements.size());
+ glDepthMask(GL_FALSE);
+ scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_DISABLED;
+
if (draw_sky) {
RENDER_TIMESTAMP("Render Sky");
- if (scene_state.current_depth_test != GLES3::SceneShaderData::DEPTH_TEST_ENABLED) {
- glEnable(GL_DEPTH_TEST);
- scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
- }
+
glEnable(GL_DEPTH_TEST);
- glDepthMask(GL_FALSE);
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
- scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_DISABLED;
scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
_draw_sky(render_data.environment, render_data.cam_projection, render_data.cam_transform, sky_energy_multiplier, p_camera_data->view_count > 1, flip_y);
}
+ if (scene_state.used_screen_texture || scene_state.used_depth_texture) {
+ texture_storage->copy_scene_to_backbuffer(rt, scene_state.used_screen_texture, scene_state.used_depth_texture);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo);
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, rt->backbuffer_fbo);
+ if (scene_state.used_screen_texture) {
+ glBlitFramebuffer(0, 0, rt->size.x, rt->size.y,
+ 0, 0, rt->size.x, rt->size.y,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 5);
+ glBindTexture(GL_TEXTURE_2D, rt->backbuffer);
+ }
+ if (scene_state.used_depth_texture) {
+ glBlitFramebuffer(0, 0, rt->size.x, rt->size.y,
+ 0, 0, rt->size.x, rt->size.y,
+ GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 6);
+ glBindTexture(GL_TEXTURE_2D, rt->backbuffer_depth);
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
+ }
+
RENDER_TIMESTAMP("Render 3D Transparent Pass");
glEnable(GL_BLEND);
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index ff043d67f6..b4e787ad85 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -37,13 +37,13 @@
#include "core/templates/paged_allocator.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
+#include "drivers/gles3/shaders/cubemap_filter.glsl.gen.h"
+#include "drivers/gles3/shaders/sky.glsl.gen.h"
#include "scene/resources/mesh.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
#include "shader_gles3.h"
-#include "shaders/cubemap_filter.glsl.gen.h"
-#include "shaders/sky.glsl.gen.h"
#include "storage/light_storage.h"
#include "storage/material_storage.h"
#include "storage/render_scene_buffers_gles3.h"
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index 10f42bf22b..ded5793e8f 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/drivers/gles3/shader_gles3.cpp
@@ -242,6 +242,41 @@ static void _display_error_with_code(const String &p_error, const String &p_code
ERR_PRINT(p_error);
}
+void ShaderGLES3::_get_uniform_locations(Version::Specialization &spec, Version *p_version) {
+ glUseProgram(spec.id);
+
+ spec.uniform_location.resize(uniform_count);
+ for (int i = 0; i < uniform_count; i++) {
+ spec.uniform_location[i] = glGetUniformLocation(spec.id, uniform_names[i]);
+ }
+
+ for (int i = 0; i < texunit_pair_count; i++) {
+ GLint loc = glGetUniformLocation(spec.id, texunit_pairs[i].name);
+ if (loc >= 0) {
+ if (texunit_pairs[i].index < 0) {
+ glUniform1i(loc, max_image_units + texunit_pairs[i].index);
+ } else {
+ glUniform1i(loc, texunit_pairs[i].index);
+ }
+ }
+ }
+
+ for (int i = 0; i < ubo_count; i++) {
+ GLint loc = glGetUniformBlockIndex(spec.id, ubo_pairs[i].name);
+ if (loc >= 0) {
+ glUniformBlockBinding(spec.id, loc, ubo_pairs[i].index);
+ }
+ }
+ // textures
+ for (int i = 0; i < p_version->texture_uniforms.size(); 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);
+ }
+
+ glUseProgram(0);
+}
+
void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_t p_variant, Version *p_version, uint64_t p_specialization) {
spec.id = glCreateProgram();
spec.ok = false;
@@ -402,40 +437,8 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_
ERR_FAIL();
}
- // get uniform locations
-
- glUseProgram(spec.id);
-
- spec.uniform_location.resize(uniform_count);
- for (int i = 0; i < uniform_count; i++) {
- spec.uniform_location[i] = glGetUniformLocation(spec.id, uniform_names[i]);
- }
-
- for (int i = 0; i < texunit_pair_count; i++) {
- GLint loc = glGetUniformLocation(spec.id, texunit_pairs[i].name);
- if (loc >= 0) {
- if (texunit_pairs[i].index < 0) {
- glUniform1i(loc, max_image_units + texunit_pairs[i].index);
- } else {
- glUniform1i(loc, texunit_pairs[i].index);
- }
- }
- }
-
- for (int i = 0; i < ubo_count; i++) {
- GLint loc = glGetUniformBlockIndex(spec.id, ubo_pairs[i].name);
- if (loc >= 0) {
- glUniformBlockBinding(spec.id, loc, ubo_pairs[i].index);
- }
- }
- // textures
- for (int i = 0; i < p_version->texture_uniforms.size(); 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);
- }
+ _get_uniform_locations(spec, p_version);
- glUseProgram(0);
spec.ok = true;
}
@@ -504,11 +507,20 @@ String ShaderGLES3::_version_get_sha1(Version *p_version) const {
return hash_build.as_string().sha1_text();
}
-//static const char *shader_file_header = "GLSC";
-//static const uint32_t cache_file_version = 2;
+#ifndef WEB_ENABLED // not supported in webgl
+static const char *shader_file_header = "GLSC";
+static const uint32_t cache_file_version = 3;
+#endif
bool ShaderGLES3::_load_from_cache(Version *p_version) {
-#if 0
+#ifdef WEB_ENABLED // not supported in webgl
+ return false;
+#else
+#ifdef GLES_OVER_GL
+ if (glProgramBinary == NULL) { // ARB_get_program_binary extension not available
+ return false;
+ }
+#endif
String sha1 = _version_get_sha1(p_version);
String path = shader_cache_dir.path_join(name).path_join(base_sha256).path_join(sha1) + ".cache";
@@ -517,7 +529,7 @@ bool ShaderGLES3::_load_from_cache(Version *p_version) {
return false;
}
- char header[5] = { 0, 0, 0, 0, 0 };
+ char header[5] = {};
f->get_buffer((uint8_t *)header, 4);
ERR_FAIL_COND_V(header != String(shader_file_header), false);
@@ -526,70 +538,98 @@ bool ShaderGLES3::_load_from_cache(Version *p_version) {
return false; // wrong version
}
- uint32_t variant_count = f->get_32();
+ int cache_variant_count = static_cast<int>(f->get_32());
+ ERR_FAIL_COND_V_MSG(cache_variant_count != this->variant_count, false, "shader cache variant count mismatch, expected " + itos(this->variant_count) + " got " + itos(cache_variant_count)); //should not happen but check
+
+ LocalVector<OAHashMap<uint64_t, Version::Specialization>> variants;
+ for (int i = 0; i < cache_variant_count; i++) {
+ uint32_t cache_specialization_count = f->get_32();
+ OAHashMap<uint64_t, Version::Specialization> variant;
+ for (uint32_t j = 0; j < cache_specialization_count; j++) {
+ uint64_t specialization_key = f->get_64();
+ uint32_t variant_size = f->get_32();
+ if (variant_size == 0) {
+ continue;
+ }
+ uint32_t variant_format = f->get_32();
+ Vector<uint8_t> variant_bytes;
+ variant_bytes.resize(variant_size);
+
+ uint32_t br = f->get_buffer(variant_bytes.ptrw(), variant_size);
- ERR_FAIL_COND_V(variant_count != (uint32_t)variant_count, false); //should not happen but check
+ ERR_FAIL_COND_V(br != variant_size, false);
- for (uint32_t i = 0; i < variant_count; i++) {
- uint32_t variant_size = f->get_32();
- ERR_FAIL_COND_V(variant_size == 0 && variants_enabled[i], false);
- if (!variants_enabled[i]) {
- continue;
- }
- Vector<uint8_t> variant_bytes;
- variant_bytes.resize(variant_size);
+ Version::Specialization specialization;
- uint32_t br = f->get_buffer(variant_bytes.ptrw(), variant_size);
+ specialization.id = glCreateProgram();
+ glProgramBinary(specialization.id, variant_format, variant_bytes.ptr(), variant_bytes.size());
- ERR_FAIL_COND_V(br != variant_size, false);
+ _get_uniform_locations(specialization, p_version);
- p_version->variant_data[i] = variant_bytes;
- }
+ specialization.ok = true;
- for (uint32_t i = 0; i < variant_count; i++) {
- if (!variants_enabled[i]) {
- MutexLock lock(variant_set_mutex);
- p_version->variants[i] = RID();
- continue;
- }
- RID shader = GLES3::get_singleton()->shader_create_from_bytecode(p_version->variant_data[i]);
- if (shader.is_null()) {
- for (uint32_t j = 0; j < i; j++) {
- GLES3::get_singleton()->free(p_version->variants[i]);
- }
- ERR_FAIL_COND_V(shader.is_null(), false);
- }
- {
- MutexLock lock(variant_set_mutex);
- p_version->variants[i] = shader;
+ variant.insert(specialization_key, specialization);
}
+ variants.push_back(variant);
}
+ p_version->variants = variants;
- memdelete_arr(p_version->variant_data); //clear stages
- p_version->variant_data = nullptr;
- p_version->valid = true;
return true;
-#endif
- return false;
+#endif // WEB_ENABLED
}
void ShaderGLES3::_save_to_cache(Version *p_version) {
-#if 0
+#ifdef WEB_ENABLED // not supported in webgl
+ return;
+#else
+#ifdef GLES_OVER_GL
+ if (glGetProgramBinary == NULL) { // ARB_get_program_binary extension not available
+ return;
+ }
+#endif
String sha1 = _version_get_sha1(p_version);
String path = shader_cache_dir.path_join(name).path_join(base_sha256).path_join(sha1) + ".cache";
- Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE);
+ Error error;
+ Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE, &error);
ERR_FAIL_COND(f.is_null());
f->store_buffer((const uint8_t *)shader_file_header, 4);
- f->store_32(cache_file_version); //file version
- uint32_t variant_count = variant_count;
- f->store_32(variant_count); //variant count
+ f->store_32(cache_file_version);
+ f->store_32(variant_count);
+
+ for (int i = 0; i < variant_count; i++) {
+ int cache_specialization_count = p_version->variants[i].get_num_elements();
+ f->store_32(cache_specialization_count);
+
+ for (OAHashMap<uint64_t, ShaderGLES3::Version::Specialization>::Iterator it = p_version->variants[i].iter(); it.valid; it = p_version->variants[i].next_iter(it)) {
+ const uint64_t specialization_key = *it.key;
+ f->store_64(specialization_key);
- for (uint32_t i = 0; i < variant_count; i++) {
- f->store_32(p_version->variant_data[i].size()); //stage count
- f->store_buffer(p_version->variant_data[i].ptr(), p_version->variant_data[i].size());
+ const Version::Specialization *specialization = it.value;
+ if (specialization == nullptr) {
+ f->store_32(0);
+ continue;
+ }
+ GLint program_size = 0;
+ glGetProgramiv(specialization->id, GL_PROGRAM_BINARY_LENGTH, &program_size);
+ if (program_size == 0) {
+ f->store_32(0);
+ continue;
+ }
+ PackedByteArray compiled_program;
+ compiled_program.resize(program_size);
+ GLenum binary_format = 0;
+ glGetProgramBinary(specialization->id, program_size, nullptr, &binary_format, compiled_program.ptrw());
+ if (program_size != compiled_program.size()) {
+ f->store_32(0);
+ continue;
+ }
+ f->store_32(program_size);
+ f->store_32(binary_format);
+ f->store_buffer(compiled_program.ptr(), compiled_program.size());
+ }
}
-#endif
+#endif // WEB_ENABLED
}
void ShaderGLES3::_clear_version(Version *p_version) {
@@ -613,6 +653,9 @@ void ShaderGLES3::_clear_version(Version *p_version) {
void ShaderGLES3::_initialize_version(Version *p_version) {
ERR_FAIL_COND(p_version->variants.size() > 0);
+ if (_load_from_cache(p_version)) {
+ return;
+ }
p_version->variants.reserve(variant_count);
for (int i = 0; i < variant_count; i++) {
OAHashMap<uint64_t, Version::Specialization> variant;
@@ -621,6 +664,7 @@ void ShaderGLES3::_initialize_version(Version *p_version) {
_compile_specialization(spec, i, p_version, specialization_default_mask);
p_version->variants[i].insert(specialization_default_mask, spec);
}
+ _save_to_cache(p_version);
}
void ShaderGLES3::version_set_code(RID p_version, const HashMap<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines, const Vector<StringName> &p_texture_uniforms, bool p_initialize) {
diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h
index 0b2ecbaca6..565434bb36 100644
--- a/drivers/gles3/shader_gles3.h
+++ b/drivers/gles3/shader_gles3.h
@@ -98,7 +98,6 @@ private:
GLuint frag_id;
LocalVector<GLint> uniform_location;
LocalVector<GLint> texture_uniform_locations;
- HashMap<StringName, GLint> custom_uniform_locations;
bool build_queued = false;
bool ok = false;
Specialization() {
@@ -113,6 +112,7 @@ private:
Mutex variant_set_mutex;
+ void _get_uniform_locations(Version::Specialization &spec, Version *p_version);
void _compile_specialization(Version::Specialization &spec, uint32_t p_variant, Version *p_version, uint64_t p_specialization);
void _clear_version(Version *p_version);
@@ -209,6 +209,7 @@ protected:
_compile_specialization(s, p_variant, version, p_specialization);
version->variants[p_variant].insert(p_specialization, s);
spec = version->variants[p_variant].lookup_ptr(p_specialization);
+ _save_to_cache(version);
}
} else if (spec->build_queued) {
// Still queued, wait
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index ea0a0b660d..ae3892fb61 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -589,7 +589,7 @@ void main() {
if (bool(read_draw_data_flags & FLAGS_FLIP_V)) {
normal.y = -normal.y;
}
- normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
+ normal.z = sqrt(max(0.0, 1.0 - dot(normal.xy, normal.xy)));
normal_used = true;
} else {
normal = vec3(0.0, 0.0, 1.0);
diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl
index f8741a22ab..40881a1808 100644
--- a/drivers/gles3/shaders/particles.glsl
+++ b/drivers/gles3/shaders/particles.glsl
@@ -300,28 +300,23 @@ void main() {
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;
+ if (attractors[i].type == 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);
+ } else if (attractors[i].type == 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);
+ } else if (attractors[i].type == ATTRACTOR_TYPE_VECTOR_FIELD) {
}
amount = pow(amount, attractors[i].attenuation);
dir = safe_normalize(mix(dir, attractors[i].transform[2].xyz, attractors[i].directionality));
@@ -383,80 +378,72 @@ void main() {
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 (colliders[i].type == 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);
- }
+ if (d < 0.0) {
+ col = true;
+ depth = -d;
+ normal = normalize(rel_vec);
+ }
+ } else if (colliders[i].type == COLLIDER_TYPE_BOX) {
+ vec3 abs_pos = abs(local_pos);
+ vec3 sgn_pos = sign(local_pos);
- } 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);
- }
+ 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;
- depth = dot(normal * axis_len, vec3(1)) + particle_size;
- normal = mat3(colliders[i].transform) * (normal * sgn_pos);
+ normal = mat3(colliders[i].transform) * (normalize(rel) * sgn_pos);
+ depth = -depth;
}
-
- } 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;
+ } 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);
}
- const float DELTA = 1.0 / 8192.0;
- vec3 uvw_pos = vec3(local_pos_bottom / colliders[i].extents.xyz) * 0.5 + 0.5;
+ col = true;
+ depth = dot(normal * axis_len, vec3(1)) + particle_size;
+ normal = mat3(colliders[i].transform) * (normal * sgn_pos);
+ }
+ } else if (colliders[i].type == COLLIDER_TYPE_SDF) {
+ } else if (colliders[i].type == COLLIDER_TYPE_HEIGHT_FIELD) {
+ vec3 local_pos_bottom = local_pos;
+ local_pos_bottom.y -= particle_size;
- float y = 1.0 - texture(height_field_texture, uvw_pos.xz).r;
+ if (any(greaterThan(abs(local_pos_bottom), colliders[i].extents.xyz))) {
+ continue;
+ }
+ const float DELTA = 1.0 / 8192.0;
- if (y > uvw_pos.y) {
- //inside heightfield
+ vec3 uvw_pos = vec3(local_pos_bottom / colliders[i].extents.xyz) * 0.5 + 0.5;
- 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;
+ float y = 1.0 - texture(height_field_texture, uvw_pos.xz).r;
- normal = normalize(cross(pos1 - pos2, pos1 - pos3));
- float local_y = (vec3(local_pos / colliders[i].extents.xyz) * 0.5 + 0.5).y;
+ if (y > uvw_pos.y) {
+ //inside heightfield
- col = true;
- depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
- }
+ 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;
- } break;
+ 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);
+ }
}
if (col) {
diff --git a/drivers/gles3/shaders/particles_copy.glsl b/drivers/gles3/shaders/particles_copy.glsl
index f273cb7b64..774aa139b3 100644
--- a/drivers/gles3/shaders/particles_copy.glsl
+++ b/drivers/gles3/shaders/particles_copy.glsl
@@ -44,8 +44,12 @@ uniform highp mat4 inv_emission_transform;
#define PARTICLE_FLAG_ACTIVE uint(1)
+#define FLT_MAX float(3.402823466e+38)
+
void main() {
- mat4 txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); // zero scale, becomes invisible.
+ // Set scale to zero and translate to -INF so particle will be invisible
+ // even for materials that ignore rotation/scale (i.e. billboards).
+ mat4 txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(-FLT_MAX, -FLT_MAX, -FLT_MAX, 0.0));
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)));
@@ -102,9 +106,8 @@ void main() {
// as they will be drawn with the node position as origin.
txform = inv_emission_transform * txform;
#endif
-
- txform = transpose(txform);
}
+ 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];
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 0b389b0478..37976bb9a0 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -624,7 +624,7 @@ float SchlickFresnel(float u) {
return m2 * m2 * m; // pow(m,5)
}
-void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float attenuation, vec3 f0, float roughness, float metallic, float specular_amount, vec3 albedo, inout float alpha,
+void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_directional, float attenuation, vec3 f0, float roughness, float metallic, float specular_amount, vec3 albedo, inout float alpha,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
@@ -771,7 +771,7 @@ 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 // LIGHT_CODE_USED
+#endif // USE_LIGHT_SHADER_CODE
}
float get_omni_spot_attenuation(float distance, float inv_range, float decay) {
@@ -809,7 +809,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
size_A = max(0.0, 1.0 - 1.0 / sqrt(1.0 + t * t));
}
- light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, omni_attenuation, f0, roughness, metallic, omni_lights[idx].specular_amount, albedo, alpha,
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, omni_attenuation, f0, roughness, metallic, omni_lights[idx].specular_amount, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -860,7 +860,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
size_A = max(0.0, 1.0 - 1.0 / sqrt(1.0 + t * t));
}
- light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, spot_attenuation, f0, roughness, metallic, spot_lights[idx].specular_amount, albedo, alpha,
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, spot_attenuation, f0, roughness, metallic, spot_lights[idx].specular_amount, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -1189,7 +1189,7 @@ void main() {
#ifndef DISABLE_LIGHT_DIRECTIONAL
//diffuse_light = normal; //
for (uint i = uint(0); i < scene_data.directional_light_count; i++) {
- light_compute(normal, normalize(directional_lights[i].direction), normalize(view), directional_lights[i].size, directional_lights[i].color * directional_lights[i].energy, 1.0, f0, roughness, metallic, 1.0, albedo, alpha,
+ light_compute(normal, normalize(directional_lights[i].direction), normalize(view), directional_lights[i].size, directional_lights[i].color * directional_lights[i].energy, true, 1.0, f0, roughness, metallic, 1.0, albedo, alpha,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp
index 026f7467a8..8da5e657cd 100644
--- a/drivers/gles3/storage/light_storage.cpp
+++ b/drivers/gles3/storage/light_storage.cpp
@@ -76,6 +76,7 @@ void LightStorage::_light_initialize(RID p_light, RS::LightType p_type) {
light.param[RS::LIGHT_PARAM_SHADOW_BLUR] = 0;
light.param[RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE] = 20.0;
light.param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] = 0.05;
+ light.param[RS::LIGHT_PARAM_INTENSITY] = p_type == RS::LIGHT_DIRECTIONAL ? 100000.0 : 1000.0;
light_owner.initialize_rid(p_light, light);
}
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index fc6c2f3a26..c7b2a715be 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -1489,7 +1489,7 @@ MaterialStorage::MaterialStorage() {
global_shader_uniforms.buffer_size = MAX(4096, (int)GLOBAL_GET("rendering/limits/global_shader_variables/buffer_size"));
if (global_shader_uniforms.buffer_size > uint32_t(Config::get_singleton()->max_uniform_buffer_size)) {
global_shader_uniforms.buffer_size = uint32_t(Config::get_singleton()->max_uniform_buffer_size);
- WARN_PRINT("Project setting: rendering/limits/global_shader_variables/buffer_size exceeds maximum uniform buffer size of: " + itos(Config::get_singleton()->max_uniform_buffer_size));
+ WARN_PRINT("Project setting \"rendering/limits/global_shader_variables/buffer_size\" exceeds maximum uniform buffer size of: " + itos(Config::get_singleton()->max_uniform_buffer_size));
}
global_shader_uniforms.buffer_values = memnew_arr(GlobalShaderUniforms::Value, global_shader_uniforms.buffer_size);
@@ -1603,6 +1603,7 @@ MaterialStorage::MaterialStorage() {
//builtins
actions.renames["TIME"] = "scene_data.time";
+ actions.renames["EXPOSURE"] = "(1.0 / scene_data.emissive_exposure_normalization)";
actions.renames["PI"] = _MKSTR(Math_PI);
actions.renames["TAU"] = _MKSTR(Math_TAU);
actions.renames["E"] = _MKSTR(Math_E);
@@ -1650,7 +1651,7 @@ MaterialStorage::MaterialStorage() {
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["NODE_POSITION_VIEW"] = "(scene_data.view_matrix * model_matrix)[3].xyz";
actions.renames["VIEW_INDEX"] = "ViewIndex";
actions.renames["VIEW_MONO_LEFT"] = "uint(0)";
@@ -1659,7 +1660,9 @@ MaterialStorage::MaterialStorage() {
//for light
actions.renames["VIEW"] = "view";
+ actions.renames["SPECULAR_AMOUNT"] = "specular_amount";
actions.renames["LIGHT_COLOR"] = "light_color";
+ actions.renames["LIGHT_IS_DIRECTIONAL"] = "is_directional";
actions.renames["LIGHT"] = "light";
actions.renames["ATTENUATION"] = "attenuation";
actions.renames["DIFFUSE_LIGHT"] = "diffuse_light";
diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h
index 4c5861b017..92399127bb 100644
--- a/drivers/gles3/storage/material_storage.h
+++ b/drivers/gles3/storage/material_storage.h
@@ -42,11 +42,11 @@
#include "servers/rendering/storage/material_storage.h"
#include "servers/rendering/storage/utilities.h"
-#include "../shaders/canvas.glsl.gen.h"
-#include "../shaders/cubemap_filter.glsl.gen.h"
-#include "../shaders/particles.glsl.gen.h"
-#include "../shaders/scene.glsl.gen.h"
-#include "../shaders/sky.glsl.gen.h"
+#include "drivers/gles3/shaders/canvas.glsl.gen.h"
+#include "drivers/gles3/shaders/cubemap_filter.glsl.gen.h"
+#include "drivers/gles3/shaders/particles.glsl.gen.h"
+#include "drivers/gles3/shaders/scene.glsl.gen.h"
+#include "drivers/gles3/shaders/sky.glsl.gen.h"
namespace GLES3 {
diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h
index e1c2bc3f63..f9122771f9 100644
--- a/drivers/gles3/storage/mesh_storage.h
+++ b/drivers/gles3/storage/mesh_storage.h
@@ -33,10 +33,10 @@
#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"
+#include "drivers/gles3/shaders/skeleton.glsl.gen.h"
#include "servers/rendering/storage/mesh_storage.h"
#include "servers/rendering/storage/utilities.h"
diff --git a/drivers/gles3/storage/particles_storage.cpp b/drivers/gles3/storage/particles_storage.cpp
index 2b47271408..4b64e2aec1 100644
--- a/drivers/gles3/storage/particles_storage.cpp
+++ b/drivers/gles3/storage/particles_storage.cpp
@@ -919,7 +919,7 @@ void ParticlesStorage::_particles_update_instance_buffer(Particles *particles, c
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 lifetime_split = (MIN(int(particles->amount * particles->phase), particles->amount - 1) + 1) % particles->amount;
uint32_t stride = particles->process_buffer_stride_cache;
glBindBuffer(GL_ARRAY_BUFFER, particles->back_process_buffer);
@@ -1135,14 +1135,13 @@ void ParticlesStorage::_particles_reverse_lifetime_sort(Particles *particles) {
glGetBufferSubData(GL_ARRAY_BUFFER, 0, buffer_size, particle_array);
#endif
- uint32_t lifetime_split = MIN(particles->amount * particles->sort_buffer_phase, particles->amount - 1);
-
+ uint32_t lifetime_split = (MIN(int(particles->amount * particles->sort_buffer_phase), particles->amount - 1) + 1) % particles->amount;
for (uint32_t i = 0; i < lifetime_split / 2; i++) {
- SWAP(particle_array[i], particle_array[lifetime_split - i]);
+ SWAP(particle_array[i], particle_array[lifetime_split - i - 1]);
}
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]);
+ SWAP(particle_array[lifetime_split + i], particle_array[particles->amount - 1 - i]);
}
#ifndef __EMSCRIPTEN__
diff --git a/drivers/gles3/storage/particles_storage.h b/drivers/gles3/storage/particles_storage.h
index b220c48de9..0e84c2ca8f 100644
--- a/drivers/gles3/storage/particles_storage.h
+++ b/drivers/gles3/storage/particles_storage.h
@@ -33,10 +33,10 @@
#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 "drivers/gles3/shaders/particles_copy.glsl.gen.h"
#include "servers/rendering/storage/particles_storage.h"
#include "servers/rendering/storage/utilities.h"
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index b4dea0dfe2..3fd54e9180 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -1140,6 +1140,13 @@ RID TextureStorage::texture_get_rd_texture(RID p_texture, bool p_srgb) const {
return RID();
}
+uint64_t TextureStorage::texture_get_native_handle(RID p_texture, bool p_srgb) const {
+ const Texture *texture = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND_V(!texture, 0);
+
+ return texture->tex_id;
+}
+
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);
@@ -1782,7 +1789,64 @@ void TextureStorage::_create_render_target_backbuffer(RenderTarget *rt) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
}
+void GLES3::TextureStorage::copy_scene_to_backbuffer(RenderTarget *rt, const bool uses_screen_texture, const bool uses_depth_texture) {
+ if (rt->backbuffer != 0 && rt->backbuffer_depth != 0) {
+ return;
+ }
+
+ Config *config = Config::get_singleton();
+ bool use_multiview = rt->view_count > 1 && config->multiview_supported;
+ GLenum texture_target = use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
+ if (rt->backbuffer_fbo == 0) {
+ glGenFramebuffers(1, &rt->backbuffer_fbo);
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->backbuffer_fbo);
+ if (rt->backbuffer == 0 && uses_screen_texture) {
+ glGenTextures(1, &rt->backbuffer);
+ glBindTexture(texture_target, rt->backbuffer);
+ 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);
+ }
+ 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->backbuffer, 0, 0, rt->view_count);
+ } else {
+#else
+ {
+#endif
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->backbuffer, 0);
+ }
+ }
+ if (rt->backbuffer_depth == 0 && uses_depth_texture) {
+ glGenTextures(1, &rt->backbuffer_depth);
+ glBindTexture(texture_target, rt->backbuffer_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->backbuffer_depth, 0, 0, rt->view_count);
+ } else {
+#else
+ {
+#endif
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->backbuffer_depth, 0);
+ }
+ }
+}
void TextureStorage::_clear_render_target(RenderTarget *rt) {
// there is nothing to clear when DIRECT_TO_SCREEN is used
if (rt->direct_to_screen) {
@@ -1848,6 +1912,10 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
rt->backbuffer = 0;
rt->backbuffer_fbo = 0;
}
+ if (rt->backbuffer_depth != 0) {
+ glDeleteTextures(1, &rt->backbuffer_depth);
+ rt->backbuffer_depth = 0;
+ }
_render_target_clear_sdf(rt);
}
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index c702904648..c6bdd39dbd 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -39,7 +39,7 @@
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/storage/texture_storage.h"
-#include "../shaders/canvas_sdf.glsl.gen.h"
+#include "drivers/gles3/shaders/canvas_sdf.glsl.gen.h"
// This must come first to avoid windows.h mess
#include "platform_config.h"
@@ -345,6 +345,7 @@ struct RenderTarget {
GLuint depth = 0;
GLuint backbuffer_fbo = 0;
GLuint backbuffer = 0;
+ GLuint backbuffer_depth = 0;
GLuint color_internal_format = GL_RGBA8;
GLuint color_format = GL_RGBA;
@@ -536,6 +537,7 @@ public:
virtual Size2 texture_size_with_proxy(RID p_proxy) override;
virtual RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) const override;
+ virtual uint64_t texture_get_native_handle(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);
@@ -604,6 +606,8 @@ public:
RenderTarget *get_render_target(RID p_rid) { return render_target_owner.get_or_null(p_rid); };
bool owns_render_target(RID p_rid) { return render_target_owner.owns(p_rid); };
+ void copy_scene_to_backbuffer(RenderTarget *rt, const bool uses_screen_texture, const bool uses_depth_texture);
+
virtual RID render_target_create() override;
virtual void render_target_free(RID p_rid) override;
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index 797ffd67fe..ab94d8911f 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -222,8 +222,8 @@ Error AudioDriverPulseAudio::init_output_device() {
break;
}
- int latency = GLOBAL_GET("audio/driver/output_latency");
- buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
+ int tmp_latency = GLOBAL_GET("audio/driver/output_latency");
+ buffer_frames = closest_power_of_2(tmp_latency * mix_rate / 1000);
pa_buffer_size = buffer_frames * pa_map.channels;
print_verbose("PulseAudio: detected " + itos(pa_map.channels) + " output channels");
@@ -290,10 +290,22 @@ Error AudioDriverPulseAudio::init() {
return ERR_CANT_OPEN;
}
#endif
+ bool ver_ok = false;
+ String version = String::utf8(pa_get_library_version());
+ Vector<String> ver_parts = version.split(".");
+ if (ver_parts.size() >= 2) {
+ ver_ok = (ver_parts[0].to_int() >= 8); // 8.0.0
+ }
+ print_verbose(vformat("PulseAudio %s detected.", version));
+ if (!ver_ok) {
+ print_verbose("Unsupported PulseAudio library version!");
+ return ERR_CANT_OPEN;
+ }
+
active.clear();
exit_thread.clear();
- mix_rate = GLOBAL_GET("audio/driver/mix_rate");
+ mix_rate = _get_configured_mix_rate();
pa_ml = pa_mainloop_new();
ERR_FAIL_COND_V(pa_ml == nullptr, ERR_CANT_OPEN);
@@ -664,7 +676,9 @@ void AudioDriverPulseAudio::finish() {
}
exit_thread.set();
- thread.wait_to_finish();
+ if (thread.is_started()) {
+ thread.wait_to_finish();
+ }
finish_output_device();
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index 3c2f36c7c0..e9affe41af 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -301,11 +301,11 @@ bool FileAccessUnix::file_exists(const String &p_path) {
uint64_t FileAccessUnix::_get_modified_time(const String &p_file) {
String file = fix_path(p_file);
- struct stat flags = {};
- int err = stat(file.utf8().get_data(), &flags);
+ struct stat status = {};
+ int err = stat(file.utf8().get_data(), &status);
if (!err) {
- return flags.st_mtime;
+ return status.st_mtime;
} else {
print_verbose("Failed to get modified time for: " + p_file + "");
return 0;
@@ -314,11 +314,11 @@ uint64_t FileAccessUnix::_get_modified_time(const String &p_file) {
uint32_t FileAccessUnix::_get_unix_permissions(const String &p_file) {
String file = fix_path(p_file);
- struct stat flags = {};
- int err = stat(file.utf8().get_data(), &flags);
+ struct stat status = {};
+ int err = stat(file.utf8().get_data(), &status);
if (!err) {
- return flags.st_mode & 0x7FF; //only permissions
+ return status.st_mode & 0x7FF; //only permissions
} else {
ERR_FAIL_V_MSG(0, "Failed to get unix permissions for: " + p_file + ".");
}
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index 178f01b185..967699c5f3 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -41,9 +41,12 @@
#include "drivers/unix/thread_posix.h"
#include "servers/rendering_server.h"
-#ifdef __APPLE__
+#if defined(__APPLE__)
#include <mach-o/dyld.h>
+#include <mach/host_info.h>
+#include <mach/mach_host.h>
#include <mach/mach_time.h>
+#include <sys/sysctl.h>
#endif
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
@@ -51,6 +54,19 @@
#include <sys/sysctl.h>
#endif
+#if defined(__FreeBSD__)
+#include <kvm.h>
+#endif
+
+#if defined(__OpenBSD__)
+#include <sys/swap.h>
+#include <uvm/uvmexp.h>
+#endif
+
+#if defined(__NetBSD__)
+#include <uvm/uvm_extern.h>
+#endif
+
#include <dlfcn.h>
#include <errno.h>
#include <poll.h>
@@ -59,6 +75,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/resource.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <time.h>
@@ -274,6 +291,192 @@ uint64_t OS_Unix::get_ticks_usec() const {
return longtime;
}
+Dictionary OS_Unix::get_memory_info() const {
+ Dictionary meminfo;
+
+ meminfo["physical"] = -1;
+ meminfo["free"] = -1;
+ meminfo["available"] = -1;
+ meminfo["stack"] = -1;
+
+#if defined(__APPLE__)
+ int pagesize = 0;
+ size_t len = sizeof(pagesize);
+ if (sysctlbyname("vm.pagesize", &pagesize, &len, nullptr, 0) < 0) {
+ ERR_PRINT(vformat("Could not get vm.pagesize, error code: %d - %s", errno, strerror(errno)));
+ }
+
+ int64_t phy_mem = 0;
+ len = sizeof(phy_mem);
+ if (sysctlbyname("hw.memsize", &phy_mem, &len, nullptr, 0) < 0) {
+ ERR_PRINT(vformat("Could not get hw.memsize, error code: %d - %s", errno, strerror(errno)));
+ }
+
+ mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
+ vm_statistics64_data_t vmstat;
+ if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&vmstat, &count) != KERN_SUCCESS) {
+ ERR_PRINT(vformat("Could not get host vm statistics."));
+ }
+ struct xsw_usage swap_used;
+ len = sizeof(swap_used);
+ if (sysctlbyname("vm.swapusage", &swap_used, &len, nullptr, 0) < 0) {
+ ERR_PRINT(vformat("Could not get vm.swapusage, error code: %d - %s", errno, strerror(errno)));
+ }
+
+ if (phy_mem != 0) {
+ meminfo["physical"] = phy_mem;
+ }
+ if (vmstat.free_count * (int64_t)pagesize != 0) {
+ meminfo["free"] = vmstat.free_count * (int64_t)pagesize;
+ }
+ if (swap_used.xsu_avail + vmstat.free_count * (int64_t)pagesize != 0) {
+ meminfo["available"] = swap_used.xsu_avail + vmstat.free_count * (int64_t)pagesize;
+ }
+#elif defined(__FreeBSD__)
+ int pagesize = 0;
+ size_t len = sizeof(pagesize);
+ if (sysctlbyname("vm.stats.vm.v_page_size", &pagesize, &len, nullptr, 0) < 0) {
+ ERR_PRINT(vformat("Could not get vm.stats.vm.v_page_size, error code: %d - %s", errno, strerror(errno)));
+ }
+
+ uint64_t mtotal = 0;
+ len = sizeof(mtotal);
+ if (sysctlbyname("vm.stats.vm.v_page_count", &mtotal, &len, nullptr, 0) < 0) {
+ ERR_PRINT(vformat("Could not get vm.stats.vm.v_page_count, error code: %d - %s", errno, strerror(errno)));
+ }
+ uint64_t mfree = 0;
+ len = sizeof(mfree);
+ if (sysctlbyname("vm.stats.vm.v_free_count", &mfree, &len, nullptr, 0) < 0) {
+ ERR_PRINT(vformat("Could not get vm.stats.vm.v_free_count, error code: %d - %s", errno, strerror(errno)));
+ }
+
+ uint64_t stotal = 0;
+ uint64_t sused = 0;
+ char errmsg[_POSIX2_LINE_MAX] = {};
+ kvm_t *kd = kvm_openfiles(nullptr, "/dev/null", nullptr, 0, errmsg);
+ if (kd == nullptr) {
+ ERR_PRINT(vformat("kvm_openfiles failed, error: %s", errmsg));
+ } else {
+ struct kvm_swap swap_info[32];
+ int count = kvm_getswapinfo(kd, swap_info, 32, 0);
+ for (int i = 0; i < count; i++) {
+ stotal += swap_info[i].ksw_total;
+ sused += swap_info[i].ksw_used;
+ }
+ kvm_close(kd);
+ }
+
+ if (mtotal * pagesize != 0) {
+ meminfo["physical"] = mtotal * pagesize;
+ }
+ if (mfree * pagesize != 0) {
+ meminfo["free"] = mfree * pagesize;
+ }
+ if ((mfree + stotal - sused) * pagesize != 0) {
+ meminfo["available"] = (mfree + stotal - sused) * pagesize;
+ }
+#elif defined(__OpenBSD__)
+ int pagesize = sysconf(_SC_PAGESIZE);
+
+ const int mib[] = { CTL_VM, VM_UVMEXP };
+ uvmexp uvmexp_info;
+ size_t len = sizeof(uvmexp_info);
+ if (sysctl(mib, 2, &uvmexp_info, &len, nullptr, 0) < 0) {
+ ERR_PRINT(vformat("Could not get CTL_VM, VM_UVMEXP, error code: %d - %s", errno, strerror(errno)));
+ }
+
+ uint64_t stotal = 0;
+ uint64_t sused = 0;
+ int count = swapctl(SWAP_NSWAP, 0, 0);
+ if (count > 0) {
+ swapent swap_info[count];
+ count = swapctl(SWAP_STATS, swap_info, count);
+
+ for (int i = 0; i < count; i++) {
+ if (swap_info[i].se_flags & SWF_ENABLE) {
+ sused += swap_info[i].se_inuse;
+ stotal += swap_info[i].se_nblks;
+ }
+ }
+ }
+
+ if (uvmexp_info.npages * pagesize != 0) {
+ meminfo["physical"] = uvmexp_info.npages * pagesize;
+ }
+ if (uvmexp_info.free * pagesize != 0) {
+ meminfo["free"] = uvmexp_info.free * pagesize;
+ }
+ if ((uvmexp_info.free * pagesize) + (stotal - sused) * DEV_BSIZE != 0) {
+ meminfo["available"] = (uvmexp_info.free * pagesize) + (stotal - sused) * DEV_BSIZE;
+ }
+#elif defined(__NetBSD__)
+ int pagesize = sysconf(_SC_PAGESIZE);
+
+ const int mib[] = { CTL_VM, VM_UVMEXP2 };
+ uvmexp_sysctl uvmexp_info;
+ size_t len = sizeof(uvmexp_info);
+ if (sysctl(mib, 2, &uvmexp_info, &len, nullptr, 0) < 0) {
+ ERR_PRINT(vformat("Could not get CTL_VM, VM_UVMEXP2, error code: %d - %s", errno, strerror(errno)));
+ }
+
+ if (uvmexp_info.npages * pagesize != 0) {
+ meminfo["physical"] = uvmexp_info.npages * pagesize;
+ }
+ if (uvmexp_info.free * pagesize != 0) {
+ meminfo["free"] = uvmexp_info.free * pagesize;
+ }
+ if ((uvmexp_info.free + uvmexp_info.swpages - uvmexp_info.swpginuse) * pagesize != 0) {
+ meminfo["available"] = (uvmexp_info.free + uvmexp_info.swpages - uvmexp_info.swpginuse) * pagesize;
+ }
+#else
+ Error err;
+ Ref<FileAccess> f = FileAccess::open("/proc/meminfo", FileAccess::READ, &err);
+ uint64_t mtotal = 0;
+ uint64_t mfree = 0;
+ uint64_t sfree = 0;
+ while (f.is_valid() && !f->eof_reached()) {
+ String s = f->get_line().strip_edges();
+ if (s.begins_with("MemTotal:")) {
+ Vector<String> stok = s.replace("MemTotal:", "").strip_edges().split(" ");
+ if (stok.size() == 2) {
+ mtotal = stok[0].to_int() * 1024;
+ }
+ }
+ if (s.begins_with("MemFree:")) {
+ Vector<String> stok = s.replace("MemFree:", "").strip_edges().split(" ");
+ if (stok.size() == 2) {
+ mfree = stok[0].to_int() * 1024;
+ }
+ }
+ if (s.begins_with("SwapFree:")) {
+ Vector<String> stok = s.replace("SwapFree:", "").strip_edges().split(" ");
+ if (stok.size() == 2) {
+ sfree = stok[0].to_int() * 1024;
+ }
+ }
+ }
+
+ if (mtotal != 0) {
+ meminfo["physical"] = mtotal;
+ }
+ if (mfree != 0) {
+ meminfo["free"] = mfree;
+ }
+ if (mfree + sfree != 0) {
+ meminfo["available"] = mfree + sfree;
+ }
+#endif
+
+ rlimit stackinfo = {};
+ getrlimit(RLIMIT_STACK, &stackinfo);
+
+ if (stackinfo.rlim_cur != 0) {
+ meminfo["stack"] = (int64_t)stackinfo.rlim_cur;
+ }
+
+ return meminfo;
+}
+
Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
#ifdef __EMSCRIPTEN__
// Don't compile this code at all to avoid undefined references.
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index 03429622ae..86b0e38e92 100644
--- a/drivers/unix/os_unix.h
+++ b/drivers/unix/os_unix.h
@@ -73,6 +73,8 @@ public:
virtual void delay_usec(uint32_t p_usec) const override;
virtual uint64_t get_ticks_usec() const override;
+ virtual Dictionary get_memory_info() const override;
+
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) override;
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override;
virtual Error kill(const ProcessID &p_pid) override;
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 2166d12d31..69d9baf910 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -1825,7 +1825,6 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
}
if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
- printf("vkformat: %x\n", image_create_info.format);
ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as depth-stencil attachment.");
}
@@ -2463,10 +2462,10 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
}
ERR_FAIL_COND_V_MSG(texture->bound, ERR_CANT_ACQUIRE_RESOURCE,
- "Texture can't be updated while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
+ "Texture can't be updated while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to update this texture.");
ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT), ERR_INVALID_PARAMETER,
- "Texture requires the TEXTURE_USAGE_CAN_UPDATE_BIT in order to be updatable.");
+ "Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_UPDATE_BIT` to be set to be updatable.");
uint32_t layer_count = texture->layers;
if (texture->type == TEXTURE_TYPE_CUBE || texture->type == TEXTURE_TYPE_CUBE_ARRAY) {
@@ -2739,9 +2738,9 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t
ERR_FAIL_COND_V(!tex, Vector<uint8_t>());
ERR_FAIL_COND_V_MSG(tex->bound, Vector<uint8_t>(),
- "Texture can't be retrieved while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
+ "Texture can't be retrieved while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to retrieve this texture.");
ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), Vector<uint8_t>(),
- "Texture requires the TEXTURE_USAGE_CAN_COPY_FROM_BIT in order to be retrieved.");
+ "Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved.");
uint32_t layer_count = tex->layers;
if (tex->type == TEXTURE_TYPE_CUBE || tex->type == TEXTURE_TYPE_CUBE_ARRAY) {
@@ -2882,6 +2881,15 @@ Size2i RenderingDeviceVulkan::texture_size(RID p_texture) {
return Size2i(tex->width, tex->height);
}
+uint64_t RenderingDeviceVulkan::texture_native_handle(RID p_texture) {
+ _THREAD_SAFE_METHOD_
+
+ Texture *tex = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND_V(!tex, 0);
+
+ return (uint64_t)tex->image;
+}
+
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_
@@ -2889,9 +2897,9 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
ERR_FAIL_COND_V(!src_tex, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,
- "Source texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
+ "Source texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture.");
ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER,
- "Source texture requires the TEXTURE_USAGE_CAN_COPY_FROM_BIT in order to be retrieved.");
+ "Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved.");
uint32_t src_layer_count = src_tex->layers;
uint32_t src_width, src_height, src_depth;
@@ -2910,9 +2918,9 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
ERR_FAIL_COND_V(!dst_tex, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V_MSG(dst_tex->bound, ERR_INVALID_PARAMETER,
- "Destination texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
+ "Destination texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture.");
ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,
- "Destination texture requires the TEXTURE_USAGE_CAN_COPY_TO_BIT in order to be retrieved.");
+ "Destination texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be retrieved.");
uint32_t dst_layer_count = dst_tex->layers;
uint32_t dst_width, dst_height, dst_depth;
@@ -3084,9 +3092,9 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
ERR_FAIL_COND_V(!src_tex, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,
- "Source texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
+ "Source texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture.");
ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER,
- "Source texture requires the TEXTURE_USAGE_CAN_COPY_FROM_BIT in order to be retrieved.");
+ "Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved.");
ERR_FAIL_COND_V_MSG(src_tex->type != TEXTURE_TYPE_2D, ERR_INVALID_PARAMETER, "Source texture must be 2D (or a slice of a 3D/Cube texture)");
ERR_FAIL_COND_V_MSG(src_tex->samples == TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Source texture must be multisampled.");
@@ -3095,9 +3103,9 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
ERR_FAIL_COND_V(!dst_tex, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V_MSG(dst_tex->bound, ERR_INVALID_PARAMETER,
- "Destination texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
+ "Destination texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture.");
ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,
- "Destination texture requires the TEXTURE_USAGE_CAN_COPY_TO_BIT in order to be retrieved.");
+ "Destination texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be retrieved.");
ERR_FAIL_COND_V_MSG(dst_tex->type != TEXTURE_TYPE_2D, ERR_INVALID_PARAMETER, "Destination texture must be 2D (or a slice of a 3D/Cube texture).");
ERR_FAIL_COND_V_MSG(dst_tex->samples != TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Destination texture must not be multisampled.");
@@ -3255,13 +3263,13 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,
ERR_FAIL_COND_V(!src_tex, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,
- "Source texture can't be cleared while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
+ "Source texture can't be cleared while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to clear this texture.");
ERR_FAIL_COND_V(p_layers == 0, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_mipmaps == 0, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,
- "Source texture requires the TEXTURE_USAGE_CAN_COPY_TO_BIT in order to be cleared.");
+ "Source texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT` to be set to be cleared.");
uint32_t src_layer_count = src_tex->layers;
if (src_tex->type == TEXTURE_TYPE_CUBE || src_tex->type == TEXTURE_TYPE_CUBE_ARRAY) {
@@ -4306,6 +4314,18 @@ RID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) {
return id;
}
+bool RenderingDeviceVulkan::sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_sampler_filter) const {
+ ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false);
+
+ _THREAD_SAFE_METHOD_
+
+ // Validate that this image is supported for the intended filtering.
+ VkFormatProperties properties;
+ vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), vulkan_formats[p_format], &properties);
+
+ return p_sampler_filter == RD::SAMPLER_FILTER_NEAREST || (p_sampler_filter == RD::SAMPLER_FILTER_LINEAR && (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT));
+}
+
/**********************/
/**** VERTEX ARRAY ****/
/**********************/
@@ -4314,10 +4334,6 @@ RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Vec
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());
- ERR_FAIL_COND_V_MSG(draw_list != nullptr && p_data.size(), RID(),
- "Creating buffers with data is forbidden during creation of a draw list");
- ERR_FAIL_COND_V_MSG(compute_list != nullptr && p_data.size(), RID(),
- "Creating buffers with data is forbidden during creation of a draw list");
uint32_t usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
if (p_use_as_storage) {
@@ -4455,10 +4471,6 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo
RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBufferFormat p_format, const Vector<uint8_t> &p_data, bool p_use_restart_indices) {
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V_MSG(draw_list != nullptr && p_data.size(), RID(),
- "Creating buffers with data is forbidden during creation of a draw list");
- ERR_FAIL_COND_V_MSG(compute_list != nullptr && p_data.size(), RID(),
- "Creating buffers with data is forbidden during creation of a draw list");
ERR_FAIL_COND_V(p_index_count == 0, RID());
@@ -5141,10 +5153,6 @@ RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Ve
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());
- ERR_FAIL_COND_V_MSG(draw_list != nullptr && p_data.size(), RID(),
- "Creating buffers with data is forbidden during creation of a draw list");
- ERR_FAIL_COND_V_MSG(compute_list != nullptr && p_data.size(), RID(),
- "Creating buffers with data is forbidden during creation of a draw list");
Buffer buffer;
Error err = _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0);
@@ -5164,10 +5172,6 @@ RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Ve
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");
- ERR_FAIL_COND_V_MSG(compute_list != nullptr && p_data.size(), RID(),
- "Creating buffers with data is forbidden during creation of a draw list");
ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID());
@@ -5190,10 +5194,6 @@ RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Ve
RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data) {
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V_MSG(draw_list != nullptr && p_data.size(), RID(),
- "Creating buffers with data is forbidden during creation of a draw list");
- ERR_FAIL_COND_V_MSG(compute_list != nullptr && p_data.size(), RID(),
- "Creating buffers with data is forbidden during creation of a draw list");
uint32_t element_size = get_format_vertex_size(p_format);
ERR_FAIL_COND_V_MSG(element_size == 0, RID(), "Format requested is not supported for texture buffers");
@@ -8115,35 +8115,14 @@ void RenderingDeviceVulkan::compute_list_dispatch_indirect(ComputeListID p_list,
}
void RenderingDeviceVulkan::compute_list_add_barrier(ComputeListID p_list) {
-#ifdef FORCE_FULL_BARRIER
- _full_barrier(true);
-#else
- _memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, true);
-#endif
+ uint32_t barrier_flags = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ uint32_t access_flags = VK_ACCESS_SHADER_READ_BIT;
+ _compute_list_add_barrier(BARRIER_MASK_COMPUTE, barrier_flags, access_flags);
}
-void RenderingDeviceVulkan::compute_list_end(BitField<BarrierMask> p_post_barrier) {
+void RenderingDeviceVulkan::_compute_list_add_barrier(BitField<BarrierMask> p_post_barrier, uint32_t p_barrier_flags, uint32_t p_access_flags) {
ERR_FAIL_COND(!compute_list);
- uint32_t barrier_flags = 0;
- uint32_t access_flags = 0;
- 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.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.has_flag(BARRIER_MASK_TRANSFER)) {
- barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
- access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
- }
-
- if (barrier_flags == 0) {
- barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
- }
-
VkImageMemoryBarrier *image_barriers = nullptr;
uint32_t image_barrier_count = compute_list->state.textures_to_sampled_layout.size();
@@ -8152,27 +8131,29 @@ void RenderingDeviceVulkan::compute_list_end(BitField<BarrierMask> p_post_barrie
image_barriers = (VkImageMemoryBarrier *)alloca(sizeof(VkImageMemoryBarrier) * image_barrier_count);
}
- uint32_t barrier_idx = 0;
+ image_barrier_count = 0; // We'll count how many we end up issuing.
for (Texture *E : compute_list->state.textures_to_sampled_layout) {
- VkImageMemoryBarrier &image_memory_barrier = image_barriers[barrier_idx++];
- image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- image_memory_barrier.pNext = nullptr;
- image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
- image_memory_barrier.dstAccessMask = access_flags;
- image_memory_barrier.oldLayout = E->layout;
- image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ if (E->layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
+ VkImageMemoryBarrier &image_memory_barrier = image_barriers[image_barrier_count++];
+ image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ image_memory_barrier.pNext = nullptr;
+ image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
+ image_memory_barrier.dstAccessMask = p_access_flags;
+ image_memory_barrier.oldLayout = E->layout;
+ image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- image_memory_barrier.image = E->image;
- image_memory_barrier.subresourceRange.aspectMask = E->read_aspect_mask;
- image_memory_barrier.subresourceRange.baseMipLevel = E->base_mipmap;
- image_memory_barrier.subresourceRange.levelCount = E->mipmaps;
- image_memory_barrier.subresourceRange.baseArrayLayer = E->base_layer;
- image_memory_barrier.subresourceRange.layerCount = E->layers;
+ image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_memory_barrier.image = E->image;
+ image_memory_barrier.subresourceRange.aspectMask = E->read_aspect_mask;
+ image_memory_barrier.subresourceRange.baseMipLevel = E->base_mipmap;
+ image_memory_barrier.subresourceRange.levelCount = E->mipmaps;
+ image_memory_barrier.subresourceRange.baseArrayLayer = E->base_layer;
+ image_memory_barrier.subresourceRange.layerCount = E->layers;
- E->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ E->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ }
if (E->used_in_frame != frames_drawn) {
E->used_in_transfer = false;
@@ -8182,19 +8163,40 @@ void RenderingDeviceVulkan::compute_list_end(BitField<BarrierMask> p_post_barrie
}
}
- VkMemoryBarrier mem_barrier;
- mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
- mem_barrier.pNext = nullptr;
- mem_barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
- mem_barrier.dstAccessMask = access_flags;
-
- if (image_barrier_count > 0 || p_post_barrier != BARRIER_MASK_NO_BARRIER) {
- vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, barrier_flags, 0, 1, &mem_barrier, 0, nullptr, image_barrier_count, image_barriers);
+ if (p_barrier_flags) {
+ VkMemoryBarrier mem_barrier;
+ mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
+ mem_barrier.pNext = nullptr;
+ mem_barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
+ mem_barrier.dstAccessMask = p_access_flags;
+ vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, p_barrier_flags, 0, 1, &mem_barrier, 0, nullptr, image_barrier_count, image_barriers);
+ } else if (image_barrier_count) {
+ vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, image_barrier_count, image_barriers);
}
#ifdef FORCE_FULL_BARRIER
_full_barrier(true);
#endif
+}
+
+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.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.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.has_flag(BARRIER_MASK_TRANSFER)) {
+ barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
+ access_flags |= VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
+ }
+ _compute_list_add_barrier(p_post_barrier, barrier_flags, access_flags);
memdelete(compute_list);
compute_list = nullptr;
@@ -8922,6 +8924,11 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
}
}
+ for (int i = 0; i < frame_count; i++) {
+ //Reset all queries in a query pool before doing any operations with them.
+ vkCmdResetQueryPool(frames[0].setup_command_buffer, frames[i].timestamp_pool, 0, max_timestamp_query_elements);
+ }
+
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.
@@ -9387,6 +9394,9 @@ bool RenderingDeviceVulkan::has_feature(const Features p_feature) const {
VulkanContext::VRSCapabilities vrs_capabilities = context->get_vrs_capabilities();
return vrs_capabilities.attachment_vrs_supported && context->get_physical_device_features().shaderStorageImageExtendedFormats;
} break;
+ case SUPPORTS_FRAGMENT_SHADER_WITH_ONLY_SIDE_EFFECTS: {
+ return true;
+ } break;
default: {
return false;
}
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
index 91a09fa970..4150e0a8e6 100644
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ b/drivers/vulkan/rendering_device_vulkan.h
@@ -954,6 +954,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
ComputeList *compute_list = nullptr;
+ void _compute_list_add_barrier(BitField<BarrierMask> p_post_barrier, uint32_t p_barrier_flags, uint32_t p_access_flags);
+
/**************************/
/**** FRAME MANAGEMENT ****/
/**************************/
@@ -1055,6 +1057,7 @@ public:
virtual bool texture_is_shared(RID p_texture);
virtual bool texture_is_valid(RID p_texture);
virtual Size2i texture_size(RID p_texture);
+ virtual uint64_t texture_native_handle(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, 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);
@@ -1082,6 +1085,7 @@ public:
/*****************/
virtual RID sampler_create(const SamplerState &p_state);
+ virtual bool sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_sampler_filter) const;
/**********************/
/**** VERTEX ARRAY ****/
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index f185a5cb88..f65056951d 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -2274,8 +2274,8 @@ Error VulkanContext::prepare_buffers() {
} else if (err == VK_SUBOPTIMAL_KHR) {
// Swapchain is not as optimal as it could be, but the platform's
// presentation engine will still present the image correctly.
- print_verbose("Vulkan: Early suboptimal swapchain.");
- break;
+ print_verbose("Vulkan: Early suboptimal swapchain, recreating.");
+ _update_swap_chain(w);
} else if (err != VK_SUCCESS) {
ERR_BREAK_MSG(err != VK_SUCCESS, "Vulkan: Did not create swapchain successfully. Error code: " + String(string_VkResult(err)));
} else {
diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp
index 72ec0c19ab..eeeb6ee689 100644
--- a/drivers/wasapi/audio_driver_wasapi.cpp
+++ b/drivers/wasapi/audio_driver_wasapi.cpp
@@ -206,8 +206,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i
IMMDeviceEnumerator *enumerator = nullptr;
IMMDevice *output_device = nullptr;
- CoInitialize(nullptr);
-
HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
@@ -482,6 +480,14 @@ Error AudioDriverWASAPI::init_output_device(bool p_reinit) {
}
switch (audio_output.channels) {
+ case 1: // Mono
+ case 3: // Surround 2.1
+ case 5: // Surround 5.0
+ case 7: // Surround 7.0
+ // We will downmix as required.
+ channels = audio_output.channels + 1;
+ break;
+
case 2: // Stereo
case 4: // Surround 3.1
case 6: // Surround 5.1
@@ -501,7 +507,7 @@ Error AudioDriverWASAPI::init_output_device(bool p_reinit) {
input_position = 0;
input_size = 0;
- print_verbose("WASAPI: detected " + itos(channels) + " channels");
+ print_verbose("WASAPI: detected " + itos(audio_output.channels) + " channels");
print_verbose("WASAPI: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
return OK;
@@ -547,7 +553,7 @@ Error AudioDriverWASAPI::finish_input_device() {
}
Error AudioDriverWASAPI::init() {
- mix_rate = GLOBAL_GET("audio/driver/mix_rate");
+ mix_rate = _get_configured_mix_rate();
target_latency_ms = GLOBAL_GET("audio/driver/output_latency");
@@ -582,8 +588,6 @@ PackedStringArray AudioDriverWASAPI::audio_device_get_list(bool p_input) {
list.push_back(String("Default"));
- CoInitialize(nullptr);
-
HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
ERR_FAIL_COND_V(hr != S_OK, PackedStringArray());
@@ -702,6 +706,8 @@ void AudioDriverWASAPI::write_sample(WORD format_tag, int bits_per_sample, BYTE
}
void AudioDriverWASAPI::thread_func(void *p_udata) {
+ CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+
AudioDriverWASAPI *ad = static_cast<AudioDriverWASAPI *>(p_udata);
uint32_t avail_frames = 0;
uint32_t write_ofs = 0;
@@ -748,6 +754,19 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
for (unsigned int i = 0; i < write_frames * ad->channels; i++) {
ad->write_sample(ad->audio_output.format_tag, ad->audio_output.bits_per_sample, buffer, i, ad->samples_in.write[write_ofs++]);
}
+ } else if (ad->channels == ad->audio_output.channels + 1) {
+ // Pass all channels except the last two as-is, and then mix the last two
+ // together as one channel. E.g. stereo -> mono, or 3.1 -> 2.1.
+ unsigned int last_chan = ad->audio_output.channels - 1;
+ for (unsigned int i = 0; i < write_frames; i++) {
+ for (unsigned int j = 0; j < last_chan; j++) {
+ ad->write_sample(ad->audio_output.format_tag, ad->audio_output.bits_per_sample, buffer, i * ad->audio_output.channels + j, ad->samples_in.write[write_ofs++]);
+ }
+ int32_t l = ad->samples_in.write[write_ofs++];
+ int32_t r = ad->samples_in.write[write_ofs++];
+ int32_t c = (int32_t)(((int64_t)l + (int64_t)r) / 2);
+ ad->write_sample(ad->audio_output.format_tag, ad->audio_output.bits_per_sample, buffer, i * ad->audio_output.channels + last_chan, c);
+ }
} else {
for (unsigned int i = 0; i < write_frames; i++) {
for (unsigned int j = 0; j < MIN(ad->channels, ad->audio_output.channels); j++) {
@@ -908,6 +927,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
OS::get_singleton()->delay_usec(1000);
}
}
+ CoUninitialize();
}
void AudioDriverWASAPI::start() {
@@ -931,7 +951,9 @@ void AudioDriverWASAPI::unlock() {
void AudioDriverWASAPI::finish() {
exit_thread.set();
- thread.wait_to_finish();
+ if (thread.is_started()) {
+ thread.wait_to_finish();
+ }
finish_input_device();
finish_output_device();
diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp
index 7b88bd8a95..88eb89656a 100644
--- a/drivers/windows/dir_access_windows.cpp
+++ b/drivers/windows/dir_access_windows.cpp
@@ -59,6 +59,14 @@ struct DirAccessWindowsPrivate {
WIN32_FIND_DATAW fu; //unicode version
};
+String DirAccessWindows::fix_path(String p_path) const {
+ String r_path = DirAccess::fix_path(p_path);
+ if (r_path.is_absolute_path() && !r_path.is_network_share_path() && r_path.length() > MAX_PATH) {
+ r_path = "\\\\?\\" + r_path.replace("/", "\\");
+ }
+ return r_path;
+}
+
// CreateFolderAsync
Error DirAccessWindows::list_dir_begin() {
@@ -158,6 +166,7 @@ Error DirAccessWindows::make_dir(String p_dir) {
p_dir = fix_path(p_dir);
if (p_dir.is_relative_path()) {
p_dir = current_dir.path_join(p_dir);
+ p_dir = fix_path(p_dir);
}
p_dir = p_dir.simplify_path().replace("/", "\\");
@@ -165,12 +174,6 @@ Error DirAccessWindows::make_dir(String p_dir) {
bool success;
int err;
- if (!p_dir.is_network_share_path()) {
- p_dir = "\\\\?\\" + p_dir;
- // Add "\\?\" to the path to extend max. path length past 248, if it's not a network share UNC path.
- // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa363855(v=vs.85).aspx
- }
-
success = CreateDirectoryW((LPCWSTR)(p_dir.utf16().get_data()), nullptr);
err = GetLastError();
diff --git a/drivers/windows/dir_access_windows.h b/drivers/windows/dir_access_windows.h
index 9d91c22f7e..1e55917756 100644
--- a/drivers/windows/dir_access_windows.h
+++ b/drivers/windows/dir_access_windows.h
@@ -53,6 +53,9 @@ class DirAccessWindows : public DirAccess {
bool _cisdir = false;
bool _cishidden = false;
+protected:
+ virtual String fix_path(String p_path) const override;
+
public:
virtual Error list_dir_begin() override; ///< This starts dir listing
virtual String get_next() override;
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index f36bbcc350..6e69743d4e 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -68,6 +68,14 @@ bool FileAccessWindows::is_path_invalid(const String &p_path) {
return invalid_files.has(fname);
}
+String FileAccessWindows::fix_path(const String &p_path) const {
+ String r_path = FileAccess::fix_path(p_path);
+ if (r_path.is_absolute_path() && !r_path.is_network_share_path() && r_path.length() > MAX_PATH) {
+ r_path = "\\\\?\\" + r_path.replace("/", "\\");
+ }
+ return r_path;
+}
+
Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) {
if (is_path_invalid(p_path)) {
#ifdef DEBUG_ENABLED
diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h
index 453f8d3b5f..13c881e562 100644
--- a/drivers/windows/file_access_windows.h
+++ b/drivers/windows/file_access_windows.h
@@ -54,6 +54,7 @@ class FileAccessWindows : public FileAccess {
static HashSet<String> invalid_files;
public:
+ virtual String fix_path(const String &p_path) const override;
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
diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp
index 44ce01d4d7..22063c52d9 100644
--- a/drivers/xaudio2/audio_driver_xaudio2.cpp
+++ b/drivers/xaudio2/audio_driver_xaudio2.cpp
@@ -39,7 +39,8 @@ Error AudioDriverXAudio2::init() {
pcm_open = false;
samples_in = nullptr;
- mix_rate = GLOBAL_GET("audio/driver/mix_rate");
+ mix_rate = _get_configured_mix_rate();
+
// FIXME: speaker_mode seems unused in the Xaudio2 driver so far
speaker_mode = SPEAKER_MODE_STEREO;
channels = 2;
@@ -150,7 +151,9 @@ void AudioDriverXAudio2::unlock() {
void AudioDriverXAudio2::finish() {
exit_thread.set();
- thread.wait_to_finish();
+ if (thread.is_started()) {
+ thread.wait_to_finish();
+ }
if (source_voice) {
source_voice->Stop(0);