Browse Source

Add 'Rml::ReleaseFontResources()' which enables garbage collection of font resources

Michael Ragazzon 3 years ago
parent
commit
ce85ba7596

+ 3 - 0
Include/RmlUi/Core/Core.h

@@ -157,6 +157,9 @@ RMLUICORE_API StringList GetTextureSourceList();
 RMLUICORE_API void ReleaseTextures(RenderInterface* render_interface = nullptr);
 RMLUICORE_API void ReleaseTextures(RenderInterface* render_interface = nullptr);
 /// Forces all compiled geometry handles generated by RmlUi to be released.
 /// Forces all compiled geometry handles generated by RmlUi to be released.
 RMLUICORE_API void ReleaseCompiledGeometry();
 RMLUICORE_API void ReleaseCompiledGeometry();
+/// Releases unused font textures and rendered glyphs to free up memory, and regenerates actively used fonts.
+/// @note Invalidates all existing FontFaceHandles returned from the font engine.
+RMLUICORE_API void ReleaseFontResources();
 
 
 /// Forces all memory pools used by RmlUi to be released.
 /// Forces all memory pools used by RmlUi to be released.
 RMLUICORE_API void ReleaseMemoryPools();
 RMLUICORE_API void ReleaseMemoryPools();

+ 3 - 0
Include/RmlUi/Core/Element.h

@@ -30,6 +30,7 @@
 #define RMLUI_CORE_ELEMENT_H
 #define RMLUI_CORE_ELEMENT_H
 
 
 #include "Box.h"
 #include "Box.h"
+#include "Core.h"
 #include "Event.h"
 #include "Event.h"
 #include "Header.h"
 #include "Header.h"
 #include "ObserverPtr.h"
 #include "ObserverPtr.h"
@@ -667,6 +668,7 @@ private:
 	void UpdateTransformState();
 	void UpdateTransformState();
 
 
 	void OnDpRatioChangeRecursive();
 	void OnDpRatioChangeRecursive();
+	void DirtyFontFaceRecursive();
 
 
 	/// Start an animation, replacing any existing animations of the same property name. If start_value is null, the element's current value is used.
 	/// Start an animation, replacing any existing animations of the same property name. If start_value is null, the element's current value is used.
 	ElementAnimationList::iterator StartAnimation(PropertyId property_id, const Property * start_value, int num_iterations, bool alternate_direction, float delay, bool initiated_by_animation_property);
 	ElementAnimationList::iterator StartAnimation(PropertyId property_id, const Property * start_value, int num_iterations, bool alternate_direction, float delay, bool initiated_by_animation_property);
@@ -773,6 +775,7 @@ private:
 	friend class Rml::LayoutBlockBox;
 	friend class Rml::LayoutBlockBox;
 	friend class Rml::LayoutInlineBox;
 	friend class Rml::LayoutInlineBox;
 	friend class Rml::ElementScroll;
 	friend class Rml::ElementScroll;
+	friend void Rml::ReleaseFontResources();
 };
 };
 
 
 } // namespace Rml
 } // namespace Rml

+ 4 - 0
Include/RmlUi/Core/FontEngineInterface.h

@@ -130,6 +130,10 @@ public:
 	/// @param[in] face_handle The font handle.
 	/// @param[in] face_handle The font handle.
 	/// @return The version required for using any geometry generated with the face handle.
 	/// @return The version required for using any geometry generated with the face handle.
 	virtual int GetVersion(FontFaceHandle handle);
 	virtual int GetVersion(FontFaceHandle handle);
+
+	/// Called by RmlUi when it wants to garbage collect memory used by fonts.
+	/// @note All existing FontFaceHandles and FontEffectsHandles are considered invalid after this call.
+	virtual void ReleaseFontResources();
 };
 };
 
 
 } // namespace Rml
 } // namespace Rml

+ 15 - 0
Source/Core/Core.cpp

@@ -28,6 +28,7 @@
 
 
 #include "../../Include/RmlUi/Core/Core.h"
 #include "../../Include/RmlUi/Core/Core.h"
 #include "../../Include/RmlUi/Core/Context.h"
 #include "../../Include/RmlUi/Core/Context.h"
+#include "../../Include/RmlUi/Core/Element.h"
 #include "../../Include/RmlUi/Core/Factory.h"
 #include "../../Include/RmlUi/Core/Factory.h"
 #include "../../Include/RmlUi/Core/FileInterface.h"
 #include "../../Include/RmlUi/Core/FileInterface.h"
 #include "../../Include/RmlUi/Core/FontEngineInterface.h"
 #include "../../Include/RmlUi/Core/FontEngineInterface.h"
@@ -388,4 +389,18 @@ void ReleaseMemoryPools()
 	}
 	}
 }
 }
 
 
+void ReleaseFontResources()
+{
+	if (font_interface)
+	{
+		for (const auto& name_context : contexts)
+			name_context.second->GetRootElement()->DirtyFontFaceRecursive();
+
+		font_interface->ReleaseFontResources();
+
+		for (const auto& name_context : contexts)
+			name_context.second->Update();
+	}
+}
+
 } // namespace Rml
 } // namespace Rml

+ 11 - 0
Source/Core/Element.cpp

@@ -2864,4 +2864,15 @@ void Element::OnDpRatioChangeRecursive()
 		GetChild(i)->OnDpRatioChangeRecursive();
 		GetChild(i)->OnDpRatioChangeRecursive();
 }
 }
 
 
+void Element::DirtyFontFaceRecursive()
+{
+	// Dirty the font size to force the element to update the face handle during the next Update(), and update any existing text geometry.
+	meta->style.DirtyProperty(PropertyId::FontSize);
+	meta->computed_values.font_face_handle(0);
+
+	const int num_children = GetNumChildren(true);
+	for (int i = 0; i < num_children; ++i)
+		GetChild(i)->DirtyFontFaceRecursive();
+}
+
 } // namespace Rml
 } // namespace Rml

+ 2 - 2
Source/Core/ElementStyle.h

@@ -128,6 +128,8 @@ public:
 	/// some operations may require to dirty these manually, such as when moving an element into another.
 	/// some operations may require to dirty these manually, such as when moving an element into another.
 	void DirtyInheritedProperties();
 	void DirtyInheritedProperties();
 
 
+	// Sets a single property as dirty.
+	void DirtyProperty(PropertyId id);
 	/// Dirties all properties with any of the given units (OR-ed together) on the current element (*not* recursive).
 	/// Dirties all properties with any of the given units (OR-ed together) on the current element (*not* recursive).
 	void DirtyPropertiesWithUnits(Property::Unit units);
 	void DirtyPropertiesWithUnits(Property::Unit units);
 	/// Dirties all properties with any of the given units (OR-ed together) on the current element and recursively on all children.
 	/// Dirties all properties with any of the given units (OR-ed together) on the current element and recursively on all children.
@@ -147,8 +149,6 @@ public:
 private:
 private:
 	// Dirty all child definitions
 	// Dirty all child definitions
 	void DirtyChildDefinitions();
 	void DirtyChildDefinitions();
-	// Sets a single property as dirty.
-	void DirtyProperty(PropertyId id);
 	// Sets a list of properties as dirty.
 	// Sets a list of properties as dirty.
 	void DirtyProperties(const PropertyIdSet& properties);
 	void DirtyProperties(const PropertyIdSet& properties);
 
 

+ 4 - 0
Source/Core/ElementText.cpp

@@ -382,7 +382,11 @@ void ElementText::OnPropertyChange(const PropertyIdSet& changed_properties)
 		font_face_changed = true;
 		font_face_changed = true;
 
 
 		geometry.clear();
 		geometry.clear();
+		geometry_dirty = true;
+
+		font_effects_handle = 0;
 		font_effects_dirty = true;
 		font_effects_dirty = true;
+		font_handle_version = 0;
 	}
 	}
 
 
 	if (changed_properties.Contains(PropertyId::FontEffect))
 	if (changed_properties.Contains(PropertyId::FontEffect))

+ 5 - 0
Source/Core/FontEngineDefault/FontEngineInterfaceDefault.cpp

@@ -113,4 +113,9 @@ int FontEngineInterfaceDefault::GetVersion(FontFaceHandle handle)
 	return handle_default->GetVersion();
 	return handle_default->GetVersion();
 }
 }
 
 
+void FontEngineInterfaceDefault::ReleaseFontResources()
+{
+	FontProvider::ReleaseFontResources();
+}
+
 } // namespace Rml
 } // namespace Rml

+ 3 - 0
Source/Core/FontEngineDefault/FontEngineInterfaceDefault.h

@@ -74,6 +74,9 @@ public:
 
 
 	/// Returns the current version of the font face.
 	/// Returns the current version of the font face.
 	int GetVersion(FontFaceHandle handle) override;
 	int GetVersion(FontFaceHandle handle) override;
+
+	/// Releases resources owned by sized font faces, including their textures and rendered glyphs.
+	void ReleaseFontResources() override;
 };
 };
 
 
 } // namespace Rml
 } // namespace Rml

+ 4 - 0
Source/Core/FontEngineDefault/FontFace.cpp

@@ -87,5 +87,9 @@ FontFaceHandleDefault* FontFace::GetHandle(int size, bool load_default_glyphs)
 	return result;
 	return result;
 }
 }
 
 
+void FontFace::ReleaseFontResources()
+{
+	HandleMap().swap(handles);
+}
 
 
 } // namespace Rml
 } // namespace Rml

+ 3 - 0
Source/Core/FontEngineDefault/FontFace.h

@@ -55,6 +55,9 @@ public:
 	/// @return The font handle.
 	/// @return The font handle.
 	FontFaceHandleDefault* GetHandle(int size, bool load_default_glyphs);
 	FontFaceHandleDefault* GetHandle(int size, bool load_default_glyphs);
 
 
+	/// Releases resources owned by sized font faces, including their textures and rendered glyphs.
+	void ReleaseFontResources();
+
 private:
 private:
 	Style::FontStyle style;
 	Style::FontStyle style;
 	Style::FontWeight weight;
 	Style::FontWeight weight;

+ 6 - 0
Source/Core/FontEngineDefault/FontFamily.cpp

@@ -89,4 +89,10 @@ FontFace* FontFamily::AddFace(FontFaceHandleFreetype ft_face, Style::FontStyle s
 	return result;
 	return result;
 }
 }
 
 
+void FontFamily::ReleaseFontResources()
+{
+	for (auto& entry : font_faces)
+		entry.face->ReleaseFontResources();
+}
+
 } // namespace Rml
 } // namespace Rml

+ 3 - 1
Source/Core/FontEngineDefault/FontFamily.h

@@ -53,7 +53,6 @@ public:
 	/// @return A valid handle if a matching (or closely matching) font face was found, nullptr otherwise.
 	/// @return A valid handle if a matching (or closely matching) font face was found, nullptr otherwise.
 	FontFaceHandleDefault* GetFaceHandle(Style::FontStyle style, Style::FontWeight weight, int size);
 	FontFaceHandleDefault* GetFaceHandle(Style::FontStyle style, Style::FontWeight weight, int size);
 
 
-
 	/// Adds a new face to the family.
 	/// Adds a new face to the family.
 	/// @param[in] ft_face The previously loaded FreeType face.
 	/// @param[in] ft_face The previously loaded FreeType face.
 	/// @param[in] style The style of the new face.
 	/// @param[in] style The style of the new face.
@@ -61,6 +60,9 @@ public:
 	/// @param[in] face_memory Optionally pass ownership of the face's memory to the face itself, automatically releasing it on destruction.
 	/// @param[in] face_memory Optionally pass ownership of the face's memory to the face itself, automatically releasing it on destruction.
 	/// @return True if the face was loaded successfully, false otherwise.
 	/// @return True if the face was loaded successfully, false otherwise.
 	FontFace* AddFace(FontFaceHandleFreetype ft_face, Style::FontStyle style, Style::FontWeight weight, UniquePtr<byte[]> face_memory);
 	FontFace* AddFace(FontFaceHandleFreetype ft_face, Style::FontStyle style, Style::FontWeight weight, UniquePtr<byte[]> face_memory);
+	
+	/// Releases resources owned by sized font faces, including their textures and rendered glyphs.
+	void ReleaseFontResources();
 
 
 protected:
 protected:
 	String name;
 	String name;

+ 6 - 0
Source/Core/FontEngineDefault/FontProvider.cpp

@@ -103,6 +103,12 @@ FontFaceHandleDefault* FontProvider::GetFallbackFontFace(int index, int font_siz
 	return nullptr;
 	return nullptr;
 }
 }
 
 
+void FontProvider::ReleaseFontResources()
+{
+	RMLUI_ASSERT(g_font_provider);
+	for (auto& name_family : g_font_provider->font_families)
+		name_family.second->ReleaseFontResources();
+}
 
 
 bool FontProvider::LoadFontFace(const String& file_name, bool fallback_face, Style::FontWeight weight)
 bool FontProvider::LoadFontFace(const String& file_name, bool fallback_face, Style::FontWeight weight)
 {
 {

+ 3 - 0
Source/Core/FontEngineDefault/FontProvider.h

@@ -72,6 +72,9 @@ public:
 	/// Return a font face handle with the given index, at the given font size.
 	/// Return a font face handle with the given index, at the given font size.
 	static FontFaceHandleDefault* GetFallbackFontFace(int index, int font_size);
 	static FontFaceHandleDefault* GetFallbackFontFace(int index, int font_size);
 
 
+	/// Releases resources owned by sized font faces, including their textures and rendered glyphs.
+	static void ReleaseFontResources();
+
 private:
 private:
 	FontProvider();
 	FontProvider();
 	~FontProvider();
 	~FontProvider();

+ 2 - 0
Source/Core/FontEngineInterface.cpp

@@ -97,4 +97,6 @@ int FontEngineInterface::GetVersion(FontFaceHandle /*handle*/)
 	return 0;
 	return 0;
 }
 }
 
 
+void FontEngineInterface::ReleaseFontResources() {}
+
 } // namespace Rml
 } // namespace Rml

+ 1 - 1
Source/Core/TextureDatabase.cpp

@@ -91,7 +91,7 @@ SharedPtr<TextureResource> TextureDatabase::Fetch(const String& source, const St
 	auto resource = MakeShared<TextureResource>();
 	auto resource = MakeShared<TextureResource>();
 	resource->Set(path);
 	resource->Set(path);
 
 
-	texture_database->textures[resource->GetSource()] = resource;
+	texture_database->textures[path] = resource;
 	return resource;
 	return resource;
 }
 }