[win32 + OpenGL] Win32 WM_TIMER voor scene update?

Pagina: 1
Acties:
  • 100 views sinds 30-01-2008
  • Reageer

  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 03-09 16:40
Ik heb in mijn vers ontwikkelde framework de scherm refresh middels een windows timer...

Op deze manier dus:
code:
1
SetTimer(hWnd, 1, 11, NULL);

De WM_TIMER wordt zo afgevangen in mijn windows procedure:
code:
1
2
3
4
5
case WM_TIMER:
    {
        engine->SceneUpdate(timer->GetElapsedSeconds(1));
        return 0;
    }

Dit betekent 90 refreshes per seconde. (maximaal natuurlijk) Want 1000 / 11 = 90(komma nog wat)

Nu vroeg ik me af of dit een goede architectuur was. Vaak zie je dat een GL rendering rechtstreeks in de messageloop wordt gekwakt,
[nu volgt een stukje onzin ben ik inmiddels achter]
terwijl ik op mijn manier dus tijdens het renderen alweer andere messages ga afhandelen. (behalve de WM_TIMER messages, want zolang er daarvan 1 in de windows procedure zit, gaat windows niet een nieuwe WM_TIMER afhandelen)
[einde onzin]

Nu denk je misschien: wat dan als je meer WM_TIMER messages genereert dan je message rij lang is? Nou, leuke is dat er in je message rij maximaal 1 WM_TIMER gezet wordt door windows.

Het is wel grappig, als ik in plaats van iedere 11 miliseconden iedere 10 miliseconden een WM_TIMER genereer, dan schiet mijn prosessor gebruik onevenredig de lucht in. Waarschijnlijk zit op dit moment tussen 10 en 11 millis. De scheiding dat hij wel of niet al een WM_TIMER in de rij heeft.

Nogmaals, mijn vraag aan jullie, is dit een goede opzet of mis ik even iets?

edit:
Ik kan het ook zo doen:
code:
1
SetTimer(hWnd, 1, 11, engine->SceneUpdate);

Let op de laatste NULL is nu dus vervangen door mijn update functie.. tevens kan ik nu de WM_TIMER uit mijn winproc slopen. De default windows procedure regelt het namelijk nu voor me.

Ik ga het nog een keer in een thread doen, mits dat nuttig blijkt. Ik weet niet hoe de overhead zich verhoudt tot de performance. Als je je rendering namelijk als een thread gaat doen, dan moet je je engine opzetten als een statemachine die constant op nieuw gerenderd wordt. Nu denk je what the fuck? Een beetje programmeur weet dat je je display kan bufferen, enne buffer om weer te geven, het andere om op te tekenen. Ben je klaar met tekenen, hup buffer switch.

Dit kan dus ook met je openGL engine... Twee instanties. Eentje die gerenderd wordt, de ander waarin je alle states update. Klaar met updaten, switchen die hap. Verhaal van voren af aan.

States zijn zaken als: lokatie, rotatie etc van objecten, health statusen. Licht posities... kortom alles wat een variabele waarde heeft.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 08:34

.oisyn

Moderator Devschuur®

Demotivational Speaker

.edit: hier stond een hoop onzin die je zelf waarschijnlijk ook al door had :)

maar iig, dit is in principe hetzelfde als SceneUpdate () aanroepen vanuit de messagepump, alleen wordt het nu aangeroepen vanuit de windowproc. Overigens handelt ie nu nog steeds niet andere messages af tijdens je scene update, terwijl je zegt van wel

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 03-09 16:40
Op donderdag 11 oktober 2001 00:51 schreef OiSyN het volgende:
.edit: hier stond een hoop onzin die je zelf waarschijnlijk ook al door had :)

maar iig, dit is in principe hetzelfde als SceneUpdate () aanroepen vanuit de messagepump, alleen wordt het nu aangeroepen vanuit de windowproc. Overigens handelt ie nu nog steeds niet andere messages af tijdens je scene update, terwijl je zegt van wel
Dat is dan mijn fout :o Maar op zich is dit dus een uitstekende manier. Of? hetvoordeel dat ik aan deze opzet zie is dat de implementatie die ik op dit moment heb, slechts 30 procent CPU gebruikt terwijl een ongelimiteerde aanroep van de render routine altijd 100% pakt. Terwijl het in frames op mijn systeem slecht 5 scheelt. En als ik ipv. elke 11 miliseconden iedere 8 milliseconden refresh dan zit ie ook aan 100% en zelfs 1 frame per seconde meer.

Oh ja, en dat verhaal over de rendering in een thread proppen, heeft dat zin of niet? Enig idee daarover?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 08:34

.oisyn

Moderator Devschuur®

Demotivational Speaker

in een andere thread zou ik niet doen, zeker omdat je dan ook meerdere states moet bijhouden zoals je zelf al aangaf. Het kunnen processen van messages is in een 3d engine totaal niet van belang, de enige zijn eigenlijk keyboard en mouse messages (die trouwens ook via directInput kunnen natuurlijk), maar die gebruik je toch pas in de volgende frame, dus die kunnen ook wel gewoon in de messagequeue blijven wachten tot ze nodig zijn.

Overigens zie ik niet in waarom je in een 3d-engine zou willen dat ie niet de volledige processorcapaciteiten pakt... Dat is meer bedoeld voor programma's tijdens multitasken en background processes, wat je in een 3d-engine totaal niet hebt :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

die timer kan niet zo fine grained zijn. Je moet de system ticker values gebruiken.

Zie http://www.demogl.com/sourcecode.asp voor de sourcecode van DemoGL (C/C++), het OpenGL framework dat ik een tijdje geleden gemaakt heb. Daar zit o.a. het timer gebeuren in. Zie de startup, kernel en demodat files voor meer details omtrent de tickervalues, hoe de dingen te timen, hoe alles af te handelen etc.

Succes. :)

Verwijderd

Op donderdag 11 oktober 2001 01:10 schreef The - DDD het volgende:
Dat is dan mijn fout :o Maar op zich is dit dus een uitstekende manier. Of? hetvoordeel dat ik aan deze opzet zie is dat de implementatie die ik op dit moment heb, slechts 30 procent CPU gebruikt terwijl een ongelimiteerde aanroep van de render routine altijd 100% pakt.
Dit is een illusie. Je engine wil toch full framerate lopen of niet? -> je zit dan aan een timerloop vast die de system ticker pollt. Wat je wel kunt doen, bv bij VSYNC enabled rendering op een snelle bak, is dat je je thread sleept voor een x aantal ms. Dit kun je uitrekenen mbv de executietijden van je frames en het aantal fps.
Terwijl het in frames op mijn systeem slecht 5 scheelt. En als ik ipv. elke 11 miliseconden iedere 8 milliseconden refresh dan zit ie ook aan 100% en zelfs 1 frame per seconde meer.
Deze SetTimer overspoelt je queue met WM_TIMER messages. Been there, done that. de MSDN zegt ook dat je voor high speed apps en timers met kleine waardes, je de system ticker moet pakken, niet die timer.
Oh ja, en dat verhaal over de rendering in een thread proppen, heeft dat zin of niet? Enig idee daarover?
Multithreaded rendering in OpenGL in win32 is wat vervelend. De rendercontext die gecreeerd is in thread X is niet valid in thread Y. Dit komt omdat per thread een aparte DC wordt afgegeven voor een window (logisch, zodoende is er een threadlocalstorage in de window structures). Creeer je dus je window in je main thread, ga je je textures uploaden daar en ga je daarna je geometry renderen in de andere thread, dan heb je geen textures.

Multithreaded rendering is ook alleen nuttig indien je 2 of meer CPU's hebt. Op een 1 CPU bak heb je alleen maar overhead, er gebeurt immers niets parallel. Wat je veelal hebt is dat je een thread (de mainthread) alles laat renderen en een serie workerthreads daar af en toe info naar sturen. Bv zo krijg je een interactive console, die info rendert wat wordt gelogd door workerthreads.

multithreaded rendering op 2CPU's kan alleen sneller zijn als je bv de ene CPU vertex/element arrays laat klaarzetten die de andere naar de kaart pompt. Je snapt het al, dat kan ook niet parallel voor hetzelfde frame want dan staat de een nog steeds op de ander te wachten, maar moet je om het frame doen (CPU 1 ragt de vertex/element arrays naar de kaart van frame N, CPU 2 berekent / vult arrays voor frame N+1). Carmack heeft hier veel tests mee gedaan (heeft in zn .plan gestaan, de results daarvan), en hij kreeg nauwelijks snelheidswinst uit het inzetten van die extra cpu in q3a.

  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 03-09 16:40
Op donderdag 11 oktober 2001 10:17 schreef Otis het volgende:
die timer kan niet zo fine grained zijn. Je moet de system ticker values gebruiken.

Zie http://www.demogl.com/sourcecode.asp voor de sourcecode van DemoGL (C/C++), het OpenGL framework dat ik een tijdje geleden gemaakt heb. Daar zit o.a. het timer gebeuren in. Zie de startup, kernel en demodat files voor meer details omtrent de tickervalues, hoe de dingen te timen, hoe alles af te handelen etc.

Succes. :)
Om te bepalen wat het verschil in tijd is tussen de scene refreshes gebruik ik een de hardware high resolution timer. En niet de WM_TIMER messages zelf...

Als ik dus bijvoorbeeld slechts 2 WM_TIMER messages per seconden genereer is de netto rotatie (bijvoorbeeld) gelijk aan die wanneer 100 WM_TIMER messages afgeef per seconde.

Maar in principe maakt het toch niet uit of ik de render loop alsmaar aanroep met een timer bericht, of mis ik nu iets. Stel dat ik het wel netjes windows wil houden (want dat is wel een doelstelling die ik heb). Dan moet ik dus in mijn winmain een rendering thread starten die zsm. loopt. In die loop handel ik alle input af. Zodra ik een input heb die aangeeft dat de boel bijvoorbeeld gestopt moet worden, geef ik een message naar mijn hoofd app. Die zet een bool of false zodat de rendering en input polling stopt. Na mijn render loop in mijn extra thread post ik dan een WM_CLOSE of WM_DESTROY. Zodat mijn winproc weet dat ie de boel af kan breken en netjes sluiten. Zodoende hou ik het daadwerkelijke applicatie management (inweze alleen het starten, instantieren objecten, deleten objecten en sluiten) in mijn windows procedure.
Als ik dan ook de render thread max prioriteit geef en de winMain thread zo min mogelijk, dan gaat alles precies zoals ik wil. De rendering gaat zo snel mogelijk. Maar de WinMain is degene die als enige het vermogen heeft omzichzelf te killen. Zodoende kan mijn app van buitenaf ook makkelijker gekilled worden. Een WM_DESTROY of iets dergelijks in de message rij gooien van mijn app en klaar alles wordt netjes afgesloten.

Enne, ik ga die demoGL source is een beetje uitpluizen, altijd interresant. En handig om nieuwe inzichten te verwerven.
Pagina: 1