godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.03k stars 21.18k forks source link

Drawing more than 445,525 circles every frame causes the project to permanently freeze #84141

Open MewPurPur opened 1 year ago

MewPurPur commented 1 year ago

Godot version

Godot v4.2.beta3 - Pop!_OS 22.04 LTS - X11 - Vulkan (Forward+) - integrated Intel(R) Graphics (ADL GT2) () - 12th Gen Intel(R) Core(TM) i5-1235U (12 Threads)

System information

Godot v4.2.beta3 - Pop!_OS 22.04 LTS - X11 - Vulkan (Forward+) - integrated Intel(R) Graphics (ADL GT2) () - 12th Gen Intel(R) Core(TM) i5-1235U (12 Threads)

Issue description

This isn't as silly as it might sound!

My script looks like this:

extends Control

const ITERATIONS = 445526

func _process(_delta: float) -> void:
    queue_redraw()

func _draw() -> void:
    for i in ITERATIONS:
        draw_circle(Vector2(randf_range(0, size.x), randf_range(0, size.y)), 3, Color(randf(), randf(), randf()))

Expectation: Each frame takes a tens of seconds to render, and only when it does, _process() is triggered again, causing another redraw.

Reality: At some point, if there are enough circles drawn, I get a flurry of errors after about a minute. The errors look something like this:

E 0:01:00:0877 swap_buffers: Vulkan: Cannot submit graphics queue. Error code: VK_ERROR_DEVICE_LOST <C++ Error> Condition "err" is true. Returning: ERR_CANT_CREATE <C++ Source> drivers/vulkan/vulkan_context.cpp:2536 @ swap_buffers()

Then 7 of these errors:

E 0:01:26:0490 control.gd:10 @ _draw(): Condition "err" is true. <C++ Source> drivers/vulkan/vulkan_context.cpp:2393 @ flush()

control.gd:10 @ _draw() This sequence of errors pops up 3-4 times, then the project freezes forever. ### Steps to reproduce Copy the script into a control node at Full Rect, nothing more is needed. ### Minimal reproduction project N/A
AThousandShips commented 1 year ago

Sounds like you're overloading the graphics, not sure how this would be handled other than putting some kind of hard limit on how much you can draw

I don't know that this is a likely scenario for people to come upon though

MewPurPur commented 1 year ago

Ah, well I did... :sweat_smile:

Also this is more of a crash than a performance bug, I didn't expect drawing a million object to be cheap ofc. I just expected it to eventually finish, or at least for Godot to refuse to draw at some point, but to still be alive and kicking.

AThousandShips commented 1 year ago

What were you trying to do? I don't see many situations where you'd be drawing this much to the screen

It's likely also hardware sensitive

MewPurPur commented 1 year ago

I don't 100% know if this use case is related to the bug, but it seems to be:

Copying a 69 kB SVG entirely made of paths into my SVG editor. My custom logic for path contours had the following drawing costs:

The polylines were drawn in bulk first, the circles were drawn after. In general, this massive routine seemed to always pass the polyline and line drawing, even as I started simplifying the SVG a bit. But then it always choked a few hundred circles in.

AThousandShips commented 1 year ago

I'm not sure how much re-useage is done with this, but each circle has 64 points, so if no re-usage of data is done this would take some 560 megabytes at minimum

MewPurPur commented 1 year ago

Just reporting that I was redrawing the polylines and multilines more times than necessary, so on my end I no longer run into this. However, Godot should probably still handle this situation more gracefully.