Page 3 of 5

Re: love-loader: load resources in a separate thread, easily

Posted: Sun Jan 29, 2012 7:48 pm
by slime
If you serialize the argument values and pass those to the thread, it would work for everything, right?

Something like:

Code: Select all

function SerializeArgs(...)
	local args = {}
	for i=1, select("#", ...) do
		local val = select(i, ...)
		if type(val) == "string" then
			args[i] = string.format("%q", val)
		else
			args[i] = tostring(val)
		end
	end
	return table.concat(args, ", ")
end

function UnserializeArgs(argstr)
	return loadstring("return "..argstr)()
end

Re: love-loader: load resources in a separate thread, easily

Posted: Sun Jan 29, 2012 8:14 pm
by kikito
Not that easy - in some cases the parameters passed are userData. But thanks for the code.

Re: love-loader: load resources in a separate thread, easily

Posted: Sun Jan 29, 2012 10:31 pm
by Robin
But LÖVE objects can just be passed to other threads, right? So it would just take a Decoder as argument, which can be passed just as easily as an Image (AFAIK).
Jasoco wrote:It appears to be a license for usage of the music file in that folder which is an MP3 (Converted to OGG) of a remix from Mega Man 9 called "Astro Fusion" from the Galaxy Man stage.
Oh man, I didn't even look! I thought it was a binary file, and opening it would teach me nothing.

Re: love-loader: load resources in a separate thread, easily

Posted: Sun Jan 29, 2012 10:51 pm
by Jasoco
I think it should be labeled "License.txt" or "OCLicense.txt" or something more obvious.

Re: love-loader: load resources in a separate thread, easily

Posted: Sun Jan 29, 2012 10:57 pm
by Robin
Tru dat.

Re: love-loader: load resources in a separate thread, easily

Posted: Sun Jan 29, 2012 11:28 pm
by kikito
Regarding soundData: I'm really wondering if it makes sense at all to include the soundDatas created from 4 integers on this lib. Is that really a blocking call that benefits from loading in another thread?

I really think I need to understand this better before modifying the lib unnecessarily. I have created a separate post demanding explanations.
Jasoco wrote:I think it should be labeled "License.txt" or "OCLicense.txt" or something more obvious.
Will do. EDIT: Done.

Re: love-loader: load resources in a separate thread, easily

Posted: Tue Jan 31, 2012 7:07 pm
by bartbes
kikito wrote:Is that really a blocking call that benefits from loading in another thread?
Not really. I mean it blocks, but it really only allocates some memory, and therefore takes barely any time.

As for the send/receive => set/get change, in the code I've written that's supposed to be portable I define local functions that either call send or set depending on the love version, and then use that. (Same goes for receive and get, of course.)

Code: Select all

local set
local get

if love._version_major > 0 or love._version_minor > 7 then
    set = function(thread, key, value)
        return thread:set(key, value)
    end
    get = function(thread, key)
        return thread:get(key)
    end
else
    set = function(thread, key, value)
        return thread:send(key, value)
    end
    get = function(thread, key)
        return thread:receive(key)
    end
end
(Untested, I may have borked the version check.)

EDIT: Something I thought of while looking at the code, perhaps you could implement a function that waits for the thread to finish, if it is not? It's something I've implemented in the past, where if someone was to skip the intro, it would just start loading all (remaining) resources in a blocking way.

Re: love-loader: load resources in a separate thread, easily

Posted: Wed Feb 01, 2012 9:24 am
by kikito
bartbes wrote:
kikito wrote:Is that really a blocking call that benefits from loading in another thread?
Not really. I mean it blocks, but it really only allocates some memory, and therefore takes barely any time.
I already figured that much on my cry for help in the support forum. I just have been a bit busy this week to post much or do any work on love-loader. But thanks for confirming.
bartbes wrote:As for the send/receive => set/get change, in the code I've written that's supposed to be portable I define local functions that either call send or set depending on the love version, and then use that. (Same goes for receive and get, of course.)
Makes sense. I don't like having to test for the concrete love version though. Seems a bit brittle. How about testing whether the thread has a method or not?

Code: Select all

local function set(thread, key, value)
  local f = thread.send or thread.set
  return f(thread, key, value)
end
And same with receive/get. Does it look right to you?
bartbes wrote:EDIT: Something I thought of while looking at the code, perhaps you could implement a function that waits for the thread to finish, if it is not? It's something I've implemented in the past, where if someone was to skip the intro, it would just start loading all (remaining) resources in a blocking way.
That goes pretty much against what I wanted to accomplish. The whole idea is not blocking the main thread while loading resources. But there is an alternative. The command that "starts the loading thread" is loader.start(finishCallback, loadedResourceCallback). They are both optional. But finishcallback is very recommended (in fact, in the initial version of love-loader it was mandatory).

One can check that everything has been loaded by setting a boolean, or changing the game state from "loading" to "finishedLoading" in the finishCallback. While it is loading, you can play an animation of a dancing fish, or what have you, and it will play without hiccups.

A much worse alternative, but one that also works, would be comparing love.loadedCount with love.resourceCount on each update cycle. When love.loadedCount == love.resourceCount, all files have been loaded. But your code will be much cleaner if you just use finishCallback to perform the action of that if.

My point is - if you want to block the main thread while loading, it's better not using love-loader at all. Its core idea is avoiding blocking on the main thread.

The second loader.start parameter is a callback called every time an individual resource is finished loading. It receives some parameters, like what kind of resource was it, what was its name, and where it is stored. If you open the demo in the console, you will see that loadedResourceCallback prints lots of stuff on it.

Regarding the loading of imageData/soundData: I'm pretty sure that if I'm to support those, soundDatas will only be "supported" while being created from a path or a decoder. I'm also investigating whether it would be possible to get a soundData or imageData from a source or image in an issue. Will update this when I know more.

Re: love-loader: load resources in a separate thread, easily

Posted: Wed Feb 01, 2012 9:52 am
by bartbes

Code: Select all

local function set(thread, key, value)
  local f = thread.send or thread.set
  return f(thread, key, value)
end
I don't know how well userdata behaves with these manipulations, but if it works, that'd be fine.
kikito wrote: That goes pretty much against what I wanted to accomplish. [snip]
I know, my reasoning was that sometimes when having loaded stuff in a parallel fashion for a while, you might want to simply cut to the chase and wait, I guess with your code that doesn't really matter too much, but my loader spread things out over the available loading time.

Re: love-loader: load resources in a separate thread, easily

Posted: Wed Feb 01, 2012 12:03 pm
by kikito
bartbes wrote:I know, my reasoning was that sometimes when having loaded stuff in a parallel fashion for a while, you might want to simply cut to the chase and wait, I guess with your code that doesn't really matter too much, but my loader spread things out over the available loading time.
Just to make sure we understand each other: changing the game state on the "finishedLoading" callback accomplishes just that; you stay on the "loading state" until everything is loaded. But love.update() and love.draw() are still being called every frame.

EDIT: I made a new (alpha for now) version. Please find modified demo for that version below.

On this new version:
  • I have changed names of lots of internal things to make the code more clear
  • I have added support for soundData(only when creating it from a path or decoder) and ImageData
  • I have added forward-compatibility with 0.8.x thread methods
  • After loading, the spacebar will play a source loaded directly with love-loader, while the intro key will play a source created from a soundData loaded with love-loader.
I'd be especially grateful if you could please test in in 0.8.x, since I don't have it yet.

If everything goes well, I'll release the new version with those enhancements tomorrow.