Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setting a text that contains emojis to a textedit is slow #88809

Open
derkork opened this issue Feb 25, 2024 · 13 comments
Open

Setting a text that contains emojis to a textedit is slow #88809

derkork opened this issue Feb 25, 2024 · 13 comments

Comments

@derkork
Copy link

derkork commented Feb 25, 2024

Tested versions

  • v4.2.stable.mono.official [46dc277]
  • v4.2.1.stable.mono.official [b09f793]

System information

Godot v4.2.stable.mono - Windows 10.0.22631 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 4080 (NVIDIA; 31.0.15.5123) - AMD Ryzen 9 7950X3D 16-Core Processor (32 Threads)

Issue description

I have a TextEdit node that I pre-fill with some text that contains a range of emojis. In my example I set about 300 lines of text each line containing an emoji. Setting this text of 300 lines with emojis to the text property of the TextEdit takes about 16-18ms on my machine. If I remove the emojis from the text, the same operation only takes about 2-3ms on my machine.

Steps to reproduce

In the example project I have this script which will produce a text at the start and then try to set it every frame:

extends Control

@onready var text_edit = $TextEdit

var text:String

func _ready():
	text = make_300_lines()

func _process(delta):
	text_edit.text = text


func make_300_lines():
	var emojis = ["🔴", "🟢", "⚡", "↪️"]
	var result:String = ""
	for i in 300:
		# use the following line to get a text without emojis
		# result += " this is a line " + "[c]" + "\n"
		
		# this will produce a text with emojis 
		# comment it to use the other line
		result += " this is a line " + emojis.pick_random() + "\n"
	
	return result

You can use the alternative line to produce a text without emojis. Profile each variant to see the difference in performance.

Minimal reproduction project (MRP)

emoji_reproducer.zip

@AThousandShips
Copy link
Member

Can you please test this with 4.2.1 or 4.2.2.rc1? Your version is no longer supported and this might already have been fixed

@MidZik
Copy link
Contributor

MidZik commented Feb 25, 2024

I'm using 4.2.1 and the issue exists there, I'll double check 4.2.2.rc1 and report back.

@derkork
Copy link
Author

derkork commented Feb 25, 2024

Added a reference to 4.2.1 to the top.

@MidZik
Copy link
Contributor

MidZik commented Feb 25, 2024

Same issue in 4.2.2.rc1. (In case it matters, I tested the standard, non-.net versions.)

@Mickeon
Copy link
Contributor

Mickeon commented Feb 25, 2024

Have not tested anything, but the test without emojis is a bit skewed since pick_random is not even called.

@derkork
Copy link
Author

derkork commented Feb 25, 2024

The function to create the text is only called a single time during ready. What is slow is the setting of the text in process.

@Mickeon
Copy link
Contributor

Mickeon commented Feb 25, 2024

Ok, that's silly then. Since the text remains unchanged, setting it every _process frame should do nothing, and yet...

@MidZik
Copy link
Contributor

MidZik commented Feb 26, 2024

extends Node

func _generate_text(characters:Array, amount = 200):
	var result = ""
	for i in amount:
		result += characters.pick_random()
	return result

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
	_set_with_emojis()
	_set_without_emojis()
	_set_with_emojis_no_newline()
	_set_without_emojis_no_newline()

func _set_with_emojis():
	%TextEdit.text = _generate_text(["🔴\n", "🟢\n", "⚡\n", "↪️\n"])

func _set_without_emojis():
	%TextEdit.text = _generate_text(["AAA\n", "BBB\n", "CCC\n", "DDD\n"])

func _set_with_emojis_no_newline():
	%TextEdit.text = _generate_text(["🔴", "🟢", "⚡", "↪️"])

func _set_without_emojis_no_newline():
	%TextEdit.text = _generate_text(["AAA", "BBB", "CCC", "DDD"])

Results (4.2.1 stable official standard):
image

@derkork
Copy link
Author

derkork commented Feb 26, 2024

Interesting how just adding newlines makes it an order of magnitude slower...

@Calinou
Copy link
Member

Calinou commented Feb 26, 2024

Can you test a build that uses the fallback text server instead of the advanced text server? To do so, compile from source with the module_text_server_adv_enabled=no module_text_server_fb_enabled=yes SCons options.

This disables support for right-to-left typesetting and complex scripts, but emoji support should remain intact.

@MidZik
Copy link
Contributor

MidZik commented Feb 26, 2024

Built with scons platform=windows module_text_server_adv_enabled=no module_text_server_fb_enabled=yes debug_symbols=yes:

image

I profiled a bit with VS, and a large amount of time is spent here, regardless of which text server is used:

Vector<String> OS_Windows::get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale, const String &p_script, int p_weight, int p_stretch, bool p_italic) const {

~33% of all CPU time is spent on line 1191 HANDLE fnd = FindFirstFileW((LPCWSTR)&file_path[0], &d);
~10% of all CPU time is spent on line 1197 FindClose(fnd);
~10% of all CPU time is spent on line 1133 hr = system_font_fallback->MapCharacters(...)

@Calinou
Copy link
Member

Calinou commented Feb 26, 2024

This is likely due to the same cause as #83688.

@MidZik
Copy link
Contributor

MidZik commented Feb 27, 2024

I added a font override to the TextEdit that has the system font "Segoe UI Emoji" as a fallback font and the performance becomes nearly identical:

image

(4.2.1 stable)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants