News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Fast Multimedia Timer for Games and Demos

Started by Siekmanski, April 14, 2018, 09:34:04 AM

Previous topic - Next topic

Siekmanski

Here is my first contribution to the Game Development project.  :biggrin:

A fast MultimediaTimers ( release version ) routine you can use in your Games and Demos.
15 resettable timers to control your animations and other time based routines.
A FrameDelta timer to create smooth and stutter free animated scenes.
 
If you need a routine that also displays the frames per second, download the "MultimediaTimers.zip" in this thread:
http://masm32.com/board/index.php?topic=7060.msg75835#msg75835

.const
QPinteger struct
    Low32bit    dd ?
    High32bit   dd ?
QPinteger ends

fp1 real4 1.0

MEDIATIMERS struct  ; don't change the order of the members!
    Timer1                      real4 ? ; 15 resettable timers to time control your animations or other routines.
    Timer2                      real4 ? ; The timers are updated every screen refresh.
    Timer3                      real4 ? ; Clear them to reset a timer.
    Timer4                      real4 ? ;
    Timer5                      real4 ?
    Timer6                      real4 ?
    Timer7                      real4 ?
    Timer8                      real4 ?
    Timer9                      real4 ?
    Timer10                     real4 ?
    Timer11                     real4 ?
    Timer12                     real4 ?
    Timer13                     real4 ?
    Timer14                     real4 ?
    Timer15                     real4 ?
    TotalTime                   real4 ? ; Time elapsed from the start of your application.
    FrameTimeDelta              real4 ? ; Use this to synchronize your routines for a stutter free animation.
    TicksPerSecondReciprocal    real4 ? ; The next 3 members are used for internal control, don't write to it!
    FrameTimeOld                QPinteger <?>
    FrameTimeNew                QPinteger <?>
MEDIATIMERS ends

.data?
align 16
Timers      MEDIATIMERS <?> ; must be 16 bytes aligned!

.code
align 4     ; Call this routine once at the start of your application
InitTimers proc uses esi   ; Get frequency of the performance counter and set the time to seconds units
    mov         esi,offset Timers
    invoke      QueryPerformanceFrequency,addr [esi].MEDIATIMERS.FrameTimeNew
    movss       xmm0,fp1
    cvtsi2ss    xmm1,[esi].MEDIATIMERS.FrameTimeNew.Low32bit
    divss       xmm0,xmm1                   ; calculate the reciprocal to get rid of a divss instruction in the UpdateTimers function
    movss       [esi].MEDIATIMERS.TicksPerSecondReciprocal,xmm0
    invoke      QueryPerformanceCounter,addr [esi].MEDIATIMERS.FrameTimeOld ; start time value
    ret
InitTimers endp

align 4     ; Call this routine before the other routines at every new screen refresh
UpdateTimers proc uses esi
    mov         esi,offset Timers
    invoke      QueryPerformanceCounter,addr [esi].MEDIATIMERS.FrameTimeNew
    mov         eax,[esi].MEDIATIMERS.FrameTimeNew.Low32bit       ; calculate the time elapsed between screen refreshes
    mov         edx,eax
    sub         eax,[esi].MEDIATIMERS.FrameTimeOld.Low32bit
    mov         [esi].MEDIATIMERS.FrameTimeOld.Low32bit,edx
    cvtsi2ss    xmm0,eax
    mulss       xmm0,[esi].MEDIATIMERS.TicksPerSecondReciprocal   ; calculate the Frame Time Delta
    movss       [esi].MEDIATIMERS.FrameTimeDelta,xmm0             ; time between screen refresh updates ( multiply "FrameTimeDelta" with your animation speed for smooth animations )
    shufps      xmm0,xmm0,0             ; 4 copies of the FrameTimeDelta
    movaps      xmm1,oword ptr[esi]     ; read all 15 timers and TotalTime
    movaps      xmm2,oword ptr[esi+16]
    movaps      xmm3,oword ptr[esi+32]
    movaps      xmm4,oword ptr[esi+48]
    addps       xmm1,xmm0               ; increase timers 1 - 4 with the FrameTimeDelta
    addps       xmm2,xmm0               ; increase timers 5 - 8 with the FrameTimeDelta
    addps       xmm3,xmm0               ; increase timers 9 - 12 with the FrameTimeDelta
    addps       xmm4,xmm0               ; increase timers 13 - 15  and TotalTime with the FrameTimeDelta
    movaps      oword ptr[esi],xmm1     ; update all 15 timers and TotalTime
    movaps      oword ptr[esi+16],xmm2
    movaps      oword ptr[esi+32],xmm3
    movaps      oword ptr[esi+48],xmm4
    ret
UpdateTimers endp
Creative coders use backward thinking techniques as a strategy.

zedd151

Wow! Now this looks like it will be a very useful piece of code for game dev.  :t

I myself have never had much success at making graphics move, but since the Game Development board opened, I've been itching to give it another shot. But sadly must wait - still no 'puter here yet.   :(

Lonewolff

Nice Siekmanski  8)

Hoping to get back on to my game today too. Wife's having visitors over - bloody housework  :icon_confused:

LordAdef

(the capital letters are intended in a good way)


THANK YOU VERY MUCH MY FRIEND!!


The game forum is definitely taking off with everyone in full mood.


Marinus, your code will be used in my game immediately. Credit will be obviously given!


Siekmanski

Alex, all source code I post in this forum is under the SHARE & ENJOY licence. Do whatever you want with it.  :t

As ( future ) game developers we all know that on multitasking systems like Windows there is no stable vertical retrace interrupt available.
This is noticeable when animations are stuttering.
We can make the animations smooth by multiplying the frame time delta to the speed update factors.
This has some disadvantages when you want to rotate an exact amount of degrees or move an object the exact number of pixels per time unit.
So, we need a vertical retrace jitter correction factor of +/- 1.0
When we multiply this factor with our animation speed factors, we can do exact calculations that are very smooth, pixel and time precise.

I have a solution for this and will demonstrate it with a source code example in a couple of weeks from now. ( always too busy...  :lol:)

In the attachment an example of the vertical retrace jitter correction factor.
Creative coders use backward thinking techniques as a strategy.

Lonewolff

With the sync thing, if you are using DX or OpenGL you can enable vSync and/or additional buffers. This will kill any jitters most of the time.

Not sure if this is possible with GDI though.

I make habit of using delta time also to make animations frame time independent.

Siekmanski

Quote from: Lonewolff on April 14, 2018, 12:50:07 PM
With the sync thing, if you are using DX or OpenGL you can enable vSync and/or additional buffers.

Yes, but it is not stable enough.

Quote
Not sure if this is possible with GDI though.

It's been a long time ago since I have done some coding with GDI.
I think it is possible with double buffering and a nano interrupt timer to get it smooth.
Maybe caballero can provide me the masm GDI source code of the FloorWF01.exe, this would be a great example to try it on.
I will ask him.
Creative coders use backward thinking techniques as a strategy.


Siekmanski

I mean you always have varying times between screen refreshes.
On non multitasking sytems like MS-DOS you could use the hardware vertical retrace interrupt without varying times between screen refreshes and have a smooth animated scene.
Creative coders use backward thinking techniques as a strategy.

Lonewolff

Ah ok. Get where you are coming from.

I have always just divided the animation time against delta time. This way it doesn't matter if the frame rate fluctuates in extremes like 5000 FPS or 30 FPS. Animation and movement speed remains consistent.

daydreamer

great work Marinus :t
wouldnt it be better to put timecritical code in a workerthread so its less risk of when mainthread is switched to another process/program that you miss vertical retrace, what about setthreadpriority?
what about peekmessage with one thread switched to getmessage and workerthreads?
too much work when you use peekmessage, makes all functions in messagehandler unresponsive, if you prefer a cpu rasterizer code
I think timercode like that would be useful for synchronize everything in your game, if you decide to use several threads for different tasks so your enemy AI you put in separate thread isnt unsynchronized with animation thread etc
my none asm creations
https://masm32.com/board/index.php?topic=6937.msg74303#msg74303
I am an Invoker
"An Invoker is a mage who specializes in the manipulation of raw and elemental energies."
Like SIMD coding

Lonewolff

Isn't SetThreadAfinity a 'serving suggestion' only?

From what I understand Windows has the discretion to assign threads to another core regardless of where you tell it to run.

Siekmanski

Quote from: daydreamer on April 14, 2018, 09:22:19 PM
great work Marinus :t
wouldnt it be better to put timecritical code in a workerthread so its less risk of when mainthread is switched to another process/program that you miss vertical retrace, what about setthreadpriority?
what about peekmessage with one thread switched to getmessage and workerthreads?
too much work when you use peekmessage, makes all functions in messagehandler unresponsive, if you prefer a cpu rasterizer code
I think timercode like that would be useful for synchronize everything in your game, if you decide to use several threads for different tasks so your enemy AI you put in separate thread isnt unsynchronized with animation thread etc

Hi Magnus,

Maybe you can discard the whole message pump in certain Games.
As long the application is fast and the human eye and brain doesn't detect stutter in animations I'm happy.

Many years ago ( 15 or so ) I played with the Raster Status on video cards to check if the raster was in the vertical blank period or else on what scanline the rasterizer was.
I remember that the scanline position was a rough approximation so I used the timing code again.
It was not really a success because not every video card supported that function in those days.

It's worth investigate all of this stuff again and also find a way to get stutter free GDI for the people who use GDI for their games.
Creative coders use backward thinking techniques as a strategy.

avcaballero

Yes, you can make smooth graphics with GDI. Almost the 90% of what my production is with GDI.

DirectX seems to use a buffer rectangle determinated, let's say 600x400 and if you want to see it in full screen what it does is stretch this buffer to the whole screen. That is what I have done here with the GDI templates. Some time ago made this full screen fire demo, no tricky involved here, the program calculates your screen dimension and makes a buffer with this size (full screen), in my computer runs smootly. This is a very big buffer where to write to.

I wonder how faster is DirectX than GDI in fact. When I have time I will make this proof.

There's no doubt that DirectX has some advantages over GDI. It is a big library of functions prepared to be used in graphics programming such 2d and 3d that you have already installed in your pc, so the programs you made with DirectX are smaller that those made with GDI for these themes. In GDI you have to make your own graphics functions, what I find more attractive.

Regards

PS: Don't know if it is possible to make a no suttering at all graphic demo with GDI, maybe it depends on the workload of the processor at all times. I can not tell if DirectX is able to monopolize all that capacity.

Siekmanski

GDI is a long time ago for me but, just like you I also liked it to make my own graphic functions in the old MS-DOS days.
Did some conversions of my old Amiga demo routines.
I have run your GDI FloorWF01.exe and it does stutter on my machine, does it run smooth on yours?
So for me thats an example to test if I can come up with a routine to get rid of the stutter.

About GDI vs. DirectX.
Direct3D9 is 100% hardware accelerated and you have total access to the video card so, you are not restricted to use the full capabilities of the video card.

About the big DirectX wrapper lib.
I don't like it and don't use it because there are more than 20 versions and the user needs to download the right version first before he/she can run your application.
I only use d3d9.dll ( at least available from XP up to Win10 ) and my own math and texture loader libs.
That's all I need to do fast hardware accelerated graphics programming.

I have some ideas which I still need to test and proof and if it works out, to make a function to wait for the Vertical Retrace signal from the monitor and use that in GDI applications to blit the backbuffer(s) to the frontbuffer.
Creative coders use backward thinking techniques as a strategy.