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

Betsy GPU compression usage in the editor causes an error on exit #103443

Closed
Zylann opened this issue Mar 1, 2025 · 8 comments · Fixed by #103521
Closed

Betsy GPU compression usage in the editor causes an error on exit #103443

Zylann opened this issue Mar 1, 2025 · 8 comments · Fixed by #103521

Comments

@Zylann
Copy link
Contributor

Zylann commented Mar 1, 2025

Tested versions

Godot 4.4 RC3 15ff450

System information

Windows 10 64 bits NVIDIA GeForce GTX 1060 6GB

Issue description

While debugging something unrelated, I came across the following error when closing the editor:

ERROR: This function (finalize) can only be called from the render thread.

Since I had a debugger attached to the error callback, I got its call stack:

godot.windows.editor.dev.x86_64.exe!_err_print_error(const char * p_function, const char * p_file, int p_line, const char * p_error, const char * p_message, bool p_editor_notify, ErrorHandlerType p_type) Line 92 (godot4_fork\core\error\error_macros.cpp:92)
godot.windows.editor.dev.x86_64.exe!_err_print_error(const char * p_function, const char * p_file, int p_line, const char * p_error, const String & p_message, bool p_editor_notify, ErrorHandlerType p_type) Line 138 (godot4_fork\core\error\error_macros.cpp:138)
godot.windows.editor.dev.x86_64.exe!RenderingDevice::finalize() Line 7092 (godot4_fork\servers\rendering\rendering_device.cpp:7092)
godot.windows.editor.dev.x86_64.exe!RenderingDevice::~RenderingDevice() Line 8007 (godot4_fork\servers\rendering\rendering_device.cpp:8007)
godot.windows.editor.dev.x86_64.exe!RenderingDevice::`scalar deleting destructor'(unsigned int) (Unknown Source:0)
godot.windows.editor.dev.x86_64.exe!memdelete<RenderingDevice>(RenderingDevice * p_class) Line 143 (godot4_fork\core\os\memory.h:143)
godot.windows.editor.dev.x86_64.exe!BetsyCompressor::finish() Line 275 (godot4_fork\modules\betsy\image_compress_betsy.cpp:275)
godot.windows.editor.dev.x86_64.exe!free_device() Line 740 (godot4_fork\modules\betsy\image_compress_betsy.cpp:740)
godot.windows.editor.dev.x86_64.exe!uninitialize_betsy_module(ModuleInitializationLevel p_level) Line 50 (godot4_fork\modules\betsy\register_types.cpp:50)
godot.windows.editor.dev.x86_64.exe!uninitialize_modules(ModuleInitializationLevel p_level) Line 287 (godot4_fork\modules\register_module_types.gen.cpp:287)
godot.windows.editor.dev.x86_64.exe!Main::cleanup(bool p_force) Line 4706 (godot4_fork\main\main.cpp:4706)
godot.windows.editor.dev.x86_64.exe!widechar_main(int argc, wchar_t * * argv) Line 102 (godot4_fork\platform\windows\godot_windows.cpp:102)
godot.windows.editor.dev.x86_64.exe!_main() Line 122 (godot4_fork\platform\windows\godot_windows.cpp:122)
godot.windows.editor.dev.x86_64.exe!main(int argc, char * * argv) Line 136 (godot4_fork\platform\windows\godot_windows.cpp:136)
godot.windows.editor.dev.x86_64.exe!WinMain(HINSTANCE__ * hInstance, HINSTANCE__ * hPrevInstance, char * lpCmdLine, int nCmdShow) Line 150 (godot4_fork\platform\windows\godot_windows.cpp:150)
godot.windows.editor.dev.x86_64.exe!invoke_main() Line 107 (d:\a01\_work\12\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:107)
godot.windows.editor.dev.x86_64.exe!__scrt_common_main_seh() Line 288 (d:\a01\_work\12\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288)
godot.windows.editor.dev.x86_64.exe!__scrt_common_main() Line 331 (d:\a01\_work\12\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:331)
godot.windows.editor.dev.x86_64.exe!WinMainCRTStartup(void * __formal) Line 17 (d:\a01\_work\12\s\src\vctools\crt\vcstartup\src\startup\exe_winmain.cpp:17)
kernel32.dll!00007ffc3f8f7374() (Unknown Source:0)

Which shows it is because of the BetsyCompressor.

Steps to reproduce

I don't have them since I was in the middle of something else in a non-trivial project, and wasn't a blocker.
But I suspect it involves importing textures in the editor such that the Betsy GPU compressor gets invoked (Forward+), then closing the editor.

Minimal reproduction project (MRP)

N.A

@Zylann Zylann changed the title Betsy compression usage in the editor causes an error on exit Betsy GPU compression usage in the editor causes an error on exit Mar 1, 2025
@clayjohn
Copy link
Member

clayjohn commented Mar 1, 2025

This should be a quick fix. The call to finalize should be wrapped in RenderingServer.call_on_render_thread()

@Olle-Lukowski
Copy link
Contributor

I will go ahead and tackle this! This is the first issue I'm solving, so I hope I do it correctly.

@Olle-Lukowski
Copy link
Contributor

Ran into a bit of an issue. It seems that deferring the finalize call to the render thread causes it to not get called anymore. I only found out about this because of this warning about a leak:

WARNING: ObjectDB instances leaked at exit (run with --verbose for details).
     at: cleanup (core/object/object.cpp:2378)
Leaked instance: Object:96217338099

After some classic print-debugging, it seems that the finalize method does not get called anymore. Maybe my code is wrong? Here is the line I placed in the RenderingDevice::~RenderingDevice (which is the only place where finalize was called as far as I can tell):

RenderingServer::get_singleton()->call_on_render_thread(Callable(this, "finalize"));

I would really appreciate any and all guidance here!

@Olle-Lukowski
Copy link
Contributor

I figured this out I think! Had to bind the finalize method in _bind_methods like this:

ClassDB::bind_method(D_METHOD("finalize"), &RenderingDevice::finalize);

@Zylann
Copy link
Contributor Author

Zylann commented Mar 3, 2025

If binding it is not desired, this might work instead:

RenderingServer::get_singleton()->call_on_render_thread(callable_mp(this, &RenderingDevice::finalize));

@Olle-Lukowski
Copy link
Contributor

If binding it is not desired, this might work instead:

RenderingServer::get_singleton()->call_on_render_thread(callable_mp(this, &RenderingDevice::finalize));

Is it fine if I submit the PR with the binding? I can still change it if this is preferred.

@clayjohn
Copy link
Member

clayjohn commented Mar 3, 2025

finalize shouldn't be bound through the ClassDB. That is for exposing functions to scripting

@Olle-Lukowski
Copy link
Contributor

Well, I just opened the PR. I will update it ASAP.

@Repiteo Repiteo added this to the 4.5 milestone Mar 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants