Code that heats CPU more than other code that do same thing
- Psychophanta
- Always Here

- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
Code that heats CPU more than other code that do same thing
I have a very curious quest which i have decided to write here, in "General Discussion".
I have tried several programs (in MS Windows) in 3 different notebooks PCs (all of them above pentium III epoch, this means, all of them with a fan which is activated depending of cpu and mainboard heat detected).
For example, many hardware platforms emulators using windowed or full screen (MAME (with most roms being emulated), ZSNES for windows, BlueMSX, VMWARE (with MSDOS 6.22 as virtual machine), MagicENGINE (all versiones), etc.) don't seem to make cpu fan to be acelerated.
VirtualPC not tested.
But others like NLMSX, ParaMSX, etc. make cpu fan to be accelerated.
NOTE: all tests performed in a 60 m^2 room at 25 degrees, about 50% humidity.
PB compiled programs, when using windowed or full screen always make cpu fan to be accelerated, at least use WaitWindowEvent() (instead of WindowEvent()) to check to exit the program, but there are not a "Wait" for the Keyboard library (to exit with ESC, for example), or some way to select the execution priority in the compiler for a program made in PB, or some way to say the compiler to say the final executeable that DO NOT work whenever there are nothing to do...
As an add comment, I've noticed that ALL the time used when the FlipBuffers() function WAITS FOR actually swap the screen buffers seems to be wasting CPU resources, what is innecessary. So, if that is true, it is sure that the FlipBuffers() function need to be modified.
I have tried several programs (in MS Windows) in 3 different notebooks PCs (all of them above pentium III epoch, this means, all of them with a fan which is activated depending of cpu and mainboard heat detected).
For example, many hardware platforms emulators using windowed or full screen (MAME (with most roms being emulated), ZSNES for windows, BlueMSX, VMWARE (with MSDOS 6.22 as virtual machine), MagicENGINE (all versiones), etc.) don't seem to make cpu fan to be acelerated.
VirtualPC not tested.
But others like NLMSX, ParaMSX, etc. make cpu fan to be accelerated.
NOTE: all tests performed in a 60 m^2 room at 25 degrees, about 50% humidity.
PB compiled programs, when using windowed or full screen always make cpu fan to be accelerated, at least use WaitWindowEvent() (instead of WindowEvent()) to check to exit the program, but there are not a "Wait" for the Keyboard library (to exit with ESC, for example), or some way to select the execution priority in the compiler for a program made in PB, or some way to say the compiler to say the final executeable that DO NOT work whenever there are nothing to do...
As an add comment, I've noticed that ALL the time used when the FlipBuffers() function WAITS FOR actually swap the screen buffers seems to be wasting CPU resources, what is innecessary. So, if that is true, it is sure that the FlipBuffers() function need to be modified.
- Psychophanta
- Always Here

- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
- Psychophanta
- Always Here

- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
Aha, Fred.
That's the answer i was waiting for.
But, uffhhh! I think you, or Freak, or anyone in PB developer team should work on it, because it is very important, and I'm sure that it is very easy to do, and i'm sure too that there are much programmers who know how to do it, because it is made in most of emulators as i have seen.

Surely, the trick remains in act (swap buffers) just when vsync IRQ happens.
I think when the FlipBuffers() function is reached, the thread process should be passed to the system inactive process, and when vsync happens then swap buffers and end the function.
That's the answer i was waiting for.
But, uffhhh! I think you, or Freak, or anyone in PB developer team should work on it, because it is very important, and I'm sure that it is very easy to do, and i'm sure too that there are much programmers who know how to do it, because it is made in most of emulators as i have seen.
Surely, the trick remains in act (swap buffers) just when vsync IRQ happens.
I think when the FlipBuffers() function is reached, the thread process should be passed to the system inactive process, and when vsync happens then swap buffers and end the function.
Quoted fromGenerally, the display refresh rate could be from 60 to 120Hz. or 1/60 down to 1/120 second. DirectX function ::WaitForVerticalBlank is just to wait for the VSYNC interval, but it is by Polling. That is a little ridiculous. Since the windows system is not a real time operating system, that function consume a lot of CPU resource but sometimes it still misses VSYNC.
Here I use both multimedia Timer and DirectX function to track the vertical sync. The main point is starting a multimedia Timer with 2ms interval. In the multimedia Timer callback handler, use function ::GetScanLine to get the current scan line number, then judge whether it is the time to draw.
http://www.codeproject.com/gdi/tearingfreedrawing.asp
- Psychophanta
- Always Here

- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
I insist about the importance of this.
Execute this example code and input firstly "1" for the 2 requests. Then ESCape and try again with max values for the 2 requests (switch off debugger).
If you chack the CPU % use in the first time and compare to the second time, you will see it is the same 8O 8O 8O
Do you think that the first execution eats 100% CPU and 2nd 100% too? That is simply a deceit.
I am not sure if wilbert method is the best or the right one.
What I can and must say to Fred is that blueMSX, MAME32, and ZSNES are optimal in this ESSENTIAL matter, and all three are OPEN SOURCE.
I've wrote to blueMSX main author about this quest, but surely and logically he will answer me something like: sorry, i have no time to teach; blueMSX is OPENSOURCE software.
Sorry my insistence, Fred, but you must consider this matter as crucial if you want that PB is good for 2D and 3D graphics performance.
Execute this example code and input firstly "1" for the 2 requests. Then ESCape and try again with max values for the 2 requests (switch off debugger).
Code: Select all
; This example shows the way to make a "elastic perfectly collision" between 2 spheric (with masses
;centre same as geometrical centre) objects in the emptyness (no rub).
;Elastic perfectly collision in a closed system (closed system means no external forces but only the
;two ones of the both colliding objects forces) mean no lossing kinetic energy from the closed system.
;It is ideal, because in reality there is always a kinetic energy lossing in rub, deformation, rotation,
;heat, etc.
; NOTE: decrease #lines constant and/or number of objects if your computer is too slow.
; NOTE2: you can add external forces (like gravities between objects, or absolute to all)
;playing with dirX and dirY parameters.
; 2003-12-25 (Psychophanta)
;-INITS:
#PI=3.14159265
bitplanes.b=32:RX.w=1024:RY.w=768
If InitMouse()=0 Or InitSprite()=0 Or InitSprite3D()=0 Or InitKeyboard()=0
MessageRequester("Error","Can't open DirectX",0)
End
EndIf
Structure balls
sprite.w;<-#Sprite
x.f:y.f;<-coordenadas instantáneas
dirX.f:dirY.f;<-Vector director
HalfWidth.w:HalfHeight.w;<-centro geométrico
Dimension.w
Mass.f;<-masa
Kinetic.f;<-energÃa cinética
EndStructure
NewList Capsule.balls():Cursor.balls
;-FUNCTIONS:
Procedure Shock0(*a.balls)
;*;al momento de chocar tenemos:
;ENTRADAS: Vectores directores de los movimientos ((dirX,dirY) para Objeto0 y (dirX,dirY) para Objeto1)
; Masas de Objeto1 y de Objeto0 (Objeto0 Mass y Objeto1 Mass)
;*;Debemos calcular:
;SALIDAS: Nuevo vector director de los movimientos de Objeto1 y de Objeto0 ((dirX,dirY) de Objeto0 y (dirX,dirY) de Objeto1).
;*;CANTIDADES DE MOVIMIENTO:
; MQBallX.f=Capsule()\dirX*Capsule()\Mass:MQBallY.f=Capsule()\dirY*Capsule()\Mass;<-cantidad de movimiento de Ball
; MQCursorX.f=*a\dirX**a\Mass:MQCursorY.f=*a\dirY**a\Mass;<-cantidad de movimiento de Cursor
; MQBall.f=Sqr(MQBallX.f*MQBallX.f+MQBallY.f*MQBallY.f)
; MQCursor.f=Sqr(MQCursorX.f*MQCursorX.f+MQCursorY.f*MQCursorY.f)
;*;ENERGIAS CINETICAS:
;*a\Kinetic=(Pow(*a\dirX,2)+Pow(*a\dirY,2))**a\Mass/2;<-(m/2)*v^2 de Objeto0
;Capsule()\Kinetic=(Pow(Capsule()\dirX,2)+Pow(Capsule()\dirY,2))*Capsule()\Mass/2;<-(m/2)*v^2 de Objeto1
;*;COMPONENTES POR CONTACTO:
;Es un vector que está en la lÃnea de choque (recta normal a la recta tangente, en el punto de contacto, sobre la superficie contra la que se choca).
;Obtenemos su sentido y dirección, que viene marcado por la diferencia de coordenadas de cada objeto al momento de chocar:
DiffX.f=Capsule()\x-*a\x:DiffY.f=Capsule()\y-*a\y;<-rectángulo que forman las posiciones de los colisionantes
Distance.f=Sqr(DiffX*DiffX+DiffY*DiffY)
;A continuación, su módulo, que depende de la de las cantidades de movimiento de ambos cuerpos:
;ModuloObjeto1.f=Sqr(1+Pow(*a\Mass/Capsule()\Mass,2));<-Módulo de la componente por contacto de Objeto1.
;ModuloObjeto0.f=Sqr(1+Pow(Capsule()\Mass/*a\Mass,2));<-Módulo de la componente por contacto de Objeto0.
ModuloObjeto1.f=*a\Mass/(*a\Mass+Capsule()\Mass)
ModuloObjeto0.f=Capsule()\Mass/(*a\Mass+Capsule()\Mass)
;Probar con:
;ModuloObjeto1.f=*a\Kinetic/(*a\Kinetic+Capsule()\Kinetic)
;ModuloObjeto0.f=Capsule()\Kinetic/(*a\Kinetic+Capsule()\Kinetic)
;y con:
;ModuloObjeto1.f=*a\Kinetic/Sqr(Pow(*a\Kinetic,2)+Pow(Capsule()\Kinetic,2))
;ModuloObjeto0.f=Capsule()\Kinetic/Sqr(Pow(*a\Kinetic,2)+Pow(Capsule()\Kinetic,2))
;y con:
;ModuloObjeto1.f=Sqr(Capsule()\Kinetic+*a\Kinetic)/2
;ModuloObjeto0.f=Sqr(Capsule()\Kinetic+*a\Kinetic)/2
;*;Calcular las COMPONENTES POR CONTACTO (un vector normal a la tangente
;en el punto de contacto con la superficie contra la que se choca); que tendrán sus módulo dados,
;añadiendo dichas componentes a las componentes de los vectores directores de los movimientos
;de Objeto0 y Objeto1
Capsule()\dirX+DiffX*ModuloObjeto1/Distance.f
Capsule()\dirY+DiffY*ModuloObjeto1/Distance.f
*a\dirX-DiffX*ModuloObjeto0/Distance.f
*a\dirY-DiffY*ModuloObjeto0/Distance.f
;*;Preservar distancia:
Clip.f=(*a\Dimension/2+Capsule()\Dimension/2)-Distance.f
If Clip.f>0:Clip.f/2
Capsule()\x+DiffX.f*Clip.f/Distance.f
Capsule()\y+DiffY.f*Clip.f/Distance.f
*a\x-DiffX.f*Clip.f/Distance.f
*a\y-DiffY.f*Clip.f/Distance.f
EndIf
EndProcedure
Procedure Shock(*a.balls)
;*;al momento de chocar tenemos:
;ENTRADAS: Vectores directores de los movimientos ((dirX,dirY) para Objeto0 y (dirX,dirY) para Objeto1)
; Masas de Objeto1 y de Objeto0 (Objeto0 Mass y Objeto1 Mass)
;*;Debemos calcular:
;SALIDAS: Nuevo vector director de los movimientos de Objeto1 y de Objeto0 ((dirX,dirY) de Objeto0 y (dirX,dirY) de Objeto1).
;*;CANTIDADES DE MOVIMIENTO:
; MQBallX.f=Capsule()\dirX*Capsule()\Mass:MQBallY.f=Capsule()\dirY*Capsule()\Mass;<-cantidad de movimiento de Ball
; MQCursorX.f=*a\dirX**a\Mass:MQCursorY.f=*a\dirY**a\Mass;<-cantidad de movimiento de Cursor
; MQBall.f=Sqr(MQBallX.f*MQBallX.f+MQBallY.f*MQBallY.f)
; MQCursor.f=Sqr(MQCursorX.f*MQCursorX.f+MQCursorY.f*MQCursorY.f)
;*;ENERGIAS CINETICAS:
;*a\Kinetic=(Pow(*a\dirX,2)+Pow(*a\dirY,2))**a\Mass/2;<-(m/2)*v^2 de Objeto0
;Capsule()\Kinetic=(Pow(Capsule()\dirX,2)+Pow(Capsule()\dirY,2))*Capsule()\Mass/2;<-(m/2)*v^2 de Objeto1
;*;COMPONENTES POR CONTACTO:
;Es un vector que está en la lÃnea de choque (recta normal a la recta tangente, en el punto de contacto, sobre la superficie contra la que se choca).
;Obtenemos su sentido y dirección, que viene marcado por la diferencia de coordenadas de cada objeto al momento de chocar:
DiffX.f=Capsule()\x-*a\x:DiffY.f=Capsule()\y-*a\y;<-Vector de distancia
;su módulo depende de la componente de la velocidad con respecto a la linea de choque (DiffX,DiffY) (proyección del vector (dirX,dirY) sobre el (DiffX,DiffY)):
K.f=(DiffX.f**a\dirX+DiffY.f**a\dirY)/(DiffX.f*DiffX.f+DiffY.f*DiffY.f);<-constante de proyección del actual vector del movimiento de Cursor sobre la lÃnea de choque.
dirCursorXK.f=K.f*DiffX.f:dirCursorYK.f=K.f*DiffY.f;<-vector componente en lÃnea de choque de la velocidad de Cursor.
K.f=(-DiffX.f*Capsule()\dirX-DiffY.f*Capsule()\dirY)/(-DiffX.f*-DiffX.f+-DiffY.f*-DiffY.f);<-constante de proyección del actual vector del movimiento de Ball sobre la lÃnea de choque.
dirBallXK.f=K.f*-DiffX.f:dirBallYK.f=K.f*-DiffY.f;<-vector componente en lÃnea de choque de la velocidad de Ball.
CX.f=(2*Capsule()\Mass*dirBallXK.f+*a\Mass*dirCursorXK.f-Capsule()\Mass*dirCursorXK.f)/(*a\Mass+Capsule()\Mass)
CY.f=(2*Capsule()\Mass*dirBallYK.f+*a\Mass*dirCursorYK.f-Capsule()\Mass*dirCursorYK.f)/(*a\Mass+Capsule()\Mass)
BX.f=(2**a\Mass*dirCursorXK.f+Capsule()\Mass*dirBallXK.f-*a\Mass*dirBallXK.f)/(*a\Mass+Capsule()\Mass)
BY.f=(2**a\Mass*dirCursorYK.f+Capsule()\Mass*dirBallYK.f-*a\Mass*dirBallYK.f)/(*a\Mass+Capsule()\Mass)
;*;Ahora obtener el vector resultante para el movimiento de Ball:
;Se mantiene la componente perpendicular a la linea de choque del movimiento de Ball (componente que no afecta al choque):
Capsule()\dirX-dirBallXK.f+BX.f:Capsule()\dirY-dirBallYK.f+BY.f;<-se suman, obteniendo el vector buscado.
;*;Finalmente obtener el vector director resultante para el movimiento de Cursor:
;Se mantiene la componente perpendicular a la linea de choque del movimiento de Cursor (componente que no afecta al choque):
*a\dirX-dirCursorXK.f+CX.f:*a\dirY-dirCursorYK.f+CY.f;<-se suman, obteniendo el vector buscado.
;*;Preservar distancia:
Distance.f=Sqr(DiffX*DiffX+DiffY*DiffY)
Clip.f=(*a\Dimension/2+Capsule()\Dimension/2)-Distance.f
If Clip.f>0:Clip.f/2
Capsule()\x+DiffX.f*Clip.f/Distance.f
Capsule()\y+DiffY.f*Clip.f/Distance.f
*a\x-DiffX.f*Clip.f/Distance.f
*a\y-DiffY.f*Clip.f/Distance.f
EndIf
EndProcedure
Procedure CreateBallSprite(c.l,size.l,color.l)
CreateSprite(c,size,size,#PB_Sprite_Texture)
StartDrawing(SpriteOutput(c))
BackColor(0,0,0):R.w=color&$FF:G.w=color>>8&$FF:B.w=color>>16&$FF
For t.l=size/2 To 1 Step -1
R+160/size:G+160/size:B+160/size:If R>255:R=255:EndIf:If G>255:G=255:EndIf:If B>255:B=255:EndIf
Circle(size/2,size/2,t,RGB(R,G,B))
Next
StopDrawing()
EndProcedure
;-MOREINITS:
BallsDiameter.l=76;Val(InputRequester("Input","Please input 2D spheres diameter in #pixels (max. "+Str(RX.w/3)+")",Str(76)))
Lines.l=Val(InputRequester("Input","Please input number of lines of 2D spheres (max. "+Str(RY.w/BallsDiameter.l)+")",Str(2)))
BallsPerLine.l=Val(InputRequester("Input","Please input number of 2D spheres per line (max. "+Str(RX.w/BallsDiameter.l)+")",Str(RX.w/BallsDiameter.l-1)));<-Número de Objeto1 por lineas
While OpenScreen(RX.w,RY.w,bitplanes.b,"Balls")=0
If bitplanes.b>16:bitplanes.b-8
ElseIf RY.w>600:RX.w=800:RY.w=600
ElseIf RY.w>480:RX.w=640:RY.w=480
ElseIf RY.w>400:RX.w=640:RY.w=400
ElseIf RY.w>240:RX.w=320:RY.w=240
ElseIf RY.w>200:RX.w=320:RY.w=200
Else:MessageRequester("VGA limitation","Can't open Screen!",0):End
EndIf
Wend
Cursor\sprite=0
CreateBallSprite(Cursor\sprite,64,$009eae)
CreateSprite3D(Cursor\sprite,Cursor\sprite):ZoomSprite3D(Cursor\sprite,64,64)
Cursor\HalfWidth=SpriteWidth(Cursor\sprite)/2:Cursor\HalfHeight=SpriteHeight(Cursor\sprite)/2;<-centro de Objeto0
Cursor\Dimension=(SpriteWidth(Cursor\sprite)+SpriteHeight(Cursor\sprite))/2
Cursor\Mass=4*#PI*Pow(Cursor\Dimension/2,3)/3;<-masa de Objeto0
For g.b=1 To Lines.l
For t.w=1 To BallsPerLine.l
AddElement(Capsule())
Capsule()\sprite=t
CreateBallSprite(Capsule()\sprite,BallsDiameter.l,$6dae00)
CreateSprite3D(Capsule()\sprite,Capsule()\sprite):ZoomSprite3D(Capsule()\sprite,BallsDiameter.l,BallsDiameter.l)
Capsule()\HalfWidth=SpriteWidth(Capsule()\sprite)/2:Capsule()\HalfHeight=SpriteHeight(Capsule()\sprite)/2;<-centro de Objeto1
Capsule()\Dimension=(SpriteWidth(Capsule()\sprite)+SpriteHeight(Capsule()\sprite))/2
Capsule()\Mass=4*#PI*Pow(Capsule()\Dimension/2,3)/3;<-masa de Objeto1
Capsule()\x=t.w*BallsDiameter.l-Capsule()\HalfWidth+((RX.w-BallsDiameter.l*BallsPerLine.l)/2);<-Posición inicial X
Capsule()\y=g.b*BallsDiameter.l-Capsule()\HalfHeight;<-Posición inicial Y
Next
Next
mouseX=RX.w/2:mouseY=RY.w*4/5
Cursor\x=mouseX:Cursor\y=mouseY
MouseLocate(mouseX,mouseY);<-Posición inicial de Objeto0
Cursor\dirX=Random(1000000)/100000-5:Cursor\dirY=-Random(4000000)/1000000-1
;-MAIN:
Repeat
ExamineKeyboard()
ExamineMouse()
ClearScreen(0,0,0)
; Cursor position and vector:
prevmouseX=mouseX:prevmouseY=mouseY;<-previous mouse coordinates
mouseX=MouseX():mouseY=MouseY();<-current mouse coordinates
If mouseX<>prevmouseX Or mouseY<>prevmouseY;If mouse is moved:
Cursor\dirX=mouseX-prevmouseX:Cursor\dirY=mouseY-prevmouseY;<-vector director del movimiento de Cursor
mouseX=Cursor\x+Cursor\dirX:mouseY=Cursor\y+Cursor\dirY;<-actualizamos las coordenadas del mouse
MouseLocate(mouseX,mouseY);<-y reposicionamos el mouse en las actuales coordenadas de Cursor
EndIf
Cursor\x+Cursor\dirX:Cursor\y+Cursor\dirY;<-que son estas (se suma el vector director a las anteriores)
; Cursor-Screen limits:
If Cursor\x<=0:Cursor\dirX=Abs(Cursor\dirX):EndIf
If Cursor\x>=RX.w:Cursor\dirX=-Abs(Cursor\dirX):EndIf
If Cursor\y<=0:Cursor\dirY=Abs(Cursor\dirY):EndIf
If Cursor\y>=RY.w:Cursor\dirY=-Abs(Cursor\dirY):EndIf
Start3D()
ForEach Capsule()
; Ball-Screen limits:
If Capsule()\x<=0:Capsule()\dirX=Abs(Capsule()\dirX):EndIf
If Capsule()\x>=RX.w:Capsule()\dirX=-Abs(Capsule()\dirX):EndIf
If Capsule()\y<=0:Capsule()\dirY=Abs(Capsule()\dirY):EndIf
If Capsule()\y>=RY.w:Capsule()\dirY=-Abs(Capsule()\dirY):EndIf
; Ball-moving:
Capsule()\x+Capsule()\dirX:Capsule()\y+Capsule()\dirY;<-Coordenadas actuales de Ball (se suma a las anteriores el vector director)
; collision:
*i.balls=@Capsule()
While NextElement(Capsule())
If SpritePixelCollision(*i\sprite,*i\x-*i\HalfWidth,*i\y-*i\HalfHeight,Capsule()\sprite,Capsule()\x-Capsule()\HalfWidth,Capsule()\y-Capsule()\HalfHeight);Si hay colisión:
Shock(*i)
EndIf
Wend
ChangeCurrentElement(Capsule(),*i)
If SpritePixelCollision(Cursor\sprite,Cursor\x-Cursor\HalfWidth,Cursor\y-Cursor\HalfHeight,*i\sprite,*i\x-*i\HalfWidth,*i\y-*i\HalfHeight);Si hay colisión:
Shock(@Cursor)
EndIf
DisplaySprite3D(*i\sprite,*i\x-*i\HalfWidth,*i\y-*i\HalfHeight,255)
Next
DisplaySprite3D(Cursor\sprite,Cursor\x-Cursor\HalfWidth,Cursor\y-Cursor\HalfHeight,255)
Stop3D()
FlipBuffers()
Until KeyboardPushed(#PB_Key_All)
CloseScreen()
End
Do you think that the first execution eats 100% CPU and 2nd 100% too? That is simply a deceit.
I am not sure if wilbert method is the best or the right one.
What I can and must say to Fred is that blueMSX, MAME32, and ZSNES are optimal in this ESSENTIAL matter, and all three are OPEN SOURCE.
I've wrote to blueMSX main author about this quest, but surely and logically he will answer me something like: sorry, i have no time to teach; blueMSX is OPENSOURCE software.
Sorry my insistence, Fred, but you must consider this matter as crucial if you want that PB is good for 2D and 3D graphics performance.
Psychophanta, your code example crashes on my computer (win xp sp2).
A little off topic...
I never heard of blueMSX, thought RuMSX was the most advanced emulator. My favorites were the MSX games made by Konami. Amazing what they could do with 16KB (KnightMare) or 32KB (The Goonies). And of course MSX Basic... One MicroSoft product that wasn't buggy
A little off topic...
I never heard of blueMSX, thought RuMSX was the most advanced emulator. My favorites were the MSX games made by Konami. Amazing what they could do with 16KB (KnightMare) or 32KB (The Goonies). And of course MSX Basic... One MicroSoft product that wasn't buggy
- Psychophanta
- Always Here

- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
About blueMSX; is now the best MSX emulator, RuMSX and fMSX are worse than ParaMSX and NLMSX, and these two are worse than blueMSX. If you doubt on my words, then compare yourself.
By the way, with MSX basic (year 1983 Microsoft basic interpreter) i can do this:
the result is shown as scientific notation. This is:
8.6609539007937E+29
...and Z80 have no FPU
. This is for Fred too, and perhaps i write another post thread saying this.

Anyway, never mind.
I just want Fred and PB comunity to understand that this matter treated in this post is essential for a well optimiced final code for graphics.
Yeah. Perhaps because B. Gates brain was more clean to do well done things than after 1983, and so on, heheheAnd of course MSX Basic... One MicroSoft product that wasn't buggy
By the way, with MSX basic (year 1983 Microsoft basic interpreter) i can do this:
Code: Select all
10 A=2.46779045923852834394506004705067054*350959858377373743848834834883
20 PRINT A8.6609539007937E+29
...and Z80 have no FPU
Very, very strange. I use WinXP SP2 too. I guess you have a PBlib which cause problems or something.Psychophanta, your code example crashes on my computer (win xp sp2).
Anyway, never mind.
I just want Fred and PB comunity to understand that this matter treated in this post is essential for a well optimiced final code for graphics.
- Psychophanta
- Always Here

- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
Fred, I have just receved the Daniel Vik (blueMSX main author) answer.
Sure it is a good help.
I'm sure that it is possible to do it still better.
Sure it is a good help.
This is complex to perform in a function in PB, because this uses 1 thread dedicated only to perform DirectX drawing. And on the other hand it creates a 1ms. timer to use it to check needs of DX drawings instead to check it continuosly.The reason why some DirectX apps use 100% cpu is actually not because of
DirectX itself. In normal windows apps, the message loop looks something
like:
while (GetMessage(&msx, NULL, 0, 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
With this method you will not get the good timing required for DirectX
apps to run smoothly.
A common practice in DirectX apps is to busy wait in the main message loop
in order to get more accurate timing. This is recommended in most DirectX
getting started books and for a game that runs in fullscreen it is ok to
use 100% cpu since no other apps needs to get much response. They do it
like this:
for (;;) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
time = getTime();
if (time >= frameTime) {
drawFrame();
}
}
The getTime() method (has to be implemented) uses the high performance
counters to get a high resolution time stamp. If it is time to draw a
frame it does it otherwise, the loop continues. The PeekMessage function
returns immediately if no windows message has arrived so most of the cpu
time is spent spinning in this loop.
In blueMSX I changed this loop to not busy wait using PeekMessage. To get
the accurate timing I have a 1 ms timer that sets an event which breaks
the blocking message call MsgWaitForMultipleObjects and the loop is
something like:
while (!doExit) {
DWORD rv = MsgWaitForMultipleObjects(1, &Prt.ddrawEvent, FALSE,
INFINITE, QS_ALLINPUT);
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
doExit = 1;
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (rv == WAIT_OBJECT_0) { // The 1ms timer expired...
time = getTime();
if (time >= frameTime) {
drawFrame();
}
}
}
So what happens is that the Message receive method is intercepted every 1
ms and then I do the checks if the DirectX frame needs to be redrawn. This
adds only a little overhead to the common message loop used in regular
windows apps but i gets pretty much the same good accuracy as the busy
wait one.
On top of this I use two threads. One that does the directx drawing and
one that does all the emulation. This actually gives some performance
gains since as you said, the flip and other directx commands take some
time. But the time spent in directx waits are not that long though so
running everything in one thread also works ok.
I hope this explanation was not too confusing
Take care,
Daniel
I'm sure that it is possible to do it still better.
This code will add a dynamic delay so FlipBuffer() will be called just before 1/60 second. The delay will not be added at all if the frame takes > 1/60 second to compute.
Change both 16 in the code below to 1000/refresh rate to make this code work at different refresh rates. Always round the number down to the nearest whole number, and if it already is a whole number or real close to one, subtract 1 more.
Oh, I am at work so if the code contains bugs or doesn't work, sorry.
Fred:
Maybe you can do something like this in the FlipBuffer() procedure.
Change both 16 in the code below to 1000/refresh rate to make this code work at different refresh rates. Always round the number down to the nearest whole number, and if it already is a whole number or real close to one, subtract 1 more.
Oh, I am at work so if the code contains bugs or doesn't work, sorry.
Code: Select all
While exit = 0
; do everything here
;*** keep this code together
timer = ElapsedMilliseconds() - timer
If timer < 16
delay(16 - timer)
EndIf
FlipBuffer()
timer = ElapsedMilliseconds()
Wend
;*** keep this code together
Maybe you can do something like this in the FlipBuffer() procedure.
Nathan Beckstrand -- XPSP2, AMD Athlon XP 3000+, GF2 GTS, 512MB RAM
-
The_Pharao
- User

- Posts: 57
- Joined: Sun Jan 04, 2004 2:11 pm
there is no reason to limit the frame rate in a fullscreen game, IMHO.
more frames -> more cpu usage -> more heat.... ok.
but also means -> smoot movement
everybody who plays first person shooters knows there's a BIIIIIG difference between 30fps, 60fps or 120fps!
of course there are games that do not need to display > 30 frames a second
more frames -> more cpu usage -> more heat.... ok.
but also means -> smoot movement
everybody who plays first person shooters knows there's a BIIIIIG difference between 30fps, 60fps or 120fps!
of course there are games that do not need to display > 30 frames a second
- Psychophanta
- Always Here

- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
TheBeck, that method is of course better than the used now in PB (probed and it works
), but there are still wasted time.
wilbert, try to update your VGA drivers.
The_Pharao, I am agree with your post, but we are not talking about limit or extend the frame rate, but about to optimize and save CPU resources.
Is it possible to patch vsync display Interrupt Service Routine in Windows? This should be the best and perfect solution for FlipBuffers().
I mean; if the Default ISR for Vsync in Windows is:
then patch it and set up as:
I asked to Daniel Vik if it possible to do an even better job for freeing the wasted time in waiting for swap buffers, and he answered.

wilbert, try to update your VGA drivers.
The_Pharao, I am agree with your post, but we are not talking about limit or extend the frame rate, but about to optimize and save CPU resources.
Is it possible to patch vsync display Interrupt Service Routine in Windows? This should be the best and perfect solution for FlipBuffers().
I mean; if the Default ISR for Vsync in Windows is:
Code: Select all
Windows_VSYNC_ISR: code a
code b
...code c...
RETurn from ISR
Code: Select all
Windows_VSYNC_ISR: FLIP the Screen Buffers
CALL [our drawing code]
code a
code b
...code c...
RETurn from ISR
I asked to Daniel Vik if it possible to do an even better job for freeing the wasted time in waiting for swap buffers, and he answered.
Fred, At least keep in mind the TheBeck solutionI think it would be possible to do an even better job. I think there are
some waiting in the DirectX calls that probably could be avoided by using
the No Delay option. That requires some more knowledge about DirectX
though. In blueMSX at least there are some commands that are issued after
each other so only the last one (which is the flip) can be done with the
No Delay option. I'm not sure how this can be made more effective.
- Psychophanta
- Always Here

- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:

