diff options
64 files changed, 506 insertions, 222 deletions
diff --git a/.travis.yml b/.travis.yml index 7350849d6a..c8b123c79c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -94,7 +94,7 @@ matrix: - name: Linux export template (release_debug, GCC 5, without 3D support) stage: build - env: PLATFORM=x11 TOOLS=no TARGET=release_debug CACHE_NAME=${PLATFORM}-gcc-5 EXTRA_ARGS="disable_3d=yes" + env: PLATFORM=x11 TOOLS=no TARGET=release_debug CACHE_NAME=${PLATFORM}-gcc-5 EXTRA_ARGS="CXXFLAGS=-fno-strict-aliasing disable_3d=yes" os: linux compiler: gcc addons: diff --git a/doc/classes/CPUParticles.xml b/doc/classes/CPUParticles.xml index e68b0feb2d..cef0ee7587 100644 --- a/doc/classes/CPUParticles.xml +++ b/doc/classes/CPUParticles.xml @@ -367,5 +367,8 @@ <constant name="EMISSION_SHAPE_DIRECTED_POINTS" value="4" enum="EmissionShape"> Particles will be emitted at a position chosen randomly among [member emission_points]. Particle velocity and rotation will be set based on [member emission_normals]. Particle color will be modulated by [member emission_colors]. </constant> + <constant name="EMISSION_SHAPE_MAX" value="5" enum="EmissionShape"> + Represents the size of the [enum EmissionShape] enum. + </constant> </constants> </class> diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml index c8dbffb4cb..dac00051a9 100644 --- a/doc/classes/CPUParticles2D.xml +++ b/doc/classes/CPUParticles2D.xml @@ -360,5 +360,8 @@ <constant name="EMISSION_SHAPE_DIRECTED_POINTS" value="4" enum="EmissionShape"> Particles will be emitted at a position chosen randomly among [member emission_points]. Particle velocity and rotation will be set based on [member emission_normals]. Particle color will be modulated by [member emission_colors]. </constant> + <constant name="EMISSION_SHAPE_MAX" value="5" enum="EmissionShape"> + Represents the size of the [enum EmissionShape] enum. + </constant> </constants> </class> diff --git a/doc/classes/Light.xml b/doc/classes/Light.xml index fde25ef2c5..ae5bba4f06 100644 --- a/doc/classes/Light.xml +++ b/doc/classes/Light.xml @@ -80,7 +80,7 @@ Constant for accessing [member light_indirect_energy]. </constant> <constant name="PARAM_SPECULAR" value="2" enum="Param"> - Constant for accessing [member light_specular]. + Constant for accessing [member light_specular]. </constant> <constant name="PARAM_RANGE" value="3" enum="Param"> Constant for accessing [member OmniLight.omni_range] or [member SpotLight.spot_range]. diff --git a/doc/classes/ParticlesMaterial.xml b/doc/classes/ParticlesMaterial.xml index 187ad1688d..1f23649b75 100644 --- a/doc/classes/ParticlesMaterial.xml +++ b/doc/classes/ParticlesMaterial.xml @@ -321,5 +321,8 @@ <constant name="EMISSION_SHAPE_DIRECTED_POINTS" value="4" enum="EmissionShape"> Particles will be emitted at a position determined by sampling a random point on the [member emission_point_texture]. Particle velocity and rotation will be set based on [member emission_normal_texture]. Particle color will be modulated by [member emission_color_texture]. </constant> + <constant name="EMISSION_SHAPE_MAX" value="5" enum="EmissionShape"> + Represents the size of the [enum EmissionShape] enum. + </constant> </constants> </class> diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index b0b14ed413..3fd9ecd1ce 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -109,6 +109,7 @@ PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT #define glFramebufferTexture2DMultisample glFramebufferTexture2DMultisampleANGLE #endif +#define GL_TEXTURE_3D 0x806F #define GL_MAX_SAMPLES 0x8D57 #endif //!GLES_OVER_GL @@ -565,11 +566,11 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_ texture->target = GL_TEXTURE_CUBE_MAP; texture->images.resize(6); } break; - case VS::TEXTURE_TYPE_2D_ARRAY: { - texture->images.resize(p_depth_3d); - } break; + case VS::TEXTURE_TYPE_2D_ARRAY: case VS::TEXTURE_TYPE_3D: { - texture->images.resize(p_depth_3d); + texture->target = GL_TEXTURE_3D; + ERR_PRINT("3D textures and Texture Arrays are not supported in GLES2. Please switch to the GLES3 backend."); + return; } break; default: { ERR_PRINT("Unknown texture type!"); @@ -626,6 +627,10 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p Texture *texture = texture_owner.getornull(p_texture); ERR_FAIL_COND(!texture); + if (texture->target == GL_TEXTURE_3D) { + // Target is set to a 3D texture or array texture, exit early to avoid spamming errors + return; + } ERR_FAIL_COND(!texture->active); ERR_FAIL_COND(texture->render_target); ERR_FAIL_COND(texture->format != p_image->get_format()); diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index fc59486090..24b89aedc2 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -522,9 +522,6 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener SL::ArrayDeclarationNode *arr_dec_node = (SL::ArrayDeclarationNode *)p_node; StringBuffer<> declaration; - if (arr_dec_node->is_const) { - declaration += "const "; - } declaration += _prestr(arr_dec_node->precision); declaration += _typestr(arr_dec_node->datatype); @@ -540,22 +537,6 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener declaration += "["; declaration += itos(arr_dec_node->declarations[i].size); declaration += "]"; - int sz = arr_dec_node->declarations[i].initializer.size(); - if (sz > 0) { - declaration += "="; - declaration += _typestr(arr_dec_node->datatype); - declaration += "["; - declaration += itos(sz); - declaration += "]"; - declaration += "("; - for (int j = 0; j < sz; j++) { - declaration += _dump_node_code(arr_dec_node->declarations[i].initializer[j], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - if (j != sz - 1) { - declaration += ", "; - } - } - declaration += ")"; - } } code += declaration.as_string(); diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index ec40b3254f..1853133bc7 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -146,7 +146,17 @@ void ConnectDialog::_tree_node_selected() { return; dst_path = source->get_path_to(current); - get_ok()->set_disabled(false); + _update_ok_enabled(); +} + +/* + * Called each time a target node is activated within the target node tree. + */ +void ConnectDialog::_tree_item_activated() { + + if (!get_ok()->is_disabled()) { + get_ok()->emit_signal("pressed"); + } } /* @@ -200,6 +210,27 @@ void ConnectDialog::_remove_bind() { cdbinds->notify_changed(); } +/* + * Enables or disables the connect button. The connect button is enabled if a + * node is selected and valid in the selected mode. + */ +void ConnectDialog::_update_ok_enabled() { + + Node *target = tree->get_selected(); + + if (target == nullptr) { + get_ok()->set_disabled(true); + return; + } + + if (!advanced->is_pressed() && target->get_script().is_null()) { + get_ok()->set_disabled(true); + return; + } + + get_ok()->set_disabled(false); +} + void ConnectDialog::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { @@ -212,8 +243,10 @@ void ConnectDialog::_bind_methods() { ClassDB::bind_method("_advanced_pressed", &ConnectDialog::_advanced_pressed); ClassDB::bind_method("_cancel", &ConnectDialog::_cancel_pressed); ClassDB::bind_method("_tree_node_selected", &ConnectDialog::_tree_node_selected); + ClassDB::bind_method("_tree_item_activated", &ConnectDialog::_tree_item_activated); ClassDB::bind_method("_add_bind", &ConnectDialog::_add_bind); ClassDB::bind_method("_remove_bind", &ConnectDialog::_remove_bind); + ClassDB::bind_method("_update_ok_enabled", &ConnectDialog::_update_ok_enabled); ADD_SIGNAL(MethodInfo("connected")); } @@ -290,13 +323,12 @@ void ConnectDialog::init(Connection c, bool bEdit) { tree->set_marked(source, true); if (c.target) { - get_ok()->set_disabled(false); set_dst_node(static_cast<Node *>(c.target)); set_dst_method(c.method); - } else { - get_ok()->set_disabled(true); } + _update_ok_enabled(); + bool bDeferred = (c.flags & CONNECT_DEFERRED) == CONNECT_DEFERRED; bool bOneshot = (c.flags & CONNECT_ONESHOT) == CONNECT_ONESHOT; @@ -339,6 +371,8 @@ void ConnectDialog::_advanced_pressed() { error_label->set_visible(!_find_first_script(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root())); } + _update_ok_enabled(); + set_position((get_viewport_rect().size - get_custom_minimum_size()) / 2); } @@ -363,7 +397,7 @@ ConnectDialog::ConnectDialog() { tree = memnew(SceneTreeEditor(false)); tree->set_connecting_signal(true); - tree->get_scene_tree()->connect("item_activated", this, "_ok"); + tree->get_scene_tree()->connect("item_activated", this, "_tree_item_activated"); tree->connect("node_selected", this, "_tree_node_selected"); tree->set_connect_to_script_mode(true); diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h index 8ef4eddea1..c30413953a 100644 --- a/editor/connections_dialog.h +++ b/editor/connections_dialog.h @@ -76,9 +76,11 @@ class ConnectDialog : public ConfirmationDialog { void ok_pressed(); void _cancel_pressed(); void _tree_node_selected(); + void _tree_item_activated(); void _add_bind(); void _remove_bind(); void _advanced_pressed(); + void _update_ok_enabled(); protected: void _notification(int p_what); diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index 7de6db7add..a418915830 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -1302,6 +1302,8 @@ Error EditorSceneImporterGLTF::_parse_images(GLTFState &state, const String &p_b if (mimetype.findn("png") != -1) { //is a png + ERR_FAIL_COND_V(Image::_png_mem_loader_func == NULL, ERR_UNAVAILABLE); + const Ref<Image> img = Image::_png_mem_loader_func(data_ptr, data_size); ERR_FAIL_COND_V(img.is_null(), ERR_FILE_CORRUPT); @@ -1316,6 +1318,8 @@ Error EditorSceneImporterGLTF::_parse_images(GLTFState &state, const String &p_b if (mimetype.findn("jpeg") != -1) { //is a jpg + ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == NULL, ERR_UNAVAILABLE); + const Ref<Image> img = Image::_jpg_mem_loader_func(data_ptr, data_size); ERR_FAIL_COND_V(img.is_null(), ERR_FILE_CORRUPT); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index f0e4a4bfdc..1432c3fc63 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -691,13 +691,16 @@ void ScriptTextEditor::_update_bookmark_list() { bookmarks_menu->add_separator(); for (int i = 0; i < bookmark_list.size(); i++) { - String line = code_editor->get_text_edit()->get_line(bookmark_list[i]).strip_edges(); + // Strip edges to remove spaces or tabs. + // Also replace any tabs by spaces, since we can't print tabs in the menu. + String line = code_editor->get_text_edit()->get_line(bookmark_list[i]).replace("\t", " ").strip_edges(); + // Limit the size of the line if too big. if (line.length() > 50) { line = line.substr(0, 50); } - bookmarks_menu->add_item(String::num((int)bookmark_list[i] + 1) + " - \"" + line + "\""); + bookmarks_menu->add_item(String::num((int)bookmark_list[i] + 1) + " - `" + line + "`"); bookmarks_menu->set_item_metadata(bookmarks_menu->get_item_count() - 1, bookmark_list[i]); } } @@ -841,13 +844,16 @@ void ScriptTextEditor::_update_breakpoint_list() { breakpoints_menu->add_separator(); for (int i = 0; i < breakpoint_list.size(); i++) { - String line = code_editor->get_text_edit()->get_line(breakpoint_list[i]).strip_edges(); + // Strip edges to remove spaces or tabs. + // Also replace any tabs by spaces, since we can't print tabs in the menu. + String line = code_editor->get_text_edit()->get_line(breakpoint_list[i]).replace("\t", " ").strip_edges(); + // Limit the size of the line if too big. if (line.length() > 50) { line = line.substr(0, 50); } - breakpoints_menu->add_item(String::num((int)breakpoint_list[i] + 1) + " - \"" + line + "\""); + breakpoints_menu->add_item(String::num((int)breakpoint_list[i] + 1) + " - `" + line + "`"); breakpoints_menu->set_item_metadata(breakpoints_menu->get_item_count() - 1, breakpoint_list[i]); } } diff --git a/modules/assimp/import_utils.h b/modules/assimp/import_utils.h index f4505249db..c522b01727 100644 --- a/modules/assimp/import_utils.h +++ b/modules/assimp/import_utils.h @@ -355,11 +355,13 @@ public: print_verbose("Open Asset Import: Loading embedded texture " + filename); if (tex->mHeight == 0) { if (tex->CheckFormat("png")) { + ERR_FAIL_COND_V(Image::_png_mem_loader_func == NULL, Ref<Image>()); Ref<Image> img = Image::_png_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth); ERR_FAIL_COND_V(img.is_null(), Ref<Image>()); state.path_to_image_cache.insert(p_path, img); return img; } else if (tex->CheckFormat("jpg")) { + ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == NULL, Ref<Image>()); Ref<Image> img = Image::_jpg_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth); ERR_FAIL_COND_V(img.is_null(), Ref<Image>()); state.path_to_image_cache.insert(p_path, img); diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index fd86bc4e14..a255b92257 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -915,14 +915,43 @@ GDScript::GDScript() : #endif } +void GDScript::_save_orphaned_subclasses() { + struct ClassRefWithName { + ObjectID id; + String fully_qualified_name; + }; + Vector<ClassRefWithName> weak_subclasses; + // collect subclasses ObjectID and name + for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) { + E->get()->_owner = NULL; //bye, you are no longer owned cause I died + ClassRefWithName subclass; + subclass.id = E->get()->get_instance_id(); + subclass.fully_qualified_name = E->get()->fully_qualified_name; + weak_subclasses.push_back(subclass); + } + + // clear subclasses to allow unused subclasses to be deleted + subclasses.clear(); + // subclasses are also held by constants, clear those as well + constants.clear(); + + // keep orphan subclass only for subclasses that are still in use + for (int i = 0; i < weak_subclasses.size(); i++) { + ClassRefWithName subclass = weak_subclasses[i]; + Object *obj = ObjectDB::get_instance(subclass.id); + if (!obj) + continue; + // subclass is not released + GDScriptLanguage::get_singleton()->add_orphan_subclass(subclass.fully_qualified_name, subclass.id); + } +} + GDScript::~GDScript() { for (Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) { memdelete(E->get()); } - for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) { - E->get()->_owner = NULL; //bye, you are no longer owned cause I died - } + _save_orphaned_subclasses(); #ifdef DEBUG_ENABLED if (GDScriptLanguage::get_singleton()->lock) { @@ -2176,6 +2205,22 @@ GDScriptLanguage::~GDScriptLanguage() { singleton = NULL; } +void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass) { + orphan_subclasses[p_qualified_name] = p_subclass; +} + +Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_name) { + Map<String, ObjectID>::Element *orphan_subclass_element = orphan_subclasses.find(p_qualified_name); + if (!orphan_subclass_element) + return Ref<GDScript>(); + ObjectID orphan_subclass = orphan_subclass_element->get(); + Object *obj = ObjectDB::get_instance(orphan_subclass); + orphan_subclasses.erase(orphan_subclass_element); + if (!obj) + return Ref<GDScript>(); + return Ref<GDScript>(Object::cast_to<GDScript>(obj)); +} + /*************** RESOURCE ***************/ RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error) { diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 0e2b812a22..4ae52238ce 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -132,6 +132,8 @@ class GDScript : public Script { bool _update_exports(); + void _save_orphaned_subclasses(); + protected: bool _get(const StringName &p_name, Variant &r_ret) const; bool _set(const StringName &p_name, const Variant &p_value); @@ -355,6 +357,8 @@ class GDScriptLanguage : public ScriptLanguage { bool profiling; uint64_t script_frame_time; + Map<String, ObjectID> orphan_subclasses; + public: int calls; @@ -506,6 +510,9 @@ public: virtual bool handles_global_class_type(const String &p_type) const; virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL, String *r_icon_path = NULL) const; + void add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass); + Ref<GDScript> get_orphan_subclass(const String &p_qualified_name); + GDScriptLanguage(); ~GDScriptLanguage(); }; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 711fa54d0b..fba1b992ec 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -2123,15 +2123,21 @@ void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::C StringName name = p_class->subclasses[i]->name; Ref<GDScript> subclass; + String fully_qualified_name = p_script->fully_qualified_name + "::" + name; if (old_subclasses.has(name)) { subclass = old_subclasses[name]; } else { - subclass.instance(); + Ref<GDScript> orphan_subclass = GDScriptLanguage::get_singleton()->get_orphan_subclass(fully_qualified_name); + if (orphan_subclass.is_valid()) { + subclass = orphan_subclass; + } else { + subclass.instance(); + } } subclass->_owner = p_script; - subclass->fully_qualified_name = p_script->fully_qualified_name + "::" + name; + subclass->fully_qualified_name = fully_qualified_name; p_script->subclasses.insert(name, subclass); _make_scripts(subclass.ptr(), p_class->subclasses[i], false); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index c7e5387072..65c61cb57c 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -557,7 +557,7 @@ static String _get_visual_datatype(const PropertyInfo &p_info, bool p_isarg = tr } if (p_info.type == Variant::NIL) { if (p_isarg || (p_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT)) { - return "var"; + return "Variant"; } else { return "void"; } @@ -1738,14 +1738,12 @@ static String _make_arguments_hint(const MethodInfo &p_info, int p_arg_idx) { for (const List<PropertyInfo>::Element *E = p_info.arguments.front(); E; E = E->next()) { if (i > 0) { arghint += ", "; - } else { - arghint += " "; } if (i == p_arg_idx) { arghint += String::chr(0xFFFF); } - arghint += _get_visual_datatype(E->get(), true) + " " + E->get().name; + arghint += E->get().name + ": " + _get_visual_datatype(E->get(), true); if (i - def_args >= 0) { arghint += String(" = ") + p_info.default_arguments[i - def_args].get_construct_string(); @@ -1761,8 +1759,6 @@ static String _make_arguments_hint(const MethodInfo &p_info, int p_arg_idx) { if (p_info.flags & METHOD_FLAG_VARARG) { if (p_info.arguments.size() > 0) { arghint += ", "; - } else { - arghint += " "; } if (p_arg_idx >= p_info.arguments.size()) { arghint += String::chr(0xFFFF); @@ -1772,9 +1768,6 @@ static String _make_arguments_hint(const MethodInfo &p_info, int p_arg_idx) { arghint += String::chr(0xFFFF); } } - if (p_info.arguments.size() > 0 || (p_info.flags & METHOD_FLAG_VARARG)) { - arghint += " "; - } arghint += ")"; @@ -1789,14 +1782,12 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio for (int i = 0; i < p_function->arguments.size(); i++) { if (i > 0) { arghint += ", "; - } else { - arghint += " "; } if (i == p_arg_idx) { arghint += String::chr(0xFFFF); } - arghint += p_function->argument_types[i].to_string() + " " + p_function->arguments[i].operator String(); + arghint += p_function->arguments[i].operator String() + ": " + p_function->argument_types[i].to_string(); if (i - def_args >= 0) { String def_val = "<unknown>"; @@ -1820,9 +1811,6 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio } } - if (p_function->arguments.size() > 0) { - arghint += " "; - } arghint += ")"; return arghint; diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index 236ca720a2..ad95ebc543 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -76,14 +76,17 @@ struct GDScriptDataType { if (p_variant.get_type() != Variant::OBJECT) { return false; } + Object *obj = p_variant.operator Object *(); - if (obj) { - if (!ClassDB::is_parent_class(obj->get_class_name(), native_type)) { - // Try with underscore prefix - StringName underscore_native_type = "_" + native_type; - if (!ClassDB::is_parent_class(obj->get_class_name(), underscore_native_type)) { - return false; - } + if (!obj || !ObjectDB::instance_validate(obj)) { + return false; + } + + if (!ClassDB::is_parent_class(obj->get_class_name(), native_type)) { + // Try with underscore prefix + StringName underscore_native_type = "_" + native_type; + if (!ClassDB::is_parent_class(obj->get_class_name(), underscore_native_type)) { + return false; } } return true; @@ -96,7 +99,12 @@ struct GDScriptDataType { if (p_variant.get_type() != Variant::OBJECT) { return false; } + Object *obj = p_variant.operator Object *(); + if (!obj || !ObjectDB::instance_validate(obj)) { + return false; + } + Ref<Script> base = obj && obj->get_script_instance() ? obj->get_script_instance()->get_script() : NULL; bool valid = false; while (base.is_valid()) { diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index fc2e626795..5c2e7137bf 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -4741,10 +4741,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { member.line = tokenizer->get_token_line(); member.usages = 0; member.rpc_mode = rpc_mode; -#ifdef TOOLS_ENABLED - Variant::CallError ce; - member.default_value = Variant::construct(member._export.type, NULL, 0, ce); -#endif if (current_class->constant_expressions.has(member.identifier)) { _set_error("A constant named \"" + String(member.identifier) + "\" already exists in this class (at line: " + @@ -4797,6 +4793,32 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } + if (autoexport && member.data_type.has_type) { + if (member.data_type.kind == DataType::BUILTIN) { + member._export.type = member.data_type.builtin_type; + } else if (member.data_type.kind == DataType::NATIVE) { + if (ClassDB::is_parent_class(member.data_type.native_type, "Resource")) { + member._export.type = Variant::OBJECT; + member._export.hint = PROPERTY_HINT_RESOURCE_TYPE; + member._export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; + member._export.hint_string = member.data_type.native_type; + member._export.class_name = member.data_type.native_type; + } else { + _set_error("Invalid export type. Only built-in and native resource types can be exported.", member.line); + return; + } + + } else { + _set_error("Invalid export type. Only built-in and native resource types can be exported.", member.line); + return; + } + } + +#ifdef TOOLS_ENABLED + Variant::CallError ce; + member.default_value = Variant::construct(member._export.type, NULL, 0, ce); +#endif + if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) { #ifdef DEBUG_ENABLED @@ -4930,27 +4952,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { member.initial_assignment = op; } - if (autoexport && member.data_type.has_type) { - if (member.data_type.kind == DataType::BUILTIN) { - member._export.type = member.data_type.builtin_type; - } else if (member.data_type.kind == DataType::NATIVE) { - if (ClassDB::is_parent_class(member.data_type.native_type, "Resource")) { - member._export.type = Variant::OBJECT; - member._export.hint = PROPERTY_HINT_RESOURCE_TYPE; - member._export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; - member._export.hint_string = member.data_type.native_type; - member._export.class_name = member.data_type.native_type; - } else { - _set_error("Invalid export type. Only built-in and native resource types can be exported.", member.line); - return; - } - - } else { - _set_error("Invalid export type. Only built-in and native resource types can be exported.", member.line); - return; - } - } - if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_SETGET) { tokenizer->advance(); diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 3678a82bee..0f6b8357b8 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -559,6 +559,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() #ifdef DEBUG_ENABLED _TLS_RECURSION_GUARD_V_(Vector<StackInfo>()); + GD_MONO_SCOPE_THREAD_ATTACH; if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_core_api_assembly() || !GDMonoCache::cached_data.corlib_cache_updated) return Vector<StackInfo>(); @@ -583,6 +584,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObject *p_stack_trace) { _TLS_RECURSION_GUARD_V_(Vector<StackInfo>()); + GD_MONO_SCOPE_THREAD_ATTACH; MonoException *exc = NULL; @@ -689,6 +691,7 @@ void CSharpLanguage::reload_all_scripts() { #ifdef GD_MONO_HOT_RELOAD if (is_assembly_reloading_needed()) { + GD_MONO_SCOPE_THREAD_ATTACH; reload_assemblies(false); } #endif @@ -706,6 +709,7 @@ void CSharpLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft #ifdef GD_MONO_HOT_RELOAD if (is_assembly_reloading_needed()) { + GD_MONO_SCOPE_THREAD_ATTACH; reload_assemblies(p_soft_reload); } #endif @@ -1356,6 +1360,8 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) { if (finalizing) return; // inside CSharpLanguage::finish(), all the gchandle bindings are released there + GD_MONO_ASSERT_THREAD_ATTACHED; + { SCOPED_MUTEX_LOCK(language_bind_mutex); @@ -1382,6 +1388,7 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) { #ifdef DEBUG_ENABLED CRASH_COND(!ref_owner); + CRASH_COND(!p_object->has_script_instance_binding(get_language_index())); #endif void *data = p_object->get_script_instance_binding(get_language_index()); @@ -1394,6 +1401,8 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) { return; if (ref_owner->reference_get_count() > 1 && gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 + GD_MONO_SCOPE_THREAD_ATTACH; + // The reference count was increased after the managed side was the only one referencing our owner. // This means the owner is being referenced again by the unmanaged side, // so the owner must hold the managed side alive again to avoid it from being GCed. @@ -1415,6 +1424,7 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) { #ifdef DEBUG_ENABLED CRASH_COND(!ref_owner); + CRASH_COND(!p_object->has_script_instance_binding(get_language_index())); #endif void *data = p_object->get_script_instance_binding(get_language_index()); @@ -1429,6 +1439,8 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) { return refcount == 0; if (refcount == 1 && gchandle.is_valid() && !gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 + GD_MONO_SCOPE_THREAD_ATTACH; + // If owner owner is no longer referenced by the unmanaged side, // the managed instance takes responsibility of deleting the owner when GCed. @@ -1480,6 +1492,8 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) { ERR_FAIL_COND_V(!script.is_valid(), false); + GD_MONO_SCOPE_THREAD_ATTACH; + MonoObject *mono_object = get_mono_object(); ERR_FAIL_NULL_V(mono_object, false); @@ -1532,6 +1546,8 @@ bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const { ERR_FAIL_COND_V(!script.is_valid(), false); + GD_MONO_SCOPE_THREAD_ATTACH; + MonoObject *mono_object = get_mono_object(); ERR_FAIL_NULL_V(mono_object, false); @@ -1625,6 +1641,8 @@ void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const { ERR_FAIL_COND(!script.is_valid()); + GD_MONO_SCOPE_THREAD_ATTACH; + MonoObject *mono_object = get_mono_object(); ERR_FAIL_NULL(mono_object); @@ -1669,6 +1687,8 @@ bool CSharpInstance::has_method(const StringName &p_method) const { if (!script.is_valid()) return false; + GD_MONO_SCOPE_THREAD_ATTACH; + GDMonoClass *top = script->script_class; while (top && top != script->native) { @@ -1684,6 +1704,11 @@ bool CSharpInstance::has_method(const StringName &p_method) const { Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { + if (!script.is_valid()) + ERR_FAIL_V(Variant()); + + GD_MONO_SCOPE_THREAD_ATTACH; + MonoObject *mono_object = get_mono_object(); if (!mono_object) { @@ -1691,9 +1716,6 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args, ERR_FAIL_V(Variant()); } - if (!script.is_valid()) - ERR_FAIL_V(Variant()); - GDMonoClass *top = script->script_class; while (top && top != script->native) { @@ -1721,6 +1743,8 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args, void CSharpInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { + GD_MONO_SCOPE_THREAD_ATTACH; + if (script.is_valid()) { MonoObject *mono_object = get_mono_object(); @@ -1732,6 +1756,8 @@ void CSharpInstance::call_multilevel(const StringName &p_method, const Variant * void CSharpInstance::_call_multilevel(MonoObject *p_mono_object, const StringName &p_method, const Variant **p_args, int p_argcount) { + GD_MONO_ASSERT_THREAD_ATTACHED; + GDMonoClass *top = script->script_class; while (top && top != script->native) { @@ -1894,6 +1920,8 @@ void CSharpInstance::refcount_incremented() { Reference *ref_owner = Object::cast_to<Reference>(owner); if (ref_owner->reference_get_count() > 1 && gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 + GD_MONO_SCOPE_THREAD_ATTACH; + // The reference count was increased after the managed side was the only one referencing our owner. // This means the owner is being referenced again by the unmanaged side, // so the owner must hold the managed side alive again to avoid it from being GCed. @@ -1917,6 +1945,8 @@ bool CSharpInstance::refcount_decremented() { int refcount = ref_owner->reference_get_count(); if (refcount == 1 && !gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 + GD_MONO_SCOPE_THREAD_ATTACH; + // If owner owner is no longer referenced by the unmanaged side, // the managed instance takes responsibility of deleting the owner when GCed. @@ -1957,6 +1987,8 @@ MultiplayerAPI::RPCMode CSharpInstance::_member_get_rpc_mode(IMonoClassMember *p MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) const { + GD_MONO_SCOPE_THREAD_ATTACH; + GDMonoClass *top = script->script_class; while (top && top != script->native) { @@ -1973,6 +2005,8 @@ MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variable) const { + GD_MONO_SCOPE_THREAD_ATTACH; + GDMonoClass *top = script->script_class; while (top && top != script->native) { @@ -1994,6 +2028,8 @@ MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variab void CSharpInstance::notification(int p_notification) { + GD_MONO_SCOPE_THREAD_ATTACH; + if (p_notification == Object::NOTIFICATION_PREDELETE) { // When NOTIFICATION_PREDELETE is sent, we also take the chance to call Dispose(). // It's safe to call Dispose() multiple times and NOTIFICATION_PREDELETE is guaranteed @@ -2031,6 +2067,8 @@ void CSharpInstance::notification(int p_notification) { void CSharpInstance::_call_notification(int p_notification) { + GD_MONO_ASSERT_THREAD_ATTACHED; + MonoObject *mono_object = get_mono_object(); ERR_FAIL_NULL(mono_object); @@ -2055,6 +2093,8 @@ void CSharpInstance::_call_notification(int p_notification) { } String CSharpInstance::to_string(bool *r_valid) { + GD_MONO_SCOPE_THREAD_ATTACH; + MonoObject *mono_object = get_mono_object(); if (mono_object == NULL) { @@ -2103,6 +2143,8 @@ CSharpInstance::CSharpInstance() : CSharpInstance::~CSharpInstance() { + GD_MONO_SCOPE_THREAD_ATTACH; + destructing_script_instance = true; if (gchandle.is_valid()) { @@ -2206,6 +2248,8 @@ void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List void CSharpScript::_update_member_info_no_exports() { if (exports_invalidated) { + GD_MONO_ASSERT_THREAD_ATTACHED; + exports_invalidated = false; member_info.clear(); @@ -2264,6 +2308,8 @@ bool CSharpScript::_update_exports() { bool changed = false; if (exports_invalidated) { + GD_MONO_SCOPE_THREAD_ATTACH; + exports_invalidated = false; changed = true; @@ -2413,6 +2459,8 @@ void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_nati // make sure this classes signals are empty when loading for the first time _signals.clear(); + GD_MONO_SCOPE_THREAD_ATTACH; + GDMonoClass *top = p_class; while (top && top != p_native_class) { const Vector<GDMonoClass *> &delegates = top->get_all_delegates(); @@ -2433,6 +2481,8 @@ void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_nati } bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> ¶ms) { + GD_MONO_ASSERT_THREAD_ATTACHED; + if (p_delegate->has_attribute(CACHED_CLASS(SignalAttribute))) { MonoType *raw_type = p_delegate->get_mono_type(); @@ -2474,6 +2524,8 @@ bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Ve */ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect_export, PropertyInfo &r_prop_info, bool &r_exported) { + GD_MONO_ASSERT_THREAD_ATTACHED; + // Goddammit, C++. All I wanted was some nested functions. #define MEMBER_FULL_QUALIFIED_NAME(m_member) \ (m_member->get_enclosing_class()->get_full_name() + "." + (String)m_member->get_name()) @@ -2552,6 +2604,8 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string) { + GD_MONO_ASSERT_THREAD_ATTACHED; + if (p_variant_type == Variant::INT && p_type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(p_type.type_class->get_mono_ptr())) { r_hint = PROPERTY_HINT_ENUM; @@ -2661,6 +2715,8 @@ Variant CSharpScript::call(const StringName &p_method, const Variant **p_args, i return Variant(); } + GD_MONO_SCOPE_THREAD_ATTACH; + GDMonoClass *top = script_class; while (top && top != native) { @@ -2853,6 +2909,8 @@ StringName CSharpScript::get_instance_base_type() const { CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error) { + GD_MONO_ASSERT_THREAD_ATTACHED; + /* STEP 1, CREATE */ // Search the constructor first, to fail with an error if it's not found before allocating anything else. @@ -2947,12 +3005,14 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Variant::Call } r_error.error = Variant::CallError::CALL_OK; - REF ref; ERR_FAIL_NULL_V(native, Variant()); + GD_MONO_SCOPE_THREAD_ATTACH; + Object *owner = ClassDB::instance(NATIVE_GDMONOCLASS_NAME(native)); + REF ref; Reference *r = Object::cast_to<Reference>(owner); if (r) { ref = REF(r); @@ -2990,6 +3050,8 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) { } } + GD_MONO_SCOPE_THREAD_ATTACH; + Variant::CallError unchecked_error; return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this) != NULL, unchecked_error); } @@ -3037,6 +3099,8 @@ void CSharpScript::get_script_method_list(List<MethodInfo> *p_list) const { if (!script_class) return; + GD_MONO_SCOPE_THREAD_ATTACH; + // TODO: Filter out things unsuitable for explicit calls, like constructors. const Vector<GDMonoMethod *> &methods = script_class->get_all_methods(); for (int i = 0; i < methods.size(); ++i) { @@ -3049,6 +3113,8 @@ bool CSharpScript::has_method(const StringName &p_method) const { if (!script_class) return false; + GD_MONO_SCOPE_THREAD_ATTACH; + return script_class->has_fetched_method_unknown_params(p_method); } @@ -3057,6 +3123,8 @@ MethodInfo CSharpScript::get_method_info(const StringName &p_method) const { if (!script_class) return MethodInfo(); + GD_MONO_SCOPE_THREAD_ATTACH; + GDMonoClass *top = script_class; while (top && top != native) { @@ -3081,6 +3149,8 @@ Error CSharpScript::reload(bool p_keep_state) { ERR_FAIL_COND_V(!p_keep_state && has_instances, ERR_ALREADY_IN_USE); + GD_MONO_SCOPE_THREAD_ATTACH; + GDMonoAssembly *project_assembly = GDMono::get_singleton()->get_project_assembly(); if (project_assembly) { @@ -3308,39 +3378,7 @@ RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p script->set_path(p_original_path); -#ifndef TOOLS_ENABLED - -#ifdef DEBUG_ENABLED - // User is responsible for thread attach/detach - CRASH_COND_MSG(mono_domain_get() == NULL, "Thread is not attached."); -#endif - -#endif - -#ifdef TOOLS_ENABLED - MonoDomain *domain = mono_domain_get(); - if (Engine::get_singleton()->is_editor_hint() && domain == NULL) { - - CRASH_COND(Thread::get_caller_id() == Thread::get_main_id()); - - // Thread is not attached, but we will make an exception in this case - // because this may be called by one of the editor's worker threads. - // Attach this thread temporarily to reload the script. - - if (domain) { - MonoThread *mono_thread = mono_thread_attach(domain); - CRASH_COND(mono_thread == NULL); - script->reload(); - mono_thread_detach(mono_thread); - } - - } else { // just reload it normally -#endif - script->reload(); - -#ifdef TOOLS_ENABLED - } -#endif + script->reload(); if (r_error) *r_error = OK; diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 6bb9f28a32..4e7f590a69 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -125,10 +125,12 @@ void set_main_thread(MonoThread *p_thread) { mono_thread_set_main(p_thread); } -void attach_current_thread() { - ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized()); - MonoThread *mono_thread = mono_thread_attach(mono_get_root_domain()); - ERR_FAIL_NULL(mono_thread); +MonoThread *attach_current_thread() { + ERR_FAIL_COND_V(!GDMono::get_singleton()->is_runtime_initialized(), NULL); + MonoDomain *scripts_domain = GDMono::get_singleton()->get_scripts_domain(); + MonoThread *mono_thread = mono_thread_attach(scripts_domain ? scripts_domain : mono_get_root_domain()); + ERR_FAIL_NULL_V(mono_thread, NULL); + return mono_thread; } void detach_current_thread() { @@ -138,10 +140,20 @@ void detach_current_thread() { mono_thread_detach(mono_thread); } +void detach_current_thread(MonoThread *p_mono_thread) { + ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized()); + ERR_FAIL_NULL(p_mono_thread); + mono_thread_detach(p_mono_thread); +} + MonoThread *get_current_thread() { return mono_thread_current(); } +bool is_thread_attached() { + return mono_domain_get() != NULL; +} + void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc) { GDMonoMethod *ctor = p_class->get_method(".ctor", 0); ERR_FAIL_NULL(ctor); @@ -617,4 +629,19 @@ GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, Mon } // namespace Marshal +ScopeThreadAttach::ScopeThreadAttach() : + mono_thread(NULL) { + if (likely(GDMono::get_singleton()->is_runtime_initialized()) && unlikely(!mono_domain_get())) { + mono_thread = GDMonoUtils::attach_current_thread(); + } +} + +ScopeThreadAttach::~ScopeThreadAttach() { + if (unlikely(mono_thread)) { + GDMonoUtils::detach_current_thread(mono_thread); + } +} + +// namespace Marshal + } // namespace GDMonoUtils diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index d9eb912cd7..db9f99bfdc 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -83,9 +83,11 @@ _FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash) MonoObject *unmanaged_get_managed(Object *unmanaged); void set_main_thread(MonoThread *p_thread); -void attach_current_thread(); +MonoThread *attach_current_thread(); void detach_current_thread(); +void detach_current_thread(MonoThread *p_mono_thread); MonoThread *get_current_thread(); +bool is_thread_attached(); _FORCE_INLINE_ bool is_main_thread() { return mono_domain_get() != NULL && mono_thread_get_main() == mono_thread_current(); @@ -142,6 +144,14 @@ uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool & void dispose(MonoObject *p_mono_object, MonoException **r_exc); +struct ScopeThreadAttach { + ScopeThreadAttach(); + ~ScopeThreadAttach(); + +private: + MonoThread *mono_thread; +}; + } // namespace GDMonoUtils #define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoMarshal::mono_string_to_godot((MonoString *)m_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(NULL))) @@ -153,4 +163,15 @@ void dispose(MonoObject *p_mono_object, MonoException **r_exc); #define GD_MONO_END_RUNTIME_INVOKE \ _runtime_invoke_count_ref -= 1; +#define GD_MONO_SCOPE_THREAD_ATTACH \ + GDMonoUtils::ScopeThreadAttach __gdmono__scope__thread__attach__; \ + (void)__gdmono__scope__thread__attach__; + +#ifdef DEBUG_ENABLED +#define GD_MONO_ASSERT_THREAD_ATTACHED \ + { CRASH_COND(!GDMonoUtils::is_thread_attached()); } +#else +#define GD_MONO_ASSERT_THREAD_ATTACHED +#endif + #endif // GD_MONOUTILS_H diff --git a/modules/websocket/doc_classes/WebSocketServer.xml b/modules/websocket/doc_classes/WebSocketServer.xml index cd47c10f80..2074a10fa9 100644 --- a/modules/websocket/doc_classes/WebSocketServer.xml +++ b/modules/websocket/doc_classes/WebSocketServer.xml @@ -83,7 +83,7 @@ </method> </methods> <members> - <member name="bind_ip" type="String" setter="set_bind_ip" getter="get_bind_ip"> + <member name="bind_ip" type="String" setter="set_bind_ip" getter="get_bind_ip" default=""*""> When not set to [code]*[/code] will restrict incoming connections to the specified IP address. Setting [code]bind_ip[/code] to [code]127.0.0.1[/code] will cause the server to listen only to the local host. </member> <member name="ca_chain" type="X509Certificate" setter="set_ca_chain" getter="get_ca_chain"> diff --git a/platform/windows/context_gl_windows.cpp b/platform/windows/context_gl_windows.cpp index 434d685250..ad62e3a306 100644 --- a/platform/windows/context_gl_windows.cpp +++ b/platform/windows/context_gl_windows.cpp @@ -43,6 +43,11 @@ #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#if defined(__GNUC__) +// Workaround GCC warning from -Wcast-function-type. +#define wglGetProcAddress (void *)wglGetProcAddress +#endif + typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *); void ContextGL_Windows::release_current() { diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp index c82a90bf7d..49432435b9 100644 --- a/platform/windows/joypad_windows.cpp +++ b/platform/windows/joypad_windows.cpp @@ -37,6 +37,11 @@ #define __builtin_bswap32 _byteswap_ulong #endif +#if defined(__GNUC__) +// Workaround GCC warning from -Wcast-function-type. +#define GetProcAddress (void *)GetProcAddress +#endif + DWORD WINAPI _xinput_get_state(DWORD dwUserIndex, XINPUT_STATE *pState) { return ERROR_DEVICE_NOT_CONNECTED; } diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 3868d0bc63..a6977a7a86 100755 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -74,6 +74,11 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; #define WM_POINTERUPDATE 0x0245 #endif +#if defined(__GNUC__) +// Workaround GCC warning from -Wcast-function-type. +#define GetProcAddress (void *)GetProcAddress +#endif + typedef struct { int count; int screen; diff --git a/platform/x11/detect.py b/platform/x11/detect.py index a961072bd6..957779ee83 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -171,7 +171,7 @@ def configure(env): else: env.Append(CCFLAGS=['-flto']) env.Append(LINKFLAGS=['-flto']) - + if not env['use_llvm']: env['RANLIB'] = 'gcc-ranlib' env['AR'] = 'gcc-ar' @@ -329,9 +329,15 @@ def configure(env): if env["execinfo"]: env.Append(LIBS=['execinfo']) - + if not env['tools']: - env.Append(LINKFLAGS=['-T', 'platform/x11/pck_embed.ld']) + import subprocess + import re + binutils_version = re.search('\s(\d+\.\d+)', str(subprocess.check_output(['ld', '-v']))).group(1) + if float(binutils_version) >= 2.30: + env.Append(LINKFLAGS=['-T', 'platform/x11/pck_embed.ld']) + else: + env.Append(LINKFLAGS=['-T', 'platform/x11/pck_embed.legacy.ld']) ## Cross-compilation diff --git a/platform/x11/pck_embed.ld b/platform/x11/pck_embed.ld index fe09144d88..57a1994043 100644 --- a/platform/x11/pck_embed.ld +++ b/platform/x11/pck_embed.ld @@ -1,9 +1,9 @@ SECTIONS { /* Add a zero-sized section; the exporter will patch it to enclose the data appended to the executable (embedded PCK) */ - pck 0 (NOLOAD) : + pck 0 (INFO) : { - /* Just some content to avoid the linker discarding the section */ + /* binutils >= 2.30 allow it being zero-sized, but needs something between the braces to keep the section */ . = ALIGN(8); } } diff --git a/platform/x11/pck_embed.legacy.ld b/platform/x11/pck_embed.legacy.ld new file mode 100644 index 0000000000..a23013ba7a --- /dev/null +++ b/platform/x11/pck_embed.legacy.ld @@ -0,0 +1,10 @@ +SECTIONS +{ + /* The exporter will patch this section to enclose the data appended to the executable (embedded PCK) */ + pck 0 (INFO) : AT ( ADDR (.rodata) + SIZEOF (.rodata) ) + { + /* binutils < 2.30 need some actual content for the linker not to discard the section */ + BYTE(0); + } +} +INSERT AFTER .rodata; diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 8296f35739..c325de00b8 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -422,7 +422,7 @@ bool CPUParticles2D::get_particle_flag(Flags p_flag) const { } void CPUParticles2D::set_emission_shape(EmissionShape p_shape) { - + ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX); emission_shape = p_shape; _change_notify(); } @@ -772,6 +772,9 @@ void CPUParticles2D::_particles_process(float p_delta) { p.base_color = emission_colors.get(random_idx); } } break; + case EMISSION_SHAPE_MAX: { // Max value for validity check. + break; + } } if (!local_coords) { @@ -1416,6 +1419,7 @@ void CPUParticles2D::_bind_methods() { BIND_ENUM_CONSTANT(EMISSION_SHAPE_RECTANGLE); BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS); BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS); + BIND_ENUM_CONSTANT(EMISSION_SHAPE_MAX); } CPUParticles2D::CPUParticles2D() { diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index 6ffa1f0e97..cbaff70c2a 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -75,6 +75,7 @@ public: EMISSION_SHAPE_RECTANGLE, EMISSION_SHAPE_POINTS, EMISSION_SHAPE_DIRECTED_POINTS, + EMISSION_SHAPE_MAX }; private: diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp index 0ac424b09e..aa7a413548 100644 --- a/scene/3d/cpu_particles.cpp +++ b/scene/3d/cpu_particles.cpp @@ -405,7 +405,7 @@ bool CPUParticles::get_particle_flag(Flags p_flag) const { } void CPUParticles::set_emission_shape(EmissionShape p_shape) { - + ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX); emission_shape = p_shape; } @@ -784,6 +784,9 @@ void CPUParticles::_particles_process(float p_delta) { p.base_color = emission_colors.get(random_idx); } } break; + case EMISSION_SHAPE_MAX: { // Max value for validity check. + break; + } } if (!local_coords) { @@ -1488,6 +1491,7 @@ void CPUParticles::_bind_methods() { BIND_ENUM_CONSTANT(EMISSION_SHAPE_BOX); BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS); BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS); + BIND_ENUM_CONSTANT(EMISSION_SHAPE_MAX); } CPUParticles::CPUParticles() { diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h index 18f9718e70..d5a549b976 100644 --- a/scene/3d/cpu_particles.h +++ b/scene/3d/cpu_particles.h @@ -75,6 +75,7 @@ public: EMISSION_SHAPE_BOX, EMISSION_SHAPE_POINTS, EMISSION_SHAPE_DIRECTED_POINTS, + EMISSION_SHAPE_MAX }; private: diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp index 99a266af0d..518c243dd0 100644 --- a/scene/animation/skeleton_ik.cpp +++ b/scene/animation/skeleton_ik.cpp @@ -320,7 +320,7 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove new_bone_pose.basis = new_bone_pose.basis * p_task->chain.tips[0].end_effector->goal_transform.basis; } - p_task->skeleton->set_bone_global_pose_override(ci->bone, new_bone_pose, 1.0); + p_task->skeleton->set_bone_global_pose_override(ci->bone, new_bone_pose, 1.0, true); if (!ci->children.empty()) ci = &ci->children.write[0]; diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index a058f42cb2..412b5c259c 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -198,6 +198,9 @@ void ParticlesMaterial::_update_shader() { code += "uniform sampler2D emission_texture_color : hint_white;\n"; } } break; + case EMISSION_SHAPE_MAX: { // Max value for validity check. + break; + } } code += "uniform vec4 color_value : hint_color;\n"; @@ -283,7 +286,7 @@ void ParticlesMaterial::_update_shader() { code += " float degree_to_rad = pi / 180.0;\n"; code += "\n"; - if (emission_shape >= EMISSION_SHAPE_POINTS) { + if (emission_shape == EMISSION_SHAPE_POINTS || emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) { code += " int point = min(emission_texture_point_count - 1, int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n"; code += " ivec2 emission_tex_size = textureSize(emission_texture_points, 0);\n"; code += " ivec2 emission_tex_ofs = ivec2(point % emission_tex_size.x, point / emission_tex_size.x);\n"; @@ -368,6 +371,9 @@ void ParticlesMaterial::_update_shader() { } } } break; + case EMISSION_SHAPE_MAX: { // Max value for validity check. + break; + } } code += " VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n"; code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; @@ -515,7 +521,7 @@ void ParticlesMaterial::_update_shader() { } else { code += " COLOR = hue_rot_mat * color_value;\n"; } - if (emission_color_texture.is_valid() && emission_shape >= EMISSION_SHAPE_POINTS) { + if (emission_color_texture.is_valid() && (emission_shape == EMISSION_SHAPE_POINTS || emission_shape == EMISSION_SHAPE_DIRECTED_POINTS)) { code += " COLOR *= texelFetch(emission_texture_color, emission_tex_ofs, 0);\n"; } if (trail_color_modifier.is_valid()) { @@ -894,7 +900,7 @@ bool ParticlesMaterial::get_flag(Flags p_flag) const { } void ParticlesMaterial::set_emission_shape(EmissionShape p_shape) { - + ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX); emission_shape = p_shape; _change_notify(); _queue_shader_change(); @@ -1242,6 +1248,7 @@ void ParticlesMaterial::_bind_methods() { BIND_ENUM_CONSTANT(EMISSION_SHAPE_BOX); BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS); BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS); + BIND_ENUM_CONSTANT(EMISSION_SHAPE_MAX); } ParticlesMaterial::ParticlesMaterial() : diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h index 643c2cb10e..cc860b3812 100644 --- a/scene/resources/particles_material.h +++ b/scene/resources/particles_material.h @@ -69,6 +69,7 @@ public: EMISSION_SHAPE_BOX, EMISSION_SHAPE_POINTS, EMISSION_SHAPE_DIRECTED_POINTS, + EMISSION_SHAPE_MAX }; private: diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 225b382524..2b61d72f6a 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -2060,7 +2060,7 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { //sub-functions //array - { "length", TYPE_INT, { TYPE_VOID }, TAG_ARRAY, false }, + { "length", TYPE_INT, { TYPE_VOID }, TAG_ARRAY, true }, { NULL, TYPE_VOID, { TYPE_VOID }, TAG_GLOBAL, false } @@ -3888,6 +3888,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui if (tk.type == TK_BRACKET_OPEN) { bool unknown_size = false; + if (VisualServer::get_singleton()->is_low_end() && is_const) { + _set_error("Local const arrays are supported only on high-end platform!"); + return ERR_PARSE_ERROR; + } + ArrayDeclarationNode *node = alloc_node<ArrayDeclarationNode>(); node->datatype = type; node->precision = precision; @@ -3923,6 +3928,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui tk = _get_token(); if (tk.type == TK_OP_ASSIGN) { + + if (VisualServer::get_singleton()->is_low_end()) { + _set_error("Array initialization is supported only on high-end platform!"); + return ERR_PARSE_ERROR; + } + tk = _get_token(); if (tk.type != TK_CURLY_BRACKET_OPEN) { diff --git a/thirdparty/README.md b/thirdparty/README.md index b68c585cac..b29f4bd5e8 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -237,7 +237,7 @@ from the Android NDK r18. ## libwebp - Upstream: https://chromium.googlesource.com/webm/libwebp/ -- Version: 1.0.3 +- Version: 1.1.0 - License: BSD-3-Clause Files extracted from upstream source: diff --git a/thirdparty/libwebp/src/dec/frame_dec.c b/thirdparty/libwebp/src/dec/frame_dec.c index bda9e1a6f6..04609a8e56 100644 --- a/thirdparty/libwebp/src/dec/frame_dec.c +++ b/thirdparty/libwebp/src/dec/frame_dec.c @@ -732,7 +732,7 @@ static int AllocateMemory(VP8Decoder* const dec) { mem += f_info_size; dec->thread_ctx_.id_ = 0; dec->thread_ctx_.f_info_ = dec->f_info_; - if (dec->mt_method_ > 0) { + if (dec->filter_type_ > 0 && dec->mt_method_ > 0) { // secondary cache line. The deblocking process need to make use of the // filtering strength from previous macroblock row, while the new ones // are being decoded in parallel. We'll just swap the pointers. diff --git a/thirdparty/libwebp/src/dec/idec_dec.c b/thirdparty/libwebp/src/dec/idec_dec.c index 9bc9166808..9035df5659 100644 --- a/thirdparty/libwebp/src/dec/idec_dec.c +++ b/thirdparty/libwebp/src/dec/idec_dec.c @@ -166,9 +166,11 @@ static int AppendToMemBuffer(WebPIDecoder* const idec, VP8Decoder* const dec = (VP8Decoder*)idec->dec_; MemBuffer* const mem = &idec->mem_; const int need_compressed_alpha = NeedCompressedAlpha(idec); - const uint8_t* const old_start = mem->buf_ + mem->start_; + const uint8_t* const old_start = + (mem->buf_ == NULL) ? NULL : mem->buf_ + mem->start_; const uint8_t* const old_base = need_compressed_alpha ? dec->alpha_data_ : old_start; + assert(mem->buf_ != NULL || mem->start_ == 0); assert(mem->mode_ == MEM_MODE_APPEND); if (data_size > MAX_CHUNK_PAYLOAD) { // security safeguard: trying to allocate more than what the format @@ -184,7 +186,7 @@ static int AppendToMemBuffer(WebPIDecoder* const idec, uint8_t* const new_buf = (uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf)); if (new_buf == NULL) return 0; - memcpy(new_buf, old_base, current_size); + if (old_base != NULL) memcpy(new_buf, old_base, current_size); WebPSafeFree(mem->buf_); mem->buf_ = new_buf; mem->buf_size_ = (size_t)extra_size; @@ -192,6 +194,7 @@ static int AppendToMemBuffer(WebPIDecoder* const idec, mem->end_ = current_size; } + assert(mem->buf_ != NULL); memcpy(mem->buf_ + mem->end_, data, data_size); mem->end_ += data_size; assert(mem->end_ <= mem->buf_size_); @@ -204,7 +207,9 @@ static int RemapMemBuffer(WebPIDecoder* const idec, const uint8_t* const data, size_t data_size) { MemBuffer* const mem = &idec->mem_; const uint8_t* const old_buf = mem->buf_; - const uint8_t* const old_start = old_buf + mem->start_; + const uint8_t* const old_start = + (old_buf == NULL) ? NULL : old_buf + mem->start_; + assert(old_buf != NULL || mem->start_ == 0); assert(mem->mode_ == MEM_MODE_MAP); if (data_size < mem->buf_size_) return 0; // can't remap to a shorter buffer! diff --git a/thirdparty/libwebp/src/dec/vp8i_dec.h b/thirdparty/libwebp/src/dec/vp8i_dec.h index 3de8d86f90..600a684410 100644 --- a/thirdparty/libwebp/src/dec/vp8i_dec.h +++ b/thirdparty/libwebp/src/dec/vp8i_dec.h @@ -31,8 +31,8 @@ extern "C" { // version numbers #define DEC_MAJ_VERSION 1 -#define DEC_MIN_VERSION 0 -#define DEC_REV_VERSION 3 +#define DEC_MIN_VERSION 1 +#define DEC_REV_VERSION 0 // YUV-cache parameters. Cache is 32-bytes wide (= one cacheline). // Constraints are: We need to store one 16x16 block of luma samples (y), diff --git a/thirdparty/libwebp/src/dec/vp8l_dec.c b/thirdparty/libwebp/src/dec/vp8l_dec.c index d3e27119ea..93615d4ed2 100644 --- a/thirdparty/libwebp/src/dec/vp8l_dec.c +++ b/thirdparty/libwebp/src/dec/vp8l_dec.c @@ -754,11 +754,11 @@ static WEBP_INLINE HTreeGroup* GetHtreeGroupForPos(VP8LMetadata* const hdr, typedef void (*ProcessRowsFunc)(VP8LDecoder* const dec, int row); -static void ApplyInverseTransforms(VP8LDecoder* const dec, int num_rows, +static void ApplyInverseTransforms(VP8LDecoder* const dec, + int start_row, int num_rows, const uint32_t* const rows) { int n = dec->next_transform_; const int cache_pixs = dec->width_ * num_rows; - const int start_row = dec->last_row_; const int end_row = start_row + num_rows; const uint32_t* rows_in = rows; uint32_t* const rows_out = dec->argb_cache_; @@ -789,8 +789,7 @@ static void ProcessRows(VP8LDecoder* const dec, int row) { VP8Io* const io = dec->io_; uint8_t* rows_data = (uint8_t*)dec->argb_cache_; const int in_stride = io->width * sizeof(uint32_t); // in unit of RGBA - - ApplyInverseTransforms(dec, num_rows, rows); + ApplyInverseTransforms(dec, dec->last_row_, num_rows, rows); if (!SetCropWindow(io, dec->last_row_, row, &rows_data, in_stride)) { // Nothing to output (this time). } else { @@ -1193,6 +1192,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data, VP8LFillBitWindow(br); dist_code = GetCopyDistance(dist_symbol, br); dist = PlaneCodeToDistance(width, dist_code); + if (VP8LIsEndOfStream(br)) break; if (src - data < (ptrdiff_t)dist || src_end - src < (ptrdiff_t)length) { goto Error; @@ -1553,7 +1553,7 @@ static void ExtractAlphaRows(VP8LDecoder* const dec, int last_row) { const int cache_pixs = width * num_rows_to_process; uint8_t* const dst = output + width * cur_row; const uint32_t* const src = dec->argb_cache_; - ApplyInverseTransforms(dec, num_rows_to_process, in); + ApplyInverseTransforms(dec, cur_row, num_rows_to_process, in); WebPExtractGreen(src, dst, cache_pixs); AlphaApplyFilter(alph_dec, cur_row, cur_row + num_rows_to_process, dst, width); diff --git a/thirdparty/libwebp/src/dec/vp8li_dec.h b/thirdparty/libwebp/src/dec/vp8li_dec.h index 0a4d613f99..72b2e86120 100644 --- a/thirdparty/libwebp/src/dec/vp8li_dec.h +++ b/thirdparty/libwebp/src/dec/vp8li_dec.h @@ -37,7 +37,7 @@ struct VP8LTransform { int bits_; // subsampling bits defining transform window. int xsize_; // transform window X index. int ysize_; // transform window Y index. - uint32_t *data_; // transform data. + uint32_t* data_; // transform data. }; typedef struct { @@ -48,23 +48,23 @@ typedef struct { int huffman_mask_; int huffman_subsample_bits_; int huffman_xsize_; - uint32_t *huffman_image_; + uint32_t* huffman_image_; int num_htree_groups_; - HTreeGroup *htree_groups_; - HuffmanCode *huffman_tables_; + HTreeGroup* htree_groups_; + HuffmanCode* huffman_tables_; } VP8LMetadata; typedef struct VP8LDecoder VP8LDecoder; struct VP8LDecoder { VP8StatusCode status_; VP8LDecodeState state_; - VP8Io *io_; + VP8Io* io_; - const WebPDecBuffer *output_; // shortcut to io->opaque->output + const WebPDecBuffer* output_; // shortcut to io->opaque->output - uint32_t *pixels_; // Internal data: either uint8_t* for alpha + uint32_t* pixels_; // Internal data: either uint8_t* for alpha // or uint32_t* for BGRA. - uint32_t *argb_cache_; // Scratch buffer for temporary BGRA storage. + uint32_t* argb_cache_; // Scratch buffer for temporary BGRA storage. VP8LBitReader br_; int incremental_; // if true, incremental decoding is expected @@ -86,8 +86,8 @@ struct VP8LDecoder { // or'd bitset storing the transforms types. uint32_t transforms_seen_; - uint8_t *rescaler_memory; // Working memory for rescaling work. - WebPRescaler *rescaler; // Common rescaler for all channels. + uint8_t* rescaler_memory; // Working memory for rescaling work. + WebPRescaler* rescaler; // Common rescaler for all channels. }; //------------------------------------------------------------------------------ diff --git a/thirdparty/libwebp/src/demux/demux.c b/thirdparty/libwebp/src/demux/demux.c index ab6433e54b..1b3cc2e0a8 100644 --- a/thirdparty/libwebp/src/demux/demux.c +++ b/thirdparty/libwebp/src/demux/demux.c @@ -24,8 +24,8 @@ #include "src/webp/format_constants.h" #define DMUX_MAJ_VERSION 1 -#define DMUX_MIN_VERSION 0 -#define DMUX_REV_VERSION 3 +#define DMUX_MIN_VERSION 1 +#define DMUX_REV_VERSION 0 typedef struct { size_t start_; // start location of the data diff --git a/thirdparty/libwebp/src/dsp/dec_neon.c b/thirdparty/libwebp/src/dsp/dec_neon.c index ffa697fcf9..239ec4167e 100644 --- a/thirdparty/libwebp/src/dsp/dec_neon.c +++ b/thirdparty/libwebp/src/dsp/dec_neon.c @@ -1361,7 +1361,8 @@ static void RD4_NEON(uint8_t* dst) { // Down-right const uint32_t J = dst[-1 + 1 * BPS]; const uint32_t K = dst[-1 + 2 * BPS]; const uint32_t L = dst[-1 + 3 * BPS]; - const uint64x1_t LKJI____ = vcreate_u64(L | (K << 8) | (J << 16) | (I << 24)); + const uint64x1_t LKJI____ = + vcreate_u64((uint64_t)L | (K << 8) | (J << 16) | (I << 24)); const uint64x1_t LKJIXABC = vorr_u64(LKJI____, ____XABC); const uint8x8_t KJIXABC_ = vreinterpret_u8_u64(vshr_n_u64(LKJIXABC, 8)); const uint8x8_t JIXABC__ = vreinterpret_u8_u64(vshr_n_u64(LKJIXABC, 16)); @@ -1427,10 +1428,16 @@ static WEBP_INLINE void DC8_NEON(uint8_t* dst, int do_top, int do_left) { if (do_top) { const uint8x8_t A = vld1_u8(dst - BPS); // top row +#if defined(__aarch64__) + const uint16x8_t B = vmovl_u8(A); + const uint16_t p2 = vaddvq_u16(B); + sum_top = vdupq_n_u16(p2); +#else const uint16x4_t p0 = vpaddl_u8(A); // cascading summation of the top const uint16x4_t p1 = vpadd_u16(p0, p0); const uint16x4_t p2 = vpadd_u16(p1, p1); sum_top = vcombine_u16(p2, p2); +#endif } if (do_left) { diff --git a/thirdparty/libwebp/src/dsp/dsp.h b/thirdparty/libwebp/src/dsp/dsp.h index fafc2d05d3..a784de334a 100644 --- a/thirdparty/libwebp/src/dsp/dsp.h +++ b/thirdparty/libwebp/src/dsp/dsp.h @@ -246,9 +246,9 @@ extern VP8Fdct VP8FTransform2; // performs two transforms at a time extern VP8WHT VP8FTransformWHT; // Predictions // *dst is the destination block. *top and *left can be NULL. -typedef void (*VP8IntraPreds)(uint8_t *dst, const uint8_t* left, +typedef void (*VP8IntraPreds)(uint8_t* dst, const uint8_t* left, const uint8_t* top); -typedef void (*VP8Intra4Preds)(uint8_t *dst, const uint8_t* top); +typedef void (*VP8Intra4Preds)(uint8_t* dst, const uint8_t* top); extern VP8Intra4Preds VP8EncPredLuma4; extern VP8IntraPreds VP8EncPredLuma16; extern VP8IntraPreds VP8EncPredChroma8; diff --git a/thirdparty/libwebp/src/dsp/lossless.c b/thirdparty/libwebp/src/dsp/lossless.c index d05af84e7b..aad5f43ec9 100644 --- a/thirdparty/libwebp/src/dsp/lossless.c +++ b/thirdparty/libwebp/src/dsp/lossless.c @@ -81,7 +81,7 @@ static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1, // gcc <= 4.9 on ARM generates incorrect code in Select() when Sub3() is // inlined. -#if defined(__arm__) && LOCAL_GCC_VERSION <= 0x409 +#if defined(__arm__) && defined(__GNUC__) && LOCAL_GCC_VERSION <= 0x409 # define LOCAL_INLINE __attribute__ ((noinline)) #else # define LOCAL_INLINE WEBP_INLINE @@ -167,15 +167,20 @@ static uint32_t Predictor13_C(uint32_t left, const uint32_t* const top) { return pred; } -GENERATE_PREDICTOR_ADD(Predictor0_C, PredictorAdd0_C) +static void PredictorAdd0_C(const uint32_t* in, const uint32_t* upper, + int num_pixels, uint32_t* out) { + int x; + (void)upper; + for (x = 0; x < num_pixels; ++x) out[x] = VP8LAddPixels(in[x], ARGB_BLACK); +} static void PredictorAdd1_C(const uint32_t* in, const uint32_t* upper, int num_pixels, uint32_t* out) { int i; uint32_t left = out[-1]; + (void)upper; for (i = 0; i < num_pixels; ++i) { out[i] = left = VP8LAddPixels(in[i], left); } - (void)upper; } GENERATE_PREDICTOR_ADD(Predictor2_C, PredictorAdd2_C) GENERATE_PREDICTOR_ADD(Predictor3_C, PredictorAdd3_C) diff --git a/thirdparty/libwebp/src/dsp/lossless_common.h b/thirdparty/libwebp/src/dsp/lossless_common.h index a2648d1737..9c2ebe6809 100644 --- a/thirdparty/libwebp/src/dsp/lossless_common.h +++ b/thirdparty/libwebp/src/dsp/lossless_common.h @@ -177,6 +177,7 @@ uint32_t VP8LSubPixels(uint32_t a, uint32_t b) { static void PREDICTOR_ADD(const uint32_t* in, const uint32_t* upper, \ int num_pixels, uint32_t* out) { \ int x; \ + assert(upper != NULL); \ for (x = 0; x < num_pixels; ++x) { \ const uint32_t pred = (PREDICTOR)(out[x - 1], upper + x); \ out[x] = VP8LAddPixels(in[x], pred); \ @@ -189,6 +190,7 @@ static void PREDICTOR_ADD(const uint32_t* in, const uint32_t* upper, \ static void PREDICTOR_SUB(const uint32_t* in, const uint32_t* upper, \ int num_pixels, uint32_t* out) { \ int x; \ + assert(upper != NULL); \ for (x = 0; x < num_pixels; ++x) { \ const uint32_t pred = (PREDICTOR)(in[x - 1], upper + x); \ out[x] = VP8LSubPixels(in[x], pred); \ diff --git a/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c b/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c index 8adc52139b..e676f6fdc9 100644 --- a/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c +++ b/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c @@ -455,8 +455,9 @@ static void PredictorSub0_SSE2(const uint32_t* in, const uint32_t* upper, _mm_storeu_si128((__m128i*)&out[i], res); } if (i != num_pixels) { - VP8LPredictorsSub_C[0](in + i, upper + i, num_pixels - i, out + i); + VP8LPredictorsSub_C[0](in + i, NULL, num_pixels - i, out + i); } + (void)upper; } #define GENERATE_PREDICTOR_1(X, IN) \ diff --git a/thirdparty/libwebp/src/dsp/lossless_sse2.c b/thirdparty/libwebp/src/dsp/lossless_sse2.c index 17d7576419..aef0cee1b3 100644 --- a/thirdparty/libwebp/src/dsp/lossless_sse2.c +++ b/thirdparty/libwebp/src/dsp/lossless_sse2.c @@ -191,8 +191,9 @@ static void PredictorAdd0_SSE2(const uint32_t* in, const uint32_t* upper, _mm_storeu_si128((__m128i*)&out[i], res); } if (i != num_pixels) { - VP8LPredictorsAdd_C[0](in + i, upper + i, num_pixels - i, out + i); + VP8LPredictorsAdd_C[0](in + i, NULL, num_pixels - i, out + i); } + (void)upper; } // Predictor1: left. diff --git a/thirdparty/libwebp/src/dsp/upsampling_msa.c b/thirdparty/libwebp/src/dsp/upsampling_msa.c index 99eea70e7d..f2e03e85e9 100644 --- a/thirdparty/libwebp/src/dsp/upsampling_msa.c +++ b/thirdparty/libwebp/src/dsp/upsampling_msa.c @@ -576,9 +576,9 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bot_y, \ const uint32_t l_uv = ((cur_u[0]) | ((cur_v[0]) << 16)); \ const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \ const uint8_t* ptop_y = &top_y[1]; \ - uint8_t *ptop_dst = top_dst + XSTEP; \ + uint8_t* ptop_dst = top_dst + XSTEP; \ const uint8_t* pbot_y = &bot_y[1]; \ - uint8_t *pbot_dst = bot_dst + XSTEP; \ + uint8_t* pbot_dst = bot_dst + XSTEP; \ \ FUNC(top_y[0], uv0 & 0xff, (uv0 >> 16), top_dst); \ if (bot_y != NULL) { \ diff --git a/thirdparty/libwebp/src/dsp/upsampling_neon.c b/thirdparty/libwebp/src/dsp/upsampling_neon.c index 17cbc9f911..6ba71a7de5 100644 --- a/thirdparty/libwebp/src/dsp/upsampling_neon.c +++ b/thirdparty/libwebp/src/dsp/upsampling_neon.c @@ -58,8 +58,8 @@ } while (0) // Turn the macro into a function for reducing code-size when non-critical -static void Upsample16Pixels_NEON(const uint8_t *r1, const uint8_t *r2, - uint8_t *out) { +static void Upsample16Pixels_NEON(const uint8_t* r1, const uint8_t* r2, + uint8_t* out) { UPSAMPLE_16PIXELS(r1, r2, out); } @@ -190,14 +190,14 @@ static const int16_t kCoeffs1[4] = { 19077, 26149, 6419, 13320 }; } #define NEON_UPSAMPLE_FUNC(FUNC_NAME, FMT, XSTEP) \ -static void FUNC_NAME(const uint8_t *top_y, const uint8_t *bottom_y, \ - const uint8_t *top_u, const uint8_t *top_v, \ - const uint8_t *cur_u, const uint8_t *cur_v, \ - uint8_t *top_dst, uint8_t *bottom_dst, int len) { \ +static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \ + const uint8_t* top_u, const uint8_t* top_v, \ + const uint8_t* cur_u, const uint8_t* cur_v, \ + uint8_t* top_dst, uint8_t* bottom_dst, int len) { \ int block; \ /* 16 byte aligned array to cache reconstructed u and v */ \ uint8_t uv_buf[2 * 32 + 15]; \ - uint8_t *const r_uv = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \ + uint8_t* const r_uv = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \ const int uv_len = (len + 1) >> 1; \ /* 9 pixels must be read-able for each block */ \ const int num_blocks = (uv_len - 1) >> 3; \ diff --git a/thirdparty/libwebp/src/enc/histogram_enc.c b/thirdparty/libwebp/src/enc/histogram_enc.c index d89b98524a..a4e6bf3a98 100644 --- a/thirdparty/libwebp/src/enc/histogram_enc.c +++ b/thirdparty/libwebp/src/enc/histogram_enc.c @@ -641,7 +641,7 @@ static void HistogramAnalyzeEntropyBin(VP8LHistogramSet* const image_histo, // Merges some histograms with same bin_id together if it's advantageous. // Sets the remaining histograms to NULL. static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo, - int *num_used, + int* num_used, const uint16_t* const clusters, uint16_t* const cluster_mappings, VP8LHistogram* cur_combo, diff --git a/thirdparty/libwebp/src/enc/picture_csp_enc.c b/thirdparty/libwebp/src/enc/picture_csp_enc.c index 02d9df76d5..718e014ed2 100644 --- a/thirdparty/libwebp/src/enc/picture_csp_enc.c +++ b/thirdparty/libwebp/src/enc/picture_csp_enc.c @@ -29,11 +29,15 @@ #define USE_INVERSE_ALPHA_TABLE #ifdef WORDS_BIGENDIAN -#define ALPHA_OFFSET 0 // uint32_t 0xff000000 is 0xff,00,00,00 in memory +// uint32_t 0xff000000 is 0xff,00,00,00 in memory +#define CHANNEL_OFFSET(i) (i) #else -#define ALPHA_OFFSET 3 // uint32_t 0xff000000 is 0x00,00,00,ff in memory +// uint32_t 0xff000000 is 0x00,00,00,ff in memory +#define CHANNEL_OFFSET(i) (3-(i)) #endif +#define ALPHA_OFFSET CHANNEL_OFFSET(0) + //------------------------------------------------------------------------------ // Detection of non-trivial transparency @@ -997,10 +1001,10 @@ static int PictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace, return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION); } else { const uint8_t* const argb = (const uint8_t*)picture->argb; - const uint8_t* const a = argb + (0 ^ ALPHA_OFFSET); - const uint8_t* const r = argb + (1 ^ ALPHA_OFFSET); - const uint8_t* const g = argb + (2 ^ ALPHA_OFFSET); - const uint8_t* const b = argb + (3 ^ ALPHA_OFFSET); + const uint8_t* const a = argb + CHANNEL_OFFSET(0); + const uint8_t* const r = argb + CHANNEL_OFFSET(1); + const uint8_t* const g = argb + CHANNEL_OFFSET(2); + const uint8_t* const b = argb + CHANNEL_OFFSET(3); picture->colorspace = WEBP_YUV420; return ImportYUVAFromRGBA(r, g, b, a, 4, 4 * picture->argb_stride, @@ -1050,7 +1054,7 @@ int WebPPictureYUVAToARGB(WebPPicture* picture) { const int height = picture->height; const int argb_stride = 4 * picture->argb_stride; uint8_t* dst = (uint8_t*)picture->argb; - const uint8_t *cur_u = picture->u, *cur_v = picture->v, *cur_y = picture->y; + const uint8_t* cur_u = picture->u, *cur_v = picture->v, *cur_y = picture->y; WebPUpsampleLinePairFunc upsample = WebPGetLinePairConverter(ALPHA_OFFSET > 0); diff --git a/thirdparty/libwebp/src/enc/vp8i_enc.h b/thirdparty/libwebp/src/enc/vp8i_enc.h index 24e1944610..fedcaeea27 100644 --- a/thirdparty/libwebp/src/enc/vp8i_enc.h +++ b/thirdparty/libwebp/src/enc/vp8i_enc.h @@ -31,8 +31,8 @@ extern "C" { // version numbers #define ENC_MAJ_VERSION 1 -#define ENC_MIN_VERSION 0 -#define ENC_REV_VERSION 3 +#define ENC_MIN_VERSION 1 +#define ENC_REV_VERSION 0 enum { MAX_LF_LEVELS = 64, // Maximum loop filter level MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost @@ -249,7 +249,7 @@ typedef struct { int percent0_; // saved initial progress percent DError left_derr_; // left error diffusion (u/v) - DError *top_derr_; // top diffusion error - NULL if disabled + DError* top_derr_; // top diffusion error - NULL if disabled uint8_t* y_left_; // left luma samples (addressable from index -1 to 15). uint8_t* u_left_; // left u samples (addressable from index -1 to 7) diff --git a/thirdparty/libwebp/src/mux/muxi.h b/thirdparty/libwebp/src/mux/muxi.h index 7bc0b07e9b..ad3e1bdb97 100644 --- a/thirdparty/libwebp/src/mux/muxi.h +++ b/thirdparty/libwebp/src/mux/muxi.h @@ -28,8 +28,8 @@ extern "C" { // Defines and constants. #define MUX_MAJ_VERSION 1 -#define MUX_MIN_VERSION 0 -#define MUX_REV_VERSION 3 +#define MUX_MIN_VERSION 1 +#define MUX_REV_VERSION 0 // Chunk object. typedef struct WebPChunk WebPChunk; diff --git a/thirdparty/libwebp/src/mux/muxread.c b/thirdparty/libwebp/src/mux/muxread.c index 268f6acb53..ae3b876bc5 100644 --- a/thirdparty/libwebp/src/mux/muxread.c +++ b/thirdparty/libwebp/src/mux/muxread.c @@ -100,7 +100,7 @@ static int MuxImageParse(const WebPChunk* const chunk, int copy_data, WebPMuxImage* const wpi) { const uint8_t* bytes = chunk->data_.bytes; size_t size = chunk->data_.size; - const uint8_t* const last = bytes + size; + const uint8_t* const last = (bytes == NULL) ? NULL : bytes + size; WebPChunk subchunk; size_t subchunk_size; WebPChunk** unknown_chunk_list = &wpi->unknown_; diff --git a/thirdparty/libwebp/src/utils/color_cache_utils.h b/thirdparty/libwebp/src/utils/color_cache_utils.h index ec21d5199b..b45d47c2d5 100644 --- a/thirdparty/libwebp/src/utils/color_cache_utils.h +++ b/thirdparty/libwebp/src/utils/color_cache_utils.h @@ -26,7 +26,7 @@ extern "C" { // Main color cache struct. typedef struct { - uint32_t *colors_; // color entries + uint32_t* colors_; // color entries int hash_shift_; // Hash shift: 32 - hash_bits_. int hash_bits_; } VP8LColorCache; diff --git a/thirdparty/libwebp/src/utils/thread_utils.c b/thirdparty/libwebp/src/utils/thread_utils.c index 438296b45f..4e470e17ac 100644 --- a/thirdparty/libwebp/src/utils/thread_utils.c +++ b/thirdparty/libwebp/src/utils/thread_utils.c @@ -73,7 +73,7 @@ typedef struct { #endif static int pthread_create(pthread_t* const thread, const void* attr, - unsigned int (__stdcall *start)(void*), void* arg) { + unsigned int (__stdcall* start)(void*), void* arg) { (void)attr; #ifdef USE_CREATE_THREAD *thread = CreateThread(NULL, /* lpThreadAttributes */ diff --git a/thirdparty/libwebp/src/utils/utils.c b/thirdparty/libwebp/src/utils/utils.c index 44d5c14f01..764f752b82 100644 --- a/thirdparty/libwebp/src/utils/utils.c +++ b/thirdparty/libwebp/src/utils/utils.c @@ -216,9 +216,14 @@ void WebPSafeFree(void* const ptr) { free(ptr); } -// Public API function. +// Public API functions. + +void* WebPMalloc(size_t size) { + return WebPSafeMalloc(1, size); +} + void WebPFree(void* ptr) { - free(ptr); + WebPSafeFree(ptr); } //------------------------------------------------------------------------------ diff --git a/thirdparty/libwebp/src/webp/decode.h b/thirdparty/libwebp/src/webp/decode.h index ae8bfe840e..80dd0ef0cc 100644 --- a/thirdparty/libwebp/src/webp/decode.h +++ b/thirdparty/libwebp/src/webp/decode.h @@ -20,7 +20,7 @@ extern "C" { #endif -#define WEBP_DECODER_ABI_VERSION 0x0208 // MAJOR(8b) + MINOR(8b) +#define WEBP_DECODER_ABI_VERSION 0x0209 // MAJOR(8b) + MINOR(8b) // Note: forward declaring enumerations is not allowed in (strict) C and C++, // the types are left here for reference. @@ -91,9 +91,6 @@ WEBP_EXTERN uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size, uint8_t** u, uint8_t** v, int* stride, int* uv_stride); -// Releases memory returned by the WebPDecode*() functions above. -WEBP_EXTERN void WebPFree(void* ptr); - // These five functions are variants of the above ones, that decode the image // directly into a pre-allocated buffer 'output_buffer'. The maximum storage // available in this buffer is indicated by 'output_buffer_size'. If this diff --git a/thirdparty/libwebp/src/webp/encode.h b/thirdparty/libwebp/src/webp/encode.h index 339f8810aa..655166e7d4 100644 --- a/thirdparty/libwebp/src/webp/encode.h +++ b/thirdparty/libwebp/src/webp/encode.h @@ -20,7 +20,7 @@ extern "C" { #endif -#define WEBP_ENCODER_ABI_VERSION 0x020e // MAJOR(8b) + MINOR(8b) +#define WEBP_ENCODER_ABI_VERSION 0x020f // MAJOR(8b) + MINOR(8b) // Note: forward declaring enumerations is not allowed in (strict) C and C++, // the types are left here for reference. @@ -79,9 +79,6 @@ WEBP_EXTERN size_t WebPEncodeLosslessBGRA(const uint8_t* bgra, int width, int height, int stride, uint8_t** output); -// Releases memory returned by the WebPEncode*() functions above. -WEBP_EXTERN void WebPFree(void* ptr); - //------------------------------------------------------------------------------ // Coding parameters @@ -306,7 +303,7 @@ struct WebPPicture { // YUV input (mostly used for input to lossy compression) WebPEncCSP colorspace; // colorspace: should be YUV420 for now (=Y'CbCr). int width, height; // dimensions (less or equal to WEBP_MAX_DIMENSION) - uint8_t *y, *u, *v; // pointers to luma/chroma planes. + uint8_t* y, *u, *v; // pointers to luma/chroma planes. int y_stride, uv_stride; // luma/chroma strides. uint8_t* a; // pointer to the alpha plane int a_stride; // stride of the alpha plane @@ -350,7 +347,7 @@ struct WebPPicture { uint32_t pad3[3]; // padding for later use // Unused for now - uint8_t *pad4, *pad5; + uint8_t* pad4, *pad5; uint32_t pad6[8]; // padding for later use // PRIVATE FIELDS diff --git a/thirdparty/libwebp/src/webp/mux.h b/thirdparty/libwebp/src/webp/mux.h index 66096a92e0..7d27489a40 100644 --- a/thirdparty/libwebp/src/webp/mux.h +++ b/thirdparty/libwebp/src/webp/mux.h @@ -57,7 +57,7 @@ extern "C" { WebPMuxGetChunk(mux, "ICCP", &icc_profile); // ... (Consume icc_data). WebPMuxDelete(mux); - free(data); + WebPFree(data); */ // Note: forward declaring enumerations is not allowed in (strict) C and C++, @@ -245,7 +245,7 @@ WEBP_EXTERN WebPMuxError WebPMuxPushFrame( WebPMux* mux, const WebPMuxFrameInfo* frame, int copy_data); // Gets the nth frame from the mux object. -// The content of 'frame->bitstream' is allocated using malloc(), and NOT +// The content of 'frame->bitstream' is allocated using WebPMalloc(), and NOT // owned by the 'mux' object. It MUST be deallocated by the caller by calling // WebPDataClear(). // nth=0 has a special meaning - last position. @@ -376,10 +376,10 @@ WEBP_EXTERN WebPMuxError WebPMuxNumChunks(const WebPMux* mux, // Assembles all chunks in WebP RIFF format and returns in 'assembled_data'. // This function also validates the mux object. // Note: The content of 'assembled_data' will be ignored and overwritten. -// Also, the content of 'assembled_data' is allocated using malloc(), and NOT -// owned by the 'mux' object. It MUST be deallocated by the caller by calling -// WebPDataClear(). It's always safe to call WebPDataClear() upon return, -// even in case of error. +// Also, the content of 'assembled_data' is allocated using WebPMalloc(), and +// NOT owned by the 'mux' object. It MUST be deallocated by the caller by +// calling WebPDataClear(). It's always safe to call WebPDataClear() upon +// return, even in case of error. // Parameters: // mux - (in/out) object whose chunks are to be assembled // assembled_data - (out) assembled WebP data diff --git a/thirdparty/libwebp/src/webp/mux_types.h b/thirdparty/libwebp/src/webp/mux_types.h index ceea77dfc6..2fe8195839 100644 --- a/thirdparty/libwebp/src/webp/mux_types.h +++ b/thirdparty/libwebp/src/webp/mux_types.h @@ -14,7 +14,6 @@ #ifndef WEBP_WEBP_MUX_TYPES_H_ #define WEBP_WEBP_MUX_TYPES_H_ -#include <stdlib.h> // free() #include <string.h> // memset() #include "./types.h" @@ -56,6 +55,7 @@ typedef enum WebPMuxAnimBlend { // Data type used to describe 'raw' data, e.g., chunk data // (ICC profile, metadata) and WebP compressed image data. +// 'bytes' memory must be allocated using WebPMalloc() and such. struct WebPData { const uint8_t* bytes; size_t size; @@ -68,11 +68,11 @@ static WEBP_INLINE void WebPDataInit(WebPData* webp_data) { } } -// Clears the contents of the 'webp_data' object by calling free(). Does not -// deallocate the object itself. +// Clears the contents of the 'webp_data' object by calling WebPFree(). +// Does not deallocate the object itself. static WEBP_INLINE void WebPDataClear(WebPData* webp_data) { if (webp_data != NULL) { - free((void*)webp_data->bytes); + WebPFree((void*)webp_data->bytes); WebPDataInit(webp_data); } } @@ -83,7 +83,7 @@ static WEBP_INLINE int WebPDataCopy(const WebPData* src, WebPData* dst) { if (src == NULL || dst == NULL) return 0; WebPDataInit(dst); if (src->bytes != NULL && src->size != 0) { - dst->bytes = (uint8_t*)malloc(src->size); + dst->bytes = (uint8_t*)WebPMalloc(src->size); if (dst->bytes == NULL) return 0; memcpy((void*)dst->bytes, src->bytes, src->size); dst->size = src->size; diff --git a/thirdparty/libwebp/src/webp/types.h b/thirdparty/libwebp/src/webp/types.h index 0ce2622e41..47f7f2b007 100644 --- a/thirdparty/libwebp/src/webp/types.h +++ b/thirdparty/libwebp/src/webp/types.h @@ -7,7 +7,7 @@ // be found in the AUTHORS file in the root of the source tree. // ----------------------------------------------------------------------------- // -// Common types +// Common types + memory wrappers // // Author: Skal (pascal.massimino@gmail.com) @@ -49,4 +49,20 @@ typedef long long int int64_t; // Macro to check ABI compatibility (same major revision number) #define WEBP_ABI_IS_INCOMPATIBLE(a, b) (((a) >> 8) != ((b) >> 8)) +#ifdef __cplusplus +extern "C" { +#endif + +// Allocates 'size' bytes of memory. Returns NULL upon error. Memory +// must be deallocated by calling WebPFree(). This function is made available +// by the core 'libwebp' library. +WEBP_EXTERN void* WebPMalloc(size_t size); + +// Releases memory returned by the WebPDecode*() functions (from decode.h). +WEBP_EXTERN void WebPFree(void* ptr); + +#ifdef __cplusplus +} // extern "C" +#endif + #endif // WEBP_WEBP_TYPES_H_ |