Skip to main content
GameDev.net gamedev.net
🔒 Locked 🎮 Unity

peekmessage while vs if (main/game loop)

Started by cozzie Sep 29, 2016 at 12:18 PM 11 replies 7.1k views
Original Post
cozzie
cozzie

Hi all,

Can someone freshen up my memory on this one?

In my d3d9 engine I've Always had a main/ game loop like this:


	bool run = true;
	
	while(run)
	{
		_mainApp.mInput.UpdateKeys();
	
		while(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
			if(msg.message == WM_QUIT) run = false;
		}
		_mainApp.mTimer.Update();

Currently I'm starting from scratch with my new d3d11 engine, and during learning d3d11, I've found this other way:


	while(msg.message != WM_QUIT)
	{
		if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))			// WHILE ???
		{
            TranslateMessage( &msg );
            DispatchMessage( &msg );
		}
		else
        {	
			//mTimer.Tick();

			if(!mAppPaused )
			{
				CalculateFrameStats();
				UpdateScene(16.67f); //mTimer.DeltaTime());	
				DrawScene();
			}

Is there a performance penalty/ advantage on either one of them compared to the other?

Using 'if' from a 'simple viewpoint' sounds best, because you then only do something if there's a message. With 'while' it sounds like waiting till a message occurs.

Any input/ pointers are appreciated.

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me
vstrakh
vstrakh

Imagine you render scene with vsync turned on.

If you go with 'if' implementation, you will process single input event per rendered frame.

But there will be lots of events, especially when mouse moves. If you will process only one event, render frame, wait for 16ms (vsync on), then with simple mouse movement you will create some work for many seconds upfront. Scene update will lag to the point where app will become totally unresponsive.

So you must go with 'while' loop, processing all inputs before you start rendering.



With 'while' it sounds like waiting till a message occurs.

You don't wait for events with PeekMessage(), you would wait with GetMessage().

cozzie
cozzie
Thanks guys, clear. I can continue with my nice new engine :)
Will keep you posted
Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me
Norman Barrows
Norman Barrows
and during learning d3d11, I've found this other way:
Just in case vstrakh's answer isn't clear, first one is right, second one is wrong (it will process only one event per frame).

so, what does that tell you about the quality of the example dx11 code you're learning from? its obviously not real world code, nor has it ever been tested, otherwise they would have caught the fact that it doesn't even fricking work. i'm not saying all the code is BS, but keep your eyes peeled. example code tends to usually be about 90% correct, with the other 10% being whacked stuff like you found in that dx11 code.

caveat emptor, and you get what you pay for.

EDIT: its actually worse, because they didn't catch the error by inspection - which is entirely possible - and should have occurred before any testing, heck it should have been caught by inspection before they even compiled. does the tutorial you're using come with sample code? or just snippets? does the sample code compile at max warning level with no warning or errors? IE will it even compile, or is it just some person posting some "almost code" pseudocode on a website?

i've run into these issues even with supposedly high quality tutorials such as rastertek.

Norm Barrows Rockland Software Productions "Building PC games since 1989"</
cozzie
cozzie

@Norman barrows: the book (D3D11 Luna) focusses on learning, not performance.

So you're right about not wanting to adopt everything directly into say a d3d11 engine.

The resulting loop, all working fine:


int CAppl::Run()
{
	MSG msg = {0};
	mTimer.Reset();

	while(msg.message != WM_QUIT)
	{
		while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
            TranslateMessage(&msg);
            DispatchMessage(&msg);
		}

		mTimer.Tick();

		if(!mAppPaused )
		{
			CalculateFrameStats();
			UpdateScene(mTimer.DeltaTime());	
			DrawScene();
		}
		else
		{
			Sleep(100);
		}
    }
	return (int)msg.wParam;
}
Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me
21st Century Moose
21st Century Moose

@Norman barrows: the book (D3D11 Luna) focusses on learning, not performance.

I wouldn't consider that "performance"; I'd consider it "getting the basics right". Put it this way: if tutorial code that I expected to learn from was actually teaching me fundamental bad practices, I'd be mightily annoyed at the tutorial. I should demand no less of a professionally written book.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls. 
Kylotan
Kylotan

The resulting loop, all working fine


It won't work if you get a WM_QUIT message followed by some other message in the same frame. (That's why there was the run = false statement in the first version.)

Norman Barrows
Norman Barrows
the book (D3D11 Luna) focusses on learning, not performance.

it would seem it doesn't even focus on functioning correctly at all, much less performance.

personally i've always had the impression that Luna is one of these folks who translates DX docs into books for profit. IE "can't do, so they teach". Has the guy ever made a game?

strange that his works tend to be so well regarded when it would appear he can't even write a message loop correctly.

but enough perfectionism.

follow his code. anything that doesn't work, simply check it against a second source. that's what i always do. eventually between the various sources and your own knowledge, you'll get all the bits and pieces correct.

PS if a book doesn't come with full source that compiles and runs correctly straight out of the box, its a bad omen.

Norm Barrows Rockland Software Productions "Building PC games since 1989"</
cozzie
cozzie

@Kylotan: thanks, fixed that. See the result below.

@Norman: the book explicitly mentions that it's for learning purposes of d3d11, I don't believe things like this make the D3D11 book from Frank Luna less valuable. I believe lot's of people learned the d3d11 basics from that book.


int CAppl::Run()
{
	MSG msg = {0};
	mTimer.Reset();

	bool run = true;
	while(run)
	{
		while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
            TranslateMessage(&msg);
            DispatchMessage(&msg);
			if(msg.message == WM_QUIT) run = false;
		}

		mTimer.Tick();

		if(!mAppPaused )
		{
			CalculateFrameStats();
			UpdateScene(mTimer.DeltaTime());	
			if(!DrawScene())
			{
				MessageBox(NULL, err_render.c_str(), err_windowtext.c_str(), MB_ICONERROR);		
				return(int)msg.wParam;
			}
		}
		else
		{
			Sleep(100);
		}
    }
	return (int)msg.wParam;
}

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me
SimonForsman
SimonForsman

Imagine you render scene with vsync turned on.
If you go with 'if' implementation, you will process single input event per rendered frame.
But there will be lots of events, especially when mouse moves. If you will process only one event, render frame, wait for 16ms (vsync on), then with simple mouse movement you will create some work for many seconds upfront. Scene update will lag to the point where app will become totally unresponsive.
So you must go with 'while' loop, processing all inputs before you start rendering.


With 'while' it sounds like waiting till a message occurs.


You don't wait for events with PeekMessage(), you would wait with GetMessage().



The if version won't run any update or rendering logic unless peekmessage returns false so it should work properly.
All game and rendering code is inside the else block, it should even be a tiny bit faster since it only has to do the check for VM_QUIT (and not the extra assignment and checks for run like the while version does)
It also has the advantage of exiting almost immediately on a VM_QUIT, the while version will run through one update before exiting.
[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!
Khatharr
Khatharr

From an earlier project:


bool Window::update() {   //flush message queue, return true to continue, false to quit
  MSG msg;
  while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    if(msg.message == WM_QUIT) { return false; }
  }

  return true;
}

void Game::run() {
  timer.getDT(); //reset timer
  scene->update(0); //hack for setting initial entity positions (arg is DT)
  fadeIn();

  while(scene && window.update()) {
    input.ReadFrame();

    Scene* next = scene->update(timer.getDT());

    if(next == scene.get()) { //draw normally
      gfx.startDraw();
      scene->draw();
      gfx.endDraw();
    }
    else { //changed to new scene, so do fadey stuff
      fadeOut();

      scene.reset(next);
      if(!scene) { break; }
      scene->update(0);

      fadeIn();
    }

  }

  if(scene) { scene.reset(nullptr); } //this was a hack, but I can't remember the specifics
}

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
vstrakh
vstrakh



The if version won't run any update or rendering logic unless peekmessage returns false so it should work properly.

Ah, true. You're right. I've seen so many incorrect implementations, so just seeing 'if' caused immediate reaction.

Broken indentation also doesn't help reading code :)

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.