Threaded Canvas Drawing

BlitzMax Forums/MaxGUI Module/Threaded Canvas Drawing

AngryPenguin(Posted 2010) [#1]
Hey Everyone,
I've been trying for too many hours now to figure out the best way to update a MaxGUI Canvas via another thread. So far I have managed to lock up my iMac 3 times, and have gotten no where. I've read on other topics that the GUI must be redrawn from the main thread (I'm assuming that is where the crashes are coming from). So if I can't update the canvas from another thread, how would I go about making the rest of the GUI not block when I click a button or drag a scroll bar?


ima747(Posted 2010) [#2]
Graphics actions (like drawing and flipping) can only be done from the main thread, this is a limitation of the graphics drivers/subsystem of the computer. Event commands should also only be handled from 1 thread as the bmax event que is not thread safe.

Perhaps you can post an example of how/why you need to update from another thread.

I have no problems have my draws handled I the main thread but Im not doing animations etc. So I don't need to redraw at a game speed... To be able to requests draws from a child thread I have a second event que that I manage, whenever the normal que progresses it dumps the thread safe que into the main que, however I have an odd program flow (I don't use waitevent() for example...) so that may not nesicarily work for you...


AngryPenguin(Posted 2010) [#3]
Here is a sample of what I'm trying to achieve. I would like the spinning clock (or any other animation) to keep spinning while the user does GUI Actions. Clicking the button or holding the button down gives an example of what I would not like to happen.

SuperStrict

'Import Needed Libraries
Framework brl.blitz
Import BRL.filesystem
Import BRL.Threads
Import brl.appstub
Import maxgui.drivers
Import brl.EventQueue
Import brl.max2d
Import brl.GLGraphics
Import brl.Graphics
Import BRL.Timer
Import BRL.GLMax2d
Import BRL.Max2d
Import BRL.Retro

'Global Variables
Global frmMain:TfrmMain = TfrmMain.Create()
Global graphicsTimer:TTimer=CreateTimer(60)
Global isRunning:Byte = True

'Loop the event Listener
Repeat
	Local e:Int=WaitEvent()
	HandleEvent(CurrentEvent)
Forever

'Handle and Event
Function HandleEvent(e:TEvent)
	If isRunning
	Select e.ID
		Case EVENT_TIMERTICK
			If e.source = GraphicsTimer
				GraphicsUpdater(Null)
			End If
		Case EVENT_APPTERMINATE
			Destroy()
	End Select
	End If
End Function

'End
Function Destroy()
	IsRunning = False
	End
End Function

'Update the Graphics, Ideally this would be done on another thread
Function GraphicsUpdater:Object(data:Object)
	SetGraphics CanvasGraphics(frmMain.PreviewCanvas)
		SetOrigin 160,90
		SetLineWidth 5
		Cls
		Local t:Long=MilliSecs()
		DrawLine 0,0,120*Cos(t),120*Sin(t)
		DrawLine 0,0,80*Cos(t/60),80*Sin(t/60)
		Flip
End Function


Type TfrmMain
	Field Window:TGadget
	Field isVisible:Byte
	Field RawList:TGadget
	Field RawLabel:TGadget
	Field DisplayList:TGadget
	Field PreviewCanvas:TGadget
	Field AcceptButton:TGadget
	Field DeclineButton:TGadget
	Field SelectedItem:Int
	Field SelectedGadget:Int
	
	
	'Create the Main Window
	Function Create:TfrmMain()
		Local _frmMain:TfrmMain = New TfrmMain
		_frmMain.Window = CreateWindow("Tabernacle SMS",10,10,900,700)
		_frmMain.AcceptButton= CreateButton("A",410,300,50,25,_frmMain.Window)
		_frmMain.PreviewCanvas = CreateCanvas(500,10,320,180,_frmMain.Window)
		_frmMain.isVisible=True
		Return _frmMain
	
	End Function
	


End Type



ima747(Posted 2010) [#4]
Unfortunately that's exactly what you can't do. Graphics commands have to be on the main thread.

Try going about it another way, i.e. putting the other stuff that takes time on a child thread. and try to keep the main thread for just graphics updates, event que management, and other management tasks.

If whatever you're going to draw is going to take a long time to calculate, perhaps you can split the draw from the calculation, maybe have a child thread running your calculations and split them from the draw process...

Or if you're trying to make room for loading then do the loading in a child thread instead.

Threading is PITA to work with, and has some inherent bugs on top of the added complexity of debugging your own code, on top of the extra steps you have to go through to make sure your own code is thread safe... on top of having to know what is thread safe to begin with...


ima747(Posted 2010) [#5]
I've posted some threading tutorials, perhaps they can be helpful

http://www.blitzbasic.com/Community/posts.php?topic=91458