Frame Rates for beginners!

Started by
11 comments, last by Beginner_Joe 15 years, 9 months ago
Hi everyone! I recently decided to start learning C++, specifically for game programming, and have had some great fun working through various tutorials, and reading posts on this forum (you all seem very knowledgeable and helpful!!). I have a question which is probably really stupid, but I hope you don't mind me asking: It's a bit tricky to explain, but I'll do my best.... I've been using the tutorials from http://www.directxtutorial.com/ which seem to be quite well used, and everything is working as expected. However my quesiton is to do with frame rates; let's say the main code is as follows (I won't put the whole thing here): // include the basic windows header files and the Direct3D header file #include <windows.h> #include <windowsx.h> #include <d3d9.h> #include <d3dx9.h> // define the screen resolution and keyboard macros #define SCREEN_WIDTH 640 #define SCREEN_HEIGHT 480 #define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0) #define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1) // include the Direct3D Library files #pragma comment (lib, "d3d9.lib") #pragma comment (lib, "d3dx9.lib") // global declarations LPDIRECT3D9 d3d; // the pointer to our Direct3D interface LPDIRECT3DDEVICE9 d3ddev; // the pointer to the device class LPDIRECT3DVERTEXBUFFER9 t_buffer = NULL; // the pointer to the vertex buffer // function prototypes void initD3D(HWND hWnd); // sets up and initializes Direct3D void render_frame(void); // renders a single frame void cleanD3D(void); // closes Direct3D and releases memory void init_graphics(void); // 3D declarations struct CUSTOMVERTEX {FLOAT X, Y, Z; DWORD COLOR;}; #define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE) // the WindowProc function prototype LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); // the entry point for any Windows program int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HWND hWnd; WNDCLASSEX wc; ZeroMemory(&wc, sizeof(WNDCLASSEX)); wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)WindowProc; wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpszClassName = L"WindowClass"; RegisterClassEx(&wc); hWnd = CreateWindowEx(NULL, L"WindowClass", L"Our Direct3D Program", WS_EX_TOPMOST | WS_POPUP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInstance, NULL); ShowWindow(hWnd, nCmdShow); // set up and initialize Direct3D initD3D(hWnd); // enter the main loop: MSG msg; while(TRUE) { DWORD starting_point = GetTickCount(); if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } render_frame(); // check the 'escape' key if(KEY_DOWN(VK_ESCAPE)) PostMessage(hWnd, WM_DESTROY, 0, 0); while ((GetTickCount() - starting_point) < 25); } // clean up DirectX and COM cleanD3D(); return msg.wParam; } OK, so this bit: while ((GetTickCount() - starting_point) < 25); makes sure it only updates the frame once every 25ms or therebouts. So taking it out should mean that it updates as fast as the computer can handle. To this code I've added a basic framerate counter. So when I take out the 'limiter', it still only runs at about 100 frames per second. Now I know my PC plays some older games waaayyy faster than that, so the question I have is what in this code limits the frame rate? My guess is perhaps something to do with the way windows prioritises applications, or perhaps that's just the nature of DirectX? I'm sorry for such a silly quesiton, but any thoughts would be gratefully received. I guess 100fps is pretty much fast enough for anything, but I'm working on a pinball game with a bit of 'real world physics', and the faster the 'framerate' (or I guess you'd say main looprate) the more accurate my physics will be. Just to say I'm convinced it's not the limit of my PC, because a) the frame rate of some older games I have, and b) I've expanded the code to display multiple objects, with lodas of key inputs, text boxes etc., running at 1600x1200 and it still runs at the same framerate as when it is completely basic like above- ???!! Hope this makes sense? cheers, Joe
Advertisement
VSync ?
Thanks for that ToohrVyk - that's really quite interesting.

If that is what's limiting my 'frame rate', I guess I need to introduce something to my code that does this:

1) Turns off 'Vsync'
2) Executes the main loop as often as it possibly can
but
3) Only uses render_frame() at the correct time

i.e. the main loop runs v fast (thus the physics becomes more accurate), but the rendering only happens say 85 times per second (if that's my refresh rate) to ensure there's no tearing.

This sounds really good - I'll research how to do this;

Out of interest does anyone else think it's a different issue?

thanks again!

Joe

Are you using GetTickCount to measure fps? On average it's only accurate to ~10ms, which means it can't measure framerates > 100 or so. You'll have to use a different timing function, like QueryPerformanceCounter/QueryPerformanceFrequency or timeGetTime.
Also one other thing...

This line here:
PostMessage(hWnd, WM_DESTROY, 0, 0);


It's not really a big deal for a simple program with one window, but this isn't how you destroy a window. You use the DestroyWindow function. That function actually cleans up resources created for the window, which won't happen if you just send yourself a WM_DESTROY message.
Thanks MJP,

yes, I measure the 'loop rate' using QueryPerformanceCounter/QueryPerformanceFrequency , and (I should have posted that code here, but I'm at work at the moment!) just before the render_frame() I use counter++, and work out the fps (or lps!) by comparing the counter int to the results of the 'realtime' counter above.

In fact, I have gone as far as displaying how many microseconds each loop takes - its about 13,333 - and as mentioned doesn't change significantly no matter how many polys & objects I throw at it; this is why I reckon something is 'holding up' each loop?

perhaps I'm just being obsessive!

thanks for all the help so far,

cheers,

joe
Quote:Original post by Beginner_Joe
1) Turns off 'Vsync'
2) Executes the main loop as often as it possibly can
but
3) Only uses render_frame() at the correct time


This is a possibility. However, what's wrong with:

1) Gets the current time
2) Computes the world state for the current time
3) Renders the frame using the world state and with VSync

Regardless of VSync, you'll still get a framerate that's reasonable enough for collecting input, and you can avoid VSync problems entirely by using triple buffering if it really annoys you.

The physics loop doesn't have to run in real-time—it only has to run as if it happened in real-time.
Quote:Original post by Beginner_Joe
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

Is this still how C++ is taught? C++ has had const and inline functions since 1983 or something.
Thanks ToohrVyk that's of course a good point. Actually that's how my prog works at the moment (e.g. for the ball position it works out what the accel would be at the point in time the function is called, from that the velocity and from that the world position).

And in 99.9% of circumstances this is fine (although for collisions I 'back-engineer' to the time of collision, and update before and after etc.)

however in some circumstances I want to figure out changes smaller than the current delta ( approx 13ms),

Plus I'm thinking there must be a way to do it cos other progs I've used don't seem to have this 'limit' (i.e. played severance the other day and it runs at 400fps...!)

DevFred - I'm sure there are 100 better ways to do things than how I'm learning! let's just say the tutorials that I'm doing are about the right level for me (I did used to program the speccy in hex dumps, but I was 10 at the time, and for some reason things seemed easier then...?!!)

If you just want to disable VSYNC then, use D3DPRESENT_IMMEDIATE as the value for PresentationInterval in the D3DPRESENT_PARAMETERS struct you pass to CreateDevice.

This topic is closed to new replies.

Advertisement