Dark Bit Factory & Gravity

PROGRAMMING => Freebasic => Topic started by: Shockwave on May 13, 2006

Title: Horrible V Sync
Post by: Shockwave on May 13, 2006
I know you can wait for V-Sync with;

WAIT &H3DA, 8

And Tinypct handles double buffering for you but I've noticed that you don't get a rock steady refresh with either method.
It's not so noticeable for most things, except when you want to make a scroller and you can see that the refresh rate is definately not constant and you get tears in the display when refreshing the display.

Has anyone found a rock steady way to tie the refresh rate to a constant say 80fps without using any includes?
Perhaps an assembly language snippet to do this?
Title: Re: Horrible V Sync
Post by: Clyde on May 13, 2006
Try delta timing, when you use the fps of the current running speed of your program, divided by your actually monitor refresh rate, to give the difference in speed loss / gain. And * mutliply that to any angles / counters. That might sort you out.

I've yet to implement this method and test it, as I do find the same odd shinanigans with the fps. Even on a simple thing with a few dots on screen.
Title: Re: Horrible V Sync
Post by: Rbz on May 21, 2006
@Shockwave: Try that FPS Limiter (http://dbfinteractive.com/index.php?topic=75.0) merged with this one, I know that it uses windows.bi include, but I'm sure that your final executable won't be bloated. 

I've just recoded to FB one smart routine by Alan Macdonald (Delta time).



Code: [Select]
'
'
' Sample test by Rbraz 2006
'
'

Option Explicit

'Windowed
#define PTC_WIN
'-------------------------------------
' Includes.
'-------------------------------------
#Include Once "tinyptc.bi"

'Keys const
Const KEY_ESC = 27
Dim Key$

'Sub Routines
Declare Sub FPS_Count()
Declare Function AdjustFloat( byval fltCurrent as double, byval fltDesired as double, byval fltStepSize as double ) as double

'Variables
Dim Shared fltMultiplier as double   ' How much the effect speeds-up/slows-down in order
Dim Shared fltNewMultiplier as double = 1 ' to run at the same speed on all PC's...
Const MAX_FPS = 90.0                      ' Max. frames per second allowed

'FPS Counter
Dim Shared iFPS, bSettime,iSecStart,iFrameCount,iFrameStart as integer

'TinyPTC Buffer
Dim Shared Buffer(640*480) as integer
   
'Open TinyPTC window
If( ptc_open( "Adjust Float", 640, 480 ) = 0 ) Then
    End -1
End if

'Main Loop
While Key$ <> Chr$( KEY_ESC )
   
  Key$=Inkey$()

    FPS_Count()
   
    Locate 1,1
    Print "FPS: "; iFPS
   
    Locate 3,1
    Print "fltMultiplier: "; fltMultiplier
   
   
' Use FPS to calculate the delta time so that the
' effect will run at the same speed on all PC's.
'
If iFPS >= 1 Then
fltNewMultiplier = MAX_FPS / iFPS
fltMultiplier = AdjustFloat( fltMultiplier, fltNewMultiplier, 0.5 )
End If

 
  Ptc_Update @Buffer(0)
 
Wend

'Close TinyPTC window
ptc_close()

Sub FPS_Count()
If bSettime = 1 then
          iSecStart = Timer() * 1000
          iFrameStart = iFrameCount
          bSettime = 0
     EndIf 
     If Timer() * 1000 >= iSecStart + 1000 then
          iFPS = iFrameCount - iFrameStart
          bSettime = 1
     EndIf
     iFrameCount = iFrameCount + 1     
End Sub

'----------------------------------------------------------------------
' NAME : AdjustFloat() by Alan MacDonald
' PURPOSE : Changes a variable's current value by a given step size
'   towards a desired value.
' INPUTS : fltCurrent - The variable's current value.
'   fltDesired - The variable's desired value.
'   fltStepSize - Increment/decrement amount.
' RETURNS : The adjusted variable's value.
'----------------------------------------------------------------------
Function AdjustFloat( byval fltCurrent as double, byval fltDesired as double, byval fltStepSize as double ) as double
'
' Does the current value need to be increased to meet the desired value ?
'
If fltCurrent < fltDesired Then
fltCurrent = fltCurrent + fltStepSize
If fltCurrent > fltDesired Then
fltCurrent = fltDesired
End If
End If

'
' Does the current value need to be decreased to meet the desired value ?
'
If fltCurrent > fltDesired Then
fltCurrent = fltCurrent - fltStepSize
If fltCurrent < fltDesired Then
fltCurrent = fltDesired
End If
End If

Return fltCurrent

End Function
Title: Re: Horrible V Sync
Post by: Shockwave on May 21, 2006
Thanks Rbraz, I'll give that a bash and see if it smooths things out a bit.
Title: Re: Horrible V Sync
Post by: Optimus on May 21, 2006
That's a great thread! Our alltime problem. I have to research more into it and ask people too..
My recent demos use a timer for the movement, though I update instantly as fast as I can. What if I read the refresh rate of the current resolution, and timed the screen buffer refresh only at that framerate?

p.s. From the Blitzbasic demos I've recently watch, most cool onescreens with oldschool scrollers, I see there is no problem there and the scrolls are smooth like silk! Damn,. why isn't it the same in Freebasic or my SDL/TPTC projects in C? I have to research it if I ever find the time and ask some democoders at Pouet..
Title: Re: Horrible V Sync
Post by: Clyde on May 22, 2006
I also use Delta time, and nice snippet there Rbraz. You could do away with the need for including windows if you wanted.

Blitz Basic uses DirectX to render with. That mostly covers the Syncing issues.

With Freebasic I have a hunch it's to do with the headers and compatibility. Just a thought.
With gfxlib, there is a screen sync command, and I recon it's slightly better then tiny. Allthough, I am going to use tiny for a bit longer.
Title: Re: Horrible V Sync
Post by: Shockwave on May 22, 2006
Clyde, there has to be a way around this problem, I think that Optimus is onto the right track because if you know the refresh rate of the monitor then it would be fairly simple to time the refresh to that speed.
I did the same thing with the dbf bbstro, I matched it to 85fps, however it backfired on me causing slowdown on some systems that should have been able to run it fast.
Title: Re: Horrible V Sync
Post by: Clyde on May 22, 2006
I mostly find slugigishness when using text routines mostly bitmap scrollers.
Title: Re: Horrible V Sync
Post by: Blitz Amateur on May 26, 2006
EDIT: I fixed a small typo that made a miniscule difference in the limiting code

I've got a couple snippets of code.. They work pretty well. Checks for vsync once, and holds to a given refresh rate.

There's still some snippets in the "tinyptclib.bi" file that are under construction =)

Hopefully, my efforts may help someone

In this file you have to change vsyncrate to your monitor's refresh rate
Code: [Select]
#Define PTC_WIN
#include "TinyPTCLib.bi"
#include "RAnd.bi"

SeedRnd timer

Graphics 640,480,"Test"
dim inky as string
dim mytime as double
dim ttime as double
dim timeval as double
dim ctime as double
dim diff as double
dim am as double
dim sttime as double
dim vsyncrate as double
dim blah as string
'Set vsync rate
vsyncrate = 75
timeval = (1000.0/vsyncrate)/1000.0
WAIT &h3da, 8
mytime = timer
sttime = timer

do
    inky=inkey$
    'WAIT &H3DA, 8
    FlipSurf
    ClsSurf
    ColorSet rand(0,255),rand(0,255),rand(0,255)
    dim x as integer
    dim y as integer
    dim i as integer
    'for i=0 to rand(rand(1,15),rand(1,15))
    for x=0 to GFXWID-1
        for y=0 to GFXHT-1
            plot(x,y)
        next
    next
    'next
   
    'buffer[5*GFXWID+5] = &hFFFFFF
    ttime = timer-mytime
    ctime = timer'ttime+mytime
    if ttime < timeval then
        diff = timeval-ttime
                'print diff
        do
        loop until timer-ctime >= diff-(timeval/1000.0) or asc(inky) = 27
       
    elseif ttime > timeval then
        diff = ttime-timeval
        'ctime = timer
        am = ((cint(diff / timeval)+1)*timeval)-diff
        do
        loop until timer-ctime >= am or asc(inky) = 27
    endif
   
    ttime = timer-mytime
    mytime = timer
    print 1.0/ttime
    'print (mytime-sttime)/timeval
   
loop until asc(inky) = 27

tinyptclib.bi
Code: [Select]
#Include "tinyptc.bi"


'TinyPTC Graphics Interface Lib
'Copyright Chris Gaiter 2006
'
'
'This Library takes the basic functionality of TinyPTC and allows more advanced
'drawing operations with simplified commands. Commands such as Graphics,
'FlipSurf, ClsSurf, Plot, ColorSet, DrawLine, and Oval (Not Yet implemented)
'
'
'
'Command reference is coming soon, until then, commands should be fairly simply
'Understood. Redirect any questions either to "Http://www.dbfinteractive.com"
'Or to blitzamateur@yahoo[dot]com



Dim shared as integer ptr buffer
dim shared as integer GFXWID, GFXHT, GFXWIDH, GFXHTH, CurColor, CLEARCOUNT

declare sub Graphics(ByVal wid as integer, ByVal ht as integer, Byval appname as string)
declare sub FlipSurf()
declare sub ClsSurf()
declare sub Plot(ByVal x as integer, ByVal y as integer)
declare sub ColorSet(ByVal r as integer, ByVal g as integer, ByVal b as integer)
declare sub DrawLine(ByVal x1 as single, ByVal y1 as single, ByVal x2 as single, ByVal y2 as single)
declare sub Oval(ByVal x as single, ByVal y as single, ByVal w as single, ByVal h as single)
declare function GetVsyncRate()

Sub Graphics(ByVal Wid as integer, ByVal Ht as integer, ByVal AppName as string="FB w/ TinyPTC")
   
    if ptc_open(AppName, Wid, Ht) = 0 then
        print "Cannot open graphics display at "+str(wid)+", "+str(ht)
        sleep
        end -1
    endif
    buffer = callocate(wid*ht, Len(integer))
    CLEARCOUNT = wid*ht*Len(integer)
    GFXWID = Wid
    GFXHT = Ht
    GFXWIDH = GFXWID shr 1
    GFXHTH = GFXHT shr 1
   
End Sub

Sub FlipSurf()
   
    ptc_update(buffer)
   
End Sub

Sub ClsSurf()
   
    clear *buffer, 0, CLEARCOUNT
   
End Sub

Sub Plot(ByVal x as integer, ByVal y as integer)
   
    buffer[(y*GFXWID+x)] = CurColor
   
End Sub

Sub ColorSet(ByVal r as integer, ByVal g as integer, ByVal b as integer)
   
    CurColor = ( r shl 16 ) + ( g shl 8 ) + b
   
End Sub

Sub Oval (ByVal x as single, ByVal y as single, ByVal w as single, ByVal h as single)

End Sub
   
Sub DrawLine(ByVal x1 as single,ByVal y1 as single,ByVal x2 as single,ByVal y2 as single)
    dim temp as single
    dim xd as double
    dim yd as double
    dim y as double
    dim x as double
    dim xs as double
    dim ys as double
    if x2 < x1 then
        xd = abs(x1-x2)
    else
        xd = abs(x2-x1)
    endif
    if y2 < y1 then
        yd = abs(y1-y2)
    else
        yd = abs(y2-y1)
    endif
    if xd > yd then
        if x2 < x1 then
            temp = x1
            x1 = x2
            x2 = temp
            temp = y1
            y1 = y2
            y2 = temp
        endif
        xd = abs(x2-x1)
        yd = abs(y2-y1)
        ys = yd/xd
        y=y1
        for x=x1 to x2
            buffer[cint(y+.49)*GFXWID+cint(x+.49)] = CurColor
            y=y+ys
        next
    else
        if y2 < y1 then
            temp = x1
            x1 = x2
            x2 = temp
            temp = y1
            y1 = y2
            y2 = temp
        endif
        xd = abs(x2-x1)
        yd = abs(y2-y1)
        xs = xd/yd
        x=x1
        for y=y1 to y2
            buffer[cint(y+.49)*GFXWID+cint(x+.49)] = CurColor
            x = x + xs
        next
    endif
end sub
   
function getvsyncrate()
    dim ttime as double
    dim count as integer
    ttime = timer
    count = 0
    if WAIT(&h3da, 8)=0 then ttime = timer
    do
        WAIT(&h3da, 8)
        'out(&h3da, 0)
        count = count + 1
        print count
        print count
    loop until timer-ttime >= 1.0
   
    return count-1
   
end function

Rand.bi
Code: [Select]
declare function Rand(ByVal lower as integer, byVal upper as integer)
declare function FRand(ByVal lower as double, byVal upper as double) as double
Declare sub SeedRnd(ByVal seed as double)

sub SeedRnd(byval seed as double)
    randomize seed
end sub

function Rand(ByVal lower as integer, ByVal upper as integer)
    dim temp as integer
    if upper < lower then
        temp=upper
        upper=lower
        lower=temp
    endif
    dim value as integer
    dim dist as integer
    value=lower
    dist = abs(lower-upper)
    return (rnd(1)*dist) + value
End function

function FRand(ByVal lower as double, ByVal upper as double) as double
    dim temp as double
    if upper < lower then
        temp=upper
        upper=lower
        lower=temp
    endif
    dim value as double
    dim dist as double
    value=lower
    dist = abs(lower-upper)
    return (rnd(1)*dist) + value
End function
Title: Re: Horrible V Sync
Post by: Shockwave on May 26, 2006
Thanks BA :)
Title: Re: Horrible V Sync
Post by: Optimus on May 26, 2006
Mmm,. I think even with timing to refresh rate, there will be a problem. I checked this programm a lot, set it to my refresh rate and there was still the sync line moving down in that flashing. A little value higher it moves up. You can't keep it steady. Actually, the problem is that someone can never (or not?) time exactly at 75 for example, there is some loss. Still, if the true vsync worked, it would be the most suitable way to solve the problem. Someone told me to use DirectDraw for getting vsync, but it might be a fuzz. I am used to SDL/TinyPTC. I wish there was a way here (maybe it will and I'll search and ask if I ever get a time now ;P)
Title: Re: Horrible V Sync
Post by: Blitz Amateur on May 26, 2006
Something worth mentioning: If you fiddle with a tming setup such as this, and when you don't have your colors changing that drastically every frame, the vsync lines almost disappear.
Title: Re: Horrible V Sync
Post by: Clyde on May 26, 2006
How experimental is FreeBASIC and the includes and headers etc etc. Maybe as FB is still in it's beta years, there's some stuff thats been overlooked, and they aren't aware of certain stuff. Just a thought.
Title: Re: Horrible V Sync
Post by: TinDragon on May 26, 2006
Well if TinyPTC doesnt wait for the Vsync, which it appears your saying it doesnt, then it does the same as blitz when you do flip 0, it's just that because FB & TinyPTC are so much faster your seeing the "tearing" effect that is caused. Alot of games have the option to turn vsync on or off, the reason most have it off is for speed and on for to stop graphic tears across the screen.
Title: Re: Horrible V Sync
Post by: Shockwave on May 27, 2006
Well if TinyPTC doesnt wait for the Vsync, which it appears your saying it doesnt, then it does the same as blitz when you do flip 0, it's just that because FB & TinyPTC are so much faster your seeing the "tearing" effect that is caused. Alot of games have the option to turn vsync on or off, the reason most have it off is for speed and on for to stop graphic tears across the screen.

That's the whole point of the post Jon. Some guys turn off the vsynch on their gfx cards and it seems impossible to lock the program into a steady frame rate. What is needed is a procedure to check the status of the scan.


< AMIGA >
Code: [Select]
wait:
btst #5,$dff01f ; vbl interrupt
beq.s wait
< /AMIGA >

Something like that would be just fine.
Title: Re: Horrible V Sync
Post by: TinDragon on May 27, 2006
Ah so what you want is to lock the demos update rate to a set speed so in theory it runs the same speed for everyone but doesn't produce the tearing effect if they have vsync off ?

Getting everything to look like it's moving the same speed uses delta timing as mentioned before but I have no idea how you can lock to a set screen update speed if vsync is off. I dont think it can be very easy if even possible but maybe some form of timer delay loop to ensure the update occurs at set intervals like some of the old blitz timing code use to do before everyone went delta timing. Think I have an old source with the stuff in you might be able to convert will see if I can dig it out, perhaps using a combo of both might work.

[Edit]
Right here's what was done in blitz2d to attempt to keep games updating at a set speed on different hardware.
Code: [Select]
fpstimer=CreateTimer(60) ; Create a timer that cycles at 60
; Then in main loop
Repeat
frames = WaitTimer(fpstimer)
For t = 1 To frames
; Update stuff.
Next
; render game screen
Gosub render
Until quit=True
Dont know if FB has anything like Waittimer() ?  Or if this could be adapted but I cant think of anything else  ???
Title: Re: Horrible V Sync
Post by: Shockwave on May 27, 2006
FB has a Wait command but it seems impossible to tie this down to a specific frame rate without getting the odd glitch and tearing in the screen display.