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

Sync CPU with GPU

Started by theahnfahn Dec 20, 2004 at 10:05 PM 4 replies 700+ views
Original Post
theahnfahn
theahnfahn
*Update - I believe I've solved the problem, read down a few posts* I've come to a dead end on this one and this post is a last resort. I know this topic has been posted before but the proposed solutions to my problem don't work. My problem is that the cursor in my game seems to lag. I move my mouse and then the display shows the mouse moving at a later point in time. If I do "ShowCursor( true )" the system cursor is obviously where it should be with my bitmap cursor following far behind. Here is how I've tried to fix this problem. 1) I'm calling GetCursorPos( &cursor ) one line prior to the draw call of the cursor. 2) My main loop looks like the following. NewFrame() returns TRUE if 1.0/FPS has elapsed since the last frame. while( msg.message != WM_QUIT ) { if( PeekMessage( &msg, NULL, NULL, NULL, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else { if( NewFrame() ) ...Do Game Related Stuff... } } Now, having done the above two things I'm still seeing horrible cursor lag. Setting FPS to some rediculous value like 700 produces extreme lag whereas a FPS of 60 only lags the cursor a little. From the reading I've done it seems my application is GPU-limited, my CPU is calling Present more times than it should, several frames are getting buffered, and the result is mouse lag. Am I correct here? I'd like to have a not-so-laggy cursor at 60+ FPS. Ok, now to my current situation. I've read that using LockRect will allow you to test for D3DERR_WASSTILLDRAWING, and to sync the CPU with the GPU we shouldn't render until the system is done drawing. I've tried this approach and I simply can't get it to work. I've come to the conclusion that my LockRect call NEVER returns D3DERR_WASSTILLDRAWING, even if I remove the "if( NewFrame() )" condition in my main loop. What gives? Here is my LockRect code, if someone could please help me out I'd appreciate it. Render() { if( !StillDrawing() ) { device->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA( 0, 0, 0, 0 ), 1.0f, 0 ); ...Draw Game-Related Stuff... device->Present( NULL, NULL, NULL, NULL ); } } BOOL StillDrawing() { LPDIRECT3DSURFACE9 s; device->CreateOffscreenPlainSurface( 1, 1, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &s, NULL ); D3DLOCKED_RECT r; return ( s->LockRect( &r, 0, D3DLOCK_DONOTWAIT ) == D3DERR_WASSTILLDRAWING ); } [Edited by - theahnfahn on December 21, 2004 2:39:41 AM]
peter_b
peter_b
It is not just simply that, that you are dooing too little in your main loop? Doing too little work will hog the system and result in mouse cursor and overall system lag.

For instance, what happens if you do:

for(;;)
;


most likely it will bog down the application and even lag the rest of the system aswell, i dont know why this is, it must have something to do with windows getting bad at distributing processor time between the application and the rest of the system when so many simple instructions are preformed or something, i have no idea.

Anyhow i remember have this problem when i rewrote my game engine once, and before i had added anything to the main loop but the fps counter, it lagged terribly alot. Then it just went away when some work became avalible.
Shields up! Rrrrred alert!
IndyJones
IndyJones
Your stillDrawing() function is leaking memory.
You forget to unlock() and release() the surface you'r creating.
theahnfahn
theahnfahn
Well you see "doing too little" shouldn't negatively effect your application, now should it? My game is currently very simple and it doesn't require a whole lot from the CPU. Furthermore, your game may run fine now but let's suppose you upgrade your processor. Perhaps now your game will start to lose sync between the CPU and GPU again.

Back to my topic. I think I found a solution. After I've done all the CPU work I want to do in my frame and before I render I wait until StillDrawing() is FALSE. I corrected the structure of my Render() loop and recoded StillDrawing() and now my cursor is only one frame off of the system cursor at all times. Framerate is smooth too. I don't know if this is the ideal solution but it works for me.

	VOID Render()	{		while( StillDrawing() ) {}		device->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA( 0, 0, 0, 0 ), 1.0f, 0 );		if( SUCCEEDED( device->BeginScene() ) )		{			device->EndScene();		}		device->Present( NULL, NULL, NULL, NULL );	}	BOOL StillDrawing()	{		LPDIRECT3DSURFACE9 s;		device->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &s );		D3DLOCKED_RECT r;		HRESULT hr = s->LockRect( &r, 0, D3DLOCK_DONOTWAIT );		s->UnlockRect();		s->Release();		return ( hr == D3DERR_WASSTILLDRAWING );	}


Oh, thanks for the note on the mem leak. Sheesh...
theahnfahn
theahnfahn
The problem is that a HIGHER game framerate is causing more render calls than my GPU can handle so these calls are being buffered. When my cursor is appearing on the screen 4 frames too late it appears lagged.

I'm using QueryPerformanceCounter to measure the elapsed time between frames in my game. I currently have FPS set at 100. This is game frames, not render frames.

Topic Locked

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

Sign in to reply to this topic.