godot: Surface tool is exponentially slower when threaded

Godot version

3.4.2.stable

System information

Windows 10, GLES3, Radeon 5700xt, R7 5800

Issue description

Fast performance with no threading: noThread

Slow performance with threading: withThread

Steps to reproduce

I am aware of https://github.com/godotengine/godot/issues/51311 but the difference here is that SurfaceTool.append_from() is not being invoked.

Here is how the code is laid out

var surf = SurfaceTool.new()
var mesh = Mesh.new()

surf.begin(Mesh.PRIMITIVE_TRIANGLES)

	surf.set_material(mat)
		
	
	surf.add_normal(normal)
	surf.add_uv(Vector2(startUVx,startUVy))
	surf.add_vertex(TL)
	
	surf.add_normal(normal)
	surf.add_uv((Vector2(endUVx,startUVy)))
	surf.add_vertex(TR)
	
	surf.add_normal(normal)
	surf.add_uv(Vector2(endUVx,endUVy))
	surf.add_vertex(BR)
	
	
	surf.add_normal(normal)
	surf.add_uv(Vector2(startUVx,startUVy))
	surf.add_vertex(TL)
	
	surf.add_normal(normal)
	surf.add_uv(Vector2(endUVx,endUVy))
	surf.add_vertex(BR)
	
	surf.add_normal(normal)
	surf.add_uv(Vector2(startUVx,endUVy))
	surf.add_vertex(BL)
	
	
	surf.commit(mesh)

Minimal reproduction project

No response

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Reactions: 2
  • Comments: 17 (12 by maintainers)

Most upvoted comments

I hope https://github.com/godotengine/godot/pull/69723 will improve the performance of that class

edit: shouldn’t this issue get the bug label instead of discussion?

It may be an engine limitation that can’t be lifted, and can only be documented, especially in 3.x. OpenGL has a lot of limitations around threading, as it’s not thread-safe by design.

@DataPlusProgram you can see my comment regarding slowdown coming from synchronization on VisualServer level: https://github.com/godotengine/godot/issues/51311#issuecomment-1024966544

For your case, creating mesh var mesh = Mesh.new() (and adding it to the scene tree), handling that mesh, and altering mesh surf.commit(mesh) takes a lot of time when done on thread.

IMO, you should limit implementation running on the thread to creating SurfaceTool instances (with SurfaceTool.new()), filling them (using surf.add_ functions), and storing SurfaceTool instances in the array.

Once this is done, you should do the remaining stuff in the main thread (without extra thread). So you’d just have to iterate over that stored SurfaceTool instances in the array and for each of those create a new Mesh instance and commit the surface tool’s calculated surface to it.