[SOLVED] One thread for update() and one for draw()

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Lapin
Prole
Posts: 19
Joined: Fri Mar 20, 2015 11:53 am

[SOLVED] One thread for update() and one for draw()

Post by Lapin »

Greetings, i'm wondering if there is a way to run love.draw() in a thread and love.update() in another thread.

So basicaly don't touch the draw function, just move the update() one on a thread.

So FPS would not be bound to update() and draw() but only draw().


I found this thread : viewtopic.php?f=4&t=78795


Peoples seems to says it could be hard/not a good idea, but i just would work like a multiplayer game.

The server(One thread here) is making most of the calcs and the client (the other thread)the draw.


Thanks.
Last edited by Lapin on Mon Jun 08, 2015 2:19 pm, edited 1 time in total.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: One thread for update() and one for draw()

Post by kikito »

It is theoretically possible, but that approach has some significant hurdles to go over.

The biggest one is this: you can't share memory between threads. This means that you can't "modify a table in the update thread" and then "use it in the draw thread".

If you want to use the information produced by one thread in another thread, the first thread must "send it" and the other one must "read it". In order to do this you build a [wiki]Channel[/wiki]. And you pass along values - things like "the enemy with id 5 has moved 3 pixels to the right", for example. Values can't be tables - they must be strings, numbers or booleans.

This communication between threads isn't free - it takes time. I don't know how much. Depending on the amount of information you need to share, and how fast they are, it might be possible that your "dual-thread" system is slower than a single-thread one. There is also the fact that you will need two "structures" for your game - the "logic structure" for the update thread and the "visual structure" for the draw thread. So your memory consumption probably will also go up.
When I write def I mean function.
Lapin
Prole
Posts: 19
Joined: Fri Mar 20, 2015 11:53 am

Re: One thread for update() and one for draw()

Post by Lapin »

Oh ok, i get it.


So i guess it would be better to keep the update() function on the default thread, and create a new one for draw() and it would be here i send the draw calls.


Too bad no one tried to do that before erh.

Thanks anyway.



Edit : or maybe i should try to use OpenCL.
Edit 2 : Wait, would it be possible to compile all the draw calls (not really the draw calls but the function like love.graphics.print) into bytecode, then turn the bytecode into strings and send it to a thread ?
(Like luajit -b yourfile.lua) (Would it be slow)

Actually my game is a GUI based game, not a one with "npcs" or a map.
Last edited by Lapin on Mon Jun 08, 2015 2:17 pm, edited 1 time in total.
User avatar
slime
Solid Snayke
Posts: 3134
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: One thread for update() and one for draw()

Post by slime »

Lapin wrote:So i guess it would be better to keep the update() function on the default thread, and create a new one for draw() and it would be here i send the draw calls.


Too bad no one tried to do that before erh.

Thanks anyway.
love.graphics cannot be used on any thread other than the main one (mostly due to the way OpenGL works.)
Lapin
Prole
Posts: 19
Joined: Fri Mar 20, 2015 11:53 am

Re: One thread for update() and one for draw()

Post by Lapin »

Darn.


Understood, thanks.
User avatar
zorg
Party member
Posts: 3444
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: [SOLVED] One thread for update() and one for draw()

Post by zorg »

But you can always modify love.run to somewhat separate the update and draw routines;
An example:
1. don't enable vsync - makes the game loop in love.run loop more than what the primary (or the selected, don't know which) screen's refresh rate
2. use accumulators and conditionals (if-then-else) to only call love.update and possibly the event handling (and separately, love.draw) if enough time has passed
With some interpolation in your love.draw, it could work swell.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
Positive07
Party member
Posts: 1014
Joined: Sun Aug 12, 2012 4:34 pm
Location: Argentina

Re: One thread for update() and one for draw()

Post by Positive07 »

kikito wrote:Values can't be tables - they must be strings, numbers or booleans.
They can be simple table, that is, without references to other tables or functions
zorg wrote: 2. use accumulators and conditionals (if-then-else) to only call love.update and possibly the event handling (and separately, love.draw) if enough time has passed
Be careful with the event handling part, you should always call love.event.pump or (at least in Windows) the OS will think that the app is not responding

I wouldnt recommend separating in threads either, totally possible but would end up in less performance due to the draw thread updating too late and you would also have to deal with repeated (accumulated) information on the channels.

About zorg method, even though that is possible too, I would always call update and draw just when necessary... It is better to have an instant update than having, say 4 frames with the same things drawn to the screen, because the first would look less laggy than the second. So I wouldnt go with your approach either, sorry
Lapin wrote: Edit : or maybe i should try to use OpenCL.
Edit 2 : Wait, would it be possible to compile all the draw calls (not really the draw calls but the function like love.graphics.print) into bytecode, then turn the bytecode into strings and send it to a thread ?
(Like luajit -b yourfile.lua) (Would it be slow)

Actually my game is a GUI based game, not a one with "npcs" or a map.
First OpenCL? I dont know how would you go about that and I dont think it would be nice to create a game with that... OpenCL is useful for extremely repetitive task that can totally run in parallel with no shared information.

Second, about your EDIT 2, compiling to bytecode doesnt make your memory shared and also doesnt allow you to use those functions in a thread, the graphics functions are bound to the window, because the window is the one that displays stuffs, if you dont have a window you cant display stuff, and the window is created by the main thread.

Also dont be confused bytecode is the same as Lua code (it will be run as Lua code by the interpreter, but the compiler can skip the compilation step)

Compiling to bytecode doesnt compile your C/C++ code just your Lua code to bytecode, also C++ code is already compiled (love.exe and its dlls)
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: One thread for update() and one for draw()

Post by kikito »

Positive07 wrote: They can be simple table, that is, without references to other tables or functions
You are right, I missed that in the "value" wiki page. I stand corrected.
When I write def I mean function.
User avatar
zorg
Party member
Posts: 3444
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: One thread for update() and one for draw()

Post by zorg »

Positive07 wrote:
zorg wrote: 2. use accumulators and conditionals (if-then-else) to only call love.update and possibly the event handling (and separately, love.draw) if enough time has passed
Be careful with the event handling part, you should always call love.event.pump or (at least in Windows) the OS will think that the app is not responding
Actually, i wanted to include a paragraph about having the event handling in the "free-running" part, that is, not inside the conditional, that makes update work with a fixed rate; but then one must handle that fact in all the input handlers, like love.keypressed, with storing the input and the inter-tick dt-s, so the update callback can do meaningful work with them, and not miss those events, at least in my opinion.
Positive07 wrote: About zorg method, even though that is possible too, I would always call update and draw just when necessary... It is better to have an instant update than having, say 4 frames with the same things drawn to the screen, because the first would look less laggy than the second. So I wouldnt go with your approach either, sorry
No problem, though i'd argue that with updates set at 60 ticks/sec, and fps set at the screen's refresh rate, it would not look laggy at all.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

Re: [SOLVED] One thread for update() and one for draw()

Post by Inny »

A technique that I'm playing with is to have your game wrapped in a coroutine, so that you don't have to deal with writing your own love.run function.

Code: Select all

function StartGame()
  while true do
    local dt = coroutine.yield(true) -- maybe you can pipe back a drawing function to the update function
    x = x + math.random(10)*dt
    y = y + math.random(10)*dt
  end
end

function DrawGame()
  love.graphics.rectangle("fill", x, y, 16, 16)
end

function love.load()
  RunGame = coroutine.wrap(StartGame)
  x = 400
  y = 300
end

function love.update(dt)
  RunGame(dt)
end

function love.draw()
  DrawGame()
end
Post Reply

Who is online

Users browsing this forum: No registered users and 52 guests