Browse Source

Change the signature of TextureCallback. [breaking change]

This change also avoids many unnecessary memory allocations in the SVG and Lottie elements.
Michael Ragazzon 3 years ago
parent
commit
1811229b26

+ 3 - 2
Include/RmlUi/Core/Texture.h

@@ -39,12 +39,13 @@ class RenderInterface;
 
 /*
 	Callback function for generating textures.
+	/// @param[in] render_interface The render interface to use for generating the texture.
 	/// @param[in] name The name used to set the texture.
-	/// @param[out] data The raw data of the texture, each pixel has four 8-bit channels: red-green-blue-alpha.
+	/// @param[out] handle The texture handle obtained through the render interface.
 	/// @param[out] dimensions The width and height of the generated texture.
 	/// @return True on success.
 */
-using TextureCallback = Function<bool(const String& name, UniquePtr<const byte[]>& data, Vector2i& dimensions)>;
+using TextureCallback = Function<bool(RenderInterface* render_interface, const String& name, TextureHandle& handle, Vector2i& dimensions)>;
 
 
 /**

+ 3 - 0
Include/RmlUi/Lottie/ElementLottie.h

@@ -81,6 +81,9 @@ private:
 
 	// The texture this element is rendering from.
 	Texture texture;
+	// The texture data buffer.
+	size_t texture_data_size = 0;
+	UniquePtr<byte[]> texture_data;
 
 	// The animation's intrinsic dimensions.
 	Vector2f intrinsic_dimensions;

+ 12 - 5
Source/Core/FontEngineDefault/FontFaceLayer.cpp

@@ -27,6 +27,8 @@
  */
 
 #include "FontFaceLayer.h"
+#include "../../../Include/RmlUi/Core/Log.h"
+#include "../../../Include/RmlUi/Core/RenderInterface.h"
 #include "FontFaceHandleDefault.h"
 #include <string.h>
 
@@ -158,11 +160,16 @@ bool FontFaceLayer::Generate(const FontFaceHandleDefault* handle, const FontFace
 		// Generate the textures.
 		for (int i = 0; i < texture_layout.GetNumTextures(); ++i)
 		{
-			int texture_id = i;
-
-			TextureCallback texture_callback = [handle, effect_ptr, texture_id, handle_version](const String& /*name*/, UniquePtr<const byte[]>& data, Vector2i& dimensions) -> bool {
-				bool result = handle->GenerateLayerTexture(data, dimensions, effect_ptr, texture_id, handle_version);
-				return result;
+			const int texture_id = i;
+
+			TextureCallback texture_callback = [handle, effect_ptr, texture_id, handle_version](RenderInterface* render_interface,
+												   const String& /*name*/, TextureHandle& out_texture_handle, Vector2i& out_dimensions) -> bool {
+				UniquePtr<const byte[]> data;
+				if (!handle->GenerateLayerTexture(data, out_dimensions, effect_ptr, texture_id, handle_version) || !data)
+					return false;
+				if (!render_interface->GenerateTexture(out_texture_handle, data.get(), out_dimensions))
+					return false;
+				return true;
 			};
 
 			Texture texture;

+ 5 - 19
Source/Core/TextureResource.cpp

@@ -137,33 +137,19 @@ bool TextureResource::Load(RenderInterface* render_interface)
 	// Generate the texture from the callback function if we have one.
 	if (texture_callback)
 	{
-		Vector2i dimensions;
-		UniquePtr<const byte[]> data = nullptr;
-
 		TextureCallback& callback_fnc = *texture_callback;
+		TextureHandle handle = {};
+		Vector2i dimensions;
 
-		if (!callback_fnc(source, data, dimensions) || !data)
+		if (!callback_fnc(render_interface, source, handle, dimensions) || !handle)
 		{
 			Log::Message(Log::LT_WARNING, "Failed to generate texture from callback function %s.", source.c_str());
 			texture_data[render_interface] = TextureData(0, Vector2i(0, 0));
-
 			return false;
 		}
 
-		TextureHandle handle;
-		bool success = render_interface->GenerateTexture(handle, data.get(), dimensions);
-
-		if (success)
-		{
-			texture_data[render_interface] = TextureData(handle, dimensions);
-		}
-		else
-		{
-			Log::Message(Log::LT_WARNING, "Failed to generate internal texture %s.", source.c_str());
-			texture_data[render_interface] = TextureData(0, Vector2i(0, 0));
-		}
-
-		return success;
+		texture_data[render_interface] = TextureData(handle, dimensions);
+		return true;
 	}
 
 	// No callback function, load the texture through the render interface.

+ 16 - 7
Source/Lottie/ElementLottie.cpp

@@ -34,6 +34,7 @@
 #include "../../Include/RmlUi/Core/FileInterface.h"
 #include "../../Include/RmlUi/Core/GeometryUtilities.h"
 #include "../../Include/RmlUi/Core/PropertyIdSet.h"
+#include "../../Include/RmlUi/Core/RenderInterface.h"
 #include "../../Include/RmlUi/Core/SystemInterface.h"
 #include <cmath>
 #include <rlottie.h>
@@ -219,14 +220,22 @@ void ElementLottie::UpdateTexture()
 		return;
 	}
 
+	// Resize the texture buffer if necessary.
+	const size_t new_texture_data_size = 4 * render_dimensions.x * render_dimensions.y;
+	if (new_texture_data_size > texture_data_size)
+	{
+		texture_data.reset(new byte[new_texture_data_size]);
+		texture_data_size = new_texture_data_size;
+	}
+
 	// Callback for generating texture.
-	auto p_callback = [this, next_frame](const String& /*name*/, UniquePtr<const byte[]>& data, Vector2i& dimensions) -> bool {
+	auto p_callback = [this, next_frame](RenderInterface* render_interface, const String& /*name*/, TextureHandle& out_handle,
+						  Vector2i& out_dimensions) -> bool {
 		RMLUI_ASSERT(animation);
 
 		const size_t bytes_per_line = 4 * render_dimensions.x;
 		const size_t total_bytes = bytes_per_line * render_dimensions.y;
-
-		byte* p_data = new byte[total_bytes];
+		byte* p_data = texture_data.get();
 
 		rlottie::Surface surface(reinterpret_cast<std::uint32_t*>(p_data), render_dimensions.x, render_dimensions.y, bytes_per_line);
 		animation->renderSync(next_frame, surface);
@@ -237,10 +246,9 @@ void ElementLottie::UpdateTexture()
 			// Swap the RB order for correct color channels.
 			std::swap(p_data[i], p_data[i + 2]);
 
-			const byte a = p_data[i + 3];
-
 			// The RmlUi samples shell uses post-multiplied alpha, while rlottie serves pre-multiplied alpha.
 			// Here, we un-premultiply the colors.
+			const byte a = p_data[i + 3];
 			if (a > 0 && a < 255)
 			{
 				for (size_t j = 0; j < 3; j++)
@@ -248,9 +256,10 @@ void ElementLottie::UpdateTexture()
 			}
 		}
 
-		data.reset(p_data);
-		dimensions = render_dimensions;
+		if (!render_interface->GenerateTexture(out_handle, p_data, render_dimensions))
+			return false;
 
+		out_dimensions = render_dimensions;
 		return true;
 	};
 

+ 7 - 9
Source/SVG/ElementSVG.cpp

@@ -34,6 +34,7 @@
 #include "../../Include/RmlUi/Core/GeometryUtilities.h"
 #include "../../Include/RmlUi/Core/Math.h"
 #include "../../Include/RmlUi/Core/PropertyIdSet.h"
+#include "../../Include/RmlUi/Core/RenderInterface.h"
 #include "../../Include/RmlUi/Core/SystemInterface.h"
 #include <cmath>
 #include <lunasvg.h>
@@ -197,17 +198,14 @@ void ElementSVG::UpdateTexture()
 		return;
 
 	// Callback for generating texture.
-	auto p_callback = [this](const String& /*name*/, UniquePtr<const byte[]>& data, Vector2i& dimensions) -> bool {
+	auto p_callback = [this](RenderInterface* render_interface, const String& /*name*/, TextureHandle& out_handle, Vector2i& out_dimensions) -> bool {
 		RMLUI_ASSERT(svg_document);
-
-		const size_t total_bytes = 4 * render_dimensions.x * render_dimensions.y;
-
 		lunasvg::Bitmap bitmap = svg_document->renderToBitmap(render_dimensions.x, render_dimensions.y);
-
-		data.reset(new byte[total_bytes]);
-		memcpy((void*)data.get(), bitmap.data(), total_bytes);
-		dimensions = render_dimensions;
-
+		if (!bitmap.valid() || !bitmap.data())
+			return false;
+		if (!render_interface->GenerateTexture(out_handle, reinterpret_cast<const Rml::byte*>(bitmap.data()), render_dimensions))
+			return false;
+		out_dimensions = render_dimensions;
 		return true;
 	};