Page 1 of 1

Loading images in a thread

Posted: Wed Oct 19, 2011 6:57 pm
by mike
Hey guys, I'm trying to separate my image loading into a separate thread to show a nice loading screen (and perhaps be able to do some background loading at some point, whatevs). However, when I run it on my Mac (OSX Lion) I get a cryptic error:

Code: Select all

Bus error: 10
WTF? I googled the error and it seems to be a mac error related to child processes and OSX Lion, but I tried running the code on my windows computer (Windows 7) and it spits out a completely white image. What the hell am I doing wrong? :x

main.lua

Code: Select all

function love.load()
	image = nil
	thread = love.thread.newThread("load", "load.lua")
	thread:start()
	thread:send("path", "image.png")
end

function love.draw()
	if image then
		love.graphics.draw(image, 0, 0)
	end
end

function love.update(dt)
	local receive = thread:receive("image")
	local error = thread:receive("error")

	if receive then
		image = receive
	elseif error then
		print(error)
	end
end
load.lua

Code: Select all

require "love.graphics"
require "love.image"
require "love.filesystem"

local thread = love.thread.getThread()
local path = nil

while path == nil do
	path = thread:receive("path")
end

local image = love.graphics.newImage(path)

thread:send("image", image)
I've attached a .love file if that helps.

Re: Loading images in a thread

Posted: Wed Oct 19, 2011 7:08 pm
by Boolsheet
There's a warning on the wiki that you should not use the graphics module in threads. love.graphics.newImage tries to upload the image to the GPU, but only the main thread is allowed to do that. Use love.image.newImageData to load the data and pass that back to the main thread.

In 0.7.2 the image module has some threading problems. Don't access the functions or ImageDatas with multiple threads at the same time.

Code: Select all

function love.load()
	image = nil
	thread = love.thread.newThread("load", "load.lua")
	thread:start()
	thread:send("path", "image.png")
end

function love.draw()
	if image then
		love.graphics.draw(image, 0, 0)
	end
end

function love.update(dt)
	local receive = thread:receive("image")
	local error = thread:receive("error")

	if receive then
		image = love.graphics.newImage(receive)
	elseif error then
		print(error)
	end
end

Code: Select all

require "love.filesystem"
require "love.image"

local thread = love.thread.getThread()
local path = nil

while path == nil do
	path = thread:receive("path")
end

local image = love.image.newImageData(path)

thread:send("image", image)

Re: Loading images in a thread

Posted: Wed Oct 19, 2011 7:10 pm
by mike
Aha, awesome. I clearly didn't RTFM. Slightly related question: is this the best way to load resources (audio/images) in a separate thread?

Re: Loading images in a thread

Posted: Wed Oct 19, 2011 7:23 pm
by Taehl
In my opinion, threads are so limited and temperamental that I'd suggest just using coroutines. Load one image (or sound or whatever) per frame (or per n frames, depending on how you want to affect your framerate). Not quite the same, but close enough, and with less hassle.

Re: Loading images in a thread

Posted: Wed Oct 19, 2011 7:24 pm
by Boolsheet
It's more or less the only way to load resources in a separate thread.
I mean, it's up to you how the thread knows what to load and when. Once you have the ImageData or Source you can pass their reference back and forth between threads wherever it's needed.

I have some experience with images in threads, but don't know about audio. Perhaps someone else knows if there's some catch.

Re: Loading images in a thread

Posted: Wed Oct 19, 2011 7:50 pm
by bartbes
I am looking forward to alternatives that would allow us to do more with threads, 0.10.0 has been mentioned as complete-backend-overhaul-release-time-thingy-at-this-point-Im-just-making-the-word-longer.

Re: Loading images in a thread

Posted: Thu Oct 20, 2011 8:08 am
by kraftman
out of interest, what images are you loading that are taking long enough to need a loading screen? Ive only really had lag on startup when actually generating a large image and populating it with mapPixel/setPixel