diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/alsamidi/midi_driver_alsamidi.cpp | 184 | ||||
-rw-r--r-- | drivers/alsamidi/midi_driver_alsamidi.h | 38 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_canvas_gles3.cpp | 7 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_gles3.cpp | 10 | ||||
-rw-r--r-- | drivers/gles3/storage/config.cpp | 2 | ||||
-rw-r--r-- | drivers/gles3/storage/material_storage.cpp | 35 | ||||
-rw-r--r-- | drivers/gles3/storage/material_storage.h | 2 | ||||
-rw-r--r-- | drivers/gles3/storage/mesh_storage.cpp | 4 | ||||
-rw-r--r-- | drivers/gles3/storage/texture_storage.cpp | 62 | ||||
-rw-r--r-- | drivers/gles3/storage/utilities.cpp | 168 | ||||
-rw-r--r-- | drivers/gles3/storage/utilities.h | 85 | ||||
-rw-r--r-- | drivers/unix/os_unix.cpp | 6 | ||||
-rw-r--r-- | drivers/vulkan/vulkan_context.cpp | 48 |
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, |