summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/alsamidi/midi_driver_alsamidi.cpp184
-rw-r--r--drivers/alsamidi/midi_driver_alsamidi.h38
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp7
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp10
-rw-r--r--drivers/gles3/storage/config.cpp2
-rw-r--r--drivers/gles3/storage/material_storage.cpp35
-rw-r--r--drivers/gles3/storage/material_storage.h2
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp4
-rw-r--r--drivers/gles3/storage/texture_storage.cpp62
-rw-r--r--drivers/gles3/storage/utilities.cpp168
-rw-r--r--drivers/gles3/storage/utilities.h85
-rw-r--r--drivers/unix/os_unix.cpp6
-rw-r--r--drivers/vulkan/vulkan_context.cpp48
13 files changed, 413 insertions, 238 deletions
diff --git a/drivers/alsamidi/midi_driver_alsamidi.cpp b/drivers/alsamidi/midi_driver_alsamidi.cpp
index d2a0076023..011758e5f7 100644
--- a/drivers/alsamidi/midi_driver_alsamidi.cpp
+++ b/drivers/alsamidi/midi_driver_alsamidi.cpp
@@ -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
+ // behaviour 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..9265dede3d 100644
--- a/drivers/alsamidi/midi_driver_alsamidi.h
+++ b/drivers/alsamidi/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/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 21e06046b5..29252c8677 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -581,6 +581,13 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
_record_item_commands(ci, p_canvas_transform_inverse, current_clip, blend_mode, p_lights, index, batch_broken);
}
+ if (r_last_index >= index) {
+ // Nothing to render, just return.
+ state.current_batch_index = 0;
+ state.canvas_instance_batches.clear();
+ return;
+ }
+
// Copy over all data needed for rendering.
glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_instance_data_buffers[state.current_buffer].ubo);
#ifdef WEB_ENABLED
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index ea97dff522..b2d01b02fb 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -101,8 +101,7 @@ void RasterizerGLES3::begin_frame(double frame_step) {
scene->set_time(time_total, frame_step);
GLES3::Utilities *utils = GLES3::Utilities::get_singleton();
- utils->info.render_final = utils->info.render;
- utils->info.render.reset();
+ utils->_capture_timestamps_begin();
//scene->iteration();
}
@@ -272,6 +271,13 @@ 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, uint32_t p_layer) {
diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp
index 0e0c361add..9b496c0999 100644
--- a/drivers/gles3/storage/config.cpp
+++ b/drivers/gles3/storage/config.cpp
@@ -95,7 +95,7 @@ Config::Config() {
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");
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index f5241e33ab..6748eb3676 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -89,7 +89,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 +116,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 +145,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;
@@ -728,7 +728,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;
@@ -2214,7 +2214,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"));
@@ -2314,7 +2314,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
}
@@ -2324,7 +2324,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
@@ -2350,9 +2352,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;
diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h
index 6504c7748c..24d9a0fee1 100644
--- a/drivers/gles3/storage/material_storage.h
+++ b/drivers/gles3/storage/material_storage.h
@@ -530,7 +530,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 11ce31856d..9ec0fc0286 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -1004,7 +1004,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);
@@ -1421,7 +1421,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;
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index a7e5001271..11151c4100 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -747,6 +747,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);
@@ -783,8 +784,65 @@ Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
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
diff --git a/drivers/gles3/storage/utilities.cpp b/drivers/gles3/storage/utilities.cpp
index 58469c932d..8e7e218bb9 100644
--- a/drivers/gles3/storage/utilities.cpp
+++ b/drivers/gles3/storage/utilities.cpp
@@ -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);
@@ -213,87 +237,69 @@ 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 */
diff --git a/drivers/gles3/storage/utilities.h b/drivers/gles3/storage/utilities.h
index 936ac35cc9..55a875958e 100644
--- a/drivers/gles3/storage/utilities.h
+++ b/drivers/gles3/storage/utilities.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 */
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index fc06291a3a..161706489f 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -505,11 +505,11 @@ bool OS_Unix::set_environment(const String &p_var, const String &p_value) const
}
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;
}
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index 9ee5a67471..5df123878e 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -687,21 +687,43 @@ Error VulkanContext::_check_capabilities() {
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;
+ // We must check that the relative extension is present before assuming a
+ // feature as enabled. Actually, according to the spec we shouldn't add the
+ // structs in pNext at all, but this works fine.
+ // See also: https://github.com/godotengine/godot/issues/65409
+ for (uint32_t i = 0; i < enabled_extension_count; ++i) {
+ if (!strcmp(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME, extension_names[i])) {
+ vrs_capabilities.pipeline_vrs_supported = vrs_features.pipelineFragmentShadingRate;
+ vrs_capabilities.primitive_vrs_supported = vrs_features.primitiveFragmentShadingRate;
+ vrs_capabilities.attachment_vrs_supported = vrs_features.attachmentFragmentShadingRate;
- multiview_capabilities.is_supported = multiview_features.multiview;
- multiview_capabilities.geometry_shader_is_supported = multiview_features.multiviewGeometryShader;
- multiview_capabilities.tessellation_shader_is_supported = multiview_features.multiviewTessellationShader;
+ continue;
+ }
- shader_capabilities.shader_float16_is_supported = shader_features.shaderFloat16;
- shader_capabilities.shader_int8_is_supported = shader_features.shaderInt8;
+ if (!strcmp(VK_KHR_MULTIVIEW_EXTENSION_NAME, extension_names[i])) {
+ 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;
- 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;
+ continue;
+ }
+
+ if (!strcmp(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, extension_names[i])) {
+ shader_capabilities.shader_float16_is_supported = shader_features.shaderFloat16;
+ shader_capabilities.shader_int8_is_supported = shader_features.shaderInt8;
+
+ continue;
+ }
+
+ if (!strcmp(VK_KHR_16BIT_STORAGE_EXTENSION_NAME, extension_names[i])) {
+ 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;
+
+ continue;
+ }
+ }
}
// Check extended properties.
@@ -810,7 +832,7 @@ Error VulkanContext::_create_instance() {
}
}
- CharString cs = ProjectSettings::get_singleton()->get("application/config/name").operator String().utf8();
+ CharString cs = GLOBAL_GET("application/config/name").operator String().utf8();
const VkApplicationInfo app = {
/*sType*/ VK_STRUCTURE_TYPE_APPLICATION_INFO,
/*pNext*/ nullptr,