Sign in to follow this  

Fastest way to double buffer in Win32?

This topic is 474 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all

 

I am trying to make the simplest realtime raytracer possible that only renders spheres.

 

Before I implement the actual raytracing code, i want to make sure i have the fastest drawing and double buffering i can get out of C and win32. 

 

Below is a complete program that creates a 600x600 no resizable window, draws a square in the memory buffer and bitblts it to the screen. It also changes the position on a simple timer.

 

The tutorial that i got the code from said that it would be faster to create the Bitmap once as a global rather than create a new one each frame but every time i create the bit map either on creation or via a simple bool, the square doesnt move.

 

Also, are there any other tricks or techniques for faster double buffering?

 

Thanks for any help.

#include <windows.h>
#include <stdbool.h>

#define WNDCLASSNAME "wndclass"


//HDC hdc;
HWND hwnd;

HDC          hdcMem;
HBITMAP      hbmMem;
HANDLE       hOld;

PAINTSTRUCT  ps;
RECT		 r;
HDC          hdc;

const int ID_TIMER = 1;

bool quit = false;

int random = 0; random2 = 0;;
int ret;
int width;
int height;
int xx = 300;
int yy = 300;
bool firstTime = true;

//*=====================
//  The event handler
//*===================== 

LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	switch (msg)
	{
	case WM_CREATE:
		ret = SetTimer(hwnd, ID_TIMER, 5, NULL);
		if (ret == 0)
			MessageBox(hwnd, "Could not SetTimer()!", "Error", MB_OK | MB_ICONEXCLAMATION);

		GetClientRect(hwnd, &r);
		if (r.bottom == 0) {

			return;
		}
		width = r.right;
		height = r.bottom;

		break;
	case WM_TIMER:
		switch (wparam)
		{
		case 1:
			InvalidateRect(hwnd, NULL, FALSE);
			//UpdateWindow(hwnd);
			//ReleaseDC(hwnd, hdc);
			return 0;
		}
		break;
	case WM_ERASEBKGND:
		return 1;
	case WM_PAINT:
		

		// Get DC for window
		hdc = BeginPaint(hwnd, &ps);

		
		// Create an off-screen DC for double-buffering
		hdcMem = CreateCompatibleDC(hdc);

		//if (firstTime)
		{
			hbmMem = CreateCompatibleBitmap(hdc, width, height);
			firstTime = false;
		}

		hOld = SelectObject(hdcMem, hbmMem);

		random = rand() % 20 + (-9);
		random2 = rand() % 20 + (-9);

		xx += random;
		yy += random2;

		// Draw into hdcMem here
		for (int x = 0; x < 100; x++)
			for (int y = 0; y < 100; y++)
				SetPixel(hdcMem, x+xx, y+yy, RGB(255, 0, 0));

		// Transfer the off-screen DC to the screen
		BitBlt(hdc, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);

		// Free-up the off-screen DC
		SelectObject(hdcMem, hOld);
		DeleteObject(hbmMem);
		DeleteDC(hdcMem);

		EndPaint(hwnd, &ps);
		ReleaseDC(hwnd, hdc);
		return 0;
		break;
	case WM_CLOSE:
	{
		PostQuitMessage(0);
		KillTimer(hwnd, ID_TIMER);
		ReleaseDC(hwnd, hdc);
		break;
	}
	}
	return DefWindowProc(hwnd, msg, wparam, lparam);
}

//*=====================
//  WinMain
//*=====================

int WINAPI WinMain(HINSTANCE hinstance,
	HINSTANCE hprevinstance,
	LPSTR lpcmdline,
	int nshowcmd)
{
	MSG msg;
	WNDCLASSEX ex;

	ex.cbSize = sizeof(WNDCLASSEX);
	ex.style = CS_OWNDC;
	ex.lpfnWndProc = WinProc;
	ex.cbClsExtra = 0;
	ex.cbWndExtra = 0;
	ex.hInstance = hinstance;
	ex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	ex.hCursor = LoadCursor(NULL, IDC_ARROW);
	ex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	ex.lpszMenuName = NULL;
	ex.lpszClassName = WNDCLASSNAME;
	ex.hIconSm = NULL;

	RegisterClassEx(&ex);
	// Create the window 

	hwnd = CreateWindowEx(NULL,
		WNDCLASSNAME,
		L"Hello",
		WS_OVERLAPPEDWINDOW&~WS_THICKFRAME&~WS_MAXIMIZEBOX,
		200, 0,
		600, 600,
		NULL,
		NULL,
		hinstance,
		NULL);

	ShowWindow(hwnd, SW_SHOW);
	UpdateWindow(hwnd);

	// The message loop
	//HDC hdc = GetDC(hwnd);

	while (!quit)
	{
		if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
				quit = true;
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		
	}

	
}

Share this post


Link to post
Share on other sites

A few things to note:

- The BitBlt should be in your main loop not in message handling under WM_PAINT.

- The bitmap should only be created once.

- Don't use SetPixel, get the address of the bitmap and write to it directly (use CreateDIBSection instead of CreateCompatibleBitmap)

 

If you do everything right you should only have the cost of one ram-to-vram memory copy per frame.

Share this post


Link to post
Share on other sites

This topic is 474 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this