Page 1 of 1
Graphics module in threads
Posted: Sun Dec 31, 2017 5:54 am
by DekuJuice
According to the wiki, love.graphics isn't usable from a thread. However, I've found that there's nothing stopping you from requiring the graphics module and calling functions from it. Can I assume it's safe to use as long as I don't do anything that might cause concurrency issues, like drawing to the screen or modifying graphics objects at the same time other threads do so?
Re: Graphics module in threads
Posted: Sun Dec 31, 2017 6:13 am
by jojomickymack
Nope - totally unsafe to do that, here's what'll happen
- giphy.gif (488.78 KiB) Viewed 7395 times
all joking aside, what are you worried about occurring?
Re: Graphics module in threads
Posted: Sun Dec 31, 2017 8:01 am
by zorg
No, it will most likely either error (hopefully) or crash (hopefully not); it's not about concurrency, rather about the fact that you can only have one thread be a dedicated openGL thread, or something like that.
Re: Graphics module in threads
Posted: Thu Jan 04, 2018 6:13 pm
by raidho36
In my experience the OpenGL simply fails to render stuff properly if you attempt multithreading. You can however use multiple threads to generate render list data and feed it back to main thread.
Re: Graphics module in threads
Posted: Thu Jan 04, 2018 7:07 pm
by jojomickymack
is this an actual problem or a theoretical one? I wonder if it's possible to create a love program that demonstrates the limitation a single graphics thread poses here.
Re: Graphics module in threads
Posted: Wed Mar 21, 2018 4:43 pm
by pgimeno
jojomickymack wrote: ↑Thu Jan 04, 2018 7:07 pm
is this an actual problem or a theoretical one? I wonder if it's possible to create a love program that demonstrates the limitation a single graphics thread poses here.
This crashes for me with a segfault, despite the extra care taken in not using love.graphics in two threads simultaneously.
main.lua:
Code: Select all
local chan = love.thread.getChannel('chan')
local img = love.graphics.newImage('anything.png')
local thread = love.thread.newThread('thread.lua')
love.graphics.clear()
love.run = function() end -- no main loop
thread:start() -- calls to love.graphics within the thread start here
chan:supply(img) -- pass the image to the thread
chan:demand() -- wait for thread to finish
love.graphics.present()
love.timer.sleep(3)
thread.lua:
Code: Select all
require 'love.graphics'
local chan = love.thread.getChannel('chan')
local img = chan:demand() -- get the image
love.graphics.draw(img, 0, 0) -- call a love.graphics function
chan:push('done') -- we're done - the main thread can use love.graphics again
It's the love.graphics.draw call within the thread that causes the segfault. Without it, it runs without problems, but without drawing anything, of course.
I was trying to make an animated loading screen, but short of using coroutines and loading in small chunks, which isn't always possible, I don't see how. Even love.graphics.newImage segfaults, therefore a thread can't even load images that way. At best it can load ImageData so that the main thread can use love.graphics.newImage(imageData) when the loading finishes; not sure whether that's costly for a big number of big images, but I suppose it is.
Edit: The segfault happens in libGL.so.1, within glEnableVertexAttribArray().
Re: Graphics module in threads
Posted: Wed Mar 21, 2018 5:49 pm
by Jasoco
Well you'd have to start the new thread and have the main thread wait for the new thread (Which I guess loads everything) to send the "all done!" message back to the main thread. And while you wait you'd draw that loading screen.
Re: Graphics module in threads
Posted: Wed Mar 21, 2018 7:06 pm
by pgimeno
Jasoco wrote: ↑Wed Mar 21, 2018 5:49 pm
Well you'd have to start the new thread and have the main thread wait for the new thread (Which I guess loads everything) to send the "all done!" message back to the main thread. And while you wait you'd draw that loading screen.
The point is that in the thread you can't load images with love.graphics.newImage(). You can load sounds, maps, library files, and so on, but not images, except with love.image.newImageData().
Edit: Also, there's still the problem that the environments are not shared, which makes loading certain kinds of objects more difficult or impossible from a thread. Example of "more difficult": stuff you allocate in FFI memory. You need to use malloc for it to not be garbage-collected, and you need to pass the pointer to the main thread, which isn't exactly a trivial task. Example of "impossible": userdata objects (fortunately it's not likely you need to create one of these that takes long to load).
Re: Graphics module in threads
Posted: Wed Feb 08, 2023 10:05 pm
by BrotSagtMist
jojomickymack wrote: ↑Thu Jan 04, 2018 7:07 pm
I was trying to make an animated loading screen, but short of using coroutines and loading in small chunks, which isn't always possible, I don't see how. Even love.graphics.newImage segfaults, therefore a thread can't even load images that way.
Sorry to necrodig this old thread but i just happen to have played with this.
It looks like calling love.window.setMode from within the thread hands over the graphic stuff to the thread and it magically worked.
So rendering stuff in the thread actually works for me and this could play an animation while the mainthread loads data.
Re: Graphics module in threads
Posted: Wed Feb 08, 2023 10:12 pm
by slime
It will completely break on different operating systems, please don't do that.
You can load data on other threads and render on the main thread instead, and everything will work fine - for example for Images, usually the most time-consuming part by far is loading the file from your hard drive and decoding it into raw pixels, which love.image.newImageData does. You can then pass the result into love.graphics.newImage on the main thread via Channels.
There are several libraries to make that super simple, e.g.:
https://github.com/kikito/love-loader or
https://github.com/MikuAuahDark/lily