summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/io/resource_loader.cpp29
-rw-r--r--core/io/resource_loader.h2
-rw-r--r--doc/classes/CollisionObject2D.xml4
-rw-r--r--doc/classes/CollisionObject3D.xml4
-rw-r--r--doc/classes/PhysicsPointQueryParameters2D.xml2
-rw-r--r--doc/classes/PopupMenu.xml2
-rw-r--r--doc/classes/RenderingServer.xml6
-rw-r--r--doc/classes/TextServer.xml2
-rw-r--r--doc/classes/Tree.xml2
-rw-r--r--doc/classes/TreeItem.xml4
-rw-r--r--doc/classes/XRInterfaceExtension.xml2
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp15
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.h4
-rw-r--r--editor/find_in_files.cpp2
-rw-r--r--editor/plugins/script_text_editor.cpp101
-rw-r--r--editor/plugins/text_editor.cpp4
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp293
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h11
-rw-r--r--main/main.cpp4
-rw-r--r--modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml2
-rw-r--r--modules/webrtc/doc_classes/WebRTCDataChannel.xml4
-rw-r--r--scene/2d/touch_screen_button.cpp4
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp17
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h4
-rw-r--r--thirdparty/README.md2
-rw-r--r--thirdparty/basis_universal/encoder/basisu_comp.cpp178
-rw-r--r--thirdparty/basis_universal/encoder/basisu_comp.h21
-rw-r--r--thirdparty/basis_universal/encoder/basisu_enc.cpp4
-rw-r--r--thirdparty/basis_universal/encoder/basisu_frontend.cpp4
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_transcoder.cpp2
30 files changed, 552 insertions, 183 deletions
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 6219ea70e4..20445a8b03 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -923,6 +923,35 @@ void ResourceLoader::clear_translation_remaps() {
}
}
+void ResourceLoader::clear_thread_load_tasks() {
+ thread_load_mutex->lock();
+
+ for (KeyValue<String, ResourceLoader::ThreadLoadTask> &E : thread_load_tasks) {
+ switch (E.value.status) {
+ case ResourceLoader::ThreadLoadStatus::THREAD_LOAD_LOADED: {
+ E.value.resource = Ref<Resource>();
+ } break;
+
+ case ResourceLoader::ThreadLoadStatus::THREAD_LOAD_IN_PROGRESS: {
+ if (E.value.thread != nullptr) {
+ E.value.thread->wait_to_finish();
+ memdelete(E.value.thread);
+ E.value.thread = nullptr;
+ }
+ E.value.resource = Ref<Resource>();
+ } break;
+
+ case ResourceLoader::ThreadLoadStatus::THREAD_LOAD_FAILED:
+ default: {
+ // do nothing
+ }
+ }
+ }
+ thread_load_tasks.clear();
+
+ thread_load_mutex->unlock();
+}
+
void ResourceLoader::load_path_remaps() {
if (!ProjectSettings::get_singleton()->has_setting("path_remap/remapped_paths")) {
return;
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 243670b2d0..af10098bd8 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -219,6 +219,8 @@ public:
static void load_translation_remaps();
static void clear_translation_remaps();
+ static void clear_thread_load_tasks();
+
static void set_load_callback(ResourceLoadedCallback p_callback);
static ResourceLoaderImport import;
diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml
index ee69015ae1..3ed2c9d3de 100644
--- a/doc/classes/CollisionObject2D.xml
+++ b/doc/classes/CollisionObject2D.xml
@@ -157,7 +157,7 @@
<param index="0" name="owner_id" type="int" />
<param index="1" name="shape_id" type="int" />
<description>
- Returns the [Shape2D] with the given id from the given shape owner.
+ Returns the [Shape2D] with the given ID from the given shape owner.
</description>
</method>
<method name="shape_owner_get_shape_count" qualifiers="const">
@@ -172,7 +172,7 @@
<param index="0" name="owner_id" type="int" />
<param index="1" name="shape_id" type="int" />
<description>
- Returns the child index of the [Shape2D] with the given id from the given shape owner.
+ Returns the child index of the [Shape2D] with the given ID from the given shape owner.
</description>
</method>
<method name="shape_owner_get_transform" qualifiers="const">
diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml
index f10136521a..c302963b92 100644
--- a/doc/classes/CollisionObject3D.xml
+++ b/doc/classes/CollisionObject3D.xml
@@ -130,7 +130,7 @@
<param index="0" name="owner_id" type="int" />
<param index="1" name="shape_id" type="int" />
<description>
- Returns the [Shape3D] with the given id from the given shape owner.
+ Returns the [Shape3D] with the given ID from the given shape owner.
</description>
</method>
<method name="shape_owner_get_shape_count" qualifiers="const">
@@ -145,7 +145,7 @@
<param index="0" name="owner_id" type="int" />
<param index="1" name="shape_id" type="int" />
<description>
- Returns the child index of the [Shape3D] with the given id from the given shape owner.
+ Returns the child index of the [Shape3D] with the given ID from the given shape owner.
</description>
</method>
<method name="shape_owner_get_transform" qualifiers="const">
diff --git a/doc/classes/PhysicsPointQueryParameters2D.xml b/doc/classes/PhysicsPointQueryParameters2D.xml
index e49d2a9f5f..76dc816dab 100644
--- a/doc/classes/PhysicsPointQueryParameters2D.xml
+++ b/doc/classes/PhysicsPointQueryParameters2D.xml
@@ -10,7 +10,7 @@
</tutorials>
<members>
<member name="canvas_instance_id" type="int" setter="set_canvas_instance_id" getter="get_canvas_instance_id" default="0">
- If different from [code]0[/code], restricts the query to a specific canvas layer specified by its instance id. See [method Object.get_instance_id].
+ If different from [code]0[/code], restricts the query to a specific canvas layer specified by its instance ID. See [method Object.get_instance_id].
</member>
<member name="collide_with_areas" type="bool" setter="set_collide_with_areas" getter="is_collide_with_areas_enabled" default="false">
If [code]true[/code], the query will take [Area2D]s into account.
diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml
index a69163f429..6810b0e8e4 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -206,7 +206,7 @@
<return type="int" />
<param index="0" name="index" type="int" />
<description>
- Returns the id of the item at the given [param index]. [code]id[/code] can be manually assigned, while index can not.
+ Returns the ID of the item at the given [param index]. [code]id[/code] can be manually assigned, while index can not.
</description>
</method>
<method name="get_item_indent" qualifiers="const">
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 2ffa4dc50b..fc05f67416 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -1295,13 +1295,13 @@
<method name="get_test_cube">
<return type="RID" />
<description>
- Returns the id of the test cube. Creates one if none exists.
+ Returns the ID of the test cube. Creates one if none exists.
</description>
</method>
<method name="get_test_texture">
<return type="RID" />
<description>
- Returns the id of the test texture. Creates one if none exists.
+ Returns the ID of the test texture. Creates one if none exists.
</description>
</method>
<method name="get_video_adapter_api_version" qualifiers="const">
@@ -1335,7 +1335,7 @@
<method name="get_white_texture">
<return type="RID" />
<description>
- Returns the id of a white texture. Creates one if none exists.
+ Returns the ID of a white texture. Creates one if none exists.
</description>
</method>
<method name="gi_set_use_half_resolution">
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index b3e55b5cd0..4fc6ee3312 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -235,7 +235,7 @@
<param index="1" name="size" type="Vector2i" />
<param index="2" name="glyph" type="int" />
<description>
- Returns resource id of the cache texture containing the glyph.
+ Returns resource ID of the cache texture containing the glyph.
[b]Note:[/b] If there are pending glyphs to render, calling this function might trigger the texture cache update.
</description>
</method>
diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml
index 6a016c3ebd..629c271417 100644
--- a/doc/classes/Tree.xml
+++ b/doc/classes/Tree.xml
@@ -70,7 +70,7 @@
<return type="int" />
<param index="0" name="position" type="Vector2" />
<description>
- Returns the button id at [param position], or -1 if no button is there.
+ Returns the button ID at [param position], or -1 if no button is there.
</description>
</method>
<method name="get_column_at_position" qualifiers="const">
diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml
index a8ffef427f..ec6b166e57 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -78,7 +78,7 @@
<param index="0" name="column" type="int" />
<param index="1" name="id" type="int" />
<description>
- Returns the button index if there is a button with id [param id] in column [param column], otherwise returns -1.
+ Returns the button index if there is a button with ID [param id] in column [param column], otherwise returns -1.
</description>
</method>
<method name="get_button_count" qualifiers="const">
@@ -93,7 +93,7 @@
<param index="0" name="column" type="int" />
<param index="1" name="button_idx" type="int" />
<description>
- Returns the id for the button at index [param button_idx] in column [param column].
+ Returns the ID for the button at index [param button_idx] in column [param column].
</description>
</method>
<method name="get_button_tooltip_text" qualifiers="const">
diff --git a/doc/classes/XRInterfaceExtension.xml b/doc/classes/XRInterfaceExtension.xml
index 0fe54e947f..5ad67a7ea9 100644
--- a/doc/classes/XRInterfaceExtension.xml
+++ b/doc/classes/XRInterfaceExtension.xml
@@ -24,7 +24,7 @@
<method name="_get_camera_feed_id" qualifiers="virtual const">
<return type="int" />
<description>
- Returns the camera feed id for the [CameraFeed] registered with the [CameraServer] that should be presented as the background on an AR capable device (if applicable).
+ Returns the camera feed ID for the [CameraFeed] registered with the [CameraServer] that should be presented as the background on an AR capable device (if applicable).
</description>
</method>
<method name="_get_camera_transform" qualifiers="virtual">
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index e5d4077393..c7e7227916 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -454,7 +454,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
update_skeletons = false;
}
// Canvas group begins here, render until before this item
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, false);
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, r_sdf_used);
item_count = 0;
if (ci->canvas_group_owner->canvas_group->mode != RS::CANVAS_GROUP_MODE_TRANSPARENT) {
@@ -485,7 +485,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
mesh_storage->update_mesh_instances();
update_skeletons = false;
}
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, true);
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, r_sdf_used, true);
item_count = 0;
if (ci->canvas_group->blur_mipmaps) {
@@ -504,7 +504,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
}
//render anything pending, including clearing if no items
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, false);
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, r_sdf_used);
item_count = 0;
texture_storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, backbuffer_gen_mipmaps);
@@ -530,7 +530,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
mesh_storage->update_mesh_instances();
update_skeletons = false;
}
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, false);
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, r_sdf_used);
//then reset
item_count = 0;
}
@@ -549,7 +549,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
state.current_buffer = (state.current_buffer + 1) % state.canvas_instance_data_buffers.size();
}
-void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, uint32_t &r_last_index, bool p_to_backbuffer) {
+void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, uint32_t &r_last_index, bool &r_sdf_used, bool p_to_backbuffer) {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
canvas_begin(p_to_render_target, p_to_backbuffer);
@@ -617,7 +617,7 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
GLES3::CanvasShaderData::BlendMode blend_mode = shader_data_cache ? shader_data_cache->blend_mode : GLES3::CanvasShaderData::BLEND_MODE_MIX;
- _record_item_commands(ci, p_to_render_target, p_canvas_transform_inverse, current_clip, blend_mode, p_lights, index, batch_broken);
+ _record_item_commands(ci, p_to_render_target, p_canvas_transform_inverse, current_clip, blend_mode, p_lights, index, batch_broken, r_sdf_used);
}
if (index == 0) {
@@ -749,7 +749,7 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
r_last_index += index;
}
-void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_render_target, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_batch_broken) {
+void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_render_target, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used) {
RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? state.default_filter : p_item->texture_filter;
if (texture_filter != state.canvas_instance_batches[state.current_batch_index].filter) {
@@ -1145,6 +1145,7 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
} else {
particles_storage->particles_set_canvas_sdf_collision(pt->particles, false, Transform2D(), Rect2(), 0);
}
+ r_sdf_used |= particles_storage->particles_has_collision(particles);
}
state.canvas_instance_batches[state.current_batch_index].command = c;
diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h
index 0a03d43d07..bd87973404 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.h
+++ b/drivers/gles3/rasterizer_canvas_gles3.h
@@ -351,8 +351,8 @@ public:
void _prepare_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index, Size2 &r_texpixel_size);
void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) override;
- void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, uint32_t &r_last_index, bool p_to_backbuffer = false);
- void _record_item_commands(const Item *p_item, RID p_render_target, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_break_batch);
+ void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, uint32_t &r_last_index, bool &r_sdf_used, bool p_to_backbuffer = false);
+ void _record_item_commands(const Item *p_item, RID p_render_target, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_break_batch, bool &r_sdf_used);
void _render_batch(Light *p_lights, uint32_t p_index);
bool _bind_material(GLES3::CanvasMaterialData *p_material_data, CanvasShaderGLES3::ShaderVariant p_variant, uint64_t p_specialization);
void _new_batch(bool &r_batch_broken, uint32_t &r_index);
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index 666444eaf9..b7e7200b11 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -769,7 +769,7 @@ void FindInFilesPanel::draw_result_text(Object *item_obj, Rect2 rect) {
Rect2 match_rect = rect;
match_rect.position.x += font->get_string_size(item_text.left(r.begin_trimmed), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x - 1;
- match_rect.size.x = font->get_string_size(_search_text_label->get_text(), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x + 2;
+ match_rect.size.x = font->get_string_size(_search_text_label->get_text(), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x + 1;
match_rect.position.y += 1 * EDSCALE;
match_rect.size.y -= 2 * EDSCALE;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 747fdfd041..38639ac811 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -1223,7 +1223,9 @@ void ScriptTextEditor::_edit_option(int p_op) {
code_editor->duplicate_selection();
} break;
case EDIT_TOGGLE_FOLD_LINE: {
- tx->toggle_foldable_line(tx->get_caret_line());
+ for (int caret_idx = 0; caret_idx < tx->get_caret_count(); caret_idx++) {
+ tx->toggle_foldable_line(tx->get_caret_line(caret_idx));
+ }
tx->queue_redraw();
} break;
case EDIT_FOLD_ALL_LINES: {
@@ -1291,28 +1293,28 @@ void ScriptTextEditor::_edit_option(int p_op) {
} break;
case EDIT_EVALUATE: {
Expression expression;
- Vector<String> lines = code_editor->get_text_editor()->get_selected_text().split("\n");
- PackedStringArray results;
-
- for (int i = 0; i < lines.size(); i++) {
- String line = lines[i];
- String whitespace = line.substr(0, line.size() - line.strip_edges(true, false).size()); //extract the whitespace at the beginning
-
- if (expression.parse(line) == OK) {
- Variant result = expression.execute(Array(), Variant(), false, true);
- if (expression.get_error_text().is_empty()) {
- results.push_back(whitespace + result.get_construct_string());
+ tx->begin_complex_operation();
+ for (int caret_idx = 0; caret_idx < tx->get_caret_count(); caret_idx++) {
+ Vector<String> lines = tx->get_selected_text(caret_idx).split("\n");
+ PackedStringArray results;
+
+ for (int i = 0; i < lines.size(); i++) {
+ String line = lines[i];
+ String whitespace = line.substr(0, line.size() - line.strip_edges(true, false).size()); // Extract the whitespace at the beginning.
+ if (expression.parse(line) == OK) {
+ Variant result = expression.execute(Array(), Variant(), false, true);
+ if (expression.get_error_text().is_empty()) {
+ results.push_back(whitespace + result.get_construct_string());
+ } else {
+ results.push_back(line);
+ }
} else {
results.push_back(line);
}
- } else {
- results.push_back(line);
}
+ tx->insert_text_at_caret(String("\n").join(results), caret_idx);
}
-
- code_editor->get_text_editor()->begin_complex_operation(); //prevents creating a two-step undo
- code_editor->get_text_editor()->insert_text_at_caret(String("\n").join(results));
- code_editor->get_text_editor()->end_complex_operation();
+ tx->end_complex_operation();
} break;
case SEARCH_FIND: {
code_editor->get_find_replace_bar()->popup_search();
@@ -1327,14 +1329,14 @@ void ScriptTextEditor::_edit_option(int p_op) {
code_editor->get_find_replace_bar()->popup_replace();
} break;
case SEARCH_IN_FILES: {
- String selected_text = code_editor->get_text_editor()->get_selected_text();
+ String selected_text = tx->get_selected_text();
// Yep, because it doesn't make sense to instance this dialog for every single script open...
// So this will be delegated to the ScriptEditor.
emit_signal(SNAME("search_in_files_requested"), selected_text);
} break;
case REPLACE_IN_FILES: {
- String selected_text = code_editor->get_text_editor()->get_selected_text();
+ String selected_text = tx->get_selected_text();
emit_signal(SNAME("replace_in_files_requested"), selected_text);
} break;
@@ -1358,10 +1360,12 @@ void ScriptTextEditor::_edit_option(int p_op) {
code_editor->remove_all_bookmarks();
} break;
case DEBUG_TOGGLE_BREAKPOINT: {
- int line = tx->get_caret_line();
- bool dobreak = !tx->is_line_breakpointed(line);
- tx->set_line_as_breakpoint(line, dobreak);
- EditorDebuggerNode::get_singleton()->set_breakpoint(script->get_path(), line + 1, dobreak);
+ for (int caret_idx = 0; caret_idx < tx->get_caret_count(); caret_idx++) {
+ int line = tx->get_caret_line(caret_idx);
+ bool dobreak = !tx->is_line_breakpointed(line);
+ tx->set_line_as_breakpoint(line, dobreak);
+ EditorDebuggerNode::get_singleton()->set_breakpoint(script->get_path(), line + 1, dobreak);
+ }
} break;
case DEBUG_REMOVE_ALL_BREAKPOINTS: {
PackedInt32Array bpoints = tx->get_breakpointed_lines();
@@ -1379,26 +1383,14 @@ void ScriptTextEditor::_edit_option(int p_op) {
return;
}
- tx->remove_secondary_carets();
- int line = tx->get_caret_line();
-
- // wrap around
- if (line >= (int)bpoints[bpoints.size() - 1]) {
- tx->unfold_line(bpoints[0]);
- tx->set_caret_line(bpoints[0]);
- tx->center_viewport_to_caret();
- } else {
- for (int i = 0; i < bpoints.size(); i++) {
- int bline = bpoints[i];
- if (bline > line) {
- tx->unfold_line(bline);
- tx->set_caret_line(bline);
- tx->center_viewport_to_caret();
- return;
- }
+ int current_line = tx->get_caret_line();
+ int bpoint_idx = 0;
+ if (current_line < (int)bpoints[bpoints.size() - 1]) {
+ while (bpoint_idx < bpoints.size() && bpoints[bpoint_idx] <= current_line) {
+ bpoint_idx++;
}
}
-
+ code_editor->goto_line_centered(bpoints[bpoint_idx]);
} break;
case DEBUG_GOTO_PREV_BREAKPOINT: {
PackedInt32Array bpoints = tx->get_breakpointed_lines();
@@ -1406,25 +1398,14 @@ void ScriptTextEditor::_edit_option(int p_op) {
return;
}
- tx->remove_secondary_carets();
- int line = tx->get_caret_line();
- // wrap around
- if (line <= (int)bpoints[0]) {
- tx->unfold_line(bpoints[bpoints.size() - 1]);
- tx->set_caret_line(bpoints[bpoints.size() - 1]);
- tx->center_viewport_to_caret();
- } else {
- for (int i = bpoints.size() - 1; i >= 0; i--) {
- int bline = bpoints[i];
- if (bline < line) {
- tx->unfold_line(bline);
- tx->set_caret_line(bline);
- tx->center_viewport_to_caret();
- return;
- }
+ int current_line = tx->get_caret_line();
+ int bpoint_idx = bpoints.size() - 1;
+ if (current_line > (int)bpoints[0]) {
+ while (bpoint_idx >= 0 && bpoints[bpoint_idx] >= current_line) {
+ bpoint_idx--;
}
}
-
+ code_editor->goto_line_centered(bpoints[bpoint_idx]);
} break;
case HELP_CONTEXTUAL: {
String text = tx->get_selected_text(0);
@@ -1835,7 +1816,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
base = _find_node_for_script(base, base, script);
}
ScriptLanguage::LookupResult result;
- if (script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_symbol_lookup(), word_at_pos, script->get_path(), base, result) == OK) {
+ if (script->get_language()->lookup_code(tx->get_text_for_symbol_lookup(), word_at_pos, script->get_path(), base, result) == OK) {
open_docs = true;
}
}
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index baf5e363f8..d6079d6285 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -353,7 +353,9 @@ void TextEditor::_edit_option(int p_op) {
code_editor->duplicate_selection();
} break;
case EDIT_TOGGLE_FOLD_LINE: {
- tx->toggle_foldable_line(tx->get_caret_line());
+ for (int caret_idx = 0; caret_idx < tx->get_caret_count(); caret_idx++) {
+ tx->toggle_foldable_line(tx->get_caret_line(caret_idx));
+ }
tx->queue_redraw();
} break;
case EDIT_FOLD_ALL_LINES: {
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 9990d5c06f..cf811067c9 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -269,6 +269,19 @@ void VisualShaderGraphPlugin::set_expression(VisualShader::Type p_type, int p_no
links[p_node_id].expression_edit->set_text(p_expression);
}
+Ref<Script> VisualShaderGraphPlugin::get_node_script(int p_node_id) const {
+ if (!links.has(p_node_id)) {
+ return Ref<Script>();
+ }
+
+ Ref<VisualShaderNodeCustom> custom = Ref<VisualShaderNodeCustom>(links[p_node_id].visual_node);
+ if (custom.is_valid()) {
+ return custom->get_script();
+ }
+
+ return Ref<Script>();
+}
+
void VisualShaderGraphPlugin::update_node_size(int p_node_id) {
if (!links.has(p_node_id)) {
return;
@@ -1137,10 +1150,6 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) {
}
}
-void VisualShaderEditor::update_nodes() {
- _update_nodes();
-}
-
void VisualShaderEditor::add_plugin(const Ref<VisualShaderNodePlugin> &p_plugin) {
if (plugins.has(p_plugin)) {
return;
@@ -1202,6 +1211,228 @@ void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script>
add_options.push_back(ao);
}
+Dictionary VisualShaderEditor::get_custom_node_data(Ref<VisualShaderNodeCustom> &p_custom_node) {
+ Dictionary dict;
+ dict["script"] = p_custom_node->get_script();
+
+ String name;
+ if (p_custom_node->has_method("_get_name")) {
+ name = (String)p_custom_node->call("_get_name");
+ } else {
+ name = "Unnamed";
+ }
+ dict["name"] = name;
+
+ String description = "";
+ if (p_custom_node->has_method("_get_description")) {
+ description = (String)p_custom_node->call("_get_description");
+ }
+ dict["description"] = description;
+
+ int return_icon_type = -1;
+ if (p_custom_node->has_method("_get_return_icon_type")) {
+ return_icon_type = (int)p_custom_node->call("_get_return_icon_type");
+ }
+ dict["return_icon_type"] = return_icon_type;
+
+ String category = "";
+ if (p_custom_node->has_method("_get_category")) {
+ category = (String)p_custom_node->call("_get_category");
+ }
+ category = category.rstrip("/");
+ category = category.lstrip("/");
+ category = "Addons/" + category;
+
+ String subcategory = "";
+ if (p_custom_node->has_method("_get_subcategory")) {
+ subcategory = (String)p_custom_node->call("_get_subcategory");
+ }
+ if (!subcategory.is_empty()) {
+ category += "/" + subcategory;
+ }
+ dict["category"] = category;
+
+ bool highend = false;
+ if (p_custom_node->has_method("_is_highend")) {
+ highend = (bool)p_custom_node->call("_is_highend");
+ }
+ dict["highend"] = highend;
+
+ return dict;
+}
+
+void VisualShaderEditor::update_custom_type(const Ref<Resource> &p_resource) {
+ Ref<Script> scr = Ref<Script>(p_resource.ptr());
+ if (scr.is_null() || scr->get_instance_base_type() != String("VisualShaderNodeCustom")) {
+ return;
+ }
+
+ Ref<VisualShaderNodeCustom> ref;
+ ref.instantiate();
+ ref->set_script(scr);
+ if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) {
+ for (int i = 0; i < add_options.size(); i++) {
+ if (add_options[i].is_custom && add_options[i].script == scr) {
+ add_options.remove_at(i);
+ _update_options_menu();
+ // TODO: Make indication for the existed custom nodes with that script on graph to be disabled.
+ break;
+ }
+ }
+ return;
+ }
+ Dictionary dict = get_custom_node_data(ref);
+
+ bool found_type = false;
+ bool need_rebuild = false;
+
+ for (int i = 0; i < add_options.size(); i++) {
+ if (add_options[i].is_custom && add_options[i].script == scr) {
+ found_type = true;
+
+ add_options.write[i].name = dict["name"];
+ add_options.write[i].return_type = dict["return_icon_type"];
+ add_options.write[i].description = dict["description"];
+ add_options.write[i].category = dict["category"];
+ add_options.write[i].highend = dict["highend"];
+
+ int max_type = 0;
+ int type_offset = 0;
+ switch (visual_shader->get_mode()) {
+ case Shader::MODE_CANVAS_ITEM:
+ case Shader::MODE_SPATIAL: {
+ max_type = 3;
+ } break;
+ case Shader::MODE_PARTICLES: {
+ max_type = 5;
+ type_offset = 3;
+ } break;
+ case Shader::MODE_SKY: {
+ max_type = 1;
+ type_offset = 8;
+ } break;
+ case Shader::MODE_FOG: {
+ max_type = 1;
+ type_offset = 9;
+ } break;
+ default: {
+ } break;
+ }
+ max_type = type_offset + max_type;
+
+ for (int t = type_offset; t < max_type; t++) {
+ VisualShader::Type type = (VisualShader::Type)t;
+ Vector<int> nodes = visual_shader->get_node_list(type);
+
+ List<VisualShader::Connection> node_connections;
+ visual_shader->get_node_connections(type, &node_connections);
+
+ List<VisualShader::Connection> custom_node_input_connections;
+ List<VisualShader::Connection> custom_node_output_connections;
+ for (const VisualShader::Connection &E : node_connections) {
+ int from = E.from_node;
+ int from_idx = E.from_port;
+ int to = E.to_node;
+ int to_idx = E.to_port;
+
+ if (graph_plugin->get_node_script(from) == scr) {
+ custom_node_output_connections.push_back({ from, from_idx, to, to_idx });
+ } else if (graph_plugin->get_node_script(to) == scr) {
+ custom_node_input_connections.push_back({ from, from_idx, to, to_idx });
+ }
+ }
+
+ for (int j = 0; j < nodes.size(); j++) {
+ int node_id = nodes[j];
+
+ Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);
+ if (vsnode.is_null()) {
+ continue;
+ }
+ Ref<VisualShaderNodeCustom> custom_node = Ref<VisualShaderNodeCustom>(vsnode.ptr());
+ if (custom_node.is_null() || custom_node->get_script() != scr) {
+ continue;
+ }
+ need_rebuild = true;
+
+ // Removes invalid connections.
+ {
+ int prev_input_port_count = custom_node->get_input_port_count();
+ int prev_output_port_count = custom_node->get_output_port_count();
+
+ custom_node->update_ports();
+
+ int input_port_count = custom_node->get_input_port_count();
+ int output_port_count = custom_node->get_output_port_count();
+
+ if (output_port_count != prev_output_port_count) {
+ for (const VisualShader::Connection &E : custom_node_output_connections) {
+ int from = E.from_node;
+ int from_idx = E.from_port;
+ int to = E.to_node;
+ int to_idx = E.to_port;
+
+ if (from_idx >= output_port_count) {
+ visual_shader->disconnect_nodes(type, from, from_idx, to, to_idx);
+ graph_plugin->disconnect_nodes(type, from, from_idx, to, to_idx);
+ }
+ }
+ }
+ if (input_port_count != prev_input_port_count) {
+ for (const VisualShader::Connection &E : custom_node_input_connections) {
+ int from = E.from_node;
+ int from_idx = E.from_port;
+ int to = E.to_node;
+ int to_idx = E.to_port;
+
+ if (to_idx >= input_port_count) {
+ visual_shader->disconnect_nodes(type, from, from_idx, to, to_idx);
+ graph_plugin->disconnect_nodes(type, from, from_idx, to, to_idx);
+ }
+ }
+ }
+ }
+
+ graph_plugin->update_node(type, node_id);
+ }
+ }
+ break;
+ }
+ }
+
+ if (!found_type) {
+ add_custom_type(dict["name"], dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]);
+ }
+
+ // To prevent updating options multiple times when multiple scripts are saved.
+ if (!_block_update_options_menu) {
+ _block_update_options_menu = true;
+
+ call_deferred(SNAME("_update_options_menu_deferred"));
+ }
+
+ // To prevent rebuilding the shader multiple times when multiple scripts are saved.
+ if (need_rebuild && !_block_rebuild_shader) {
+ _block_rebuild_shader = true;
+
+ call_deferred(SNAME("_rebuild_shader_deferred"));
+ }
+}
+
+void VisualShaderEditor::_update_options_menu_deferred() {
+ _update_options_menu();
+
+ _block_update_options_menu = false;
+}
+
+void VisualShaderEditor::_rebuild_shader_deferred() {
+ if (visual_shader.is_valid()) {
+ visual_shader->rebuild();
+ }
+
+ _block_rebuild_shader = false;
+}
+
bool VisualShaderEditor::_is_available(int p_mode) {
int current_mode = edit_type->get_selected();
@@ -1243,57 +1474,10 @@ void VisualShaderEditor::_update_nodes() {
if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) {
continue;
}
-
- String name;
- if (ref->has_method("_get_name")) {
- name = (String)ref->call("_get_name");
- } else {
- name = "Unnamed";
- }
-
- String description = "";
- if (ref->has_method("_get_description")) {
- description = (String)ref->call("_get_description");
- }
-
- int return_icon_type = -1;
- if (ref->has_method("_get_return_icon_type")) {
- return_icon_type = (int)ref->call("_get_return_icon_type");
- }
-
- String category = "";
- if (ref->has_method("_get_category")) {
- category = (String)ref->call("_get_category");
- }
-
- String subcategory = "";
- if (ref->has_method("_get_subcategory")) {
- subcategory = (String)ref->call("_get_subcategory");
- }
-
- bool highend = false;
- if (ref->has_method("_is_highend")) {
- highend = (bool)ref->call("_is_highend");
- }
-
- Dictionary dict;
- dict["name"] = name;
- dict["script"] = scr;
- dict["description"] = description;
- dict["return_icon_type"] = return_icon_type;
-
- category = category.rstrip("/");
- category = category.lstrip("/");
- category = "Addons/" + category;
- if (!subcategory.is_empty()) {
- category += "/" + subcategory;
- }
-
- dict["category"] = category;
- dict["highend"] = highend;
+ Dictionary dict = get_custom_node_data(ref);
String key;
- key = category + "/" + name;
+ key = String(dict["category"]) + "/" + String(dict["name"]);
added[key] = dict;
}
@@ -4694,6 +4878,8 @@ void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_update_constant", &VisualShaderEditor::_update_constant);
ClassDB::bind_method("_update_parameter", &VisualShaderEditor::_update_parameter);
ClassDB::bind_method("_expand_output_port", &VisualShaderEditor::_expand_output_port);
+ ClassDB::bind_method("_update_options_menu_deferred", &VisualShaderEditor::_update_options_menu_deferred);
+ ClassDB::bind_method("_rebuild_shader_deferred", &VisualShaderEditor::_rebuild_shader_deferred);
ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw);
ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw);
@@ -4704,6 +4890,7 @@ void VisualShaderEditor::_bind_methods() {
VisualShaderEditor::VisualShaderEditor() {
ShaderLanguage::get_keyword_list(&keyword_list);
+ EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &VisualShaderEditor::update_custom_type));
graph = memnew(GraphEdit);
graph->get_zoom_hbox()->set_h_size_flags(SIZE_EXPAND_FILL);
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 8afad9f668..d559237569 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -133,6 +133,7 @@ public:
void update_curve_xyz(int p_node_id);
void set_expression(VisualShader::Type p_type, int p_node_id, const String &p_expression);
int get_constant_index(float p_constant) const;
+ Ref<Script> get_node_script(int p_node_id) const;
void update_node_size(int p_node_id);
void update_theme();
VisualShader::Type get_shader_type() const;
@@ -190,6 +191,9 @@ class VisualShaderEditor : public VBoxContainer {
PanelContainer *error_panel = nullptr;
Label *error_label = nullptr;
+ bool _block_update_options_menu = false;
+ bool _block_rebuild_shader = false;
+
Point2 saved_node_pos;
bool saved_node_pos_dirty = false;
@@ -497,6 +501,9 @@ class VisualShaderEditor : public VBoxContainer {
void _update_parameter_refs(HashSet<String> &p_names);
void _update_varyings();
+ void _update_options_menu_deferred();
+ void _rebuild_shader_deferred();
+
void _visibility_changed();
protected:
@@ -504,7 +511,6 @@ protected:
static void _bind_methods();
public:
- void update_nodes();
void add_plugin(const Ref<VisualShaderNodePlugin> &p_plugin);
void remove_plugin(const Ref<VisualShaderNodePlugin> &p_plugin);
@@ -513,6 +519,9 @@ public:
void clear_custom_types();
void add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, bool p_highend);
+ Dictionary get_custom_node_data(Ref<VisualShaderNodeCustom> &p_custom_node);
+ void update_custom_type(const Ref<Resource> &p_resource);
+
virtual Size2 get_minimum_size() const override;
void edit(VisualShader *p_visual_shader);
VisualShaderEditor();
diff --git a/main/main.cpp b/main/main.cpp
index 83703c55c2..09cec68ef9 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -3328,6 +3328,8 @@ void Main::cleanup(bool p_force) {
ResourceLoader::clear_translation_remaps();
ResourceLoader::clear_path_remaps();
+ ResourceLoader::clear_thread_load_tasks();
+
ScriptServer::finish_languages();
// Sync pending commands that may have been queued from a different thread during ScriptServer finalization
@@ -3361,6 +3363,7 @@ void Main::cleanup(bool p_force) {
finalize_theme_db();
// Before deinitializing server extensions, finalize servers which may be loaded as extensions.
+ finalize_navigation_server();
finalize_physics();
NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS);
@@ -3384,7 +3387,6 @@ void Main::cleanup(bool p_force) {
OS::get_singleton()->finalize();
- finalize_navigation_server();
finalize_display();
if (input) {
diff --git a/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml b/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml
index 7ed6255a62..af7c345f15 100644
--- a/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml
+++ b/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml
@@ -17,7 +17,7 @@
<param index="0" name="filter" type="Callable" />
<description>
Adds a peer visibility filter for this synchronizer.
- [code]filter[/code] should take a peer id [int] and return a [bool].
+ [code]filter[/code] should take a peer ID [int] and return a [bool].
</description>
</method>
<method name="get_visibility_for" qualifiers="const">
diff --git a/modules/webrtc/doc_classes/WebRTCDataChannel.xml b/modules/webrtc/doc_classes/WebRTCDataChannel.xml
index a9ba8a23de..a186631ca8 100644
--- a/modules/webrtc/doc_classes/WebRTCDataChannel.xml
+++ b/modules/webrtc/doc_classes/WebRTCDataChannel.xml
@@ -22,8 +22,8 @@
<method name="get_id" qualifiers="const">
<return type="int" />
<description>
- Returns the id assigned to this channel during creation (or auto-assigned during negotiation).
- If the channel is not negotiated out-of-band the id will only be available after the connection is established (will return [code]65535[/code] until then).
+ Returns the ID assigned to this channel during creation (or auto-assigned during negotiation).
+ If the channel is not negotiated out-of-band the ID will only be available after the connection is established (will return [code]65535[/code] until then).
</description>
</method>
<method name="get_label" qualifiers="const">
diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp
index e99821e9b9..11b4718802 100644
--- a/scene/2d/touch_screen_button.cpp
+++ b/scene/2d/touch_screen_button.cpp
@@ -100,7 +100,7 @@ void TouchScreenButton::_notification(int p_what) {
if (!is_inside_tree()) {
return;
}
- if (!Engine::get_singleton()->is_editor_hint() && !!DisplayServer::get_singleton()->is_touchscreen_available() && visibility == VISIBILITY_TOUCHSCREEN_ONLY) {
+ if (!Engine::get_singleton()->is_editor_hint() && !DisplayServer::get_singleton()->is_touchscreen_available() && visibility == VISIBILITY_TOUCHSCREEN_ONLY) {
return;
}
@@ -137,7 +137,7 @@ void TouchScreenButton::_notification(int p_what) {
} break;
case NOTIFICATION_ENTER_TREE: {
- if (!Engine::get_singleton()->is_editor_hint() && !!DisplayServer::get_singleton()->is_touchscreen_available() && visibility == VISIBILITY_TOUCHSCREEN_ONLY) {
+ if (!Engine::get_singleton()->is_editor_hint() && !DisplayServer::get_singleton()->is_touchscreen_available() && visibility == VISIBILITY_TOUCHSCREEN_ONLY) {
return;
}
queue_redraw();
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index cc8238a8dd..d41daa18b4 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -398,7 +398,7 @@ void RendererCanvasRenderRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RI
r_last_texture = p_texture;
}
-void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) {
+void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants, bool &r_sdf_used) {
//create an empty push constant
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
@@ -833,6 +833,9 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
} else {
particles_storage->particles_set_canvas_sdf_collision(pt->particles, false, Transform2D(), Rect2(), RID());
}
+
+ // Signal that SDF texture needs to be updated.
+ r_sdf_used |= particles_storage->particles_has_collision(pt->particles);
}
if (mesh.is_null()) {
@@ -1045,7 +1048,7 @@ RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, boo
return uniform_set;
}
-void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer) {
+void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer) {
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
@@ -1142,7 +1145,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
}
}
- _render_item(draw_list, p_to_render_target, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants);
+ _render_item(draw_list, p_to_render_target, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants, r_sdf_used);
prev_material = material;
}
@@ -1440,7 +1443,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
update_skeletons = false;
}
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, r_sdf_used);
item_count = 0;
if (ci->canvas_group_owner->canvas_group->mode != RS::CANVAS_GROUP_MODE_TRANSPARENT) {
@@ -1472,7 +1475,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
update_skeletons = false;
}
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, true);
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, r_sdf_used, true);
item_count = 0;
if (ci->canvas_group->blur_mipmaps) {
@@ -1491,7 +1494,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
update_skeletons = false;
}
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, r_sdf_used);
item_count = 0;
texture_storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, backbuffer_gen_mipmaps);
@@ -1517,7 +1520,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
update_skeletons = false;
}
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, r_sdf_used, false);
//then reset
item_count = 0;
}
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 3fff574098..6e876b1297 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -421,8 +421,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
RID _create_base_uniform_set(RID p_to_render_target, bool p_backbuffer);
inline void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size); //recursive, so regular inline used instead.
- void _render_item(RenderingDevice::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants);
- void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer = false);
+ void _render_item(RenderingDevice::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants, bool &r_sdf_used);
+ void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false);
_FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4);
_FORCE_INLINE_ void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3);
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 937d149747..ed38fe0ec8 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -20,7 +20,7 @@ Files extracted from upstream source:
## basis_universal
- Upstream: https://github.com/BinomialLLC/basis_universal
-- Version: git (1531cfaf9ed5232248a0a45736686a849ca3befc, 2022)
+- Version: git (a91e94c8495d7f470d3df326a364d49324cfd4a3, 2022)
- License: Apache 2.0
Files extracted from upstream source:
diff --git a/thirdparty/basis_universal/encoder/basisu_comp.cpp b/thirdparty/basis_universal/encoder/basisu_comp.cpp
index 166a1c4fe0..41eae2b78a 100644
--- a/thirdparty/basis_universal/encoder/basisu_comp.cpp
+++ b/thirdparty/basis_universal/encoder/basisu_comp.cpp
@@ -1501,7 +1501,8 @@ namespace basisu
if (m_params.m_compute_stats)
{
- printf("Slice: %u\n", slice_index);
+ if (m_params.m_print_stats)
+ printf("Slice: %u\n", slice_index);
image_stats& s = m_stats[slice_index];
@@ -1511,81 +1512,100 @@ namespace basisu
// ---- .basis stats
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 3);
- em.print(".basis RGB Avg: ");
+ if (m_params.m_print_stats)
+ em.print(".basis RGB Avg: ");
s.m_basis_rgb_avg_psnr = em.m_psnr;
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 4);
- em.print(".basis RGBA Avg: ");
+ if (m_params.m_print_stats)
+ em.print(".basis RGBA Avg: ");
s.m_basis_rgba_avg_psnr = em.m_psnr;
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 1);
- em.print(".basis R Avg: ");
+ if (m_params.m_print_stats)
+ em.print(".basis R Avg: ");
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 1, 1);
- em.print(".basis G Avg: ");
+ if (m_params.m_print_stats)
+ em.print(".basis G Avg: ");
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 2, 1);
- em.print(".basis B Avg: ");
+ if (m_params.m_print_stats)
+ em.print(".basis B Avg: ");
if (m_params.m_uastc)
{
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 3, 1);
- em.print(".basis A Avg: ");
+ if (m_params.m_print_stats)
+ em.print(".basis A Avg: ");
s.m_basis_a_avg_psnr = em.m_psnr;
}
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 0);
- em.print(".basis 709 Luma: ");
+ if (m_params.m_print_stats)
+ em.print(".basis 709 Luma: ");
s.m_basis_luma_709_psnr = static_cast<float>(em.m_psnr);
s.m_basis_luma_709_ssim = static_cast<float>(em.m_ssim);
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 0, true, true);
- em.print(".basis 601 Luma: ");
+ if (m_params.m_print_stats)
+ em.print(".basis 601 Luma: ");
s.m_basis_luma_601_psnr = static_cast<float>(em.m_psnr);
if (m_slice_descs.size() == 1)
{
const uint32_t output_size = comp_size ? (uint32_t)comp_size : (uint32_t)comp_data.size();
- debug_printf(".basis RGB PSNR per bit/texel*10000: %3.3f\n", 10000.0f * s.m_basis_rgb_avg_psnr / ((output_size * 8.0f) / (slice_desc.m_orig_width * slice_desc.m_orig_height)));
- debug_printf(".basis Luma 709 PSNR per bit/texel*10000: %3.3f\n", 10000.0f * s.m_basis_luma_709_psnr / ((output_size * 8.0f) / (slice_desc.m_orig_width * slice_desc.m_orig_height)));
+ if (m_params.m_print_stats)
+ {
+ debug_printf(".basis RGB PSNR per bit/texel*10000: %3.3f\n", 10000.0f * s.m_basis_rgb_avg_psnr / ((output_size * 8.0f) / (slice_desc.m_orig_width * slice_desc.m_orig_height)));
+ debug_printf(".basis Luma 709 PSNR per bit/texel*10000: %3.3f\n", 10000.0f * s.m_basis_luma_709_psnr / ((output_size * 8.0f) / (slice_desc.m_orig_width * slice_desc.m_orig_height)));
+ }
}
if (m_decoded_output_textures_unpacked_bc7[slice_index].get_width())
{
// ---- BC7 stats
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc7[slice_index], 0, 3);
- em.print("BC7 RGB Avg: ");
+ if (m_params.m_print_stats)
+ em.print("BC7 RGB Avg: ");
s.m_bc7_rgb_avg_psnr = em.m_psnr;
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc7[slice_index], 0, 4);
- em.print("BC7 RGBA Avg: ");
+ if (m_params.m_print_stats)
+ em.print("BC7 RGBA Avg: ");
s.m_bc7_rgba_avg_psnr = em.m_psnr;
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc7[slice_index], 0, 1);
- em.print("BC7 R Avg: ");
+ if (m_params.m_print_stats)
+ em.print("BC7 R Avg: ");
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc7[slice_index], 1, 1);
- em.print("BC7 G Avg: ");
+ if (m_params.m_print_stats)
+ em.print("BC7 G Avg: ");
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc7[slice_index], 2, 1);
- em.print("BC7 B Avg: ");
+ if (m_params.m_print_stats)
+ em.print("BC7 B Avg: ");
if (m_params.m_uastc)
{
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc7[slice_index], 3, 1);
- em.print("BC7 A Avg: ");
+ if (m_params.m_print_stats)
+ em.print("BC7 A Avg: ");
s.m_bc7_a_avg_psnr = em.m_psnr;
}
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc7[slice_index], 0, 0);
- em.print("BC7 709 Luma: ");
+ if (m_params.m_print_stats)
+ em.print("BC7 709 Luma: ");
s.m_bc7_luma_709_psnr = static_cast<float>(em.m_psnr);
s.m_bc7_luma_709_ssim = static_cast<float>(em.m_ssim);
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc7[slice_index], 0, 0, true, true);
- em.print("BC7 601 Luma: ");
+ if (m_params.m_print_stats)
+ em.print("BC7 601 Luma: ");
s.m_bc7_luma_601_psnr = static_cast<float>(em.m_psnr);
}
@@ -1593,16 +1613,19 @@ namespace basisu
{
// ---- Nearly best possible ETC1S stats
em.calc(m_slice_images[slice_index], m_best_etc1s_images_unpacked[slice_index], 0, 3);
- em.print("Unquantized ETC1S RGB Avg: ");
+ if (m_params.m_print_stats)
+ em.print("Unquantized ETC1S RGB Avg: ");
s.m_best_etc1s_rgb_avg_psnr = static_cast<float>(em.m_psnr);
em.calc(m_slice_images[slice_index], m_best_etc1s_images_unpacked[slice_index], 0, 0);
- em.print("Unquantized ETC1S 709 Luma: ");
+ if (m_params.m_print_stats)
+ em.print("Unquantized ETC1S 709 Luma: ");
s.m_best_etc1s_luma_709_psnr = static_cast<float>(em.m_psnr);
s.m_best_etc1s_luma_709_ssim = static_cast<float>(em.m_ssim);
em.calc(m_slice_images[slice_index], m_best_etc1s_images_unpacked[slice_index], 0, 0, true, true);
- em.print("Unquantized ETC1S 601 Luma: ");
+ if (m_params.m_print_stats)
+ em.print("Unquantized ETC1S 601 Luma: ");
s.m_best_etc1s_luma_601_psnr = static_cast<float>(em.m_psnr);
}
}
@@ -2311,6 +2334,8 @@ namespace basisu
}
comp_params.m_compute_stats = (pStats != nullptr);
+ comp_params.m_print_stats = (flags_and_quality & cFlagPrintStats) != 0;
+ comp_params.m_status_output = (flags_and_quality & cFlagPrintStatus) != 0;
// Create the compressor, initialize it, and process the input
basis_compressor comp;
@@ -2328,6 +2353,11 @@ namespace basisu
return nullptr;
}
+ if ((pStats) && (comp.get_opencl_failed()))
+ {
+ pStats->m_opencl_failed = true;
+ }
+
// Get the output file data and return it to the caller
void* pFile_data = nullptr;
const uint8_vec* pFile_data_vec = comp_params.m_create_ktx2_file ? &comp.get_output_ktx2_file() : &comp.get_output_basis_file();
@@ -2388,4 +2418,108 @@ namespace basisu
free(p);
}
+ bool basis_benchmark_etc1s_opencl(bool* pOpenCL_failed)
+ {
+ if (pOpenCL_failed)
+ *pOpenCL_failed = false;
+
+ if (!opencl_is_available())
+ {
+ error_printf("basis_benchmark_etc1s_opencl: OpenCL support must be enabled first!\n");
+ return false;
+ }
+
+ const uint32_t W = 1024, H = 1024;
+ basisu::vector<image> images;
+ image& img = images.enlarge(1)->resize(W, H);
+
+ const uint32_t NUM_RAND_LETTERS = 6000;// 40000;
+
+ rand r;
+ r.seed(200);
+
+ for (uint32_t i = 0; i < NUM_RAND_LETTERS; i++)
+ {
+ uint32_t x = r.irand(0, W - 1), y = r.irand(0, H - 1);
+ uint32_t sx = r.irand(1, 4), sy = r.irand(1, 4);
+ color_rgba c(r.byte(), r.byte(), r.byte(), 255);
+
+ img.debug_text(x, y, sx, sy, c, nullptr, false, "%c", static_cast<char>(r.irand(32, 127)));
+ }
+
+ //save_png("test.png", img);
+
+ image_stats stats;
+
+ uint32_t flags_and_quality = cFlagSRGB | cFlagThreaded | 255;
+ size_t comp_size = 0;
+
+ double best_cpu_time = 1e+9f, best_gpu_time = 1e+9f;
+
+ const uint32_t TIMES_TO_ENCODE = 2;
+ interval_timer tm;
+
+ for (uint32_t i = 0; i < TIMES_TO_ENCODE; i++)
+ {
+ tm.start();
+ void* pComp_data = basis_compress(
+ images,
+ flags_and_quality, 1.0f,
+ &comp_size,
+ &stats);
+ double cpu_time = tm.get_elapsed_secs();
+ if (!pComp_data)
+ {
+ error_printf("basis_benchmark_etc1s_opencl: basis_compress() failed (CPU)!\n");
+ return false;
+ }
+
+ best_cpu_time = minimum(best_cpu_time, cpu_time);
+
+ basis_free_data(pComp_data);
+ }
+
+ printf("Best CPU time: %3.3f\n", best_cpu_time);
+
+ for (uint32_t i = 0; i < TIMES_TO_ENCODE; i++)
+ {
+ tm.start();
+ void* pComp_data = basis_compress(
+ images,
+ flags_and_quality | cFlagUseOpenCL, 1.0f,
+ &comp_size,
+ &stats);
+
+ if (stats.m_opencl_failed)
+ {
+ error_printf("basis_benchmark_etc1s_opencl: OpenCL failed!\n");
+
+ basis_free_data(pComp_data);
+
+ if (pOpenCL_failed)
+ *pOpenCL_failed = true;
+
+ return false;
+ }
+
+ double gpu_time = tm.get_elapsed_secs();
+ if (!pComp_data)
+ {
+ error_printf("basis_benchmark_etc1s_opencl: basis_compress() failed (GPU)!\n");
+ return false;
+ }
+
+ best_gpu_time = minimum(best_gpu_time, gpu_time);
+
+ basis_free_data(pComp_data);
+ }
+
+ printf("Best GPU time: %3.3f\n", best_gpu_time);
+
+ return best_gpu_time < best_cpu_time;
+ }
+
} // namespace basisu
+
+
+
diff --git a/thirdparty/basis_universal/encoder/basisu_comp.h b/thirdparty/basis_universal/encoder/basisu_comp.h
index aa5ea6fec3..b6c9fef9e2 100644
--- a/thirdparty/basis_universal/encoder/basisu_comp.h
+++ b/thirdparty/basis_universal/encoder/basisu_comp.h
@@ -92,6 +92,8 @@ namespace basisu
m_best_etc1s_luma_709_psnr = 0.0f;
m_best_etc1s_luma_601_psnr = 0.0f;
m_best_etc1s_luma_709_ssim = 0.0f;
+
+ m_opencl_failed = false;
}
std::string m_filename;
@@ -119,6 +121,8 @@ namespace basisu
float m_best_etc1s_luma_709_psnr;
float m_best_etc1s_luma_601_psnr;
float m_best_etc1s_luma_709_ssim;
+
+ bool m_opencl_failed;
};
template<bool def>
@@ -255,6 +259,7 @@ namespace basisu
m_write_output_basis_files.clear();
m_compression_level.clear();
m_compute_stats.clear();
+ m_print_stats.clear();
m_check_for_alpha.clear();
m_force_alpha.clear();
m_multithreading.clear();
@@ -373,6 +378,9 @@ namespace basisu
// Compute and display image metrics
bool_param<false> m_compute_stats;
+
+ // Print stats to stdout, if m_compute_stats is true.
+ bool_param<true> m_print_stats;
// Check to see if any input image has an alpha channel, if so then the output basis file will have alpha channels
bool_param<true> m_check_for_alpha;
@@ -583,11 +591,16 @@ namespace basisu
cFlagYFlip = 1 << 16, // flip source image on Y axis before compression
cFlagUASTC = 1 << 17, // use UASTC compression vs. ETC1S
- cFlagUASTCRDO = 1 << 18 // use RDO postprocessing when generating UASTC files (must set uastc_rdo_quality to the quality scalar)
+ cFlagUASTCRDO = 1 << 18, // use RDO postprocessing when generating UASTC files (must set uastc_rdo_quality to the quality scalar)
+
+ cFlagPrintStats = 1 << 19, // print image stats to stdout
+ cFlagPrintStatus = 1 << 20 // print status to stdout
};
// This function accepts an array of source images.
// If more than one image is provided, it's assumed the images form a mipmap pyramid and automatic mipmap generation is disabled.
+ // Returns a pointer to the compressed .basis or .ktx2 file data. *pSize is the size of the compressed data. The returned block must be freed using basis_free_data().
+ // basisu_encoder_init() MUST be called first!
void* basis_compress(
const basisu::vector<image> &source_images,
uint32_t flags_and_quality, float uastc_rdo_quality,
@@ -604,6 +617,12 @@ namespace basisu
// Frees the dynamically allocated file data returned by basis_compress().
void basis_free_data(void* p);
+ // Runs a short benchmark using synthetic image data to time OpenCL encoding vs. CPU encoding, with multithreading enabled.
+ // Returns true if opencl is worth using on this system, otherwise false.
+ // If pOpenCL_failed is not null, it will be set to true if OpenCL encoding failed *on this particular machine/driver/BasisU version* and the encoder falled back to CPU encoding.
+ // basisu_encoder_init() MUST be called first. If OpenCL support wasn't enabled this always returns false.
+ bool basis_benchmark_etc1s_opencl(bool *pOpenCL_failed = nullptr);
+
// Parallel compression API
struct parallel_results
{
diff --git a/thirdparty/basis_universal/encoder/basisu_enc.cpp b/thirdparty/basis_universal/encoder/basisu_enc.cpp
index b427215ee3..c431ceaf12 100644
--- a/thirdparty/basis_universal/encoder/basisu_enc.cpp
+++ b/thirdparty/basis_universal/encoder/basisu_enc.cpp
@@ -187,6 +187,8 @@ namespace basisu
opencl_init(opencl_force_serialization);
}
+ interval_timer::init(); // make sure interval_timer globals are initialized from main thread to avoid TSAN reports
+
g_library_initialized = true;
}
@@ -227,7 +229,7 @@ namespace basisu
{
QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(pTicks));
}
-#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
#include <sys/time.h>
inline void query_counter(timer_ticks* pTicks)
{
diff --git a/thirdparty/basis_universal/encoder/basisu_frontend.cpp b/thirdparty/basis_universal/encoder/basisu_frontend.cpp
index 00210e6679..1f30a33c70 100644
--- a/thirdparty/basis_universal/encoder/basisu_frontend.cpp
+++ b/thirdparty/basis_universal/encoder/basisu_frontend.cpp
@@ -2328,8 +2328,6 @@ namespace basisu
m_optimized_cluster_selectors.resize(total_selector_clusters);
- uint32_t total_clusters_processed = 0;
-
// For each selector codebook entry, and for each of the 4x4 selectors, determine which selector minimizes the error across all the blocks that use that quantized selector.
const uint32_t N = 256;
for (uint32_t cluster_index_iter = 0; cluster_index_iter < total_selector_clusters; cluster_index_iter += N)
@@ -2338,7 +2336,7 @@ namespace basisu
const uint32_t last_index = minimum<uint32_t>((uint32_t)total_selector_clusters, cluster_index_iter + N);
#ifndef __EMSCRIPTEN__
- m_params.m_pJob_pool->add_job([this, first_index, last_index, &total_clusters_processed, &total_selector_clusters] {
+ m_params.m_pJob_pool->add_job([this, first_index, last_index] {
#endif
for (uint32_t cluster_index = first_index; cluster_index < last_index; cluster_index++)
diff --git a/thirdparty/basis_universal/transcoder/basisu_transcoder.cpp b/thirdparty/basis_universal/transcoder/basisu_transcoder.cpp
index 630731900f..3aeba0ee7a 100644
--- a/thirdparty/basis_universal/transcoder/basisu_transcoder.cpp
+++ b/thirdparty/basis_universal/transcoder/basisu_transcoder.cpp
@@ -16867,7 +16867,7 @@ namespace basist
{
m_format = basist::basis_tex_format::cETC1S;
- // 3.10.2: "Whether the image has 1 or 2 slices can be determined from the DFD’s sample count."
+ // 3.10.2: "Whether the image has 1 or 2 slices can be determined from the DFD's sample count."
// If m_has_alpha is true it may be 2-channel RRRG or 4-channel RGBA, but we let the caller deal with that.
m_has_alpha = (m_header.m_dfd_byte_length == 60);