maxGUI game without tearing possible?

BlitzMax Forums/MaxGUI Module/maxGUI game without tearing possible?

James(Posted 2007) [#1]
Is it possible to have a maxGUI game in a window, not using flip(1) without any tearing? Or should I just not bother using maxGUI for games?

I can get smooth animation with no tearing using flip(1) but then it hogs all the cpu cycles. If I use flip(0) or flip(-1) then the cpu cycles are minimal but I get tearing. I'm making a small cross platform windowed toy to have on the desktop so it can't be taking up all the cpu cycles as it's for people to have open and play with while they are doing other things as well. The tearing is especially noticeable when the mouse pointer goes over the canvas. The pointer turns into an image and if you move it around just even moderately fast it tears like crazy.

I'm at work so I don't have code to post, but if anybody would explain to me a opengl setup that won't tear and won't hog the cpu that would be great. I searched through the forums but couldn't find anything that worked. Otherwise I will have to live without some of the things I would like to use maxGUI for.

Thank you,
James


DavidDC(Posted 2007) [#2]
A few guesses without much real knowledge to back them:

- Call flip 1 less often via an anim timer? So you only ever Flip when something changes

- Somehow set the Canvas Graphics hz to a multiple of your screen hz and use Flip -1 in the attempt to skip refreshes. I'm not sure how you would do that or if it would work though!

Failing that I think Flip 1 is going direct to the gl graphics driver, which by my guess would make it more a gl issue than a max gui one.

- David


skidracer(Posted 2007) [#3]
Try Flip -1 (the default) Flip 1 forces processor busy wait I think.

My nvidia card under xp seems to flip -1 without tearing and no 100 cpu % for both dx and gl. I think there is a GL extension at work for the swapinterval so may not be supported on all cards, hence your problems.

The following has been tested with gl canvas and seems to work, call before Flip 0.

Import PUB.DirectX

Function WaitVB()
	Global _ddraw7:IDirectDraw7
	If Not _ddraw7 
		DirectDrawCreateEx( Null,Varptr _ddraw7,IID_IDirectDraw7,Null )
	EndIf
	If _ddraw7
		GrabPixmap(0,0,1,1) ' flush drawing buffer
		_ddraw7.WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,0)
	EndIf
End Function



James(Posted 2007) [#4]
Thanks for the suggestions. I'll give them a try when I get home. skidracer, is theresomething equivalent to what you posted for opengl? What you posted won't work for linux or osx right? I'll give it a try on my windows machine though to see if it works.

Thanks,
James


skidracer(Posted 2007) [#5]
flip -1 should be working fine and tear free on all platforms including win32, if not let me know and I will look into it further.


TaskMaster(Posted 2007) [#6]
The "only draw when something changes" or "when you get a Paint event" is a good idea for an app that you expect to run all the time on the desktop. That way you return a LOT more CPU cycles to the PC.


skidracer(Posted 2007) [#7]
The grabpixmap trick effectively flushes the graphics pipeline which by logic seems like a good state to be in before asking for a synchronized flip.

The directdraw interface dates back to 95 and is still supported by directx9 (possibly a lot more reliably than it ever was we trust).

If you using pure max2d i'd recomend testing out the dx9 libs for your windows users, Doug seems very wise in his approach to such things.


James(Posted 2007) [#8]
Well, I'm basing my code on the example hook rendering code in the docs. All I did was to turn the mouse pointer into an image when it's over the canvas. Just edit the mousePointer field to load whatever image you want, run it and move the mouse around. It tears pretty bad on my desktop and laptop. Skidracer, the waitVB code you posted got rid of the tearing but it pegged the cpu just like flip(1). I also tried using directx but I got the same results.

' rendering a canvas using an EventHook based Applet Type

Strict

Type TApplet
   
   Field	window:TGadget
   Field	canvas:TGadget
   Field	timer:TTimer
   Field	mousePointer:TImage = LoadImage("./Assets/Textures/blob.png")
   Field	mDraw:Int
   Field	mX:Short
   Field	mY:Short

   Method Render()
		Local x,y,width,height,t,i
		width=GraphicsWidth()
   	    height=GraphicsHeight()
		SetViewport 0,0,width,height
	   	SetClsColor 0,0,0
	   	Cls
		' draw blobs
		SetBlend LIGHTBLEND
		If mDraw = True Then
			DrawImage(mousePointer,mX,mY)
		End If
		SetBlend SOLIDBLEND
   End Method
   
   Method OnEvent(event:TEvent)
   	Select event.id
   	Case EVENT_WINDOWCLOSE
   		End
   	Case EVENT_TIMERTICK
   		RedrawGadget canvas
   	Case EVENT_GADGETPAINT
   		SetGraphics CanvasGraphics(canvas)
   		Render
   		Flip
    Case EVENT_MOUSEMOVE
		mX = event.x
		my = event.y
	Case EVENT_MOUSEENTER
		HideMouse
		mDraw = True
	Case EVENT_MOUSELEAVE
		ShowMouse
		mDraw = False
   	End Select
   End Method

   Function eventhook:Object(id,data:Object,context:Object)
   	Local	event:TEvent
   	Local	app:TApplet
   	event=TEvent(data)
   	app=TApplet(context)
   	app.OnEvent event	
   End Function
   
   Method Create:TApplet(name$)
   	Local	a:TApplet
   	Local	w,h
   	window=CreateWindow(name,20,20,512,512)
   	w=ClientWidth(window)
   	h=ClientHeight(window)
   	canvas=CreateCanvas(0,0,w,h,window)
   	canvas.SetLayout 1,1,1,1
   	timer=CreateTimer(60)
   	AddHook EmitEventHook,eventhook,Self
   	Return Self		
   End Method
   
End Type

AutoMidHandle True

Local	applet:TApplet

applet=New TApplet.Create("Render Applet")

While True
   WaitEvent
Wend




James(Posted 2007) [#9]
Well, I haven't been able to get smooth non tearing graphics in a maxGUI window without maxing out the cpu utilization whether I use directx or opengl. So I'm going to have to move on and do this without maxGUI. Thanks for the help everybody.

James


James(Posted 2007) [#10]
Okay, I came up with an acceptable solution to my dilema which I'm sure people already use. I basically switch flip(1) to flip() or pause the rendering when the app is suspended to kick the cpu usage down. That way, if the user needs to stop and do something else the cpu is freed but when the user goes back to the game, flip(1) get's used and I get no tearing :) I'm using flip() while the app is suspended because I want some little animations to run in the background but otherwise I would just pause it. Flip() works alright as long as nothing is moving too fast.

James