diff options
73 files changed, 1201 insertions, 749 deletions
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index f7915261af..6721ec0953 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -1053,8 +1053,9 @@ void ResourceLoader::clear_thread_load_tasks() { thread_load_mutex.lock(); } - for (KeyValue<String, LoadToken *> &E : user_load_tokens) { - memdelete(E.value); + while (user_load_tokens.begin()) { + // User load tokens remove themselves from the map on destruction. + memdelete(user_load_tokens.begin()->value); } user_load_tokens.clear(); diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index c594f4a9b4..8c54db3c2c 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -165,8 +165,8 @@ ClassDB::APIType ClassDB::get_api_type(const StringName &p_class) { } uint32_t ClassDB::get_api_hash(APIType p_api) { - OBJTYPE_RLOCK; #ifdef DEBUG_METHODS_ENABLED + OBJTYPE_WLOCK; if (api_hashes_cache.has(p_api)) { return api_hashes_cache[p_api]; @@ -175,7 +175,9 @@ uint32_t ClassDB::get_api_hash(APIType p_api) { uint64_t hash = hash_murmur3_one_64(HashMapHasherDefault::hash(VERSION_FULL_CONFIG)); List<StringName> class_list; - ClassDB::get_class_list(&class_list); + for (const KeyValue<StringName, ClassInfo> &E : classes) { + class_list.push_back(E.key); + } // Must be alphabetically sorted for hash to compute. class_list.sort_custom<StringName::AlphCompare>(); @@ -859,8 +861,8 @@ void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_ } void ClassDB::set_method_error_return_values(const StringName &p_class, const StringName &p_method, const Vector<Error> &p_values) { - OBJTYPE_RLOCK; #ifdef DEBUG_METHODS_ENABLED + OBJTYPE_WLOCK; ClassInfo *type = classes.getptr(p_class); ERR_FAIL_NULL(type); @@ -871,6 +873,7 @@ void ClassDB::set_method_error_return_values(const StringName &p_class, const St Vector<Error> ClassDB::get_method_error_return_values(const StringName &p_class, const StringName &p_method) { #ifdef DEBUG_METHODS_ENABLED + OBJTYPE_RLOCK; ClassInfo *type = classes.getptr(p_class); ERR_FAIL_NULL_V(type, Vector<Error>()); @@ -1415,6 +1418,8 @@ void ClassDB::_bind_compatibility(ClassInfo *type, MethodBind *p_method) { } void ClassDB::_bind_method_custom(const StringName &p_class, MethodBind *p_method, bool p_compatibility) { + OBJTYPE_WLOCK; + ClassInfo *type = classes.getptr(p_class); if (!type) { ERR_FAIL_MSG("Couldn't bind custom method '" + p_method->get_name() + "' for instance '" + p_class + "'."); diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h index 5f3a70cad8..00ab1cd6c0 100644 --- a/core/object/script_language_extension.h +++ b/core/object/script_language_extension.h @@ -313,6 +313,9 @@ public: ERR_CONTINUE(!err.has("message")); ScriptError serr; + if (err.has("path")) { + serr.path = err["path"]; + } serr.line = err["line"]; serr.column = err["column"]; serr.message = err["message"]; diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml index d2b2c1fe47..15f6b16439 100644 --- a/doc/classes/Animation.xml +++ b/doc/classes/Animation.xml @@ -257,7 +257,7 @@ <param index="0" name="track_idx" type="int" /> <param index="1" name="to_animation" type="Animation" /> <description> - Adds a new track that is a copy of the given track from [param to_animation]. + Adds a new track to [param to_animation] that is a copy of the given track from this animation. </description> </method> <method name="find_track" qualifiers="const"> diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml index b08e075a23..1b0054ef25 100644 --- a/doc/classes/TabContainer.xml +++ b/doc/classes/TabContainer.xml @@ -243,7 +243,7 @@ <signal name="tab_selected"> <param index="0" name="tab" type="int" /> <description> - Emitted when a tab is selected, even if it is the current tab. + Emitted when a tab is selected via click or script, even if it is the current tab. </description> </signal> </signals> diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index fc08f1cf38..1f10f4b353 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1254,9 +1254,14 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const inst->light_passes.clear(); inst->spot_light_gl_cache.clear(); inst->omni_light_gl_cache.clear(); + uint64_t current_frame = RSG::rasterizer->get_frame_number(); + if (inst->paired_omni_light_count) { for (uint32_t j = 0; j < inst->paired_omni_light_count; j++) { RID light_instance = inst->paired_omni_lights[j]; + if (GLES3::LightStorage::get_singleton()->light_instance_get_render_pass(light_instance) != current_frame) { + continue; + } RID light = GLES3::LightStorage::get_singleton()->light_instance_get_base_light(light_instance); int32_t shadow_id = GLES3::LightStorage::get_singleton()->light_instance_get_shadow_id(light_instance); @@ -1277,6 +1282,9 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const if (inst->paired_spot_light_count) { for (uint32_t j = 0; j < inst->paired_spot_light_count; j++) { RID light_instance = inst->paired_spot_lights[j]; + if (GLES3::LightStorage::get_singleton()->light_instance_get_render_pass(light_instance) != current_frame) { + continue; + } RID light = GLES3::LightStorage::get_singleton()->light_instance_get_base_light(light_instance); int32_t shadow_id = GLES3::LightStorage::get_singleton()->light_instance_get_shadow_id(light_instance); @@ -1712,6 +1720,8 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b r_spot_light_count++; } break; } + + li->last_pass = RSG::rasterizer->get_frame_number(); } if (r_omni_light_count) { diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index ae04b63cfe..3213fa3775 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -200,14 +200,12 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) #else if (surface_version != uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION)) { - RS::_fix_surface_compatibility(new_surface); + RS::get_singleton()->fix_surface_compatibility(new_surface); surface_version = new_surface.format & (uint64_t(RS::ARRAY_FLAG_FORMAT_VERSION_MASK) << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT); - ERR_FAIL_COND_MSG(surface_version != uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION), - "Surface version provided (" + - itos((surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + - ") does not match current version (" + - itos((uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION) >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + - ")"); + ERR_FAIL_COND_MSG(surface_version != RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION, + vformat("Surface version provided (%d) does not match current version (%d).", + (surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK, + (RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK)); } #endif diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index 4d7e08c849..b7b62d78a0 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -2314,7 +2314,9 @@ Rect2i TextureStorage::_render_target_get_sdf_rect(const RenderTarget *rt) const scale = 200; } break; default: { - } + ERR_PRINT("Invalid viewport SDF oversize, defaulting to 100%."); + scale = 100; + } break; } margin = (rt->size * scale / 100) - rt->size; @@ -2391,6 +2393,7 @@ void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) { scale = 25; } break; default: { + ERR_PRINT("Invalid viewport SDF scale, defaulting to 100%."); scale = 100; } break; } diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index 23c1665cad..d6d3e34678 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -42,7 +42,7 @@ float AnimationBezierTrackEdit::_bezier_h_to_pixel(float p_h) { float h = p_h; - h = (h - v_scroll) / v_zoom; + h = (h - timeline_v_scroll) / timeline_v_zoom; h = (get_size().height / 2.0) - h; return h; } @@ -251,7 +251,9 @@ void AnimationBezierTrackEdit::_notification(int p_what) { int right_limit = get_size().width; - int vofs = vsep; + track_v_scroll_max = vsep; + + int vofs = vsep + track_v_scroll; int margin = 0; RBMap<int, Color> subtrack_colors; @@ -328,6 +330,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) { text_buf.draw(get_canvas_item(), string_pos, color); vofs += h + vsep; + track_v_scroll_max += h + vsep; } } @@ -439,6 +442,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) { subtrack_icons[current_track] = track_icons; vofs += text_buf.get_size().y + vsep; + track_v_scroll_max += text_buf.get_size().y + vsep; } } @@ -447,11 +451,11 @@ void AnimationBezierTrackEdit::_notification(int p_what) { { //guides float min_left_scale = font->get_height(font_size) + vsep; - float scale = (min_left_scale * 2) * v_zoom; + float scale = (min_left_scale * 2) * timeline_v_zoom; float step = Math::pow(10.0, Math::round(Math::log(scale / 5.0) / Math::log(10.0))) * 5.0; scale = Math::snapped(scale, step); - while (scale / v_zoom < min_left_scale * 2) { + while (scale / timeline_v_zoom < min_left_scale * 2) { scale += step; } @@ -459,8 +463,8 @@ void AnimationBezierTrackEdit::_notification(int p_what) { int prev_iv = 0; for (int i = font->get_height(font_size); i < get_size().height; i++) { float ofs = get_size().height / 2.0 - i; - ofs *= v_zoom; - ofs += v_scroll; + ofs *= timeline_v_zoom; + ofs += timeline_v_scroll; int iv = int(ofs / scale); if (ofs < 0) { @@ -908,9 +912,9 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { } if (Math::is_finite(minimum_value) && Math::is_finite(maximum_value)) { - v_scroll = (maximum_value + minimum_value) / 2.0; + timeline_v_scroll = (maximum_value + minimum_value) / 2.0; if (maximum_value - minimum_value > CMP_EPSILON) { - v_zoom = (maximum_value - minimum_value) / ((get_size().height - timeline->get_size().height) * 0.9); + timeline_v_zoom = (maximum_value - minimum_value) / ((get_size().height - timeline->get_size().height) * 0.9); } } @@ -1160,7 +1164,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { Array new_point; new_point.resize(5); - float h = (get_size().height / 2.0 - mb->get_position().y) * v_zoom + v_scroll; + float h = (get_size().height / 2.0 - mb->get_position().y) * timeline_v_zoom + timeline_v_scroll; new_point[0] = h; new_point[1] = -0.25; @@ -1393,7 +1397,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { select_single_attempt = IntPair(-1, -1); } - float y = (get_size().height / 2.0 - mm->get_position().y) * v_zoom + v_scroll; + float y = (get_size().height / 2.0 - mm->get_position().y) * timeline_v_zoom + timeline_v_scroll; float x = editor->snap_time(((mm->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value()); if (!read_only) { @@ -1422,7 +1426,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { } if ((moving_handle == 1 || moving_handle == -1) && mm.is_valid()) { - float y = (get_size().height / 2.0 - mm->get_position().y) * v_zoom + v_scroll; + float y = (get_size().height / 2.0 - mm->get_position().y) * timeline_v_zoom + timeline_v_scroll; float x = editor->snap_time((mm->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value(); Vector2 key_pos = Vector2(animation->track_get_key_time(selected_track, moving_handle_key), animation->bezier_track_get_key_value(selected_track, moving_handle_key)); @@ -1438,7 +1442,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { Animation::HandleMode handle_mode = animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key); if (handle_mode == Animation::HANDLE_MODE_BALANCED) { - real_t ratio = timeline->get_zoom_scale() * v_zoom; + real_t ratio = timeline->get_zoom_scale() * timeline_v_zoom; Transform2D xform; xform.set_scale(Vector2(1.0, 1.0 / ratio)); @@ -1455,7 +1459,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { Animation::HandleMode handle_mode = animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key); if (handle_mode == Animation::HANDLE_MODE_BALANCED) { - real_t ratio = timeline->get_zoom_scale() * v_zoom; + real_t ratio = timeline->get_zoom_scale() * timeline_v_zoom; Transform2D xform; xform.set_scale(Vector2(1.0, 1.0 / ratio)); @@ -1475,11 +1479,11 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Move Bezier Points")); if (moving_handle == -1) { - real_t ratio = timeline->get_zoom_scale() * v_zoom; + real_t ratio = timeline->get_zoom_scale() * timeline_v_zoom; undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, moving_handle_left, ratio); undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_in_handle(moving_handle_track, moving_handle_key), ratio); } else if (moving_handle == 1) { - real_t ratio = timeline->get_zoom_scale() * v_zoom; + real_t ratio = timeline->get_zoom_scale() * timeline_v_zoom; undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, moving_handle_right, ratio); undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_out_handle(moving_handle_track, moving_handle_key), ratio); } @@ -1491,22 +1495,34 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { } void AnimationBezierTrackEdit::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) { - v_scroll += p_scroll_vec.y * v_zoom; - v_scroll = CLAMP(v_scroll, -100000, 100000); - timeline->set_value(timeline->get_value() - p_scroll_vec.x / timeline->get_zoom_scale()); - queue_redraw(); + Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid()) { + if (mm->get_position().x > timeline->get_name_limit()) { + timeline_v_scroll += p_scroll_vec.y * timeline_v_zoom; + timeline_v_scroll = CLAMP(timeline_v_scroll, -100000, 100000); + timeline->set_value(timeline->get_value() - p_scroll_vec.x / timeline->get_zoom_scale()); + } else { + track_v_scroll += p_scroll_vec.y; + if (track_v_scroll < -track_v_scroll_max) { + track_v_scroll = -track_v_scroll_max; + } else if (track_v_scroll > 0) { + track_v_scroll = 0; + } + } + queue_redraw(); + } } void AnimationBezierTrackEdit::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) { - const float v_zoom_orig = v_zoom; + const float v_zoom_orig = timeline_v_zoom; Ref<InputEventWithModifiers> iewm = p_event; if (iewm.is_valid() && iewm->is_alt_pressed()) { // Alternate zoom (doesn't affect timeline). - v_zoom = CLAMP(v_zoom * p_zoom_factor, 0.000001, 100000); + timeline_v_zoom = CLAMP(timeline_v_zoom * p_zoom_factor, 0.000001, 100000); } else { timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() / p_zoom_factor); } - v_scroll = v_scroll + (p_origin.y - get_size().y / 2.0) * (v_zoom - v_zoom_orig); + timeline_v_scroll = timeline_v_scroll + (p_origin.y - get_size().y / 2.0) * (timeline_v_zoom - v_zoom_orig); queue_redraw(); } @@ -1517,7 +1533,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) { Array new_point; new_point.resize(5); - float h = (get_size().height / 2.0 - menu_insert_key.y) * v_zoom + v_scroll; + float h = (get_size().height / 2.0 - menu_insert_key.y) * timeline_v_zoom + timeline_v_scroll; new_point[0] = h; new_point[1] = -0.25; diff --git a/editor/animation_bezier_editor.h b/editor/animation_bezier_editor.h index dbc231ccac..4952869943 100644 --- a/editor/animation_bezier_editor.h +++ b/editor/animation_bezier_editor.h @@ -81,8 +81,11 @@ class AnimationBezierTrackEdit : public Control { int solo_track = -1; bool is_filtered = false; - float v_scroll = 0; - float v_zoom = 1; + float track_v_scroll = 0; + float track_v_scroll_max = 0; + + float timeline_v_scroll = 0; + float timeline_v_zoom = 1; PopupMenu *menu = nullptr; diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 0e025b4430..e37035f5eb 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -309,8 +309,10 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String r_item->set_custom_color(0, search_options->get_theme_color(SNAME("disabled_font_color"), EditorStringName(Editor))); } - bool is_deprecated = EditorHelp::get_doc_data()->class_list[p_type].is_deprecated; - bool is_experimental = EditorHelp::get_doc_data()->class_list[p_type].is_experimental; + HashMap<String, DocData::ClassDoc>::Iterator class_doc = EditorHelp::get_doc_data()->class_list.find(p_type); + + bool is_deprecated = (class_doc && class_doc->value.is_deprecated); + bool is_experimental = (class_doc && class_doc->value.is_experimental); if (is_deprecated) { r_item->add_button(0, get_editor_theme_icon("StatusError"), 0, false, TTR("This class is marked as deprecated.")); @@ -330,7 +332,7 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String r_item->set_collapsed(should_collapse); } - const String &description = DTR(EditorHelp::get_doc_data()->class_list[p_type].brief_description); + const String &description = DTR(class_doc ? class_doc->value.brief_description : ""); r_item->set_tooltip_text(0, description); if (p_type_category == TypeCategory::OTHER_TYPE && !script_type) { diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index d6eadf3ab4..0ab6e20b01 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -2360,36 +2360,38 @@ void EditorHelp::_add_text(const String &p_bbcode) { _add_text_to_rt(p_bbcode, class_desc, this, edited_class); } -Thread EditorHelp::thread; +String EditorHelp::doc_version_hash; +bool EditorHelp::doc_gen_first_attempt = true; +bool EditorHelp::doc_gen_use_threads = true; +Thread EditorHelp::gen_thread; void EditorHelp::_wait_for_thread() { - if (thread.is_started()) { - thread.wait_to_finish(); + if (gen_thread.is_started()) { + gen_thread.wait_to_finish(); } } -String EditorHelp::get_cache_full_path() { - return EditorPaths::get_singleton()->get_cache_dir().path_join("editor_doc_cache.res"); +void EditorHelp::_compute_doc_version_hash() { + uint32_t version_hash = Engine::get_singleton()->get_version_info().hash(); + doc_version_hash = vformat("%d/%d/%d/%s", version_hash, ClassDB::get_api_hash(ClassDB::API_CORE), ClassDB::get_api_hash(ClassDB::API_EDITOR), _doc_data_hash); } -static bool first_attempt = true; - -static String _compute_doc_version_hash() { - uint32_t version_hash = Engine::get_singleton()->get_version_info().hash(); - return vformat("%d/%d/%d/%s", version_hash, ClassDB::get_api_hash(ClassDB::API_CORE), ClassDB::get_api_hash(ClassDB::API_EDITOR), _doc_data_hash); +String EditorHelp::get_cache_full_path() { + return EditorPaths::get_singleton()->get_cache_dir().path_join("editor_doc_cache.res"); } void EditorHelp::_load_doc_thread(void *p_udata) { - DEV_ASSERT(first_attempt); + DEV_ASSERT(doc_gen_first_attempt); + Ref<Resource> cache_res = ResourceLoader::load(get_cache_full_path()); - if (cache_res.is_valid() && cache_res->get_meta("version_hash", "") == _compute_doc_version_hash()) { + if (cache_res.is_valid() && cache_res->get_meta("version_hash", "") == doc_version_hash) { Array classes = cache_res->get_meta("classes", Array()); for (int i = 0; i < classes.size(); i++) { doc->add_doc(DocData::ClassDoc::from_dict(classes[i])); } } else { // We have to go back to the main thread to start from scratch. - first_attempt = false; + doc_gen_first_attempt = false; callable_mp_static(&EditorHelp::generate_doc).bind(true).call_deferred(); } } @@ -2401,7 +2403,7 @@ void EditorHelp::_gen_doc_thread(void *p_udata) { Ref<Resource> cache_res; cache_res.instantiate(); - cache_res->set_meta("version_hash", _compute_doc_version_hash()); + cache_res->set_meta("version_hash", doc_version_hash); Array classes; for (const KeyValue<String, DocData::ClassDoc> &E : doc->class_list) { classes.push_back(DocData::ClassDoc::to_dict(E.value)); @@ -2413,8 +2415,6 @@ void EditorHelp::_gen_doc_thread(void *p_udata) { } } -static bool doc_gen_use_threads = true; - void EditorHelp::generate_doc(bool p_use_cache) { OS::get_singleton()->benchmark_begin_measure("EditorHelp::generate_doc"); if (doc_gen_use_threads) { @@ -2422,15 +2422,19 @@ void EditorHelp::generate_doc(bool p_use_cache) { _wait_for_thread(); } - DEV_ASSERT(first_attempt == (doc == nullptr)); + DEV_ASSERT(doc_gen_first_attempt == (doc == nullptr)); if (!doc) { doc = memnew(DocTools); } - if (p_use_cache && first_attempt && FileAccess::exists(get_cache_full_path())) { + if (doc_version_hash.is_empty()) { + _compute_doc_version_hash(); + } + + if (p_use_cache && doc_gen_first_attempt && FileAccess::exists(get_cache_full_path())) { if (doc_gen_use_threads) { - thread.start(_load_doc_thread, nullptr); + gen_thread.start(_load_doc_thread, nullptr); } else { _load_doc_thread(nullptr); } @@ -2441,7 +2445,7 @@ void EditorHelp::generate_doc(bool p_use_cache) { doc->generate(true); if (doc_gen_use_threads) { - thread.start(_gen_doc_thread, nullptr); + gen_thread.start(_gen_doc_thread, nullptr); } else { _gen_doc_thread(nullptr); } diff --git a/editor/editor_help.h b/editor/editor_help.h index 0ca3942e0b..1f813f930c 100644 --- a/editor/editor_help.h +++ b/editor/editor_help.h @@ -187,12 +187,15 @@ class EditorHelp : public VBoxContainer { String _fix_constant(const String &p_constant) const; void _toggle_scripts_pressed(); - static Thread thread; + static String doc_version_hash; + static bool doc_gen_first_attempt; + static bool doc_gen_use_threads; + static Thread gen_thread; static void _wait_for_thread(); static void _load_doc_thread(void *p_udata); static void _gen_doc_thread(void *p_udata); - static void _generate_doc_first_step(); + static void _compute_doc_version_hash(); protected: virtual void _update_theme_item_cache() override; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 30872f0288..7b0bea81d7 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -153,6 +153,7 @@ #include "editor/project_settings_editor.h" #include "editor/register_exporters.h" #include "editor/scene_tree_dock.h" +#include "editor/surface_upgrade_tool.h" #include "editor/window_wrapper.h" #include <stdio.h> @@ -575,6 +576,10 @@ void EditorNode::update_preview_themes(int p_mode) { void EditorNode::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_POSTINITIALIZE: { + EditorHelp::generate_doc(); + } break; + case NOTIFICATION_PROCESS: { if (opening_prev && !confirmation->is_visible()) { opening_prev = false; @@ -4770,21 +4775,15 @@ void EditorNode::_dock_select_input(const Ref<InputEvent> &p_input) { Ref<InputEventMouseButton> mb = me; if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed() && dock_popup_selected_idx != nrect) { - Control *dock = dock_slot[dock_popup_selected_idx]->get_current_tab_control(); - if (dock) { - dock_slot[dock_popup_selected_idx]->remove_child(dock); - } + dock_slot[nrect]->move_tab_from_tab_container(dock_slot[dock_popup_selected_idx], dock_slot[dock_popup_selected_idx]->get_current_tab(), dock_slot[nrect]->get_tab_count()); + if (dock_slot[dock_popup_selected_idx]->get_tab_count() == 0) { dock_slot[dock_popup_selected_idx]->hide(); - } else { dock_slot[dock_popup_selected_idx]->set_current_tab(0); } - dock_slot[nrect]->add_child(dock); dock_popup_selected_idx = nrect; - dock_slot[nrect]->set_current_tab(dock_slot[nrect]->get_tab_count() - 1); - dock_slot[nrect]->set_tab_title(dock_slot[nrect]->get_tab_count() - 1, TTRGET(dock->get_name())); dock_slot[nrect]->show(); dock_select->queue_redraw(); @@ -5507,11 +5506,16 @@ bool EditorNode::ensure_main_scene(bool p_from_native) { void EditorNode::_immediate_dialog_confirmed() { immediate_dialog_confirmed = true; } -bool EditorNode::immediate_confirmation_dialog(const String &p_text, const String &p_ok_text, const String &p_cancel_text) { +bool EditorNode::immediate_confirmation_dialog(const String &p_text, const String &p_ok_text, const String &p_cancel_text, uint32_t p_wrap_width) { ConfirmationDialog *cd = memnew(ConfirmationDialog); cd->set_text(p_text); cd->set_ok_button_text(p_ok_text); cd->set_cancel_button_text(p_cancel_text); + if (p_wrap_width > 0) { + cd->set_autowrap(true); + cd->get_label()->set_custom_minimum_size(Size2(p_wrap_width, 0) * EDSCALE); + } + cd->connect("confirmed", callable_mp(singleton, &EditorNode::_immediate_dialog_confirmed)); singleton->gui_base->add_child(cd); @@ -6761,7 +6765,6 @@ EditorNode::EditorNode() { DisplayServer::get_singleton()->cursor_set_custom_image(Ref<Resource>()); } - EditorHelp::generate_doc(); SceneState::set_disable_placeholders(true); ResourceLoader::clear_translation_remaps(); // Using no remaps if in editor. ResourceLoader::clear_path_remaps(); @@ -8029,6 +8032,8 @@ EditorNode::EditorNode() { String exec = OS::get_singleton()->get_executable_path(); // Save editor executable path for third-party tools. EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "executable_path", exec); + + surface_upgrade_tool = memnew(SurfaceUpgradeTool); } EditorNode::~EditorNode() { @@ -8043,6 +8048,7 @@ EditorNode::~EditorNode() { memdelete(editor_plugins_force_over); memdelete(editor_plugins_force_input_forwarding); memdelete(progress_hb); + memdelete(surface_upgrade_tool); EditorSettings::destroy(); EditorColorMap::finish(); diff --git a/editor/editor_node.h b/editor/editor_node.h index 4e36c19e96..7d85055ac2 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -113,6 +113,7 @@ class ProjectSettingsEditor; class RunSettingsDialog; class SceneImportSettings; class ScriptCreateDialog; +class SurfaceUpgradeTool; class WindowWrapper; class EditorNode : public Node { @@ -493,6 +494,8 @@ private: HashMap<String, Ref<Texture2D>> icon_type_cache; + SurfaceUpgradeTool *surface_upgrade_tool = nullptr; + static EditorBuildCallback build_callbacks[MAX_BUILD_CALLBACKS]; static EditorPluginInitializeCallback plugin_init_callbacks[MAX_INIT_CALLBACKS]; static int build_callback_count; @@ -738,7 +741,7 @@ public: static void add_init_callback(EditorNodeInitCallback p_callback) { _init_callbacks.push_back(p_callback); } static void add_build_callback(EditorBuildCallback p_callback); - static bool immediate_confirmation_dialog(const String &p_text, const String &p_ok_text = TTR("Ok"), const String &p_cancel_text = TTR("Cancel")); + static bool immediate_confirmation_dialog(const String &p_text, const String &p_ok_text = TTR("Ok"), const String &p_cancel_text = TTR("Cancel"), uint32_t p_wrap_width = 0); static void cleanup(); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index bf0c5392c1..2a42224c87 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -2046,12 +2046,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { graphn_sb_panel_selected->set_corner_radius_individual(0, 0, corner_radius * EDSCALE, corner_radius * EDSCALE); graphn_sb_panel_selected->set_expand_margin(SIDE_TOP, 17 * EDSCALE); - const int gn_titlebar_margin_side = 12; - Ref<StyleBoxFlat> graphn_sb_titlebar = make_flat_stylebox(graphnode_bg, gn_titlebar_margin_side, gn_margin_top, gn_titlebar_margin_side, 0, corner_width); + const int gn_titlebar_margin_left = 12; + const int gn_titlebar_margin_right = 4; // The rest is for the close button. + Ref<StyleBoxFlat> graphn_sb_titlebar = make_flat_stylebox(graphnode_bg, gn_titlebar_margin_left, gn_margin_top, gn_titlebar_margin_right, 0, corner_width); graphn_sb_titlebar->set_expand_margin(SIDE_TOP, 2 * EDSCALE); graphn_sb_titlebar->set_corner_radius_individual(corner_radius * EDSCALE, corner_radius * EDSCALE, 0, 0); - Ref<StyleBoxFlat> graphn_sb_titlebar_selected = make_flat_stylebox(graph_node_selected_border_color, gn_titlebar_margin_side, gn_margin_top, gn_titlebar_margin_side, 0, corner_width); + Ref<StyleBoxFlat> graphn_sb_titlebar_selected = make_flat_stylebox(graph_node_selected_border_color, gn_titlebar_margin_left, gn_margin_top, gn_titlebar_margin_right, 0, corner_width); graphn_sb_titlebar_selected->set_corner_radius_individual(corner_radius * EDSCALE, corner_radius * EDSCALE, 0, 0); graphn_sb_titlebar_selected->set_expand_margin(SIDE_TOP, 2 * EDSCALE); Ref<StyleBoxEmpty> graphn_sb_slot = make_empty_stylebox(12, 0, 12, 0); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index a1a0f68778..a491a9b214 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -2903,7 +2903,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str p_popup->add_icon_item(get_editor_theme_icon(SNAME("Load")), TTR("Open Scene"), FILE_OPEN); p_popup->add_icon_item(get_editor_theme_icon(SNAME("CreateNewSceneFrom")), TTR("New Inherited Scene"), FILE_INHERIT); if (GLOBAL_GET("application/run/main_scene") != filenames[0]) { - p_popup->add_icon_item(get_editor_theme_icon(SNAME("PlayScene")), TTR("Set As Main Scene"), FILE_MAIN_SCENE); + p_popup->add_icon_item(get_editor_theme_icon(SNAME("PlayScene")), TTR("Set as Main Scene"), FILE_MAIN_SCENE); } } else { p_popup->add_icon_item(get_editor_theme_icon(SNAME("Load")), TTR("Open Scenes"), FILE_OPEN); diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index 97b0a1b4ca..646831ca24 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -226,11 +226,6 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ bool generate_tangents = p_generate_tangents; Vector3 scale_mesh = p_scale_mesh; Vector3 offset_mesh = p_offset_mesh; - uint64_t mesh_flags = RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES; - - if (p_disable_compression) { - mesh_flags = 0; - } Vector<Vector3> vertices; Vector<Vector3> normals; @@ -374,6 +369,11 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ } } } else if (/*l.begins_with("g ") ||*/ l.begins_with("usemtl ") || (l.begins_with("o ") || f->eof_reached())) { //commit group to mesh + uint64_t mesh_flags = RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES; + + if (p_disable_compression) { + mesh_flags = 0; + } //groups are too annoying if (surf_tool->get_vertex_array().size()) { //another group going on, commit it @@ -385,7 +385,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ surf_tool->generate_tangents(); } else { // We need tangents in order to compress vertex data. So disable if tangents aren't generated. - mesh_flags &= ~RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES; + mesh_flags = 0; } surf_tool->index(); @@ -517,7 +517,7 @@ String ResourceImporterOBJ::get_importer_name() const { } String ResourceImporterOBJ::get_visible_name() const { - return "OBJ As Mesh"; + return "OBJ as Mesh"; } void ResourceImporterOBJ::get_recognized_extensions(List<String> *p_extensions) const { diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 33c2b0e238..f9c989dc20 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -2371,7 +2371,7 @@ Node *ResourceImporterScene::pre_import(const String &p_source_file, const HashM Error err = OK; HashMap<StringName, Variant> options_dupe = p_options; - Node *scene = importer->import_scene(p_source_file, EditorSceneFormatImporter::IMPORT_ANIMATION | EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS, options_dupe, nullptr, &err); + Node *scene = importer->import_scene(p_source_file, EditorSceneFormatImporter::IMPORT_ANIMATION | EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS | EditorSceneFormatImporter::IMPORT_FORCE_DISABLE_MESH_COMPRESSION, options_dupe, nullptr, &err); if (!scene || err != OK) { return nullptr; } diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 772957bc55..4a17fd89ff 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -170,7 +170,15 @@ void AnimationNodeBlendTreeEditor::update_graph() { name->connect("text_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_rename_lineedit_changed), CONNECT_DEFERRED); base = 1; agnode->set_closable(true); - node->connect("delete_request", callable_mp(this, &AnimationNodeBlendTreeEditor::_delete_node_request).bind(E), CONNECT_DEFERRED); + + if (!read_only) { + Button *delete_button = memnew(Button); + delete_button->set_flat(true); + delete_button->set_focus_mode(FOCUS_NONE); + delete_button->set_icon(get_editor_theme_icon(SNAME("Close"))); + delete_button->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_delete_node_request).bind(E), CONNECT_DEFERRED); + node->get_titlebar_hbox()->add_child(delete_button); + } } for (int i = 0; i < agnode->get_input_count(); i++) { diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 4e7db8cb07..a3fc6aa5f7 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -836,6 +836,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() { item->set_custom_color(0, disabled_color); } + tile_data_editors_tree->update_minimum_size(); + #undef ADD_TILE_DATA_EDITOR_GROUP #undef ADD_TILE_DATA_EDITOR diff --git a/editor/scene_create_dialog.cpp b/editor/scene_create_dialog.cpp index d6cb36013f..60ad7e5968 100644 --- a/editor/scene_create_dialog.cpp +++ b/editor/scene_create_dialog.cpp @@ -47,7 +47,6 @@ void SceneCreateDialog::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { select_node_button->set_icon(get_editor_theme_icon(SNAME("ClassList"))); node_type_2d->set_icon(get_editor_theme_icon(SNAME("Node2D"))); @@ -55,6 +54,10 @@ void SceneCreateDialog::_notification(int p_what) { node_type_gui->set_icon(get_editor_theme_icon(SNAME("Control"))); node_type_other->add_theme_icon_override(SNAME("icon"), get_editor_theme_icon(SNAME("Node"))); } break; + + case NOTIFICATION_READY: { + select_node_dialog->select_base(); + } break; } } @@ -180,7 +183,6 @@ SceneCreateDialog::SceneCreateDialog() { select_node_dialog = memnew(CreateDialog); add_child(select_node_dialog); select_node_dialog->set_base_type("Node"); - select_node_dialog->select_base(); select_node_dialog->connect("create", callable_mp(this, &SceneCreateDialog::on_type_picked)); VBoxContainer *main_vb = memnew(VBoxContainer); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index d1e2ba0fe0..0d106bf842 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -29,6 +29,7 @@ /**************************************************************************/ #include "scene_tree_dock.h" +#include "node_dock.h" #include "core/config/project_settings.h" #include "core/input/input.h" @@ -1040,7 +1041,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { // Fire confirmation dialog when children are editable. if (editable && !placeholder) { - placeholder_editable_instance_remove_dialog->set_text(TTR("Enabling \"Load As Placeholder\" will disable \"Editable Children\" and cause all properties of the node to be reverted to their default.")); + placeholder_editable_instance_remove_dialog->set_text(TTR("Enabling \"Load as Placeholder\" will disable \"Editable Children\" and cause all properties of the node to be reverted to their default.")); placeholder_editable_instance_remove_dialog->popup_centered(); break; } @@ -1081,6 +1082,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { undo_redo->add_do_method(node, "set_scene_file_path", ""); undo_redo->add_undo_method(node, "set_scene_file_path", node->get_scene_file_path()); _node_replace_owner(node, node, root); + _node_strip_signal_inheritance(node); + NodeDock::get_singleton()->set_node(node); // Refresh. undo_redo->add_do_method(scene_tree, "update_tree"); undo_redo->add_undo_method(scene_tree, "update_tree"); undo_redo->commit_action(); @@ -1479,6 +1482,19 @@ void SceneTreeDock::_node_replace_owner(Node *p_base, Node *p_node, Node *p_root } } +void SceneTreeDock::_node_strip_signal_inheritance(Node *p_node) { + List<Object::Connection> conns; + p_node->get_all_signal_connections(&conns); + + for (Object::Connection conn : conns) { + conn.signal.disconnect(conn.callable); + conn.signal.connect(conn.callable, conn.flags & ~CONNECT_INHERITED); + } + for (int i = 0; i < p_node->get_child_count(); i++) { + _node_strip_signal_inheritance(p_node->get_child(i)); + } +} + void SceneTreeDock::_load_request(const String &p_path) { EditorNode::get_singleton()->open_request(p_path); _local_tree_selected(); @@ -1550,6 +1566,14 @@ void SceneTreeDock::_fill_path_renames(Vector<StringName> base_path, Vector<Stri } bool SceneTreeDock::_has_tracks_to_delete(Node *p_node, List<Node *> &p_to_delete) const { + // Skip if this node will be deleted. + for (const Node *F : p_to_delete) { + if (F == p_node || F->is_ancestor_of(p_node)) { + return false; + } + } + + // This is an AnimationPlayer that survives the deletion. AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node); if (ap) { Node *root = ap->get_node(ap->get_root_node()); @@ -1578,11 +1602,13 @@ bool SceneTreeDock::_has_tracks_to_delete(Node *p_node, List<Node *> &p_to_delet } } + // Recursively check child nodes. for (int i = 0; i < p_node->get_child_count(); i++) { if (_has_tracks_to_delete(p_node->get_child(i), p_to_delete)) { return true; } } + return false; } @@ -3149,13 +3175,13 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { bool placeholder = selection[0]->get_scene_instance_load_placeholder(); if (profile_allow_editing) { menu->add_check_item(TTR("Editable Children"), TOOL_SCENE_EDITABLE_CHILDREN); - menu->add_check_item(TTR("Load As Placeholder"), TOOL_SCENE_USE_PLACEHOLDER); + menu->add_check_item(TTR("Load as Placeholder"), TOOL_SCENE_USE_PLACEHOLDER); menu->add_item(TTR("Make Local"), TOOL_SCENE_MAKE_LOCAL); } menu->add_icon_item(get_editor_theme_icon(SNAME("Load")), TTR("Open in Editor"), TOOL_SCENE_OPEN); if (profile_allow_editing) { menu->set_item_checked(menu->get_item_idx_from_text(TTR("Editable Children")), editable); - menu->set_item_checked(menu->get_item_idx_from_text(TTR("Load As Placeholder")), placeholder); + menu->set_item_checked(menu->get_item_idx_from_text(TTR("Load as Placeholder")), placeholder); } } } diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index 3f02d2881d..be0e6e1158 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -201,6 +201,7 @@ class SceneTreeDock : public VBoxContainer { }; void _node_replace_owner(Node *p_base, Node *p_node, Node *p_root, ReplaceOwnerMode p_mode = MODE_BIDI); + void _node_strip_signal_inheritance(Node *p_node); void _load_request(const String &p_path); void _script_open_request(const Ref<Script> &p_script); void _push_item(Object *p_object); diff --git a/editor/surface_upgrade_tool.cpp b/editor/surface_upgrade_tool.cpp new file mode 100644 index 0000000000..26ff6e55a0 --- /dev/null +++ b/editor/surface_upgrade_tool.cpp @@ -0,0 +1,90 @@ +/**************************************************************************/ +/* surface_upgrade_tool.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "surface_upgrade_tool.h" + +#include "editor/editor_file_system.h" +#include "editor/editor_node.h" +#include "servers/rendering_server.h" + +void SurfaceUpgradeTool::_add_files(EditorFileSystemDirectory *p_dir, HashSet<String> &r_paths, PackedStringArray &r_files) { + for (int i = 0; i < p_dir->get_subdir_count(); i++) { + _add_files(p_dir->get_subdir(i), r_paths, r_files); + } + + for (int i = 0; i < p_dir->get_file_count(); i++) { + if (p_dir->get_file_type(i) == "Mesh" || + p_dir->get_file_type(i) == "ArrayMesh" || + p_dir->get_file_type(i) == "PackedScene") { + if (FileAccess::exists(p_dir->get_file_path(i) + ".import")) { + r_files.push_back(p_dir->get_file_path(i)); + } else { + r_paths.insert(p_dir->get_file_path(i)); + } + } + } +} + +void SurfaceUpgradeTool::upgrade_all_meshes() { + // Update all meshes here. + HashSet<String> paths; + PackedStringArray files_to_import; + _add_files(EditorFileSystem::get_singleton()->get_filesystem(), paths, files_to_import); + + EditorProgress ep("Re-saving all scenes and meshes", TTR("Upgrading All Meshes in Project"), paths.size()); + + ep.step(TTR("Re-importing meshes"), 0); + EditorFileSystem::get_singleton()->reimport_files(files_to_import); + + uint32_t step = 1; + for (const String &file : paths) { + Ref<Resource> res = ResourceLoader::load(file); + ep.step(TTR("Attempting to re-save ") + file, step++); + if (res.is_valid()) { + // Ignore things that fail to load. + ResourceSaver::save(res); + } + } +} + +void SurfaceUpgradeTool::_show_popup() { + RS::get_singleton()->set_surface_upgrade_callback(nullptr); + bool accepted = EditorNode::immediate_confirmation_dialog(TTR("This project uses meshes with an outdated mesh format from previous Godot versions. The engine needs to update the format in order to use those meshes.\n\nPress 'Upgrade & Re-save' to have the engine scan the project folder and automatically update and re-save all meshes and scenes. This update may take a few minutes. Upgrading will make the meshes incompatible with previous versions of Godot.\n\nPress 'Upgrade Only' to continue opening the scene as normal. The engine will update each mesh in memory, but the update will not be saved. Choosing this option will lead to slower load times every time this project is loaded."), TTR("Upgrade & Re-save"), TTR("Upgrade Only"), 500); + if (accepted) { + RS::get_singleton()->set_warn_on_surface_upgrade(false); + upgrade_all_meshes(); + } +} + +SurfaceUpgradeTool::SurfaceUpgradeTool() { + RS::get_singleton()->set_surface_upgrade_callback(_show_popup); +} + +SurfaceUpgradeTool::~SurfaceUpgradeTool() {} diff --git a/editor/surface_upgrade_tool.h b/editor/surface_upgrade_tool.h new file mode 100644 index 0000000000..fa052200d8 --- /dev/null +++ b/editor/surface_upgrade_tool.h @@ -0,0 +1,49 @@ +/**************************************************************************/ +/* surface_upgrade_tool.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef SURFACE_UPGRADE_TOOL_H +#define SURFACE_UPGRADE_TOOL_H + +#include "scene/main/node.h" + +class EditorFileSystemDirectory; + +class SurfaceUpgradeTool { + static void upgrade_all_meshes(); + + static void _show_popup(); + static void _add_files(EditorFileSystemDirectory *p_dir, HashSet<String> &r_paths, PackedStringArray &r_files); + +public: + SurfaceUpgradeTool(); + ~SurfaceUpgradeTool(); +}; + +#endif // SURFACE_UPGRADE_TOOL_H diff --git a/main/main.cpp b/main/main.cpp index c09b437757..dff661d207 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1960,21 +1960,31 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } window_mode = (DisplayServer::WindowMode)(GLOBAL_GET("display/window/size/mode").operator int()); int initial_position_type = GLOBAL_GET("display/window/size/initial_position_type").operator int(); - if (initial_position_type == 0) { + if (initial_position_type == 0) { // Absolute. if (!init_use_custom_pos) { init_custom_pos = GLOBAL_GET("display/window/size/initial_position").operator Vector2i(); init_use_custom_pos = true; } - } else if (initial_position_type == 1) { + } else if (initial_position_type == 1) { // Center of Primary Screen. if (!init_use_custom_screen) { init_screen = DisplayServer::SCREEN_PRIMARY; init_use_custom_screen = true; } - } else if (initial_position_type == 2) { + } else if (initial_position_type == 2) { // Center of Other Screen. if (!init_use_custom_screen) { init_screen = GLOBAL_GET("display/window/size/initial_screen").operator int(); init_use_custom_screen = true; } + } else if (initial_position_type == 3) { // Center of Screen With Mouse Pointer. + if (!init_use_custom_screen) { + init_screen = DisplayServer::SCREEN_WITH_MOUSE_FOCUS; + init_use_custom_screen = true; + } + } else if (initial_position_type == 4) { // Center of Screen With Keyboard Focus. + if (!init_use_custom_screen) { + init_screen = DisplayServer::SCREEN_WITH_KEYBOARD_FOCUS; + init_use_custom_screen = true; + } } } diff --git a/modules/gltf/editor/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp index b63a938e64..ae2bd1f580 100644 --- a/modules/gltf/editor/editor_scene_importer_gltf.cpp +++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp @@ -77,7 +77,7 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t void EditorSceneFormatImporterGLTF::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) { - r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed As Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), GLTFState::HANDLE_BINARY_EXTRACT_TEXTURES)); + r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "gltf/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), GLTFState::HANDLE_BINARY_EXTRACT_TEXTURES)); } #endif // TOOLS_ENABLED diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp index c0ec004fd6..766fe41257 100644 --- a/modules/gltf/gltf_state.cpp +++ b/modules/gltf/gltf_state.cpp @@ -124,7 +124,7 @@ void GLTFState::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "skeletons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeletons", "get_skeletons"); // Vector<Ref<GLTFSkeleton>> ADD_PROPERTY(PropertyInfo(Variant::BOOL, "create_animations"), "set_create_animations", "get_create_animations"); // bool ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_animations", "get_animations"); // Vector<Ref<GLTFAnimation>> - ADD_PROPERTY(PropertyInfo(Variant::INT, "handle_binary_image", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed As Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_handle_binary_image", "get_handle_binary_image"); // enum + ADD_PROPERTY(PropertyInfo(Variant::INT, "handle_binary_image", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_handle_binary_image", "get_handle_binary_image"); // enum BIND_CONSTANT(HANDLE_BINARY_DISCARD_TEXTURES); BIND_CONSTANT(HANDLE_BINARY_EXTRACT_TEXTURES); diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs index 7b1d5c228a..1d17f3d4f5 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs @@ -1,5 +1,7 @@ using System; +using System.Linq; using Microsoft.Build.Construction; +using Microsoft.Build.Locator; namespace GodotTools.ProjectEditor { @@ -19,15 +21,18 @@ namespace GodotTools.ProjectEditor public static class ProjectUtils { - public static void MSBuildLocatorRegisterDefaults(out Version version, out string path) + public static void MSBuildLocatorRegisterLatest(out Version version, out string path) { - var instance = Microsoft.Build.Locator.MSBuildLocator.RegisterDefaults(); + var instance = MSBuildLocator.QueryVisualStudioInstances() + .OrderByDescending(x => x.Version) + .First(); + MSBuildLocator.RegisterInstance(instance); version = instance.Version; path = instance.MSBuildPath; } public static void MSBuildLocatorRegisterMSBuildPath(string msbuildPath) - => Microsoft.Build.Locator.MSBuildLocator.RegisterMSBuildPath(msbuildPath); + => MSBuildLocator.RegisterMSBuildPath(msbuildPath); public static MSBuildProject Open(string path) { diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index a00c812c79..413f6f0029 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -456,7 +456,7 @@ namespace GodotTools var dotNetSdkSearchVersion = Environment.Version; // First we try to find the .NET Sdk ourselves to make sure we get the - // correct version first (`RegisterDefaults` always picks the latest). + // correct version first, otherwise pick the latest. if (DotNetFinder.TryFindDotNetSdk(dotNetSdkSearchVersion, out var sdkVersion, out string sdkPath)) { if (Godot.OS.IsStdOutVerbose()) @@ -468,7 +468,7 @@ namespace GodotTools { try { - ProjectUtils.MSBuildLocatorRegisterDefaults(out sdkVersion, out sdkPath); + ProjectUtils.MSBuildLocatorRegisterLatest(out sdkVersion, out sdkPath); if (Godot.OS.IsStdOutVerbose()) Console.WriteLine($"Found .NET Sdk version '{sdkVersion}': {sdkPath}"); } diff --git a/modules/navigation/nav_mesh_generator_3d.cpp b/modules/navigation/nav_mesh_generator_3d.cpp index 5de1c4cba9..8719801c72 100644 --- a/modules/navigation/nav_mesh_generator_3d.cpp +++ b/modules/navigation/nav_mesh_generator_3d.cpp @@ -384,33 +384,23 @@ void NavMeshGenerator3D::generator_parse_staticbody3d_node(const Ref<NavigationM const Vector<real_t> &map_data = heightmap_shape->get_map_data(); Vector2 heightmap_gridsize(heightmap_width - 1, heightmap_depth - 1); - Vector2 start = heightmap_gridsize * -0.5; + Vector3 start = Vector3(heightmap_gridsize.x, 0, heightmap_gridsize.y) * -0.5; Vector<Vector3> vertex_array; vertex_array.resize((heightmap_depth - 1) * (heightmap_width - 1) * 6); - int map_data_current_index = 0; - - for (int d = 0; d < heightmap_depth; d++) { - for (int w = 0; w < heightmap_width; w++) { - if (map_data_current_index + 1 + heightmap_depth < map_data.size()) { - float top_left_height = map_data[map_data_current_index]; - float top_right_height = map_data[map_data_current_index + 1]; - float bottom_left_height = map_data[map_data_current_index + heightmap_depth]; - float bottom_right_height = map_data[map_data_current_index + 1 + heightmap_depth]; - - Vector3 top_left = Vector3(start.x + w, top_left_height, start.y + d); - Vector3 top_right = Vector3(start.x + w + 1.0, top_right_height, start.y + d); - Vector3 bottom_left = Vector3(start.x + w, bottom_left_height, start.y + d + 1.0); - Vector3 bottom_right = Vector3(start.x + w + 1.0, bottom_right_height, start.y + d + 1.0); - - vertex_array.push_back(top_right); - vertex_array.push_back(bottom_left); - vertex_array.push_back(top_left); - vertex_array.push_back(top_right); - vertex_array.push_back(bottom_right); - vertex_array.push_back(bottom_left); - } - map_data_current_index += 1; + Vector3 *vertex_array_ptrw = vertex_array.ptrw(); + const real_t *map_data_ptr = map_data.ptr(); + int vertex_index = 0; + + for (int d = 0; d < heightmap_depth - 1; d++) { + for (int w = 0; w < heightmap_width - 1; w++) { + vertex_array_ptrw[vertex_index] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + w], d); + vertex_array_ptrw[vertex_index + 1] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + w + 1], d); + vertex_array_ptrw[vertex_index + 2] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + heightmap_width + w], d + 1); + vertex_array_ptrw[vertex_index + 3] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + w + 1], d); + vertex_array_ptrw[vertex_index + 4] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + heightmap_width + w + 1], d + 1); + vertex_array_ptrw[vertex_index + 5] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + heightmap_width + w], d + 1); + vertex_index += 6; } } if (vertex_array.size() > 0) { @@ -540,33 +530,23 @@ void NavMeshGenerator3D::generator_parse_gridmap_node(const Ref<NavigationMesh> const Vector<real_t> &map_data = dict["heights"]; Vector2 heightmap_gridsize(heightmap_width - 1, heightmap_depth - 1); - Vector2 start = heightmap_gridsize * -0.5; + Vector3 start = Vector3(heightmap_gridsize.x, 0, heightmap_gridsize.y) * -0.5; Vector<Vector3> vertex_array; vertex_array.resize((heightmap_depth - 1) * (heightmap_width - 1) * 6); - int map_data_current_index = 0; - - for (int d = 0; d < heightmap_depth; d++) { - for (int w = 0; w < heightmap_width; w++) { - if (map_data_current_index + 1 + heightmap_depth < map_data.size()) { - float top_left_height = map_data[map_data_current_index]; - float top_right_height = map_data[map_data_current_index + 1]; - float bottom_left_height = map_data[map_data_current_index + heightmap_depth]; - float bottom_right_height = map_data[map_data_current_index + 1 + heightmap_depth]; - - Vector3 top_left = Vector3(start.x + w, top_left_height, start.y + d); - Vector3 top_right = Vector3(start.x + w + 1.0, top_right_height, start.y + d); - Vector3 bottom_left = Vector3(start.x + w, bottom_left_height, start.y + d + 1.0); - Vector3 bottom_right = Vector3(start.x + w + 1.0, bottom_right_height, start.y + d + 1.0); - - vertex_array.push_back(top_right); - vertex_array.push_back(bottom_left); - vertex_array.push_back(top_left); - vertex_array.push_back(top_right); - vertex_array.push_back(bottom_right); - vertex_array.push_back(bottom_left); - } - map_data_current_index += 1; + Vector3 *vertex_array_ptrw = vertex_array.ptrw(); + const real_t *map_data_ptr = map_data.ptr(); + int vertex_index = 0; + + for (int d = 0; d < heightmap_depth - 1; d++) { + for (int w = 0; w < heightmap_width - 1; w++) { + vertex_array_ptrw[vertex_index] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + w], d); + vertex_array_ptrw[vertex_index + 1] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + w + 1], d); + vertex_array_ptrw[vertex_index + 2] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + heightmap_width + w], d + 1); + vertex_array_ptrw[vertex_index + 3] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + w + 1], d); + vertex_array_ptrw[vertex_index + 4] = start + Vector3(w + 1, map_data_ptr[(heightmap_width * d) + heightmap_width + w + 1], d + 1); + vertex_array_ptrw[vertex_index + 5] = start + Vector3(w, map_data_ptr[(heightmap_width * d) + heightmap_width + w], d + 1); + vertex_index += 6; } } if (vertex_array.size() > 0) { diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 16046ef053..8987a491cb 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -338,6 +338,7 @@ _FORCE_INLINE_ bool is_connected_to_prev(char32_t p_chr, char32_t p_pchr) { /*************************************************************************/ bool TextServerAdvanced::icu_data_loaded = false; +PackedByteArray TextServerAdvanced::icu_data; bool TextServerAdvanced::_has_feature(Feature p_feature) const { switch (p_feature) { @@ -438,7 +439,7 @@ bool TextServerAdvanced::_load_support_data(const String &p_filename) { return false; } uint64_t len = f->get_length(); - PackedByteArray icu_data = f->get_buffer(len); + icu_data = f->get_buffer(len); UErrorCode err = U_ZERO_ERROR; udata_setCommonData(icu_data.ptr(), &err); @@ -476,10 +477,10 @@ bool TextServerAdvanced::_save_support_data(const String &p_filename) const { return false; } - PackedByteArray icu_data; - icu_data.resize(U_ICUDATA_SIZE); - memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE); - f->store_buffer(icu_data); + PackedByteArray icu_data_static; + icu_data_static.resize(U_ICUDATA_SIZE); + memcpy(icu_data_static.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE); + f->store_buffer(icu_data_static); return true; #else diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index f1932d9c50..6ce2692fd3 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -158,6 +158,7 @@ class TextServerAdvanced : public TextServerExtension { // ICU support data. static bool icu_data_loaded; + static PackedByteArray icu_data; mutable USet *allowed = nullptr; mutable USpoofChecker *sc_spoof = nullptr; mutable USpoofChecker *sc_conf = nullptr; diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 445a6ea6ea..dd5ab46bd7 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -310,9 +310,9 @@ void DisplayServerAndroid::window_set_drop_files_callback(const Callable &p_call void DisplayServerAndroid::_window_callback(const Callable &p_callable, const Variant &p_arg, bool p_deferred) const { if (!p_callable.is_null()) { if (p_deferred) { - p_callable.call(p_arg); - } else { p_callable.call_deferred(p_arg); + } else { + p_callable.call(p_arg); } } } diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 0a80467b6b..afc5748ac5 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -43,7 +43,7 @@ void AudioStreamPlayer2D::_notification(int p_what) { if (autoplay && !Engine::get_singleton()->is_editor_hint()) { play(); } - set_stream_paused(false); + set_stream_paused(!can_process()); } break; case NOTIFICATION_EXIT_TREE: { diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 9f99b5ecbd..3971e615a1 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -245,7 +245,7 @@ void AudioStreamPlayer3D::_notification(int p_what) { if (autoplay && !Engine::get_singleton()->is_editor_hint()) { play(); } - set_stream_paused(false); + set_stream_paused(!can_process()); } break; case NOTIFICATION_EXIT_TREE: { diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp index 7f6dfd0ab8..f3c986f9b3 100644 --- a/scene/audio/audio_stream_player.cpp +++ b/scene/audio/audio_stream_player.cpp @@ -40,7 +40,7 @@ void AudioStreamPlayer::_notification(int p_what) { if (autoplay && !Engine::get_singleton()->is_editor_hint()) { play(); } - set_stream_paused(false); + set_stream_paused(!can_process()); } break; case NOTIFICATION_INTERNAL_PROCESS: { diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp index 4b097412d6..79cd1056dd 100644 --- a/scene/debugger/scene_debugger.cpp +++ b/scene/debugger/scene_debugger.cpp @@ -336,6 +336,12 @@ SceneDebuggerObject::SceneDebuggerObject(ObjectID p_id) { } if (Node *node = Object::cast_to<Node>(obj)) { + // For debugging multiplayer. + { + PropertyInfo pi(Variant::INT, String("Node/multiplayer_authority"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY); + properties.push_back(SceneDebuggerProperty(pi, node->get_multiplayer_authority())); + } + // Add specialized NodePath info (if inside tree). if (node->is_inside_tree()) { PropertyInfo pi(Variant::NODE_PATH, String("Node/path")); diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index 8af73deefb..29e6d3d10d 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -321,7 +321,6 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) { } void TabBar::_shape(int p_tab) { - tabs.write[p_tab].xl_text = atr(tabs[p_tab].text); tabs.write[p_tab].text_buf->clear(); tabs.write[p_tab].text_buf->set_width(-1); if (tabs[p_tab].text_direction == Control::TEXT_DIRECTION_INHERITED) { @@ -330,7 +329,7 @@ void TabBar::_shape(int p_tab) { tabs.write[p_tab].text_buf->set_direction((TextServer::Direction)tabs[p_tab].text_direction); } - tabs.write[p_tab].text_buf->add_string(tabs[p_tab].xl_text, theme_cache.font, theme_cache.font_size, tabs[p_tab].language); + tabs.write[p_tab].text_buf->add_string(atr(tabs[p_tab].text), theme_cache.font, theme_cache.font_size, tabs[p_tab].language); } void TabBar::_notification(int p_what) { @@ -1118,7 +1117,26 @@ Variant TabBar::get_drag_data(const Point2 &p_point) { if (!drag_to_rearrange_enabled) { return Control::get_drag_data(p_point); // Allow stuff like TabContainer to override it. } + return _handle_get_drag_data("tab_bar_tab", p_point); +} + +bool TabBar::can_drop_data(const Point2 &p_point, const Variant &p_data) const { + if (!drag_to_rearrange_enabled) { + return Control::can_drop_data(p_point, p_data); // Allow stuff like TabContainer to override it. + } + return _handle_can_drop_data("tab_bar_tab", p_point, p_data); +} + +void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) { + if (!drag_to_rearrange_enabled) { + Control::drop_data(p_point, p_data); // Allow stuff like TabContainer to override it. + return; + } + _handle_drop_data("tab_bar_tab", p_point, p_data, callable_mp(this, &TabBar::move_tab), callable_mp(this, &TabBar::_move_tab_from)); +} + +Variant TabBar::_handle_get_drag_data(const String &p_type, const Point2 &p_point) { int tab_over = get_tab_idx_at_point(p_point); if (tab_over < 0) { return Variant(); @@ -1138,30 +1156,26 @@ Variant TabBar::get_drag_data(const Point2 &p_point) { drag_preview->add_child(tf); } - Label *label = memnew(Label(tabs[tab_over].xl_text)); + Label *label = memnew(Label(get_tab_title(tab_over))); drag_preview->add_child(label); set_drag_preview(drag_preview); Dictionary drag_data; - drag_data["type"] = "tab_element"; - drag_data["tab_element"] = tab_over; + drag_data["type"] = p_type; + drag_data["tab_index"] = tab_over; drag_data["from_path"] = get_path(); return drag_data; } -bool TabBar::can_drop_data(const Point2 &p_point, const Variant &p_data) const { - if (!drag_to_rearrange_enabled) { - return Control::can_drop_data(p_point, p_data); // Allow stuff like TabContainer to override it. - } - +bool TabBar::_handle_can_drop_data(const String &p_type, const Point2 &p_point, const Variant &p_data) const { Dictionary d = p_data; if (!d.has("type")) { return false; } - if (String(d["type"]) == "tab_element") { + if (String(d["type"]) == p_type) { NodePath from_path = d["from_path"]; NodePath to_path = get_path(); if (from_path == to_path) { @@ -1179,19 +1193,14 @@ bool TabBar::can_drop_data(const Point2 &p_point, const Variant &p_data) const { return false; } -void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) { - if (!drag_to_rearrange_enabled) { - Control::drop_data(p_point, p_data); // Allow stuff like TabContainer to override it. - return; - } - +void TabBar::_handle_drop_data(const String &p_type, const Point2 &p_point, const Variant &p_data, const Callable &p_move_tab_callback, const Callable &p_move_tab_from_other_callback) { Dictionary d = p_data; if (!d.has("type")) { return; } - if (String(d["type"]) == "tab_element") { - int tab_from_id = d["tab_element"]; + if (String(d["type"]) == p_type) { + int tab_from_id = d["tab_index"]; int hover_now = get_tab_idx_at_point(p_point); NodePath from_path = d["from_path"]; NodePath to_path = get_path(); @@ -1216,7 +1225,7 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) { hover_now = is_layout_rtl() ^ (p_point.x < x) ? 0 : get_tab_count() - 1; } - move_tab(tab_from_id, hover_now); + p_move_tab_callback.call(tab_from_id, hover_now); if (!is_tab_disabled(hover_now)) { emit_signal(SNAME("active_tab_rearranged"), hover_now); set_current_tab(hover_now); @@ -1242,35 +1251,42 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) { hover_now = tabs.is_empty() || (is_layout_rtl() ^ (p_point.x < get_tab_rect(0).position.x)) ? 0 : get_tab_count(); } - Tab moving_tab = from_tabs->tabs[tab_from_id]; - from_tabs->remove_tab(tab_from_id); - tabs.insert(hover_now, moving_tab); - - if (tabs.size() > 1) { - if (current >= hover_now) { - current++; - } - if (previous >= hover_now) { - previous++; - } - } + p_move_tab_from_other_callback.call(from_tabs, tab_from_id, hover_now); + } + } + } +} - if (!is_tab_disabled(hover_now)) { - set_current_tab(hover_now); - } else { - _update_cache(); - queue_redraw(); - } +void TabBar::_move_tab_from(TabBar *p_from_tabbar, int p_from_index, int p_to_index) { + Tab moving_tab = p_from_tabbar->tabs[p_from_index]; + p_from_tabbar->remove_tab(p_from_index); + tabs.insert(p_to_index, moving_tab); - update_minimum_size(); + if (tabs.size() > 1) { + if (current >= p_to_index) { + current++; + } + if (previous >= p_to_index) { + previous++; + } + } - if (tabs.size() == 1) { - emit_signal(SNAME("tab_selected"), 0); - emit_signal(SNAME("tab_changed"), 0); - } - } + if (!is_tab_disabled(p_to_index)) { + set_current_tab(p_to_index); + if (tabs.size() == 1) { + _update_cache(); + queue_redraw(); + emit_signal(SNAME("tab_changed"), 0); + } + } else { + _update_cache(); + queue_redraw(); + if (tabs.size() == 1) { + emit_signal(SNAME("tab_changed"), 0); } } + + update_minimum_size(); } int TabBar::get_tab_idx_at_point(const Point2 &p_point) const { diff --git a/scene/gui/tab_bar.h b/scene/gui/tab_bar.h index 4bce30ea52..28e3411f3d 100644 --- a/scene/gui/tab_bar.h +++ b/scene/gui/tab_bar.h @@ -55,7 +55,6 @@ public: private: struct Tab { String text; - String xl_text; String language; Control::TextDirection text_direction = Control::TEXT_DIRECTION_INHERITED; @@ -167,8 +166,13 @@ protected: Variant get_drag_data(const Point2 &p_point) override; bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override; void drop_data(const Point2 &p_point, const Variant &p_data) override; + void _move_tab_from(TabBar *p_from_tabbar, int p_from_index, int p_to_index); public: + Variant _handle_get_drag_data(const String &p_type, const Point2 &p_point); + bool _handle_can_drop_data(const String &p_type, const Point2 &p_point, const Variant &p_data) const; + void _handle_drop_data(const String &p_type, const Point2 &p_point, const Variant &p_data, const Callable &p_move_tab_callback, const Callable &p_move_tab_from_other_callback); + void add_tab(const String &p_str = "", const Ref<Texture2D> &p_icon = Ref<Texture2D>()); void set_tab_title(int p_tab, const String &p_title); diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 481f8f4131..c21a9d14cb 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -330,143 +330,59 @@ Vector<Control *> TabContainer::_get_tab_controls() const { } Variant TabContainer::_get_drag_data_fw(const Point2 &p_point, Control *p_from_control) { - if (!drag_to_rearrange_enabled) { - return Variant(); - } - - int tab_over = get_tab_idx_at_point(p_point); - if (tab_over < 0) { - return Variant(); - } - - HBoxContainer *drag_preview = memnew(HBoxContainer); - - Ref<Texture2D> icon = get_tab_icon(tab_over); - if (!icon.is_null()) { - TextureRect *tf = memnew(TextureRect); - tf->set_texture(icon); - drag_preview->add_child(tf); - } - - Label *label = memnew(Label(get_tab_title(tab_over))); - set_drag_preview(drag_preview); - drag_preview->add_child(label); - - Dictionary drag_data; - drag_data["type"] = "tabc_element"; - drag_data["tabc_element"] = tab_over; - drag_data["from_path"] = get_path(); - - return drag_data; + return tab_bar->_handle_get_drag_data("tab_container_tab", p_point); } bool TabContainer::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) const { - if (!drag_to_rearrange_enabled) { - return false; - } - - Dictionary d = p_data; - if (!d.has("type")) { - return false; - } + return tab_bar->_handle_can_drop_data("tab_container_tab", p_point, p_data); +} - if (String(d["type"]) == "tabc_element") { - NodePath from_path = d["from_path"]; - NodePath to_path = get_path(); - if (from_path == to_path) { - return true; - } else if (get_tabs_rearrange_group() != -1) { - // Drag and drop between other TabContainers. - Node *from_node = get_node(from_path); - TabContainer *from_tabc = Object::cast_to<TabContainer>(from_node); - if (from_tabc && from_tabc->get_tabs_rearrange_group() == get_tabs_rearrange_group()) { - return true; - } - } - } +void TabContainer::_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) { + return tab_bar->_handle_drop_data("tab_container_tab", p_point, p_data, callable_mp(this, &TabContainer::_drag_move_tab), callable_mp(this, &TabContainer::_drag_move_tab_from)); +} - return false; +void TabContainer::_drag_move_tab(int p_from_index, int p_to_index) { + move_child(get_tab_control(p_from_index), get_tab_control(p_to_index)->get_index(false)); } -void TabContainer::_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) { - if (!drag_to_rearrange_enabled) { +void TabContainer::_drag_move_tab_from(TabBar *p_from_tabbar, int p_from_index, int p_to_index) { + Node *parent = p_from_tabbar->get_parent(); + if (!parent) { return; } - - Dictionary d = p_data; - if (!d.has("type")) { + TabContainer *from_tab_container = Object::cast_to<TabContainer>(parent); + if (!from_tab_container) { return; } + move_tab_from_tab_container(from_tab_container, p_from_index, p_to_index); +} - if (String(d["type"]) == "tabc_element") { - int tab_from_id = d["tabc_element"]; - int hover_now = get_tab_idx_at_point(p_point); - NodePath from_path = d["from_path"]; - NodePath to_path = get_path(); - - if (from_path == to_path) { - if (tab_from_id == hover_now) { - return; - } - - // Drop the new tab to the left or right depending on where the target tab is being hovered. - if (hover_now != -1) { - Rect2 tab_rect = tab_bar->get_tab_rect(hover_now); - if (is_layout_rtl() ^ (p_point.x <= tab_rect.position.x + tab_rect.size.width / 2)) { - if (hover_now > tab_from_id) { - hover_now -= 1; - } - } else if (tab_from_id > hover_now) { - hover_now += 1; - } - } else { - hover_now = is_layout_rtl() ^ (p_point.x < tab_bar->get_tab_rect(0).position.x) ? 0 : get_tab_count() - 1; - } - - move_child(get_tab_control(tab_from_id), get_tab_control(hover_now)->get_index(false)); - if (!is_tab_disabled(hover_now)) { - emit_signal(SNAME("active_tab_rearranged"), hover_now); - set_current_tab(hover_now); - } - - } else if (get_tabs_rearrange_group() != -1) { - // Drag and drop between TabContainers. - - Node *from_node = get_node(from_path); - TabContainer *from_tabc = Object::cast_to<TabContainer>(from_node); - - if (from_tabc && from_tabc->get_tabs_rearrange_group() == get_tabs_rearrange_group()) { - // Get the tab properties before they get erased by the child removal. - String tab_title = from_tabc->get_tab_title(tab_from_id); - Ref<Texture2D> tab_icon = from_tabc->get_tab_icon(tab_from_id); - bool tab_disabled = from_tabc->is_tab_disabled(tab_from_id); - Variant tab_metadata = from_tabc->get_tab_metadata(tab_from_id); +void TabContainer::move_tab_from_tab_container(TabContainer *p_from, int p_from_index, int p_to_index) { + ERR_FAIL_NULL(p_from); + ERR_FAIL_INDEX(p_from_index, p_from->get_tab_count()); + ERR_FAIL_INDEX(p_to_index, get_tab_count() + 1); - // Drop the new tab to the left or right depending on where the target tab is being hovered. - if (hover_now != -1) { - Rect2 tab_rect = tab_bar->get_tab_rect(hover_now); - if (is_layout_rtl() ^ (p_point.x > tab_rect.position.x + tab_rect.size.width / 2)) { - hover_now += 1; - } - } else { - hover_now = is_layout_rtl() ^ (p_point.x < tab_bar->get_tab_rect(0).position.x) ? 0 : get_tab_count(); - } + // Get the tab properties before they get erased by the child removal. + String tab_title = p_from->get_tab_title(p_from_index); + Ref<Texture2D> tab_icon = p_from->get_tab_icon(p_from_index); + bool tab_disabled = p_from->is_tab_disabled(p_from_index); + Variant tab_metadata = p_from->get_tab_metadata(p_from_index); - Control *moving_tabc = from_tabc->get_tab_control(tab_from_id); - from_tabc->remove_child(moving_tabc); - add_child(moving_tabc, true); + Control *moving_tabc = p_from->get_tab_control(p_from_index); + p_from->remove_child(moving_tabc); + add_child(moving_tabc, true); - set_tab_title(get_tab_count() - 1, tab_title); - set_tab_icon(get_tab_count() - 1, tab_icon); - set_tab_disabled(get_tab_count() - 1, tab_disabled); - set_tab_metadata(get_tab_count() - 1, tab_metadata); + set_tab_title(get_tab_count() - 1, tab_title); + set_tab_icon(get_tab_count() - 1, tab_icon); + set_tab_disabled(get_tab_count() - 1, tab_disabled); + set_tab_metadata(get_tab_count() - 1, tab_metadata); - move_child(moving_tabc, get_tab_control(hover_now)->get_index(false)); - if (!is_tab_disabled(hover_now)) { - set_current_tab(hover_now); - } - } - } + if (p_to_index < 0 || p_to_index > get_tab_count() - 1) { + p_to_index = get_tab_count() - 1; + } + move_child(moving_tabc, get_tab_control(p_to_index)->get_index(false)); + if (!is_tab_disabled(p_to_index)) { + set_current_tab(p_to_index); } } @@ -496,6 +412,10 @@ void TabContainer::_on_tab_button_pressed(int p_tab) { emit_signal(SNAME("tab_button_pressed"), p_tab); } +void TabContainer::_on_active_tab_rearranged(int p_tab) { + emit_signal(SNAME("active_tab_rearranged"), p_tab); +} + void TabContainer::_refresh_tab_names() { Vector<Control *> controls = _get_tab_controls(); for (int i = 0; i < controls.size(); i++) { @@ -895,11 +815,11 @@ Popup *TabContainer::get_popup() const { } void TabContainer::set_drag_to_rearrange_enabled(bool p_enabled) { - drag_to_rearrange_enabled = p_enabled; + tab_bar->set_drag_to_rearrange_enabled(p_enabled); } bool TabContainer::get_drag_to_rearrange_enabled() const { - return drag_to_rearrange_enabled; + return tab_bar->get_drag_to_rearrange_enabled(); } void TabContainer::set_tabs_rearrange_group(int p_group_id) { @@ -1038,6 +958,7 @@ TabContainer::TabContainer() { tab_bar->connect("tab_hovered", callable_mp(this, &TabContainer::_on_tab_hovered)); tab_bar->connect("tab_selected", callable_mp(this, &TabContainer::_on_tab_selected)); tab_bar->connect("tab_button_pressed", callable_mp(this, &TabContainer::_on_tab_button_pressed)); + tab_bar->connect("active_tab_rearranged", callable_mp(this, &TabContainer::_on_active_tab_rearranged)); connect("mouse_exited", callable_mp(this, &TabContainer::_on_mouse_exited)); } diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index a831416612..5750c6b82e 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -43,7 +43,6 @@ class TabContainer : public Container { bool all_tabs_in_front = false; bool menu_hovered = false; mutable ObjectID popup_obj_id; - bool drag_to_rearrange_enabled = false; bool use_hidden_tabs_for_min_size = false; bool theme_changing = false; Vector<Control *> children_removing; @@ -97,10 +96,13 @@ class TabContainer : public Container { void _on_tab_hovered(int p_tab); void _on_tab_selected(int p_tab); void _on_tab_button_pressed(int p_tab); + void _on_active_tab_rearranged(int p_tab); Variant _get_drag_data_fw(const Point2 &p_point, Control *p_from_control); bool _can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) const; void _drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control); + void _drag_move_tab(int p_from_index, int p_to_index); + void _drag_move_tab_from(TabBar *p_from_tabbar, int p_from_index, int p_to_index); protected: virtual void gui_input(const Ref<InputEvent> &p_event) override; @@ -166,6 +168,8 @@ public: void set_popup(Node *p_popup); Popup *get_popup() const; + void move_tab_from_tab_container(TabContainer *p_from, int p_from_index, int p_to_index = -1); + void set_drag_to_rearrange_enabled(bool p_enabled); bool get_drag_to_rearrange_enabled() const; void set_tabs_rearrange_group(int p_group_id); diff --git a/scene/resources/image_texture.cpp b/scene/resources/image_texture.cpp index ecf70d96ac..337d10f75c 100644 --- a/scene/resources/image_texture.cpp +++ b/scene/resources/image_texture.cpp @@ -462,9 +462,58 @@ void ImageTexture3D::set_path(const String &p_path, bool p_take_over) { Resource::set_path(p_path, p_take_over); } +TypedArray<Image> ImageTexture3D::_get_images() const { + TypedArray<Image> images; + if (texture.is_valid()) { + Vector<Ref<Image>> raw_images = get_data(); + ERR_FAIL_COND_V(raw_images.is_empty(), TypedArray<Image>()); + + for (int i = 0; i < raw_images.size(); i++) { + images.push_back(raw_images[i]); + } + } + return images; +} + +void ImageTexture3D::_set_images(const TypedArray<Image> &p_images) { + int new_layers = p_images.size(); + ERR_FAIL_COND(new_layers == 0); + Ref<Image> img_base = p_images[0]; + ERR_FAIL_COND(img_base.is_null()); + + Image::Format new_format = img_base->get_format(); + int new_width = img_base->get_width(); + int new_height = img_base->get_height(); + int new_depth = 0; + bool new_mipmaps = false; + + for (int i = 1; i < p_images.size(); i++) { + Ref<Image> img = p_images[i]; + ERR_FAIL_COND(img.is_null()); + ERR_FAIL_COND_MSG(img->get_format() != new_format, "All images must share the same format."); + + if (img->get_width() != new_width || img->get_height() != new_height) { + new_mipmaps = true; + if (new_depth == 0) { + new_depth = i; + } + } + } + + if (new_depth == 0) { + new_depth = p_images.size(); + } + + Error err = _create(new_format, new_width, new_height, new_depth, new_mipmaps, p_images); + ERR_FAIL_COND(err != OK); +} + void ImageTexture3D::_bind_methods() { ClassDB::bind_method(D_METHOD("create", "format", "width", "height", "depth", "use_mipmaps", "data"), &ImageTexture3D::_create); ClassDB::bind_method(D_METHOD("update", "data"), &ImageTexture3D::_update); + ClassDB::bind_method(D_METHOD("_get_images"), &ImageTexture3D::_get_images); + ClassDB::bind_method(D_METHOD("_set_images", "images"), &ImageTexture3D::_set_images); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_images", PROPERTY_HINT_ARRAY_TYPE, "Image", PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT), "_set_images", "_get_images"); } ImageTexture3D::ImageTexture3D() { diff --git a/scene/resources/image_texture.h b/scene/resources/image_texture.h index 9d9c296a45..3b756fb593 100644 --- a/scene/resources/image_texture.h +++ b/scene/resources/image_texture.h @@ -137,6 +137,9 @@ class ImageTexture3D : public Texture3D { int depth = 1; bool mipmaps = false; + TypedArray<Image> _get_images() const; + void _set_images(const TypedArray<Image> &p_images); + protected: static void _bind_methods(); diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp index c7ee277a1b..1f4171c072 100644 --- a/scene/resources/importer_mesh.cpp +++ b/scene/resources/importer_mesh.cpp @@ -868,7 +868,7 @@ void ImporterMesh::_set_data(const Dictionary &p_data) { if (s.has("material")) { material = s["material"]; } - uint32_t flags = 0; + uint64_t flags = 0; if (s.has("flags")) { flags = s["flags"]; } @@ -909,9 +909,7 @@ Dictionary ImporterMesh::_get_data() const { d["name"] = surfaces[i].name; } - if (surfaces[i].flags != 0) { - d["flags"] = surfaces[i].flags; - } + d["flags"] = surfaces[i].flags; surface_arr.push_back(d); } diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 461dbbec2f..6997777623 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -1059,20 +1059,33 @@ void BaseMaterial3D::_update_shader() { } if (flags[FLAG_UV1_USE_TRIPLANAR] || flags[FLAG_UV2_USE_TRIPLANAR]) { //generate tangent and binormal in world space - code += " TANGENT = vec3(0.0,0.0,-1.0) * abs(NORMAL.x);\n"; - code += " TANGENT+= vec3(1.0,0.0,0.0) * abs(NORMAL.y);\n"; - code += " TANGENT+= vec3(1.0,0.0,0.0) * abs(NORMAL.z);\n"; - code += " TANGENT = normalize(TANGENT);\n"; + if (flags[FLAG_UV1_USE_WORLD_TRIPLANAR]) { + code += " vec3 normal = MODEL_NORMAL_MATRIX * NORMAL;\n"; + } else { + code += " vec3 normal = NORMAL;\n"; + } + code += " TANGENT = vec3(0.0,0.0,-1.0) * abs(normal.x);\n"; + code += " TANGENT+= vec3(1.0,0.0,0.0) * abs(normal.y);\n"; + code += " TANGENT+= vec3(1.0,0.0,0.0) * abs(normal.z);\n"; + if (flags[FLAG_UV1_USE_WORLD_TRIPLANAR]) { + code += " TANGENT = inverse(MODEL_NORMAL_MATRIX) * normalize(TANGENT);\n"; + } else { + code += " TANGENT = normalize(TANGENT);\n"; + } - code += " BINORMAL = vec3(0.0,1.0,0.0) * abs(NORMAL.x);\n"; - code += " BINORMAL+= vec3(0.0,0.0,-1.0) * abs(NORMAL.y);\n"; - code += " BINORMAL+= vec3(0.0,1.0,0.0) * abs(NORMAL.z);\n"; - code += " BINORMAL = normalize(BINORMAL);\n"; + code += " BINORMAL = vec3(0.0,1.0,0.0) * abs(normal.x);\n"; + code += " BINORMAL+= vec3(0.0,0.0,-1.0) * abs(normal.y);\n"; + code += " BINORMAL+= vec3(0.0,1.0,0.0) * abs(normal.z);\n"; + if (flags[FLAG_UV1_USE_WORLD_TRIPLANAR]) { + code += " BINORMAL = inverse(MODEL_NORMAL_MATRIX) * normalize(BINORMAL);\n"; + } else { + code += " BINORMAL = normalize(BINORMAL);\n"; + } } if (flags[FLAG_UV1_USE_TRIPLANAR]) { if (flags[FLAG_UV1_USE_WORLD_TRIPLANAR]) { - code += " uv1_power_normal=pow(abs(mat3(MODEL_MATRIX) * NORMAL),vec3(uv1_blend_sharpness));\n"; + code += " uv1_power_normal=pow(abs(normal),vec3(uv1_blend_sharpness));\n"; code += " uv1_triplanar_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0f)).xyz * uv1_scale + uv1_offset;\n"; } else { code += " uv1_power_normal=pow(abs(NORMAL),vec3(uv1_blend_sharpness));\n"; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 3aeec7ea87..25a65b5cc4 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1638,7 +1638,12 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) { #ifndef DISABLE_DEPRECATED uint64_t surface_version = surface.format & (ARRAY_FLAG_FORMAT_VERSION_MASK << ARRAY_FLAG_FORMAT_VERSION_SHIFT); if (surface_version != ARRAY_FLAG_FORMAT_CURRENT_VERSION) { - RS::_fix_surface_compatibility(surface); + RS::get_singleton()->fix_surface_compatibility(surface, get_path()); + surface_version = surface.format & (RS::ARRAY_FLAG_FORMAT_VERSION_MASK << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT); + ERR_FAIL_COND_MSG(surface_version != RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION, + vformat("Surface version provided (%d) does not match current version (%d).", + (surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK, + (RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK)); } #endif @@ -2008,17 +2013,19 @@ void ArrayMesh::regen_normal_maps() { return; } Vector<Ref<SurfaceTool>> surfs; + Vector<uint64_t> formats; for (int i = 0; i < get_surface_count(); i++) { Ref<SurfaceTool> st = memnew(SurfaceTool); st->create_from(Ref<ArrayMesh>(this), i); surfs.push_back(st); + formats.push_back(surface_get_format(i)); } clear_surfaces(); for (int i = 0; i < surfs.size(); i++) { surfs.write[i]->generate_tangents(); - surfs.write[i]->commit(Ref<ArrayMesh>(this)); + surfs.write[i]->commit(Ref<ArrayMesh>(this), formats[i]); } } diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index b80e258af9..2456212327 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -1028,7 +1028,7 @@ Error SceneState::_parse_connections(Node *p_owner, Node *p_node, HashMap<String cd.to = target_id; cd.method = _nm_get_string(base_callable.get_method(), name_map); cd.signal = _nm_get_string(c.signal.get_name(), name_map); - cd.flags = c.flags; + cd.flags = c.flags & ~CONNECT_INHERITED; // Do not store inherited. cd.unbinds = unbinds; for (int i = 0; i < binds.size(); i++) { diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp index 0a114d6b35..ed87468db6 100644 --- a/scene/resources/particle_process_material.cpp +++ b/scene/resources/particle_process_material.cpp @@ -984,12 +984,16 @@ void ParticleProcessMaterial::_update_shader() { } code += " \n"; code += " vec3 noise_direction = get_noise_direction(TRANSFORM[3].xyz);\n"; - code += " if (!COLLIDED) {\n"; - code += " \n"; - code += " float vel_mag = length(final_velocity);\n"; - code += " float vel_infl = clamp(dynamic_params.turb_influence * turbulence_influence, 0.0,1.0);\n"; - code += " final_velocity = mix(final_velocity, normalize(noise_direction) * vel_mag * (1.0 + (1.0 - vel_infl) * 0.2), vel_infl);\n"; - code += " }\n"; + // The following snippet causes massive performance hit. We don't need it as long as collision is disabled. + // Refer to GH-83744 for more info. + if (collision_mode != COLLISION_DISABLED) { + code += " if (!COLLIDED) {\n"; + code += " \n"; + code += " float vel_mag = length(final_velocity);\n"; + code += " float vel_infl = clamp(dynamic_params.turb_influence * turbulence_influence, 0.0,1.0);\n"; + code += " final_velocity = mix(final_velocity, normalize(noise_direction) * vel_mag * (1.0 + (1.0 - vel_infl) * 0.2), vel_infl);\n"; + code += " }\n"; + } } code += " \n"; code += " // limit velocity\n"; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 8a672d8628..9e8d654b4e 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -53,6 +53,7 @@ RendererRD::ForwardID RenderForwardMobile::ForwardIDStorageMobile::allocate_forw index = forward_id_allocators[p_type].allocations.size(); forward_id_allocators[p_type].allocations.push_back(true); forward_id_allocators[p_type].map.push_back(0xFF); + forward_id_allocators[p_type].last_pass.push_back(0); } else { forward_id_allocators[p_type].allocations[index] = true; } @@ -64,44 +65,72 @@ void RenderForwardMobile::ForwardIDStorageMobile::free_forward_id(RendererRD::Fo forward_id_allocators[p_type].allocations[p_id] = false; } -void RenderForwardMobile::ForwardIDStorageMobile::map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) { +void RenderForwardMobile::ForwardIDStorageMobile::map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index, uint64_t p_last_pass) { forward_id_allocators[p_type].map[p_id] = p_index; + forward_id_allocators[p_type].last_pass[p_id] = p_last_pass; } void RenderForwardMobile::fill_push_constant_instance_indices(SceneState::InstanceData *p_instance_data, const GeometryInstanceForwardMobile *p_instance) { - // First zero out our indices. + uint64_t current_frame = RSG::rasterizer->get_frame_number(); p_instance_data->omni_lights[0] = 0xFFFFFFFF; p_instance_data->omni_lights[1] = 0xFFFFFFFF; - p_instance_data->spot_lights[0] = 0xFFFFFFFF; - p_instance_data->spot_lights[1] = 0xFFFFFFFF; - - p_instance_data->decals[0] = 0xFFFFFFFF; - p_instance_data->decals[1] = 0xFFFFFFFF; - - p_instance_data->reflection_probes[0] = 0xFFFFFFFF; - p_instance_data->reflection_probes[1] = 0xFFFFFFFF; - - for (uint32_t i = 0; i < MAX_RDL_CULL; i++) { - uint32_t ofs = i < 4 ? 0 : 1; - uint32_t shift = (i & 0x3) << 3; + uint32_t idx = 0; + for (uint32_t i = 0; i < p_instance->omni_light_count; i++) { + uint32_t ofs = idx < 4 ? 0 : 1; + uint32_t shift = (idx & 0x3) << 3; uint32_t mask = ~(0xFF << shift); - if (i < p_instance->omni_light_count) { + + if (forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT].last_pass[p_instance->omni_lights[i]] == current_frame) { p_instance_data->omni_lights[ofs] &= mask; p_instance_data->omni_lights[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift; + idx++; } - if (i < p_instance->spot_light_count) { + } + + p_instance_data->spot_lights[0] = 0xFFFFFFFF; + p_instance_data->spot_lights[1] = 0xFFFFFFFF; + + idx = 0; + for (uint32_t i = 0; i < p_instance->spot_light_count; i++) { + uint32_t ofs = idx < 4 ? 0 : 1; + uint32_t shift = (idx & 0x3) << 3; + uint32_t mask = ~(0xFF << shift); + if (forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT].last_pass[p_instance->spot_lights[i]] == current_frame) { p_instance_data->spot_lights[ofs] &= mask; p_instance_data->spot_lights[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift; + idx++; } - if (i < p_instance->decals_count) { + } + + p_instance_data->decals[0] = 0xFFFFFFFF; + p_instance_data->decals[1] = 0xFFFFFFFF; + + idx = 0; + for (uint32_t i = 0; i < p_instance->decals_count; i++) { + uint32_t ofs = idx < 4 ? 0 : 1; + uint32_t shift = (idx & 0x3) << 3; + uint32_t mask = ~(0xFF << shift); + if (forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_DECAL].last_pass[p_instance->decals[i]] == current_frame) { p_instance_data->decals[ofs] &= mask; p_instance_data->decals[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift; + idx++; } - if (i < p_instance->reflection_probe_count) { + } + + p_instance_data->reflection_probes[0] = 0xFFFFFFFF; + p_instance_data->reflection_probes[1] = 0xFFFFFFFF; + + idx = 0; + for (uint32_t i = 0; i < p_instance->reflection_probe_count; i++) { + uint32_t ofs = idx < 4 ? 0 : 1; + uint32_t shift = (idx & 0x3) << 3; + uint32_t mask = ~(0xFF << shift); + if (forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_REFLECTION_PROBE].last_pass[p_instance->reflection_probes[i]] == current_frame) { p_instance_data->reflection_probes[ofs] &= mask; p_instance_data->reflection_probes[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift; + idx++; } } } @@ -539,7 +568,6 @@ void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, co void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); - RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); p_render_data->cube_shadows.clear(); p_render_data->shadows.clear(); @@ -598,28 +626,11 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { //full barrier here, we need raster, transfer and compute and it depends from the previous work RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL_BARRIERS, RD::BARRIER_MASK_ALL_BARRIERS); - - bool using_shadows = true; - - if (p_render_data->reflection_probe.is_valid()) { - if (!RSG::light_storage->reflection_probe_renders_shadows(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { - using_shadows = false; - } - } else { - //do not render reflections when rendering a reflection probe - light_storage->update_reflection_probe_buffer(p_render_data, *p_render_data->reflection_probes, p_render_data->scene_data->cam_transform.affine_inverse(), p_render_data->environment); - } - - uint32_t directional_light_count = 0; - uint32_t positional_light_count = 0; - light_storage->update_light_buffers(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows); - texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform); - - p_render_data->directional_light_count = directional_light_count; } void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) { RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton(); + RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); ERR_FAIL_NULL(p_render_data); @@ -668,6 +679,25 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color bool using_subpass_transparent = true; bool using_subpass_post_process = true; + bool using_shadows = true; + + if (p_render_data->reflection_probe.is_valid()) { + if (!RSG::light_storage->reflection_probe_renders_shadows(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { + using_shadows = false; + } + } else { + //do not render reflections when rendering a reflection probe + light_storage->update_reflection_probe_buffer(p_render_data, *p_render_data->reflection_probes, p_render_data->scene_data->cam_transform.affine_inverse(), p_render_data->environment); + } + + // Update light and decal buffer first so we know what lights and decals are safe to pair with. + uint32_t directional_light_count = 0; + uint32_t positional_light_count = 0; + light_storage->update_light_buffers(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows); + texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform); + + p_render_data->directional_light_count = directional_light_count; + // fill our render lists early so we can find out if we use various features _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR); render_list[RENDER_LIST_OPAQUE].sort_by_key(); diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index 50bf83b612..c8e42e2cf1 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -535,6 +535,7 @@ protected: struct ForwardIDAllocator { LocalVector<bool> allocations; LocalVector<uint8_t> map; + LocalVector<uint64_t> last_pass; }; ForwardIDAllocator forward_id_allocators[RendererRD::FORWARD_ID_MAX]; @@ -542,7 +543,7 @@ protected: public: virtual RendererRD::ForwardID allocate_forward_id(RendererRD::ForwardIDType p_type) override; virtual void free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) override; - virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) override; + virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index, uint64_t p_last_pass) override; virtual bool uses_forward_ids() const override { return true; } }; diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.h b/servers/rendering/renderer_rd/pipeline_cache_rd.h index 2f1e79b397..0ebebd0540 100644 --- a/servers/rendering/renderer_rd/pipeline_cache_rd.h +++ b/servers/rendering/renderer_rd/pipeline_cache_rd.h @@ -38,7 +38,7 @@ class PipelineCacheRD { SpinLock spin_lock; RID shader; - uint32_t input_mask; + uint64_t input_mask; RD::RenderPrimitive render_primitive; RD::PipelineRasterizationState rasterization_state; diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index 10e37c7da8..242b0301f1 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -480,6 +480,7 @@ void ShaderRD::_save_to_cache(Version *p_version, int p_group) { } void ShaderRD::_allocate_placeholders(Version *p_version, int p_group) { + ERR_FAIL_NULL(p_version->variants); for (uint32_t i = 0; i < group_to_variant_map[p_group].size(); i++) { int variant_id = group_to_variant_map[p_group][i]; RID shader = RD::get_singleton()->shader_create_placeholder(); diff --git a/servers/rendering/renderer_rd/storage_rd/forward_id_storage.h b/servers/rendering/renderer_rd/storage_rd/forward_id_storage.h index bedf5e80c7..c8f8d4f7f2 100644 --- a/servers/rendering/renderer_rd/storage_rd/forward_id_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/forward_id_storage.h @@ -59,7 +59,7 @@ public: virtual RendererRD::ForwardID allocate_forward_id(RendererRD::ForwardIDType p_type) { return -1; } virtual void free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) {} - virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) {} + virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index, uint64_t p_last_pass) {} virtual bool uses_forward_ids() const { return false; } }; diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index 4fd33ad71a..1f6d1021f4 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -793,7 +793,7 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged real_t distance = (i < omni_light_count) ? omni_light_sort[index].depth : spot_light_sort[index].depth; if (using_forward_ids) { - forward_id_storage->map_forward_id(type == RS::LIGHT_OMNI ? RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT : RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT, light_instance->forward_id, index); + forward_id_storage->map_forward_id(type == RS::LIGHT_OMNI ? RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT : RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT, light_instance->forward_id, index, light_instance->last_pass); } Transform3D light_transform = light_instance->transform; @@ -1670,7 +1670,7 @@ void LightStorage::update_reflection_probe_buffer(RenderDataRD *p_render_data, c ReflectionProbeInstance *rpi = reflection_sort[i].probe_instance; if (using_forward_ids) { - forward_id_storage->map_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id, i); + forward_id_storage->map_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id, i, rpi->last_pass); } ReflectionProbe *probe = reflection_probe_owner.get_or_null(rpi->probe); diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp index 14605b308e..3710ac0eed 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp @@ -356,14 +356,12 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) #else if (surface_version != uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION)) { - RS::_fix_surface_compatibility(new_surface); + RS::get_singleton()->fix_surface_compatibility(new_surface); surface_version = new_surface.format & (RS::ARRAY_FLAG_FORMAT_VERSION_MASK << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT); ERR_FAIL_COND_MSG(surface_version != RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION, - "Surface version provided (" + - itos((surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + - ") does not match current version (" + - itos((RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + - ")"); + vformat("Surface version provided (%d) does not match current version (%d).", + (surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK, + (RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK)); } #endif diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h index f03334baac..db54816e09 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h @@ -469,7 +469,7 @@ public: } } - _FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint32_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { + _FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint64_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); s->version_lock.lock(); @@ -501,7 +501,7 @@ public: s->version_lock.unlock(); } - _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint64_t p_surface_index, uint32_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { + _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint64_t p_surface_index, uint64_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance); ERR_FAIL_NULL(mi); Mesh *mesh = mi->mesh; diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 166b850864..678564a0e4 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -2862,7 +2862,7 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const Decal *decal = decal_sort[i].decal; if (using_forward_ids) { - forward_id_storage->map_forward_id(FORWARD_ID_TYPE_DECAL, decal_instance->forward_id, i); + forward_id_storage->map_forward_id(FORWARD_ID_TYPE_DECAL, decal_instance->forward_id, i, RSG::rasterizer->get_frame_number()); } decal_instance->cull_mask = decal->cull_mask; @@ -3511,7 +3511,9 @@ Rect2i TextureStorage::_render_target_get_sdf_rect(const RenderTarget *rt) const scale = 200; } break; default: { - } + ERR_PRINT("Invalid viewport SDF oversize, defaulting to 100%."); + scale = 100; + } break; } margin = (rt->size * scale / 100) - rt->size; @@ -3603,6 +3605,7 @@ void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) { scale = 25; } break; default: { + ERR_PRINT("Invalid viewport SDF scale, defaulting to 100%."); scale = 100; } break; } diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 2b4fe6e01b..cc42c5a3fb 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -323,16 +323,18 @@ RID RenderingServer::get_white_texture() { } void _get_axis_angle(const Vector3 &p_normal, const Vector4 &p_tangent, float &r_angle, Vector3 &r_axis) { - Vector3 tangent = Vector3(p_tangent.x, p_tangent.y, p_tangent.z); + Vector3 normal = p_normal.normalized(); + Vector3 tangent = Vector3(p_tangent.x, p_tangent.y, p_tangent.z).normalized(); float d = p_tangent.w; - Vector3 binormal = p_normal.cross(tangent); + Vector3 binormal = normal.cross(tangent).normalized(); + real_t angle; - r_angle = Math::acos((tangent.x + binormal.y + p_normal.z - 1.0) / 2.0); - float denom = 2.0 * Math::sin(r_angle); - r_axis.x = (p_normal.y - binormal.z) / denom; - r_axis.y = (tangent.z - p_normal.x) / denom; - r_axis.z = (binormal.x - tangent.y) / denom; - r_axis.normalize(); + Basis tbn = Basis(); + tbn.rows[0] = tangent; + tbn.rows[1] = binormal; + tbn.rows[2] = normal; + tbn.get_axis_angle(r_axis, angle); + r_angle = float(angle); if (d < 0.0) { r_angle = CLAMP((1.0 - r_angle / Math_PI) * 0.5, 0.0, 0.49999); @@ -346,13 +348,11 @@ void _get_axis_angle(const Vector3 &p_normal, const Vector4 &p_tangent, float &r void _get_tbn_from_axis_angle(const Vector3 &p_axis, float p_angle, Vector3 &r_normal, Vector4 &r_tangent) { float binormal_sign = p_angle > 0.5 ? 1.0 : -1.0; float angle = Math::abs(p_angle * 2.0 - 1.0) * Math_PI; - float c = cos(angle); - float s = sin(angle); - Vector3 omc_axis = (1.0 - c) * p_axis; - Vector3 s_axis = s * p_axis; - Vector3 tan = omc_axis.x * p_axis + Vector3(c, -s_axis.z, s_axis.y); + + Basis tbn = Basis(p_axis, angle); + Vector3 tan = tbn.rows[0]; r_tangent = Vector4(tan.x, tan.y, tan.z, binormal_sign); - r_normal = omc_axis.z * p_axis + Vector3(-s_axis.y, s_axis.x, c); + r_normal = tbn.rows[2]; } Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint32_t *p_offsets, uint32_t p_vertex_stride, uint32_t p_normal_stride, uint32_t p_attrib_stride, uint32_t p_skin_stride, Vector<uint8_t> &r_vertex_array, Vector<uint8_t> &r_attrib_array, Vector<uint8_t> &r_skin_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb, Vector4 &r_uv_scale) { @@ -1194,7 +1194,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa format |= RS::ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY; } - if (format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES && ((format & RS::ARRAY_FORMAT_NORMAL) || (format & RS::ARRAY_FORMAT_TANGENT))) { + if ((format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) && ((format & RS::ARRAY_FORMAT_NORMAL) || (format & RS::ARRAY_FORMAT_TANGENT))) { // If using normals or tangents, then we need all three. ERR_FAIL_COND_V_MSG(!(format & RS::ARRAY_FORMAT_VERTEX), ERR_INVALID_PARAMETER, "Can't use compression flag 'ARRAY_FLAG_COMPRESS_ATTRIBUTES' while using normals or tangents without vertex array."); ERR_FAIL_COND_V_MSG(!(format & RS::ARRAY_FORMAT_NORMAL), ERR_INVALID_PARAMETER, "Can't use compression flag 'ARRAY_FLAG_COMPRESS_ATTRIBUTES' while using tangents without normal array."); @@ -1399,7 +1399,7 @@ Array RenderingServer::_get_array_from_surface(uint64_t p_format, Vector<uint8_t tangentsw[j * 4 + 3] = tan.w; } ret[RS::ARRAY_NORMAL] = normals; - ret[RS::ARRAY_FORMAT_TANGENT] = tangents; + ret[RS::ARRAY_TANGENT] = tangents; } else { for (int j = 0; j < p_vertex_len; j++) { @@ -2036,15 +2036,39 @@ Vector<uint8_t> _convert_surface_version_1_to_surface_version_2(uint64_t p_forma return new_vertex_data; } +#ifdef TOOLS_ENABLED +void RenderingServer::set_surface_upgrade_callback(SurfaceUpgradeCallback p_callback) { + surface_upgrade_callback = p_callback; +} + +void RenderingServer::set_warn_on_surface_upgrade(bool p_warn) { + warn_on_surface_upgrade = p_warn; +} +#endif + #ifndef DISABLE_DEPRECATED -void RenderingServer::_fix_surface_compatibility(SurfaceData &p_surface) { +void RenderingServer::fix_surface_compatibility(SurfaceData &p_surface, const String &p_path) { uint64_t surface_version = p_surface.format & (ARRAY_FLAG_FORMAT_VERSION_MASK << ARRAY_FLAG_FORMAT_VERSION_SHIFT); ERR_FAIL_COND_MSG(surface_version > ARRAY_FLAG_FORMAT_CURRENT_VERSION, "Cannot convert surface with version provided (" + itos((surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + ") to current version (" + itos((RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + ")"); +#ifdef TOOLS_ENABLED + // Editor callback to ask user about re-saving all meshes. + if (surface_upgrade_callback && warn_on_surface_upgrade) { + surface_upgrade_callback(); + } + + if (warn_on_surface_upgrade) { + if (p_path.is_empty()) { + WARN_PRINT("A surface uses an old surface format and needs to be upgraded. The upgrade happens automatically at load time every time until the mesh is saved again or re-imported. Once saved (or re-imported), this mesh will be incompatible with earlier versions of Godot."); + } else { + WARN_PRINT("A surface of " + p_path + " uses an old surface format and needs to be upgraded. The upgrade happens automatically at load time every time until the mesh is saved again or re-imported. Once saved (or re-imported), this mesh will be incompatible with earlier versions of Godot."); + } + } +#endif + if (surface_version == ARRAY_FLAG_FORMAT_VERSION_1) { // The only difference for now is that Version 1 uses interleaved vertex positions while version 2 does not. // I.e. PNTPNTPNT -> PPPNTNTNT. - WARN_PRINT_ED("Upgrading mesh from older surface format. Once saved again (or re-imported), this mesh will be incompatible with earlier versions of Godot."); int vertex_size = 0; int normal_size = 0; diff --git a/servers/rendering_server.h b/servers/rendering_server.h index ba8cc3ba80..fb658aaee8 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -298,6 +298,8 @@ public: ARRAY_FLAG_FORMAT_VERSION_MASK = 0xFF, // 8 bits version }; + static_assert(sizeof(ArrayFormat) == 8, "ArrayFormat should be 64 bits long."); + enum PrimitiveType { PRIMITIVE_POINTS, PRIMITIVE_LINES, @@ -1630,8 +1632,14 @@ public: RenderingServer(); virtual ~RenderingServer(); +#ifdef TOOLS_ENABLED + typedef void (*SurfaceUpgradeCallback)(); + void set_surface_upgrade_callback(SurfaceUpgradeCallback p_callback); + void set_warn_on_surface_upgrade(bool p_warn); +#endif + #ifndef DISABLE_DEPRECATED - static void _fix_surface_compatibility(SurfaceData &p_surface); + void fix_surface_compatibility(SurfaceData &p_surface, const String &p_path = ""); #endif private: @@ -1647,6 +1655,10 @@ private: TypedArray<Dictionary> _instance_geometry_get_shader_parameter_list(RID p_instance) const; TypedArray<Image> _bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size); void _particles_set_trail_bind_poses(RID p_particles, const TypedArray<Transform3D> &p_bind_poses); +#ifdef TOOLS_ENABLED + SurfaceUpgradeCallback surface_upgrade_callback = nullptr; + bool warn_on_surface_upgrade = true; +#endif }; // Make variant understand the enums. diff --git a/thirdparty/README.md b/thirdparty/README.md index 980c35abb0..274e06bd30 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -74,7 +74,7 @@ fix build with our own copy of zstd (patch in `patches`). ## brotli - Upstream: https://github.com/google/brotli -- Version: git (ed1995b6bda19244070ab5d331111f16f67c8054, 2023) +- Version: 1.1.0 (ed738e842d2fbdf2d6459e39267a633c4a9b2f5d, 2023) - License: MIT Files extracted from upstream source: diff --git a/thirdparty/brotli/common/platform.h b/thirdparty/brotli/common/platform.h index 4186a8e96d..7406f3fe69 100644 --- a/thirdparty/brotli/common/platform.h +++ b/thirdparty/brotli/common/platform.h @@ -14,10 +14,11 @@ * BROTLI_BUILD_LITTLE_ENDIAN forces to use little-endian optimizations * BROTLI_BUILD_NO_RBIT disables "rbit" optimization for ARM CPUs * BROTLI_BUILD_NO_UNALIGNED_READ_FAST forces off the fast-unaligned-read - optimizations (mainly for testing purposes). + optimizations (mainly for testing purposes) * BROTLI_DEBUG dumps file name and line number when decoder detects stream or memory error * BROTLI_ENABLE_LOG enables asserts and dumps various state information + * BROTLI_ENABLE_DUMP overrides default "dump" behaviour */ #ifndef BROTLI_COMMON_PLATFORM_H_ @@ -208,8 +209,13 @@ OR: #define BROTLI_TARGET_RISCV64 #endif +#if defined(__loongarch_lp64) +#define BROTLI_TARGET_LOONGARCH64 +#endif + #if defined(BROTLI_TARGET_X64) || defined(BROTLI_TARGET_ARMV8_64) || \ - defined(BROTLI_TARGET_POWERPC64) || defined(BROTLI_TARGET_RISCV64) + defined(BROTLI_TARGET_POWERPC64) || defined(BROTLI_TARGET_RISCV64) || \ + defined(BROTLI_TARGET_LOONGARCH64) #define BROTLI_TARGET_64_BITS 1 #else #define BROTLI_TARGET_64_BITS 0 @@ -268,7 +274,7 @@ OR: #define BROTLI_UNALIGNED_READ_FAST (!!0) #elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \ defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY) || \ - defined(BROTLI_TARGET_RISCV64) + defined(BROTLI_TARGET_RISCV64) || defined(BROTLI_TARGET_LOONGARCH64) /* These targets are known to generate efficient code for unaligned reads * (e.g. a single instruction, not multiple 1-byte loads, shifted and or'd * together). */ @@ -402,14 +408,24 @@ static BROTLI_INLINE void BROTLI_UNALIGNED_STORE_PTR(void* p, const void* v) { #endif #if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG) +#define BROTLI_ENABLE_DUMP_DEFAULT 1 #define BROTLI_DCHECK(x) assert(x) +#else +#define BROTLI_ENABLE_DUMP_DEFAULT 0 +#define BROTLI_DCHECK(x) +#endif + +#if !defined(BROTLI_ENABLE_DUMP) +#define BROTLI_ENABLE_DUMP BROTLI_ENABLE_DUMP_DEFAULT +#endif + +#if BROTLI_ENABLE_DUMP static BROTLI_INLINE void BrotliDump(const char* f, int l, const char* fn) { fprintf(stderr, "%s:%d (%s)\n", f, l, fn); fflush(stderr); } #define BROTLI_DUMP() BrotliDump(__FILE__, __LINE__, __FUNCTION__) #else -#define BROTLI_DCHECK(x) #define BROTLI_DUMP() (void)(0) #endif @@ -517,7 +533,7 @@ BROTLI_UNUSED_FUNCTION void BrotliSuppressUnusedFunctions(void) { BROTLI_UNUSED(&brotli_max_uint8_t); BROTLI_UNUSED(&BrotliDefaultAllocFunc); BROTLI_UNUSED(&BrotliDefaultFreeFunc); -#if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG) +#if BROTLI_ENABLE_DUMP BROTLI_UNUSED(&BrotliDump); #endif } diff --git a/thirdparty/brotli/common/shared_dictionary.c b/thirdparty/brotli/common/shared_dictionary.c index 3ca40c0698..49f1c9b075 100644 --- a/thirdparty/brotli/common/shared_dictionary.c +++ b/thirdparty/brotli/common/shared_dictionary.c @@ -20,6 +20,8 @@ extern "C" { #endif +#if defined(BROTLI_EXPERIMENTAL) + #define BROTLI_NUM_ENCODED_LENGTHS (SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH \ - SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH + 1) @@ -442,6 +444,8 @@ static BROTLI_BOOL DecodeSharedDictionary( return ParseDictionary(encoded, size, dict); } +#endif /* BROTLI_EXPERIMENTAL */ + void BrotliSharedDictionaryDestroyInstance( BrotliSharedDictionary* dict) { if (!dict) { @@ -464,9 +468,12 @@ BROTLI_BOOL BrotliSharedDictionaryAttach( if (!dict) { return BROTLI_FALSE; } +#if defined(BROTLI_EXPERIMENTAL) if (type == BROTLI_SHARED_DICTIONARY_SERIALIZED) { return DecodeSharedDictionary(data, data_size, dict); - } else if (type == BROTLI_SHARED_DICTIONARY_RAW) { + } +#endif /* BROTLI_EXPERIMENTAL */ + if (type == BROTLI_SHARED_DICTIONARY_RAW) { if (dict->num_prefix >= SHARED_BROTLI_MAX_COMPOUND_DICTS) { return BROTLI_FALSE; } @@ -474,9 +481,8 @@ BROTLI_BOOL BrotliSharedDictionaryAttach( dict->prefix[dict->num_prefix] = data; dict->num_prefix++; return BROTLI_TRUE; - } else { - return BROTLI_FALSE; } + return BROTLI_FALSE; } BrotliSharedDictionary* BrotliSharedDictionaryCreateInstance( diff --git a/thirdparty/brotli/common/version.h b/thirdparty/brotli/common/version.h index 01b2998e25..8098040f64 100644 --- a/thirdparty/brotli/common/version.h +++ b/thirdparty/brotli/common/version.h @@ -9,18 +9,43 @@ #ifndef BROTLI_COMMON_VERSION_H_ #define BROTLI_COMMON_VERSION_H_ -/* This macro should only be used when library is compiled together with client. - If library is dynamically linked, use BrotliDecoderVersion and +/* Compose 3 components into a single number. In a hexadecimal representation + B and C components occupy exactly 3 digits. */ +#define BROTLI_MAKE_HEX_VERSION(A, B, C) ((A << 24) | (B << 12) | C) + +/* Those macros should only be used when library is compiled together with + the client. If library is dynamically linked, use BrotliDecoderVersion and BrotliEncoderVersion methods. */ -/* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */ -#define BROTLI_VERSION 0x1000009 +#define BROTLI_VERSION_MAJOR 1 +#define BROTLI_VERSION_MINOR 1 +#define BROTLI_VERSION_PATCH 0 + +#define BROTLI_VERSION BROTLI_MAKE_HEX_VERSION( \ + BROTLI_VERSION_MAJOR, BROTLI_VERSION_MINOR, BROTLI_VERSION_PATCH) /* This macro is used by build system to produce Libtool-friendly soname. See https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html + Version evolution rules: + - interfaces added (or change is compatible) -> current+1:0:age+1 + - interfaces removed (or changed is incompatible) -> current+1:0:0 + - interfaces not changed -> current:revision+1:age */ -/* ABI version, calculated as (CURRENT << 24) | (REVISION << 12) | AGE */ -#define BROTLI_ABI_VERSION 0x1009000 +#define BROTLI_ABI_CURRENT 2 +#define BROTLI_ABI_REVISION 0 +#define BROTLI_ABI_AGE 1 + +#if BROTLI_VERSION_MAJOR != (BROTLI_ABI_CURRENT - BROTLI_ABI_AGE) +#error ABI/API version inconsistency +#endif + +#if BROTLI_VERSION_MINOR != BROTLI_ABI_AGE +#error ABI/API version inconsistency +#endif + +#if BROTLI_VERSION_PATCH != BROTLI_ABI_REVISION +#error ABI/API version inconsistency +#endif #endif /* BROTLI_COMMON_VERSION_H_ */ diff --git a/thirdparty/brotli/dec/bit_reader.c b/thirdparty/brotli/dec/bit_reader.c index 97e21f56f6..35101ddc1a 100644 --- a/thirdparty/brotli/dec/bit_reader.c +++ b/thirdparty/brotli/dec/bit_reader.c @@ -16,7 +16,7 @@ extern "C" { #endif -const uint32_t kBrotliBitMask[33] = { 0x00000000, +const brotli_reg_t kBrotliBitMask[33] = { 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, @@ -29,7 +29,7 @@ const uint32_t kBrotliBitMask[33] = { 0x00000000, void BrotliInitBitReader(BrotliBitReader* const br) { br->val_ = 0; - br->bit_pos_ = sizeof(br->val_) << 3; + br->bit_pos_ = 0; } BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) { @@ -41,6 +41,7 @@ BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) { aligned_read_mask = 0; } if (BrotliGetAvailableBits(br) == 0) { + br->val_ = 0; if (!BrotliPullByte(br)) { return BROTLI_FALSE; } @@ -56,9 +57,9 @@ BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) { } BROTLI_BOOL BrotliSafeReadBits32Slow(BrotliBitReader* const br, - uint32_t n_bits, uint32_t* val) { - uint32_t low_val; - uint32_t high_val; + brotli_reg_t n_bits, brotli_reg_t* val) { + brotli_reg_t low_val; + brotli_reg_t high_val; BrotliBitReaderState memento; BROTLI_DCHECK(n_bits <= 32); BROTLI_DCHECK(n_bits > 24); diff --git a/thirdparty/brotli/dec/bit_reader.h b/thirdparty/brotli/dec/bit_reader.h index 64701ecacc..930dc60f1d 100644 --- a/thirdparty/brotli/dec/bit_reader.h +++ b/thirdparty/brotli/dec/bit_reader.h @@ -22,13 +22,16 @@ extern "C" { #define BROTLI_SHORT_FILL_BIT_WINDOW_READ (sizeof(brotli_reg_t) >> 1) -BROTLI_INTERNAL extern const uint32_t kBrotliBitMask[33]; +/* 162 bits + 7 bytes */ +#define BROTLI_FAST_INPUT_SLACK 28 -static BROTLI_INLINE uint32_t BitMask(uint32_t n) { +BROTLI_INTERNAL extern const brotli_reg_t kBrotliBitMask[33]; + +static BROTLI_INLINE brotli_reg_t BitMask(brotli_reg_t n) { if (BROTLI_IS_CONSTANT(n) || BROTLI_HAS_UBFX) { /* Masking with this expression turns to a single "Unsigned Bit Field Extract" UBFX instruction on ARM. */ - return ~((0xFFFFFFFFu) << n); + return ~(~((brotli_reg_t)0) << n); } else { return kBrotliBitMask[n]; } @@ -36,40 +39,57 @@ static BROTLI_INLINE uint32_t BitMask(uint32_t n) { typedef struct { brotli_reg_t val_; /* pre-fetched bits */ - uint32_t bit_pos_; /* current bit-reading position in val_ */ + brotli_reg_t bit_pos_; /* current bit-reading position in val_ */ const uint8_t* next_in; /* the byte we're reading from */ - size_t avail_in; + const uint8_t* guard_in; /* position from which "fast-path" is prohibited */ + const uint8_t* last_in; /* == next_in + avail_in */ } BrotliBitReader; typedef struct { brotli_reg_t val_; - uint32_t bit_pos_; + brotli_reg_t bit_pos_; const uint8_t* next_in; size_t avail_in; } BrotliBitReaderState; /* Initializes the BrotliBitReader fields. */ -BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* const br); +BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* br); /* Ensures that accumulator is not empty. May consume up to sizeof(brotli_reg_t) - 1 bytes of input. Returns BROTLI_FALSE if data is required but there is no input available. For !BROTLI_UNALIGNED_READ_FAST this function also prepares bit reader for aligned reading. */ -BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br); +BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* br); /* Fallback for BrotliSafeReadBits32. Extracted as noninlined method to unburden the main code-path. Never called for RFC brotli streams, required only for "large-window" mode and other extensions. */ BROTLI_INTERNAL BROTLI_NOINLINE BROTLI_BOOL BrotliSafeReadBits32Slow( - BrotliBitReader* const br, uint32_t n_bits, uint32_t* val); + BrotliBitReader* br, brotli_reg_t n_bits, brotli_reg_t* val); + +static BROTLI_INLINE size_t +BrotliBitReaderGetAvailIn(BrotliBitReader* const br) { + return (size_t)(br->last_in - br->next_in); +} static BROTLI_INLINE void BrotliBitReaderSaveState( BrotliBitReader* const from, BrotliBitReaderState* to) { to->val_ = from->val_; to->bit_pos_ = from->bit_pos_; to->next_in = from->next_in; - to->avail_in = from->avail_in; + to->avail_in = BrotliBitReaderGetAvailIn(from); +} + +static BROTLI_INLINE void BrotliBitReaderSetInput( + BrotliBitReader* const br, const uint8_t* next_in, size_t avail_in) { + br->next_in = next_in; + br->last_in = (avail_in == 0) ? next_in : (next_in + avail_in); + if (avail_in + 1 > BROTLI_FAST_INPUT_SLACK) { + br->guard_in = next_in + (avail_in + 1 - BROTLI_FAST_INPUT_SLACK); + } else { + br->guard_in = next_in; + } } static BROTLI_INLINE void BrotliBitReaderRestoreState( @@ -77,12 +97,12 @@ static BROTLI_INLINE void BrotliBitReaderRestoreState( to->val_ = from->val_; to->bit_pos_ = from->bit_pos_; to->next_in = from->next_in; - to->avail_in = from->avail_in; + BrotliBitReaderSetInput(to, from->next_in, from->avail_in); } -static BROTLI_INLINE uint32_t BrotliGetAvailableBits( +static BROTLI_INLINE brotli_reg_t BrotliGetAvailableBits( const BrotliBitReader* br) { - return (BROTLI_64_BITS ? 64 : 32) - br->bit_pos_; + return br->bit_pos_; } /* Returns amount of unread bytes the bit reader still has buffered from the @@ -90,15 +110,27 @@ static BROTLI_INLINE uint32_t BrotliGetAvailableBits( maximal ring-buffer size (larger number won't be utilized anyway). */ static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) { static const size_t kCap = (size_t)1 << BROTLI_LARGE_MAX_WBITS; - if (br->avail_in > kCap) return kCap; - return br->avail_in + (BrotliGetAvailableBits(br) >> 3); + size_t avail_in = BrotliBitReaderGetAvailIn(br); + if (avail_in > kCap) return kCap; + return avail_in + (BrotliGetAvailableBits(br) >> 3); } /* Checks if there is at least |num| bytes left in the input ring-buffer (excluding the bits remaining in br->val_). */ static BROTLI_INLINE BROTLI_BOOL BrotliCheckInputAmount( - BrotliBitReader* const br, size_t num) { - return TO_BROTLI_BOOL(br->avail_in >= num); + BrotliBitReader* const br) { + return TO_BROTLI_BOOL(br->next_in < br->guard_in); +} + +/* Load more bits into accumulator. */ +static BROTLI_INLINE brotli_reg_t BrotliBitReaderLoadBits(brotli_reg_t val, + brotli_reg_t new_bits, + brotli_reg_t count, + brotli_reg_t offset) { + BROTLI_DCHECK( + !((val >> offset) & ~new_bits & ~(~((brotli_reg_t)0) << count))); + (void)count; + return val | (new_bits << offset); } /* Guarantees that there are at least |n_bits| + 1 bits in accumulator. @@ -106,61 +138,51 @@ static BROTLI_INLINE BROTLI_BOOL BrotliCheckInputAmount( |n_bits| should be in the range [1..24] for regular build. For portable non-64-bit little-endian build only 16 bits are safe to request. */ static BROTLI_INLINE void BrotliFillBitWindow( - BrotliBitReader* const br, uint32_t n_bits) { + BrotliBitReader* const br, brotli_reg_t n_bits) { #if (BROTLI_64_BITS) if (BROTLI_UNALIGNED_READ_FAST && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 8)) { - uint32_t bit_pos = br->bit_pos_; - if (bit_pos >= 56) { - br->val_ = - (br->val_ >> 56) | (BROTLI_UNALIGNED_LOAD64LE(br->next_in) << 8); - br->bit_pos_ = - bit_pos ^ 56; /* here same as -= 56 because of the if condition */ - br->avail_in -= 7; + brotli_reg_t bit_pos = br->bit_pos_; + if (bit_pos <= 8) { + br->val_ = BrotliBitReaderLoadBits(br->val_, + BROTLI_UNALIGNED_LOAD64LE(br->next_in), 56, bit_pos); + br->bit_pos_ = bit_pos + 56; br->next_in += 7; } } else if (BROTLI_UNALIGNED_READ_FAST && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 16)) { - uint32_t bit_pos = br->bit_pos_; - if (bit_pos >= 48) { - br->val_ = - (br->val_ >> 48) | (BROTLI_UNALIGNED_LOAD64LE(br->next_in) << 16); - br->bit_pos_ = - bit_pos ^ 48; /* here same as -= 48 because of the if condition */ - br->avail_in -= 6; + brotli_reg_t bit_pos = br->bit_pos_; + if (bit_pos <= 16) { + br->val_ = BrotliBitReaderLoadBits(br->val_, + BROTLI_UNALIGNED_LOAD64LE(br->next_in), 48, bit_pos); + br->bit_pos_ = bit_pos + 48; br->next_in += 6; } } else { - uint32_t bit_pos = br->bit_pos_; - if (bit_pos >= 32) { - br->val_ = (br->val_ >> 32) | - (((uint64_t)BROTLI_UNALIGNED_LOAD32LE(br->next_in)) << 32); - br->bit_pos_ = - bit_pos ^ 32; /* here same as -= 32 because of the if condition */ - br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ; + brotli_reg_t bit_pos = br->bit_pos_; + if (bit_pos <= 32) { + br->val_ = BrotliBitReaderLoadBits(br->val_, + (uint64_t)BROTLI_UNALIGNED_LOAD32LE(br->next_in), 32, bit_pos); + br->bit_pos_ = bit_pos + 32; br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ; } } #else if (BROTLI_UNALIGNED_READ_FAST && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 8)) { - uint32_t bit_pos = br->bit_pos_; - if (bit_pos >= 24) { - br->val_ = - (br->val_ >> 24) | (BROTLI_UNALIGNED_LOAD32LE(br->next_in) << 8); - br->bit_pos_ = - bit_pos ^ 24; /* here same as -= 24 because of the if condition */ - br->avail_in -= 3; + brotli_reg_t bit_pos = br->bit_pos_; + if (bit_pos <= 8) { + br->val_ = BrotliBitReaderLoadBits(br->val_, + BROTLI_UNALIGNED_LOAD32LE(br->next_in), 24, bit_pos); + br->bit_pos_ = bit_pos + 24; br->next_in += 3; } } else { - uint32_t bit_pos = br->bit_pos_; - if (bit_pos >= 16) { - br->val_ = (br->val_ >> 16) | - (((uint32_t)BROTLI_UNALIGNED_LOAD16LE(br->next_in)) << 16); - br->bit_pos_ = - bit_pos ^ 16; /* here same as -= 16 because of the if condition */ - br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ; + brotli_reg_t bit_pos = br->bit_pos_; + if (bit_pos <= 16) { + br->val_ = BrotliBitReaderLoadBits(br->val_, + (uint32_t)BROTLI_UNALIGNED_LOAD16LE(br->next_in), 16, bit_pos); + br->bit_pos_ = bit_pos + 16; br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ; } } @@ -176,17 +198,12 @@ static BROTLI_INLINE void BrotliFillBitWindow16(BrotliBitReader* const br) { /* Tries to pull one byte of input to accumulator. Returns BROTLI_FALSE if there is no input available. */ static BROTLI_INLINE BROTLI_BOOL BrotliPullByte(BrotliBitReader* const br) { - if (br->avail_in == 0) { + if (br->next_in == br->last_in) { return BROTLI_FALSE; } - br->val_ >>= 8; -#if (BROTLI_64_BITS) - br->val_ |= ((uint64_t)*br->next_in) << 56; -#else - br->val_ |= ((uint32_t)*br->next_in) << 24; -#endif - br->bit_pos_ -= 8; - --br->avail_in; + br->val_ = BrotliBitReaderLoadBits(br->val_, + (brotli_reg_t)*br->next_in, 8, br->bit_pos_); + br->bit_pos_ += 8; ++br->next_in; return BROTLI_TRUE; } @@ -195,81 +212,90 @@ static BROTLI_INLINE BROTLI_BOOL BrotliPullByte(BrotliBitReader* const br) { The number of valid bits could be calculated by BrotliGetAvailableBits. */ static BROTLI_INLINE brotli_reg_t BrotliGetBitsUnmasked( BrotliBitReader* const br) { - return br->val_ >> br->bit_pos_; + return br->val_; } /* Like BrotliGetBits, but does not mask the result. The result contains at least 16 valid bits. */ -static BROTLI_INLINE uint32_t BrotliGet16BitsUnmasked( +static BROTLI_INLINE brotli_reg_t BrotliGet16BitsUnmasked( BrotliBitReader* const br) { BrotliFillBitWindow(br, 16); - return (uint32_t)BrotliGetBitsUnmasked(br); + return (brotli_reg_t)BrotliGetBitsUnmasked(br); } /* Returns the specified number of bits from |br| without advancing bit position. */ -static BROTLI_INLINE uint32_t BrotliGetBits( - BrotliBitReader* const br, uint32_t n_bits) { +static BROTLI_INLINE brotli_reg_t BrotliGetBits( + BrotliBitReader* const br, brotli_reg_t n_bits) { BrotliFillBitWindow(br, n_bits); - return (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits); + return BrotliGetBitsUnmasked(br) & BitMask(n_bits); } /* Tries to peek the specified amount of bits. Returns BROTLI_FALSE, if there is not enough input. */ static BROTLI_INLINE BROTLI_BOOL BrotliSafeGetBits( - BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) { + BrotliBitReader* const br, brotli_reg_t n_bits, brotli_reg_t* val) { while (BrotliGetAvailableBits(br) < n_bits) { if (!BrotliPullByte(br)) { return BROTLI_FALSE; } } - *val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits); + *val = BrotliGetBitsUnmasked(br) & BitMask(n_bits); return BROTLI_TRUE; } /* Advances the bit pos by |n_bits|. */ static BROTLI_INLINE void BrotliDropBits( - BrotliBitReader* const br, uint32_t n_bits) { - br->bit_pos_ += n_bits; + BrotliBitReader* const br, brotli_reg_t n_bits) { + br->bit_pos_ -= n_bits; + br->val_ >>= n_bits; } -static BROTLI_INLINE void BrotliBitReaderUnload(BrotliBitReader* br) { - uint32_t unused_bytes = BrotliGetAvailableBits(br) >> 3; - uint32_t unused_bits = unused_bytes << 3; - br->avail_in += unused_bytes; - br->next_in -= unused_bytes; - if (unused_bits == sizeof(br->val_) << 3) { - br->val_ = 0; - } else { - br->val_ <<= unused_bits; +/* Make sure that there are no spectre bits in accumulator. + This is important for the cases when some bytes are skipped + (i.e. never placed into accumulator). */ +static BROTLI_INLINE void BrotliBitReaderNormalize(BrotliBitReader* br) { + /* Actually, it is enough to normalize when br->bit_pos_ == 0 */ + if (br->bit_pos_ < (sizeof(brotli_reg_t) << 3u)) { + br->val_ &= (((brotli_reg_t)1) << br->bit_pos_) - 1; } - br->bit_pos_ += unused_bits; +} + +static BROTLI_INLINE void BrotliBitReaderUnload(BrotliBitReader* br) { + brotli_reg_t unused_bytes = BrotliGetAvailableBits(br) >> 3; + brotli_reg_t unused_bits = unused_bytes << 3; + br->next_in = + (unused_bytes == 0) ? br->next_in : (br->next_in - unused_bytes); + br->bit_pos_ -= unused_bits; + BrotliBitReaderNormalize(br); } /* Reads the specified number of bits from |br| and advances the bit pos. Precondition: accumulator MUST contain at least |n_bits|. */ -static BROTLI_INLINE void BrotliTakeBits( - BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) { - *val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits); +static BROTLI_INLINE void BrotliTakeBits(BrotliBitReader* const br, + brotli_reg_t n_bits, + brotli_reg_t* val) { + *val = BrotliGetBitsUnmasked(br) & BitMask(n_bits); BROTLI_LOG(("[BrotliTakeBits] %d %d %d val: %6x\n", - (int)br->avail_in, (int)br->bit_pos_, (int)n_bits, (int)*val)); + (int)BrotliBitReaderGetAvailIn(br), (int)br->bit_pos_, + (int)n_bits, (int)*val)); BrotliDropBits(br, n_bits); } /* Reads the specified number of bits from |br| and advances the bit pos. Assumes that there is enough input to perform BrotliFillBitWindow. Up to 24 bits are allowed to be requested from this method. */ -static BROTLI_INLINE uint32_t BrotliReadBits24( - BrotliBitReader* const br, uint32_t n_bits) { +static BROTLI_INLINE brotli_reg_t BrotliReadBits24( + BrotliBitReader* const br, brotli_reg_t n_bits) { BROTLI_DCHECK(n_bits <= 24); if (BROTLI_64_BITS || (n_bits <= 16)) { - uint32_t val; + brotli_reg_t val; BrotliFillBitWindow(br, n_bits); BrotliTakeBits(br, n_bits, &val); return val; } else { - uint32_t low_val; - uint32_t high_val; + brotli_reg_t low_val; + brotli_reg_t high_val; BrotliFillBitWindow(br, 16); BrotliTakeBits(br, 16, &low_val); BrotliFillBitWindow(br, 8); @@ -279,17 +305,17 @@ static BROTLI_INLINE uint32_t BrotliReadBits24( } /* Same as BrotliReadBits24, but allows reading up to 32 bits. */ -static BROTLI_INLINE uint32_t BrotliReadBits32( - BrotliBitReader* const br, uint32_t n_bits) { +static BROTLI_INLINE brotli_reg_t BrotliReadBits32( + BrotliBitReader* const br, brotli_reg_t n_bits) { BROTLI_DCHECK(n_bits <= 32); if (BROTLI_64_BITS || (n_bits <= 16)) { - uint32_t val; + brotli_reg_t val; BrotliFillBitWindow(br, n_bits); BrotliTakeBits(br, n_bits, &val); return val; } else { - uint32_t low_val; - uint32_t high_val; + brotli_reg_t low_val; + brotli_reg_t high_val; BrotliFillBitWindow(br, 16); BrotliTakeBits(br, 16, &low_val); BrotliFillBitWindow(br, 16); @@ -302,7 +328,7 @@ static BROTLI_INLINE uint32_t BrotliReadBits32( is not enough input. |n_bits| MUST be positive. Up to 24 bits are allowed to be requested from this method. */ static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits( - BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) { + BrotliBitReader* const br, brotli_reg_t n_bits, brotli_reg_t* val) { BROTLI_DCHECK(n_bits <= 24); while (BrotliGetAvailableBits(br) < n_bits) { if (!BrotliPullByte(br)) { @@ -315,7 +341,7 @@ static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits( /* Same as BrotliSafeReadBits, but allows reading up to 32 bits. */ static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits32( - BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) { + BrotliBitReader* const br, brotli_reg_t n_bits, brotli_reg_t* val) { BROTLI_DCHECK(n_bits <= 32); if (BROTLI_64_BITS || (n_bits <= 24)) { while (BrotliGetAvailableBits(br) < n_bits) { @@ -333,16 +359,19 @@ static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits32( /* Advances the bit reader position to the next byte boundary and verifies that any skipped bits are set to zero. */ static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) { - uint32_t pad_bits_count = BrotliGetAvailableBits(br) & 0x7; - uint32_t pad_bits = 0; + brotli_reg_t pad_bits_count = BrotliGetAvailableBits(br) & 0x7; + brotli_reg_t pad_bits = 0; if (pad_bits_count != 0) { BrotliTakeBits(br, pad_bits_count, &pad_bits); } + BrotliBitReaderNormalize(br); return TO_BROTLI_BOOL(pad_bits == 0); } static BROTLI_INLINE void BrotliDropBytes(BrotliBitReader* br, size_t num) { - br->avail_in -= num; + /* Check detour is legal: accumulator must to be empty. */ + BROTLI_DCHECK(br->bit_pos_ == 0); + BROTLI_DCHECK(br->val_ == 0); br->next_in += num; } @@ -357,12 +386,36 @@ static BROTLI_INLINE void BrotliCopyBytes(uint8_t* dest, ++dest; --num; } + BrotliBitReaderNormalize(br); if (num > 0) { memcpy(dest, br->next_in, num); BrotliDropBytes(br, num); } } +BROTLI_UNUSED_FUNCTION void BrotliBitReaderSuppressUnusedFunctions(void) { + BROTLI_UNUSED(&BrotliBitReaderSuppressUnusedFunctions); + + BROTLI_UNUSED(&BrotliBitReaderGetAvailIn); + BROTLI_UNUSED(&BrotliBitReaderLoadBits); + BROTLI_UNUSED(&BrotliBitReaderRestoreState); + BROTLI_UNUSED(&BrotliBitReaderSaveState); + BROTLI_UNUSED(&BrotliBitReaderSetInput); + BROTLI_UNUSED(&BrotliBitReaderUnload); + BROTLI_UNUSED(&BrotliCheckInputAmount); + BROTLI_UNUSED(&BrotliCopyBytes); + BROTLI_UNUSED(&BrotliFillBitWindow16); + BROTLI_UNUSED(&BrotliGet16BitsUnmasked); + BROTLI_UNUSED(&BrotliGetBits); + BROTLI_UNUSED(&BrotliGetRemainingBytes); + BROTLI_UNUSED(&BrotliJumpToByteBoundary); + BROTLI_UNUSED(&BrotliReadBits24); + BROTLI_UNUSED(&BrotliReadBits32); + BROTLI_UNUSED(&BrotliSafeGetBits); + BROTLI_UNUSED(&BrotliSafeReadBits); + BROTLI_UNUSED(&BrotliSafeReadBits32); +} + #if defined(__cplusplus) || defined(c_plusplus) } /* extern "C" */ #endif diff --git a/thirdparty/brotli/dec/decode.c b/thirdparty/brotli/dec/decode.c index 3ee1963a85..220c7e85c6 100644 --- a/thirdparty/brotli/dec/decode.c +++ b/thirdparty/brotli/dec/decode.c @@ -44,7 +44,7 @@ extern "C" { - doing up to two 16-byte copies for fast backward copying - inserting transformed dictionary word: 255 prefix + 32 base + 255 suffix */ -static const uint32_t kRingBufferWriteAheadSlack = 542; +static const brotli_reg_t kRingBufferWriteAheadSlack = 542; static const uint8_t kCodeLengthCodeOrder[BROTLI_CODE_LENGTH_CODES] = { 1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15, @@ -116,6 +116,10 @@ static BROTLI_NOINLINE BrotliDecoderResult SaveErrorCode( BrotliDecoderState* s, BrotliDecoderErrorCode e, size_t consumed_input) { s->error_code = (int)e; s->used_input += consumed_input; + if ((s->buffer_length != 0) && (s->br.next_in == s->br.last_in)) { + /* If internal buffer is depleted at last, reset it. */ + s->buffer_length = 0; + } switch (e) { case BROTLI_DECODER_SUCCESS: return BROTLI_DECODER_RESULT_SUCCESS; @@ -135,7 +139,7 @@ static BROTLI_NOINLINE BrotliDecoderResult SaveErrorCode( Precondition: bit-reader accumulator has at least 8 bits. */ static BrotliDecoderErrorCode DecodeWindowBits(BrotliDecoderState* s, BrotliBitReader* br) { - uint32_t n; + brotli_reg_t n; BROTLI_BOOL large_window = s->large_window; s->large_window = BROTLI_FALSE; BrotliTakeBits(br, 1, &n); @@ -145,7 +149,7 @@ static BrotliDecoderErrorCode DecodeWindowBits(BrotliDecoderState* s, } BrotliTakeBits(br, 3, &n); if (n != 0) { - s->window_bits = 17 + n; + s->window_bits = (17u + n) & 63u; return BROTLI_DECODER_SUCCESS; } BrotliTakeBits(br, 3, &n); @@ -162,7 +166,7 @@ static BrotliDecoderErrorCode DecodeWindowBits(BrotliDecoderState* s, } } if (n != 0) { - s->window_bits = 8 + n; + s->window_bits = (8u + n) & 63u; return BROTLI_DECODER_SUCCESS; } s->window_bits = 17; @@ -181,8 +185,8 @@ static BROTLI_INLINE void memmove16(uint8_t* dst, uint8_t* src) { /* Decodes a number in the range [0..255], by reading 1 - 11 bits. */ static BROTLI_NOINLINE BrotliDecoderErrorCode DecodeVarLenUint8( - BrotliDecoderState* s, BrotliBitReader* br, uint32_t* value) { - uint32_t bits; + BrotliDecoderState* s, BrotliBitReader* br, brotli_reg_t* value) { + brotli_reg_t bits; switch (s->substate_decode_uint8) { case BROTLI_STATE_DECODE_UINT8_NONE: if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, 1, &bits))) { @@ -226,7 +230,7 @@ static BROTLI_NOINLINE BrotliDecoderErrorCode DecodeVarLenUint8( /* Decodes a metablock length and flags by reading 2 - 31 bits. */ static BrotliDecoderErrorCode BROTLI_NOINLINE DecodeMetaBlockLength( BrotliDecoderState* s, BrotliBitReader* br) { - uint32_t bits; + brotli_reg_t bits; int i; for (;;) { switch (s->substate_metablock_header) { @@ -349,13 +353,13 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE DecodeMetaBlockLength( This method doesn't read data from the bit reader, BUT drops the amount of bits that correspond to the decoded symbol. bits MUST contain at least 15 (BROTLI_HUFFMAN_MAX_CODE_LENGTH) valid bits. */ -static BROTLI_INLINE uint32_t DecodeSymbol(uint32_t bits, - const HuffmanCode* table, - BrotliBitReader* br) { +static BROTLI_INLINE brotli_reg_t DecodeSymbol(brotli_reg_t bits, + const HuffmanCode* table, + BrotliBitReader* br) { BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table); BROTLI_HC_ADJUST_TABLE_INDEX(table, bits & HUFFMAN_TABLE_MASK); if (BROTLI_HC_FAST_LOAD_BITS(table) > HUFFMAN_TABLE_BITS) { - uint32_t nbits = BROTLI_HC_FAST_LOAD_BITS(table) - HUFFMAN_TABLE_BITS; + brotli_reg_t nbits = BROTLI_HC_FAST_LOAD_BITS(table) - HUFFMAN_TABLE_BITS; BrotliDropBits(br, HUFFMAN_TABLE_BITS); BROTLI_HC_ADJUST_TABLE_INDEX(table, BROTLI_HC_FAST_LOAD_VALUE(table) + @@ -367,17 +371,17 @@ static BROTLI_INLINE uint32_t DecodeSymbol(uint32_t bits, /* Reads and decodes the next Huffman code from bit-stream. This method peeks 16 bits of input and drops 0 - 15 of them. */ -static BROTLI_INLINE uint32_t ReadSymbol(const HuffmanCode* table, - BrotliBitReader* br) { +static BROTLI_INLINE brotli_reg_t ReadSymbol(const HuffmanCode* table, + BrotliBitReader* br) { return DecodeSymbol(BrotliGet16BitsUnmasked(br), table, br); } /* Same as DecodeSymbol, but it is known that there is less than 15 bits of input are currently available. */ static BROTLI_NOINLINE BROTLI_BOOL SafeDecodeSymbol( - const HuffmanCode* table, BrotliBitReader* br, uint32_t* result) { - uint32_t val; - uint32_t available_bits = BrotliGetAvailableBits(br); + const HuffmanCode* table, BrotliBitReader* br, brotli_reg_t* result) { + brotli_reg_t val; + brotli_reg_t available_bits = BrotliGetAvailableBits(br); BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table); if (available_bits == 0) { if (BROTLI_HC_FAST_LOAD_BITS(table) == 0) { @@ -386,7 +390,7 @@ static BROTLI_NOINLINE BROTLI_BOOL SafeDecodeSymbol( } return BROTLI_FALSE; /* No valid bits at all. */ } - val = (uint32_t)BrotliGetBitsUnmasked(br); + val = BrotliGetBitsUnmasked(br); BROTLI_HC_ADJUST_TABLE_INDEX(table, val & HUFFMAN_TABLE_MASK); if (BROTLI_HC_FAST_LOAD_BITS(table) <= HUFFMAN_TABLE_BITS) { if (BROTLI_HC_FAST_LOAD_BITS(table) <= available_bits) { @@ -415,8 +419,8 @@ static BROTLI_NOINLINE BROTLI_BOOL SafeDecodeSymbol( } static BROTLI_INLINE BROTLI_BOOL SafeReadSymbol( - const HuffmanCode* table, BrotliBitReader* br, uint32_t* result) { - uint32_t val; + const HuffmanCode* table, BrotliBitReader* br, brotli_reg_t* result) { + brotli_reg_t val; if (BROTLI_PREDICT_TRUE(BrotliSafeGetBits(br, 15, &val))) { *result = DecodeSymbol(val, table, br); return BROTLI_TRUE; @@ -428,8 +432,8 @@ static BROTLI_INLINE BROTLI_BOOL SafeReadSymbol( static BROTLI_INLINE void PreloadSymbol(int safe, const HuffmanCode* table, BrotliBitReader* br, - uint32_t* bits, - uint32_t* value) { + brotli_reg_t* bits, + brotli_reg_t* value) { if (safe) { return; } @@ -441,15 +445,15 @@ static BROTLI_INLINE void PreloadSymbol(int safe, /* Decodes the next Huffman code using data prepared by PreloadSymbol. Reads 0 - 15 bits. Also peeks 8 following bits. */ -static BROTLI_INLINE uint32_t ReadPreloadedSymbol(const HuffmanCode* table, +static BROTLI_INLINE brotli_reg_t ReadPreloadedSymbol(const HuffmanCode* table, BrotliBitReader* br, - uint32_t* bits, - uint32_t* value) { - uint32_t result = *value; + brotli_reg_t* bits, + brotli_reg_t* value) { + brotli_reg_t result = *value; if (BROTLI_PREDICT_FALSE(*bits > HUFFMAN_TABLE_BITS)) { - uint32_t val = BrotliGet16BitsUnmasked(br); + brotli_reg_t val = BrotliGet16BitsUnmasked(br); const HuffmanCode* ext = table + (val & HUFFMAN_TABLE_MASK) + *value; - uint32_t mask = BitMask((*bits - HUFFMAN_TABLE_BITS)); + brotli_reg_t mask = BitMask((*bits - HUFFMAN_TABLE_BITS)); BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(ext); BrotliDropBits(br, HUFFMAN_TABLE_BITS); BROTLI_HC_ADJUST_TABLE_INDEX(ext, (val >> HUFFMAN_TABLE_BITS) & mask); @@ -462,8 +466,8 @@ static BROTLI_INLINE uint32_t ReadPreloadedSymbol(const HuffmanCode* table, return result; } -static BROTLI_INLINE uint32_t Log2Floor(uint32_t x) { - uint32_t result = 0; +static BROTLI_INLINE brotli_reg_t Log2Floor(brotli_reg_t x) { + brotli_reg_t result = 0; while (x) { x >>= 1; ++result; @@ -475,16 +479,16 @@ static BROTLI_INLINE uint32_t Log2Floor(uint32_t x) { Totally 1..4 symbols are read, 1..11 bits each. The list of symbols MUST NOT contain duplicates. */ static BrotliDecoderErrorCode ReadSimpleHuffmanSymbols( - uint32_t alphabet_size_max, uint32_t alphabet_size_limit, + brotli_reg_t alphabet_size_max, brotli_reg_t alphabet_size_limit, BrotliDecoderState* s) { /* max_bits == 1..11; symbol == 0..3; 1..44 bits will be read. */ BrotliBitReader* br = &s->br; BrotliMetablockHeaderArena* h = &s->arena.header; - uint32_t max_bits = Log2Floor(alphabet_size_max - 1); - uint32_t i = h->sub_loop_counter; - uint32_t num_symbols = h->symbol; + brotli_reg_t max_bits = Log2Floor(alphabet_size_max - 1); + brotli_reg_t i = h->sub_loop_counter; + brotli_reg_t num_symbols = h->symbol; while (i <= num_symbols) { - uint32_t v; + brotli_reg_t v; if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, max_bits, &v))) { h->sub_loop_counter = i; h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_READ; @@ -500,7 +504,7 @@ static BrotliDecoderErrorCode ReadSimpleHuffmanSymbols( } for (i = 0; i < num_symbols; ++i) { - uint32_t k = i + 1; + brotli_reg_t k = i + 1; for (; k <= num_symbols; ++k) { if (h->symbols_lists_array[i] == h->symbols_lists_array[k]) { return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME); @@ -517,9 +521,9 @@ static BrotliDecoderErrorCode ReadSimpleHuffmanSymbols( C) extend corresponding index-chain D) reduce the Huffman space E) update the histogram */ -static BROTLI_INLINE void ProcessSingleCodeLength(uint32_t code_len, - uint32_t* symbol, uint32_t* repeat, uint32_t* space, - uint32_t* prev_code_len, uint16_t* symbol_lists, +static BROTLI_INLINE void ProcessSingleCodeLength(brotli_reg_t code_len, + brotli_reg_t* symbol, brotli_reg_t* repeat, brotli_reg_t* space, + brotli_reg_t* prev_code_len, uint16_t* symbol_lists, uint16_t* code_length_histo, int* next_symbol) { *repeat = 0; if (code_len != 0) { /* code_len == 1..15 */ @@ -544,14 +548,14 @@ static BROTLI_INLINE void ProcessSingleCodeLength(uint32_t code_len, PRECONDITION: code_len == BROTLI_REPEAT_PREVIOUS_CODE_LENGTH or code_len == BROTLI_REPEAT_ZERO_CODE_LENGTH */ -static BROTLI_INLINE void ProcessRepeatedCodeLength(uint32_t code_len, - uint32_t repeat_delta, uint32_t alphabet_size, uint32_t* symbol, - uint32_t* repeat, uint32_t* space, uint32_t* prev_code_len, - uint32_t* repeat_code_len, uint16_t* symbol_lists, +static BROTLI_INLINE void ProcessRepeatedCodeLength(brotli_reg_t code_len, + brotli_reg_t repeat_delta, brotli_reg_t alphabet_size, brotli_reg_t* symbol, + brotli_reg_t* repeat, brotli_reg_t* space, brotli_reg_t* prev_code_len, + brotli_reg_t* repeat_code_len, uint16_t* symbol_lists, uint16_t* code_length_histo, int* next_symbol) { - uint32_t old_repeat; - uint32_t extra_bits = 3; /* for BROTLI_REPEAT_ZERO_CODE_LENGTH */ - uint32_t new_len = 0; /* for BROTLI_REPEAT_ZERO_CODE_LENGTH */ + brotli_reg_t old_repeat; + brotli_reg_t extra_bits = 3; /* for BROTLI_REPEAT_ZERO_CODE_LENGTH */ + brotli_reg_t new_len = 0; /* for BROTLI_REPEAT_ZERO_CODE_LENGTH */ if (code_len == BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) { new_len = *prev_code_len; extra_bits = 2; @@ -576,7 +580,7 @@ static BROTLI_INLINE void ProcessRepeatedCodeLength(uint32_t code_len, BROTLI_LOG(("[ReadHuffmanCode] code_length[%d..%d] = %d\n", (int)*symbol, (int)(*symbol + repeat_delta - 1), (int)*repeat_code_len)); if (*repeat_code_len != 0) { - unsigned last = *symbol + repeat_delta; + brotli_reg_t last = *symbol + repeat_delta; int next = next_symbol[*repeat_code_len]; do { symbol_lists[next] = (uint16_t)*symbol; @@ -593,14 +597,14 @@ static BROTLI_INLINE void ProcessRepeatedCodeLength(uint32_t code_len, /* Reads and decodes symbol codelengths. */ static BrotliDecoderErrorCode ReadSymbolCodeLengths( - uint32_t alphabet_size, BrotliDecoderState* s) { + brotli_reg_t alphabet_size, BrotliDecoderState* s) { BrotliBitReader* br = &s->br; BrotliMetablockHeaderArena* h = &s->arena.header; - uint32_t symbol = h->symbol; - uint32_t repeat = h->repeat; - uint32_t space = h->space; - uint32_t prev_code_len = h->prev_code_len; - uint32_t repeat_code_len = h->repeat_code_len; + brotli_reg_t symbol = h->symbol; + brotli_reg_t repeat = h->repeat; + brotli_reg_t space = h->space; + brotli_reg_t prev_code_len = h->prev_code_len; + brotli_reg_t repeat_code_len = h->repeat_code_len; uint16_t* symbol_lists = h->symbol_lists; uint16_t* code_length_histo = h->code_length_histo; int* next_symbol = h->next_symbol; @@ -609,9 +613,9 @@ static BrotliDecoderErrorCode ReadSymbolCodeLengths( } while (symbol < alphabet_size && space > 0) { const HuffmanCode* p = h->table; - uint32_t code_len; + brotli_reg_t code_len; BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(p); - if (!BrotliCheckInputAmount(br, BROTLI_SHORT_FILL_BIT_WINDOW_READ)) { + if (!BrotliCheckInputAmount(br)) { h->symbol = symbol; h->repeat = repeat; h->prev_code_len = prev_code_len; @@ -628,10 +632,10 @@ static BrotliDecoderErrorCode ReadSymbolCodeLengths( ProcessSingleCodeLength(code_len, &symbol, &repeat, &space, &prev_code_len, symbol_lists, code_length_histo, next_symbol); } else { /* code_len == 16..17, extra_bits == 2..3 */ - uint32_t extra_bits = + brotli_reg_t extra_bits = (code_len == BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) ? 2 : 3; - uint32_t repeat_delta = - (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(extra_bits); + brotli_reg_t repeat_delta = + BrotliGetBitsUnmasked(br) & BitMask(extra_bits); BrotliDropBits(br, extra_bits); ProcessRepeatedCodeLength(code_len, repeat_delta, alphabet_size, &symbol, &repeat, &space, &prev_code_len, &repeat_code_len, @@ -643,15 +647,15 @@ static BrotliDecoderErrorCode ReadSymbolCodeLengths( } static BrotliDecoderErrorCode SafeReadSymbolCodeLengths( - uint32_t alphabet_size, BrotliDecoderState* s) { + brotli_reg_t alphabet_size, BrotliDecoderState* s) { BrotliBitReader* br = &s->br; BrotliMetablockHeaderArena* h = &s->arena.header; BROTLI_BOOL get_byte = BROTLI_FALSE; while (h->symbol < alphabet_size && h->space > 0) { const HuffmanCode* p = h->table; - uint32_t code_len; - uint32_t available_bits; - uint32_t bits = 0; + brotli_reg_t code_len; + brotli_reg_t available_bits; + brotli_reg_t bits = 0; BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(p); if (get_byte && !BrotliPullByte(br)) return BROTLI_DECODER_NEEDS_MORE_INPUT; get_byte = BROTLI_FALSE; @@ -672,8 +676,8 @@ static BrotliDecoderErrorCode SafeReadSymbolCodeLengths( &h->prev_code_len, h->symbol_lists, h->code_length_histo, h->next_symbol); } else { /* code_len == 16..17, extra_bits == 2..3 */ - uint32_t extra_bits = code_len - 14U; - uint32_t repeat_delta = (bits >> BROTLI_HC_FAST_LOAD_BITS(p)) & + brotli_reg_t extra_bits = code_len - 14U; + brotli_reg_t repeat_delta = (bits >> BROTLI_HC_FAST_LOAD_BITS(p)) & BitMask(extra_bits); if (available_bits < BROTLI_HC_FAST_LOAD_BITS(p) + extra_bits) { get_byte = BROTLI_TRUE; @@ -694,15 +698,15 @@ static BrotliDecoderErrorCode SafeReadSymbolCodeLengths( static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) { BrotliBitReader* br = &s->br; BrotliMetablockHeaderArena* h = &s->arena.header; - uint32_t num_codes = h->repeat; - unsigned space = h->space; - uint32_t i = h->sub_loop_counter; + brotli_reg_t num_codes = h->repeat; + brotli_reg_t space = h->space; + brotli_reg_t i = h->sub_loop_counter; for (; i < BROTLI_CODE_LENGTH_CODES; ++i) { const uint8_t code_len_idx = kCodeLengthCodeOrder[i]; - uint32_t ix; - uint32_t v; + brotli_reg_t ix; + brotli_reg_t v; if (BROTLI_PREDICT_FALSE(!BrotliSafeGetBits(br, 4, &ix))) { - uint32_t available_bits = BrotliGetAvailableBits(br); + brotli_reg_t available_bits = BrotliGetAvailableBits(br); if (available_bits != 0) { ix = BrotliGetBitsUnmasked(br) & 0xF; } else { @@ -747,10 +751,10 @@ static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) { encoded with predefined entropy code. 32 - 74 bits are used. B.2) Decoded table is used to decode code lengths of symbols in resulting Huffman table. In worst case 3520 bits are read. */ -static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size_max, - uint32_t alphabet_size_limit, +static BrotliDecoderErrorCode ReadHuffmanCode(brotli_reg_t alphabet_size_max, + brotli_reg_t alphabet_size_limit, HuffmanCode* table, - uint32_t* opt_table_size, + brotli_reg_t* opt_table_size, BrotliDecoderState* s) { BrotliBitReader* br = &s->br; BrotliMetablockHeaderArena* h = &s->arena.header; @@ -796,9 +800,9 @@ static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size_max, /* Fall through. */ case BROTLI_STATE_HUFFMAN_SIMPLE_BUILD: { - uint32_t table_size; + brotli_reg_t table_size; if (h->symbol == 3) { - uint32_t bits; + brotli_reg_t bits; if (!BrotliSafeReadBits(br, 1, &bits)) { h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_BUILD; return BROTLI_DECODER_NEEDS_MORE_INPUT; @@ -806,8 +810,9 @@ static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size_max, h->symbol += bits; } BROTLI_LOG_UINT(h->symbol); - table_size = BrotliBuildSimpleHuffmanTable( - table, HUFFMAN_TABLE_BITS, h->symbols_lists_array, h->symbol); + table_size = BrotliBuildSimpleHuffmanTable(table, HUFFMAN_TABLE_BITS, + h->symbols_lists_array, + (uint32_t)h->symbol); if (opt_table_size) { *opt_table_size = table_size; } @@ -817,7 +822,7 @@ static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size_max, /* Decode Huffman-coded code lengths. */ case BROTLI_STATE_HUFFMAN_COMPLEX: { - uint32_t i; + brotli_reg_t i; BrotliDecoderErrorCode result = ReadCodeLengthCodeLengths(s); if (result != BROTLI_DECODER_SUCCESS) { return result; @@ -841,7 +846,7 @@ static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size_max, /* Fall through. */ case BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS: { - uint32_t table_size; + brotli_reg_t table_size; BrotliDecoderErrorCode result = ReadSymbolCodeLengths( alphabet_size_limit, s); if (result == BROTLI_DECODER_NEEDS_MORE_INPUT) { @@ -872,10 +877,10 @@ static BrotliDecoderErrorCode ReadHuffmanCode(uint32_t alphabet_size_max, } /* Decodes a block length by reading 3..39 bits. */ -static BROTLI_INLINE uint32_t ReadBlockLength(const HuffmanCode* table, - BrotliBitReader* br) { - uint32_t code; - uint32_t nbits; +static BROTLI_INLINE brotli_reg_t ReadBlockLength(const HuffmanCode* table, + BrotliBitReader* br) { + brotli_reg_t code; + brotli_reg_t nbits; code = ReadSymbol(table, br); nbits = _kBrotliPrefixCodeRanges[code].nbits; /* nbits == 2..24 */ return _kBrotliPrefixCodeRanges[code].offset + BrotliReadBits24(br, nbits); @@ -884,9 +889,9 @@ static BROTLI_INLINE uint32_t ReadBlockLength(const HuffmanCode* table, /* WARNING: if state is not BROTLI_STATE_READ_BLOCK_LENGTH_NONE, then reading can't be continued with ReadBlockLength. */ static BROTLI_INLINE BROTLI_BOOL SafeReadBlockLength( - BrotliDecoderState* s, uint32_t* result, const HuffmanCode* table, + BrotliDecoderState* s, brotli_reg_t* result, const HuffmanCode* table, BrotliBitReader* br) { - uint32_t index; + brotli_reg_t index; if (s->substate_read_block_length == BROTLI_STATE_READ_BLOCK_LENGTH_NONE) { if (!SafeReadSymbol(table, br, &index)) { return BROTLI_FALSE; @@ -895,9 +900,9 @@ static BROTLI_INLINE BROTLI_BOOL SafeReadBlockLength( index = s->block_length_index; } { - uint32_t bits; - uint32_t nbits = _kBrotliPrefixCodeRanges[index].nbits; - uint32_t offset = _kBrotliPrefixCodeRanges[index].offset; + brotli_reg_t bits; + brotli_reg_t nbits = _kBrotliPrefixCodeRanges[index].nbits; + brotli_reg_t offset = _kBrotliPrefixCodeRanges[index].offset; if (!BrotliSafeReadBits(br, nbits, &bits)) { s->block_length_index = index; s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX; @@ -924,10 +929,10 @@ static BROTLI_INLINE BROTLI_BOOL SafeReadBlockLength( Most of input values are 0 and 1. To reduce number of branches, we replace inner for loop with do-while. */ static BROTLI_NOINLINE void InverseMoveToFrontTransform( - uint8_t* v, uint32_t v_len, BrotliDecoderState* state) { + uint8_t* v, brotli_reg_t v_len, BrotliDecoderState* state) { /* Reinitialize elements that could have been changed. */ - uint32_t i = 1; - uint32_t upper_bound = state->mtf_upper_bound; + brotli_reg_t i = 1; + brotli_reg_t upper_bound = state->mtf_upper_bound; uint32_t* mtf = &state->mtf[1]; /* Make mtf[-1] addressable. */ uint8_t* mtf_u8 = (uint8_t*)mtf; /* Load endian-aware constant. */ @@ -970,7 +975,7 @@ static BrotliDecoderErrorCode HuffmanTreeGroupDecode( h->substate_tree_group = BROTLI_STATE_TREE_GROUP_LOOP; } while (h->htree_index < group->num_htrees) { - uint32_t table_size; + brotli_reg_t table_size; BrotliDecoderErrorCode result = ReadHuffmanCode(group->alphabet_size_max, group->alphabet_size_limit, h->next, &table_size, s); if (result != BROTLI_DECODER_SUCCESS) return result; @@ -990,8 +995,8 @@ static BrotliDecoderErrorCode HuffmanTreeGroupDecode( This table will be used for reading context map items. 3) Read context map items; "0" values could be run-length encoded. 4) Optionally, apply InverseMoveToFront transform to the resulting map. */ -static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size, - uint32_t* num_htrees, +static BrotliDecoderErrorCode DecodeContextMap(brotli_reg_t context_map_size, + brotli_reg_t* num_htrees, uint8_t** context_map_arg, BrotliDecoderState* s) { BrotliBitReader* br = &s->br; @@ -1021,7 +1026,7 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size, /* Fall through. */ case BROTLI_STATE_CONTEXT_MAP_READ_PREFIX: { - uint32_t bits; + brotli_reg_t bits; /* In next stage ReadHuffmanCode uses at least 4 bits, so it is safe to peek 4 bits ahead. */ if (!BrotliSafeGetBits(br, 5, &bits)) { @@ -1040,7 +1045,7 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size, /* Fall through. */ case BROTLI_STATE_CONTEXT_MAP_HUFFMAN: { - uint32_t alphabet_size = *num_htrees + h->max_run_length_prefix; + brotli_reg_t alphabet_size = *num_htrees + h->max_run_length_prefix; result = ReadHuffmanCode(alphabet_size, alphabet_size, h->context_map_table, NULL, s); if (result != BROTLI_DECODER_SUCCESS) return result; @@ -1050,10 +1055,10 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size, /* Fall through. */ case BROTLI_STATE_CONTEXT_MAP_DECODE: { - uint32_t context_index = h->context_index; - uint32_t max_run_length_prefix = h->max_run_length_prefix; + brotli_reg_t context_index = h->context_index; + brotli_reg_t max_run_length_prefix = h->max_run_length_prefix; uint8_t* context_map = *context_map_arg; - uint32_t code = h->code; + brotli_reg_t code = h->code; BROTLI_BOOL skip_preamble = (code != 0xFFFF); while (context_index < context_map_size || skip_preamble) { if (!skip_preamble) { @@ -1078,7 +1083,7 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size, } /* RLE sub-stage. */ { - uint32_t reps; + brotli_reg_t reps; if (!BrotliSafeReadBits(br, code, &reps)) { h->code = code; h->context_index = context_index; @@ -1099,7 +1104,7 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size, /* Fall through. */ case BROTLI_STATE_CONTEXT_MAP_TRANSFORM: { - uint32_t bits; + brotli_reg_t bits; if (!BrotliSafeReadBits(br, 1, &bits)) { h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_TRANSFORM; return BROTLI_DECODER_NEEDS_MORE_INPUT; @@ -1121,14 +1126,14 @@ static BrotliDecoderErrorCode DecodeContextMap(uint32_t context_map_size, Reads 3..54 bits. */ static BROTLI_INLINE BROTLI_BOOL DecodeBlockTypeAndLength( int safe, BrotliDecoderState* s, int tree_type) { - uint32_t max_block_type = s->num_block_types[tree_type]; + brotli_reg_t max_block_type = s->num_block_types[tree_type]; const HuffmanCode* type_tree = &s->block_type_trees[ tree_type * BROTLI_HUFFMAN_MAX_SIZE_258]; const HuffmanCode* len_tree = &s->block_len_trees[ tree_type * BROTLI_HUFFMAN_MAX_SIZE_26]; BrotliBitReader* br = &s->br; - uint32_t* ringbuffer = &s->block_type_rb[tree_type * 2]; - uint32_t block_type; + brotli_reg_t* ringbuffer = &s->block_type_rb[tree_type * 2]; + brotli_reg_t block_type; if (max_block_type <= 1) { return BROTLI_FALSE; } @@ -1173,6 +1178,7 @@ static BROTLI_INLINE void DetectTrivialLiteralBlockTypes( size_t sample = s->context_map[offset]; size_t j; for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS);) { + /* NOLINTNEXTLINE(bugprone-macro-repeated-side-effects) */ BROTLI_REPEAT_4({ error |= s->context_map[offset + j++] ^ sample; }) } if (error == 0) { @@ -1184,8 +1190,8 @@ static BROTLI_INLINE void DetectTrivialLiteralBlockTypes( static BROTLI_INLINE void PrepareLiteralDecoding(BrotliDecoderState* s) { uint8_t context_mode; size_t trivial; - uint32_t block_type = s->block_type_rb[1]; - uint32_t context_offset = block_type << BROTLI_LITERAL_CONTEXT_BITS; + brotli_reg_t block_type = s->block_type_rb[1]; + brotli_reg_t context_offset = block_type << BROTLI_LITERAL_CONTEXT_BITS; s->context_map_slice = s->context_map + context_offset; trivial = s->trivial_literal_contexts[block_type >> 5]; s->trivial_literal_context = (trivial >> (block_type & 31)) & 1; @@ -1549,8 +1555,8 @@ static int CopyFromCompoundDictionary(BrotliDecoderState* s, int pos) { BROTLI_BOOL BrotliDecoderAttachDictionary( BrotliDecoderState* state, BrotliSharedDictionaryType type, size_t data_size, const uint8_t data[BROTLI_ARRAY_PARAM(data_size)]) { - uint32_t i; - uint32_t num_prefix_before = state->dictionary->num_prefix; + brotli_reg_t i; + brotli_reg_t num_prefix_before = state->dictionary->num_prefix; if (state->state != BROTLI_STATE_UNINITED) return BROTLI_FALSE; if (!BrotliSharedDictionaryAttach(state->dictionary, type, data_size, data)) { return BROTLI_FALSE; @@ -1616,7 +1622,7 @@ static BrotliDecoderErrorCode ReadContextModes(BrotliDecoderState* s) { int i = s->loop_counter; while (i < (int)s->num_block_types[0]) { - uint32_t bits; + brotli_reg_t bits; if (!BrotliSafeReadBits(br, 2, &bits)) { s->loop_counter = i; return BROTLI_DECODER_NEEDS_MORE_INPUT; @@ -1656,7 +1662,7 @@ static BROTLI_INLINE void TakeDistanceFromRingBuffer(BrotliDecoderState* s) { } static BROTLI_INLINE BROTLI_BOOL SafeReadBits( - BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) { + BrotliBitReader* const br, brotli_reg_t n_bits, brotli_reg_t* val) { if (n_bits != 0) { return BrotliSafeReadBits(br, n_bits, val); } else { @@ -1666,7 +1672,7 @@ static BROTLI_INLINE BROTLI_BOOL SafeReadBits( } static BROTLI_INLINE BROTLI_BOOL SafeReadBits32( - BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) { + BrotliBitReader* const br, brotli_reg_t n_bits, brotli_reg_t* val) { if (n_bits != 0) { return BrotliSafeReadBits32(br, n_bits, val); } else { @@ -1744,16 +1750,16 @@ static BROTLI_INLINE BROTLI_BOOL SafeReadBits32( NB: it is possible to have all 64 tables precalculated. */ static void CalculateDistanceLut(BrotliDecoderState* s) { BrotliMetablockBodyArena* b = &s->arena.body; - uint32_t npostfix = s->distance_postfix_bits; - uint32_t ndirect = s->num_direct_distance_codes; - uint32_t alphabet_size_limit = s->distance_hgroup.alphabet_size_limit; - uint32_t postfix = 1u << npostfix; - uint32_t j; - uint32_t bits = 1; - uint32_t half = 0; + brotli_reg_t npostfix = s->distance_postfix_bits; + brotli_reg_t ndirect = s->num_direct_distance_codes; + brotli_reg_t alphabet_size_limit = s->distance_hgroup.alphabet_size_limit; + brotli_reg_t postfix = 1u << npostfix; + brotli_reg_t j; + brotli_reg_t bits = 1; + brotli_reg_t half = 0; /* Skip short codes. */ - uint32_t i = BROTLI_NUM_DISTANCE_SHORT_CODES; + brotli_reg_t i = BROTLI_NUM_DISTANCE_SHORT_CODES; /* Fill direct codes. */ for (j = 0; j < ndirect; ++j) { @@ -1764,7 +1770,7 @@ static void CalculateDistanceLut(BrotliDecoderState* s) { /* Fill regular distance codes. */ while (i < alphabet_size_limit) { - uint32_t base = ndirect + ((((2 + half) << bits) - 4) << npostfix) + 1; + brotli_reg_t base = ndirect + ((((2 + half) << bits) - 4) << npostfix) + 1; /* Always fill the complete group. */ for (j = 0; j < postfix; ++j) { b->dist_extra_bits[i] = (uint8_t)bits; @@ -1780,8 +1786,8 @@ static void CalculateDistanceLut(BrotliDecoderState* s) { static BROTLI_INLINE BROTLI_BOOL ReadDistanceInternal( int safe, BrotliDecoderState* s, BrotliBitReader* br) { BrotliMetablockBodyArena* b = &s->arena.body; - uint32_t code; - uint32_t bits; + brotli_reg_t code; + brotli_reg_t bits; BrotliBitReaderState memento; HuffmanCode* distance_tree = s->distance_hgroup.htrees[s->dist_htree_index]; if (!safe) { @@ -1827,9 +1833,9 @@ static BROTLI_INLINE BROTLI_BOOL SafeReadDistance( static BROTLI_INLINE BROTLI_BOOL ReadCommandInternal( int safe, BrotliDecoderState* s, BrotliBitReader* br, int* insert_length) { - uint32_t cmd_code; - uint32_t insert_len_extra = 0; - uint32_t copy_length; + brotli_reg_t cmd_code; + brotli_reg_t insert_len_extra = 0; + brotli_reg_t copy_length; CmdLutElement v; BrotliBitReaderState memento; if (!safe) { @@ -1874,11 +1880,11 @@ static BROTLI_INLINE BROTLI_BOOL SafeReadCommand( } static BROTLI_INLINE BROTLI_BOOL CheckInputAmount( - int safe, BrotliBitReader* const br, size_t num) { + int safe, BrotliBitReader* const br) { if (safe) { return BROTLI_TRUE; } - return BrotliCheckInputAmount(br, num); + return BrotliCheckInputAmount(br); } #define BROTLI_SAFE(METHOD) \ @@ -1901,7 +1907,7 @@ static BROTLI_INLINE BrotliDecoderErrorCode ProcessCommandsInternal( BrotliBitReader* br = &s->br; int compound_dictionary_size = GetCompoundDictionarySize(s); - if (!CheckInputAmount(safe, br, 28)) { + if (!CheckInputAmount(safe, br)) { result = BROTLI_DECODER_NEEDS_MORE_INPUT; goto saveStateAndReturn; } @@ -1926,7 +1932,7 @@ CommandBegin: if (safe) { s->state = BROTLI_STATE_COMMAND_BEGIN; } - if (!CheckInputAmount(safe, br, 28)) { /* 156 bits + 7 bytes */ + if (!CheckInputAmount(safe, br)) { s->state = BROTLI_STATE_COMMAND_BEGIN; result = BROTLI_DECODER_NEEDS_MORE_INPUT; goto saveStateAndReturn; @@ -1950,25 +1956,23 @@ CommandInner: } /* Read the literals in the command. */ if (s->trivial_literal_context) { - uint32_t bits; - uint32_t value; + brotli_reg_t bits; + brotli_reg_t value; PreloadSymbol(safe, s->literal_htree, br, &bits, &value); do { - if (!CheckInputAmount(safe, br, 28)) { /* 162 bits + 7 bytes */ + if (!CheckInputAmount(safe, br)) { s->state = BROTLI_STATE_COMMAND_INNER; result = BROTLI_DECODER_NEEDS_MORE_INPUT; goto saveStateAndReturn; } if (BROTLI_PREDICT_FALSE(s->block_length[0] == 0)) { - BROTLI_SAFE(DecodeLiteralBlockSwitch(s)); - PreloadSymbol(safe, s->literal_htree, br, &bits, &value); - if (!s->trivial_literal_context) goto CommandInner; + goto NextLiteralBlock; } if (!safe) { s->ringbuffer[pos] = (uint8_t)ReadPreloadedSymbol(s->literal_htree, br, &bits, &value); } else { - uint32_t literal; + brotli_reg_t literal; if (!SafeReadSymbol(s->literal_htree, br, &literal)) { result = BROTLI_DECODER_NEEDS_MORE_INPUT; goto saveStateAndReturn; @@ -1990,14 +1994,13 @@ CommandInner: do { const HuffmanCode* hc; uint8_t context; - if (!CheckInputAmount(safe, br, 28)) { /* 162 bits + 7 bytes */ + if (!CheckInputAmount(safe, br)) { s->state = BROTLI_STATE_COMMAND_INNER; result = BROTLI_DECODER_NEEDS_MORE_INPUT; goto saveStateAndReturn; } if (BROTLI_PREDICT_FALSE(s->block_length[0] == 0)) { - BROTLI_SAFE(DecodeLiteralBlockSwitch(s)); - if (s->trivial_literal_context) goto CommandInner; + goto NextLiteralBlock; } context = BROTLI_CONTEXT(p1, p2, s->context_lookup); BROTLI_LOG_UINT(context); @@ -2006,7 +2009,7 @@ CommandInner: if (!safe) { p1 = (uint8_t)ReadSymbol(hc, br); } else { - uint32_t literal; + brotli_reg_t literal; if (!SafeReadSymbol(hc, br, &literal)) { result = BROTLI_DECODER_NEEDS_MORE_INPUT; goto saveStateAndReturn; @@ -2087,7 +2090,7 @@ CommandPostDecodeLiterals: const BrotliDictionary* words = s->dictionary->words[dict_id]; const BrotliTransforms* transforms = s->dictionary->transforms[dict_id]; int offset = (int)words->offsets_by_length[i]; - uint32_t shift = words->size_bits_by_length[i]; + brotli_reg_t shift = words->size_bits_by_length[i]; int address = s->distance_code - s->max_distance - 1 - compound_dictionary_size; int mask = (int)BitMask(shift); @@ -2110,7 +2113,7 @@ CommandPostDecodeLiterals: if (dict_id2 != dict_id && words2->size_bits_by_length[i] != 0) { const BrotliTransforms* transforms2 = s->dictionary->transforms[dict_id2]; - uint32_t shift2 = words2->size_bits_by_length[i]; + brotli_reg_t shift2 = words2->size_bits_by_length[i]; int num = (int)((1u << shift2) & ~1u) * (int)transforms2->num_transforms; if (dist_remaining < num) { @@ -2236,6 +2239,10 @@ CommandPostWrapCopy: goto CommandBegin; } +NextLiteralBlock: + BROTLI_SAFE(DecodeLiteralBlockSwitch(s)); + goto CommandInner; + saveStateAndReturn: s->pos = pos; s->loop_counter = i; @@ -2312,14 +2319,13 @@ BrotliDecoderResult BrotliDecoderDecompressStream( } if (!*available_out) next_out = 0; if (s->buffer_length == 0) { /* Just connect bit reader to input stream. */ - br->avail_in = *available_in; - br->next_in = *next_in; + BrotliBitReaderSetInput(br, *next_in, *available_in); } else { /* At least one byte of input is required. More than one byte of input may be required to complete the transaction -> reading more data must be done in a loop -> do it in a main loop. */ result = BROTLI_DECODER_NEEDS_MORE_INPUT; - br->next_in = &s->buffer.u8[0]; + BrotliBitReaderSetInput(br, &s->buffer.u8[0], s->buffer_length); } /* State machine */ for (;;) { @@ -2336,23 +2342,23 @@ BrotliDecoderResult BrotliDecoderDecompressStream( } } if (s->buffer_length != 0) { /* Used with internal buffer. */ - if (br->avail_in == 0) { + if (br->next_in == br->last_in) { /* Successfully finished read transaction. Accumulator contains less than 8 bits, because internal buffer is expanded byte-by-byte until it is enough to complete read. */ s->buffer_length = 0; /* Switch to input stream and restart. */ result = BROTLI_DECODER_SUCCESS; - br->avail_in = *available_in; - br->next_in = *next_in; + BrotliBitReaderSetInput(br, *next_in, *available_in); continue; } else if (*available_in != 0) { /* Not enough data in buffer, but can take one more byte from input stream. */ result = BROTLI_DECODER_SUCCESS; + BROTLI_DCHECK(s->buffer_length < 8); s->buffer.u8[s->buffer_length] = **next_in; s->buffer_length++; - br->avail_in = s->buffer_length; + BrotliBitReaderSetInput(br, &s->buffer.u8[0], s->buffer_length); (*next_in)++; (*available_in)--; /* Retry with more data in buffer. */ @@ -2363,7 +2369,7 @@ BrotliDecoderResult BrotliDecoderDecompressStream( } else { /* Input stream doesn't contain enough input. */ /* Copy tail to internal buffer and return. */ *next_in = br->next_in; - *available_in = br->avail_in; + *available_in = BrotliBitReaderGetAvailIn(br); while (*available_in) { s->buffer.u8[s->buffer_length] = **next_in; s->buffer_length++; @@ -2386,7 +2392,7 @@ BrotliDecoderResult BrotliDecoderDecompressStream( stream it has less than 8 bits in accumulator, so it is safe to return unused accumulator bits there. */ BrotliBitReaderUnload(br); - *available_in = br->avail_in; + *available_in = BrotliBitReaderGetAvailIn(br); *next_in = br->next_in; } break; @@ -2410,17 +2416,20 @@ BrotliDecoderResult BrotliDecoderDecompressStream( s->state = BROTLI_STATE_INITIALIZE; break; - case BROTLI_STATE_LARGE_WINDOW_BITS: - if (!BrotliSafeReadBits(br, 6, &s->window_bits)) { + case BROTLI_STATE_LARGE_WINDOW_BITS: { + brotli_reg_t bits; + if (!BrotliSafeReadBits(br, 6, &bits)) { result = BROTLI_DECODER_NEEDS_MORE_INPUT; break; } + s->window_bits = bits & 63u; if (s->window_bits < BROTLI_LARGE_MIN_WBITS || s->window_bits > BROTLI_LARGE_MAX_WBITS) { result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS); break; } s->state = BROTLI_STATE_INITIALIZE; + } /* Fall through. */ case BROTLI_STATE_INITIALIZE: @@ -2518,7 +2527,7 @@ BrotliDecoderResult BrotliDecoderDecompressStream( /* Fall through. */ case BROTLI_STATE_HUFFMAN_CODE_1: { - uint32_t alphabet_size = s->num_block_types[s->loop_counter] + 2; + brotli_reg_t alphabet_size = s->num_block_types[s->loop_counter] + 2; int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_SIZE_258; result = ReadHuffmanCode(alphabet_size, alphabet_size, &s->block_type_trees[tree_offset], NULL, s); @@ -2528,7 +2537,7 @@ BrotliDecoderResult BrotliDecoderDecompressStream( /* Fall through. */ case BROTLI_STATE_HUFFMAN_CODE_2: { - uint32_t alphabet_size = BROTLI_NUM_BLOCK_LEN_SYMBOLS; + brotli_reg_t alphabet_size = BROTLI_NUM_BLOCK_LEN_SYMBOLS; int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_SIZE_26; result = ReadHuffmanCode(alphabet_size, alphabet_size, &s->block_len_trees[tree_offset], NULL, s); @@ -2569,7 +2578,7 @@ BrotliDecoderResult BrotliDecoderDecompressStream( break; case BROTLI_STATE_METABLOCK_HEADER_2: { - uint32_t bits; + brotli_reg_t bits; if (!BrotliSafeReadBits(br, 6, &bits)) { result = BROTLI_DECODER_NEEDS_MORE_INPUT; break; @@ -2610,15 +2619,16 @@ BrotliDecoderResult BrotliDecoderDecompressStream( /* Fall through. */ case BROTLI_STATE_CONTEXT_MAP_2: { - uint32_t npostfix = s->distance_postfix_bits; - uint32_t ndirect = s->num_direct_distance_codes; - uint32_t distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE( + brotli_reg_t npostfix = s->distance_postfix_bits; + brotli_reg_t ndirect = s->num_direct_distance_codes; + brotli_reg_t distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE( npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS); - uint32_t distance_alphabet_size_limit = distance_alphabet_size_max; + brotli_reg_t distance_alphabet_size_limit = distance_alphabet_size_max; BROTLI_BOOL allocation_success = BROTLI_TRUE; if (s->large_window) { BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit( - BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect); + BROTLI_MAX_ALLOWED_DISTANCE, (uint32_t)npostfix, + (uint32_t)ndirect); distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE( npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS); distance_alphabet_size_limit = limit.max_alphabet_size; @@ -2749,7 +2759,7 @@ BrotliDecoderResult BrotliDecoderDecompressStream( } if (s->buffer_length == 0) { BrotliBitReaderUnload(br); - *available_in = br->avail_in; + *available_in = BrotliBitReaderGetAvailIn(br); *next_in = br->next_in; } s->state = BROTLI_STATE_DONE; @@ -2821,7 +2831,7 @@ BrotliDecoderErrorCode BrotliDecoderGetErrorCode(const BrotliDecoderState* s) { const char* BrotliDecoderErrorString(BrotliDecoderErrorCode c) { switch (c) { #define BROTLI_ERROR_CODE_CASE_(PREFIX, NAME, CODE) \ - case BROTLI_DECODER ## PREFIX ## NAME: return #NAME; + case BROTLI_DECODER ## PREFIX ## NAME: return #PREFIX #NAME; #define BROTLI_NOTHING_ BROTLI_DECODER_ERROR_CODES_LIST(BROTLI_ERROR_CODE_CASE_, BROTLI_NOTHING_) #undef BROTLI_ERROR_CODE_CASE_ @@ -2846,16 +2856,16 @@ void BrotliDecoderSetMetadataCallbacks( /* Escalate internal functions visibility; for testing purposes only. */ #if defined(BROTLI_TEST) BROTLI_BOOL SafeReadSymbolForTest( - const HuffmanCode*, BrotliBitReader*, uint32_t*); + const HuffmanCode*, BrotliBitReader*, brotli_reg_t*); BROTLI_BOOL SafeReadSymbolForTest( - const HuffmanCode* table, BrotliBitReader* br, uint32_t* result) { + const HuffmanCode* table, BrotliBitReader* br, brotli_reg_t* result) { return SafeReadSymbol(table, br, result); } void InverseMoveToFrontTransformForTest( - uint8_t*, uint32_t, BrotliDecoderState*); + uint8_t*, brotli_reg_t, BrotliDecoderState*); void InverseMoveToFrontTransformForTest( - uint8_t* v, uint32_t l, BrotliDecoderState* s) { + uint8_t* v, brotli_reg_t l, BrotliDecoderState* s) { InverseMoveToFrontTransform(v, l, s); } #endif diff --git a/thirdparty/brotli/dec/state.c b/thirdparty/brotli/dec/state.c index a3baf37b6d..be6a26680b 100644 --- a/thirdparty/brotli/dec/state.c +++ b/thirdparty/brotli/dec/state.c @@ -98,9 +98,9 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s, void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s) { s->meta_block_remaining_len = 0; - s->block_length[0] = 1U << 24; - s->block_length[1] = 1U << 24; - s->block_length[2] = 1U << 24; + s->block_length[0] = BROTLI_BLOCK_SIZE_CAP; + s->block_length[1] = BROTLI_BLOCK_SIZE_CAP; + s->block_length[2] = BROTLI_BLOCK_SIZE_CAP; s->num_block_types[0] = 1; s->num_block_types[1] = 1; s->num_block_types[2] = 1; @@ -158,8 +158,8 @@ void BrotliDecoderStateCleanup(BrotliDecoderState* s) { } BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(BrotliDecoderState* s, - HuffmanTreeGroup* group, uint32_t alphabet_size_max, - uint32_t alphabet_size_limit, uint32_t ntrees) { + HuffmanTreeGroup* group, brotli_reg_t alphabet_size_max, + brotli_reg_t alphabet_size_limit, brotli_reg_t ntrees) { /* 376 = 256 (1-st level table) + 4 + 7 + 15 + 31 + 63 (2-nd level mix-tables) This number is discovered "unlimited" "enough" calculator; it is actually a wee bigger than required in several cases (especially for alphabets with diff --git a/thirdparty/brotli/dec/state.h b/thirdparty/brotli/dec/state.h index 84fddc8a72..fd250b6842 100644 --- a/thirdparty/brotli/dec/state.h +++ b/thirdparty/brotli/dec/state.h @@ -211,15 +211,15 @@ typedef struct BrotliMetablockHeaderArena { BrotliRunningContextMapState substate_context_map; BrotliRunningHuffmanState substate_huffman; - uint32_t sub_loop_counter; + brotli_reg_t sub_loop_counter; - uint32_t repeat_code_len; - uint32_t prev_code_len; + brotli_reg_t repeat_code_len; + brotli_reg_t prev_code_len; /* For ReadHuffmanCode. */ - uint32_t symbol; - uint32_t repeat; - uint32_t space; + brotli_reg_t symbol; + brotli_reg_t repeat; + brotli_reg_t space; /* Huffman table for "histograms". */ HuffmanCode table[32]; @@ -233,21 +233,22 @@ typedef struct BrotliMetablockHeaderArena { uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES]; /* Population counts for the code lengths. */ uint16_t code_length_histo[16]; + /* TODO(eustas): +2 bytes padding */ /* For HuffmanTreeGroupDecode. */ int htree_index; HuffmanCode* next; /* For DecodeContextMap. */ - uint32_t context_index; - uint32_t max_run_length_prefix; - uint32_t code; + brotli_reg_t context_index; + brotli_reg_t max_run_length_prefix; + brotli_reg_t code; HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272]; } BrotliMetablockHeaderArena; typedef struct BrotliMetablockBodyArena { uint8_t dist_extra_bits[544]; - uint32_t dist_offset[544]; + brotli_reg_t dist_offset[544]; } BrotliMetablockBodyArena; struct BrotliDecoderStateStruct { @@ -268,7 +269,7 @@ struct BrotliDecoderStateStruct { uint64_t u64; uint8_t u8[8]; } buffer; - uint32_t buffer_length; + brotli_reg_t buffer_length; int pos; int max_backward_distance; @@ -278,6 +279,8 @@ struct BrotliDecoderStateStruct { int dist_rb_idx; int dist_rb[4]; int error_code; + int meta_block_remaining_len; + uint8_t* ringbuffer; uint8_t* ringbuffer_end; HuffmanCode* htree_command; @@ -298,29 +301,30 @@ struct BrotliDecoderStateStruct { /* Distance context is actual after command is decoded and before distance is computed. After distance computation it is used as a temporary variable. */ int distance_context; - int meta_block_remaining_len; - uint32_t block_length_index; - uint32_t block_length[3]; - uint32_t num_block_types[3]; - uint32_t block_type_rb[6]; - uint32_t distance_postfix_bits; - uint32_t num_direct_distance_codes; - uint32_t num_dist_htrees; + brotli_reg_t block_length[3]; + brotli_reg_t block_length_index; + brotli_reg_t num_block_types[3]; + brotli_reg_t block_type_rb[6]; + brotli_reg_t distance_postfix_bits; + brotli_reg_t num_direct_distance_codes; + brotli_reg_t num_dist_htrees; uint8_t* dist_context_map; HuffmanCode* literal_htree; - uint8_t dist_htree_index; - - int copy_length; - int distance_code; /* For partial write operations. */ size_t rb_roundtrips; /* how many times we went around the ring-buffer */ size_t partial_pos_out; /* how much output to the user in total */ /* For InverseMoveToFrontTransform. */ - uint32_t mtf_upper_bound; + brotli_reg_t mtf_upper_bound; uint32_t mtf[64 + 1]; + int copy_length; + int distance_code; + + uint8_t dist_htree_index; + /* TODO(eustas): +3 bytes padding */ + /* Less used attributes are at the end of this struct. */ brotli_decoder_metadata_start_func metadata_start_func; @@ -336,18 +340,20 @@ struct BrotliDecoderStateStruct { BrotliRunningDecodeUint8State substate_decode_uint8; BrotliRunningReadBlockLengthState substate_read_block_length; + int new_ringbuffer_size; + /* TODO(eustas): +4 bytes padding */ + unsigned int is_last_metablock : 1; unsigned int is_uncompressed : 1; unsigned int is_metadata : 1; unsigned int should_wrap_ringbuffer : 1; unsigned int canny_ringbuffer_allocation : 1; unsigned int large_window : 1; + unsigned int window_bits : 6; unsigned int size_nibbles : 8; - uint32_t window_bits; - - int new_ringbuffer_size; + /* TODO(eustas): +12 bits padding */ - uint32_t num_literal_htrees; + brotli_reg_t num_literal_htrees; uint8_t* context_map; uint8_t* context_modes; @@ -372,8 +378,9 @@ BROTLI_INTERNAL void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s); BROTLI_INTERNAL void BrotliDecoderStateCleanupAfterMetablock( BrotliDecoderState* s); BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit( - BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size_max, - uint32_t alphabet_size_limit, uint32_t ntrees); + BrotliDecoderState* s, HuffmanTreeGroup* group, + brotli_reg_t alphabet_size_max, brotli_reg_t alphabet_size_limit, + brotli_reg_t ntrees); #define BROTLI_DECODER_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L) @@ -382,6 +389,10 @@ BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit( X = NULL; \ } +/* Literal/Command/Distance block size maximum; same as maximum metablock size; + used as block size when there is no block switching. */ +#define BROTLI_BLOCK_SIZE_CAP (1U << 24) + #if defined(__cplusplus) || defined(c_plusplus) } /* extern "C" */ #endif diff --git a/thirdparty/brotli/include/brotli/decode.h b/thirdparty/brotli/include/brotli/decode.h index 3c473d611e..af1aa23f60 100644 --- a/thirdparty/brotli/include/brotli/decode.h +++ b/thirdparty/brotli/include/brotli/decode.h @@ -357,7 +357,7 @@ BROTLI_DEC_API const char* BrotliDecoderErrorString(BrotliDecoderErrorCode c); /** * Gets a decoder library version. * - * Look at BROTLI_VERSION for more information. + * Look at BROTLI_MAKE_HEX_VERSION for more information. */ BROTLI_DEC_API uint32_t BrotliDecoderVersion(void); diff --git a/thirdparty/brotli/include/brotli/encode.h b/thirdparty/brotli/include/brotli/encode.h index 7247d3d698..dea9931ebb 100644 --- a/thirdparty/brotli/include/brotli/encode.h +++ b/thirdparty/brotli/include/brotli/encode.h @@ -490,7 +490,7 @@ BROTLI_ENC_EXTRA_API size_t BrotliEncoderGetPreparedDictionarySize( /** * Gets an encoder library version. * - * Look at BROTLI_VERSION for more information. + * Look at BROTLI_MAKE_HEX_VERSION for more information. */ BROTLI_ENC_API uint32_t BrotliEncoderVersion(void); diff --git a/thirdparty/brotli/include/brotli/shared_dictionary.h b/thirdparty/brotli/include/brotli/shared_dictionary.h index ceb6cf1cd2..2970c2dcc9 100644 --- a/thirdparty/brotli/include/brotli/shared_dictionary.h +++ b/thirdparty/brotli/include/brotli/shared_dictionary.h @@ -35,7 +35,10 @@ typedef struct BrotliSharedDictionaryStruct BrotliSharedDictionary; typedef enum BrotliSharedDictionaryType { /** Raw LZ77 prefix dictionary. */ BROTLI_SHARED_DICTIONARY_RAW = 0, - /** Serialized shared dictionary. */ + /** Serialized shared dictionary. + * + * DO NOT USE: methods accepting this value will fail. + */ BROTLI_SHARED_DICTIONARY_SERIALIZED = 1 } BrotliSharedDictionaryType; |