Changeset - r24876:e68a991d2383
[Not reviewed]
master
0 2 0
Michael Lutz - 3 years ago 2021-01-16 15:58:48
michi@icosahedron.de
Codechange: [Win32] Move GDI specific drawing code into the GDI video driver class.
2 files changed with 142 insertions and 133 deletions:
0 comments (0 inline, 0 general)
src/video/win32_v.cpp
Show inline comments
 
@@ -182,23 +182,6 @@ static uint MapWindowsKey(uint sym)
 
	return key;
 
}
 

	
 
static bool AllocateDibSection(int w, int h, bool force = false);
 

	
 
static void ClientSizeChanged(int w, int h)
 
{
 
	/* allocate new dib section of the new size */
 
	if (AllocateDibSection(w, h)) {
 
		/* mark all palette colours dirty */
 
		_cur_palette.first_dirty = 0;
 
		_cur_palette.count_dirty = 256;
 
		_local_palette = _cur_palette;
 

	
 
		BlitterFactory::GetCurrentBlitter()->PostResize();
 

	
 
		GameSizeChanged();
 
	}
 
}
 

	
 
#ifdef _DEBUG
 
/* Keep this function here..
 
 * It allows you to redraw the screen from within the MSVC debugger */
 
@@ -327,69 +310,6 @@ bool VideoDriver_Win32Base::MakeWindow(b
 
	return true; // the request succeeded
 
}
 

	
 
/** Do palette animation and blit to the window. */
 
void VideoDriver_Win32Base::Paint()
 
{
 
	PerformanceMeasurer framerate(PFE_VIDEO);
 

	
 
	if (IsEmptyRect(_dirty_rect)) return;
 

	
 
	HDC dc = GetDC(_wnd.main_wnd);
 
	HDC dc2 = CreateCompatibleDC(dc);
 

	
 
	HBITMAP old_bmp = (HBITMAP)SelectObject(dc2, _wnd.dib_sect);
 
	HPALETTE old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE);
 

	
 
	if (_cur_palette.count_dirty != 0) {
 
		Blitter *blitter = BlitterFactory::GetCurrentBlitter();
 

	
 
		switch (blitter->UsePaletteAnimation()) {
 
			case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND:
 
				UpdatePalette(dc2, _local_palette.first_dirty, _local_palette.count_dirty);
 
				break;
 

	
 
			case Blitter::PALETTE_ANIMATION_BLITTER:
 
				blitter->PaletteAnimate(_local_palette);
 
				break;
 

	
 
			case Blitter::PALETTE_ANIMATION_NONE:
 
				break;
 

	
 
			default:
 
				NOT_REACHED();
 
		}
 
		_cur_palette.count_dirty = 0;
 
	}
 

	
 
	BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY);
 
	SelectPalette(dc, old_palette, TRUE);
 
	SelectObject(dc2, old_bmp);
 
	DeleteDC(dc2);
 

	
 
	ReleaseDC(_wnd.main_wnd, dc);
 

	
 
	_dirty_rect = {};
 
}
 

	
 
void VideoDriver_Win32Base::PaintThread()
 
{
 
	/* First tell the main thread we're started */
 
	std::unique_lock<std::recursive_mutex> lock(*_draw_mutex);
 
	_draw_signal->notify_one();
 

	
 
	/* Now wait for the first thing to draw! */
 
	_draw_signal->wait(*_draw_mutex);
 

	
 
	while (_draw_continue) {
 
		this->Paint();
 

	
 
		/* Flush GDI buffer to ensure drawing here doesn't conflict with any GDI usage in the main WndProc. */
 
		GdiFlush();
 

	
 
		_draw_signal->wait(*_draw_mutex);
 
	}
 
}
 

	
 
/* static */ void VideoDriver_Win32Base::PaintThreadThunk(VideoDriver_Win32Base *drv)
 
{
 
	drv->PaintThread();
 
@@ -622,18 +542,9 @@ LRESULT CALLBACK WndProcGdi(HWND hwnd, U
 
			if ((HWND)wParam == hwnd) return 0;
 
			FALLTHROUGH;
 

	
 
		case WM_QUERYNEWPALETTE: {
 
			HDC hDC = GetWindowDC(hwnd);
 
			HPALETTE hOldPalette = SelectPalette(hDC, _wnd.gdi_palette, FALSE);
 
			UINT nChanged = RealizePalette(hDC);
 

	
 
			SelectPalette(hDC, hOldPalette, TRUE);
 
			ReleaseDC(hwnd, hDC);
 
			if (nChanged != 0) {
 
				video_driver->MakeDirty(0, 0, _screen.width, _screen.height);
 
			}
 
		case WM_QUERYNEWPALETTE:
 
			video_driver->PaletteChanged(hwnd);
 
			return 0;
 
		}
 

	
 
		case WM_CLOSE:
 
			HandleExitGameRequest();
 
@@ -839,7 +750,7 @@ LRESULT CALLBACK WndProcGdi(HWND hwnd, U
 
				 * switched to fullscreen from a maximized state */
 
				_window_maximize = (wParam == SIZE_MAXIMIZED || (_window_maximize && _fullscreen));
 
				if (_window_maximize || _fullscreen) _bck_resolution = _cur_resolution;
 
				ClientSizeChanged(LOWORD(lParam), HIWORD(lParam));
 
				video_driver->ClientSizeChanged(LOWORD(lParam), HIWORD(lParam));
 
			}
 
			return 0;
 

	
 
@@ -978,43 +889,6 @@ static void RegisterWndClass()
 
	if (!RegisterClass(&wnd)) usererror("RegisterClass failed");
 
}
 

	
 
static bool AllocateDibSection(int w, int h, bool force)
 
{
 
	BITMAPINFO *bi;
 
	HDC dc;
 
	uint bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
 

	
 
	w = std::max(w, 64);
 
	h = std::max(h, 64);
 

	
 
	if (!force && w == _screen.width && h == _screen.height) return false;
 

	
 
	bi = (BITMAPINFO*)alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);
 
	memset(bi, 0, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);
 
	bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 

	
 
	bi->bmiHeader.biWidth = _wnd.width = w;
 
	bi->bmiHeader.biHeight = -(_wnd.height = h);
 

	
 
	bi->bmiHeader.biPlanes = 1;
 
	bi->bmiHeader.biBitCount = bpp;
 
	bi->bmiHeader.biCompression = BI_RGB;
 

	
 
	if (_wnd.dib_sect) DeleteObject(_wnd.dib_sect);
 

	
 
	dc = GetDC(0);
 
	_wnd.dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID**)&_wnd.buffer_bits, nullptr, 0);
 
	if (_wnd.dib_sect == nullptr) usererror("CreateDIBSection failed");
 
	ReleaseDC(0, dc);
 

	
 
	_screen.width = w;
 
	_screen.pitch = (bpp == 8) ? Align(w, 4) : w;
 
	_screen.height = h;
 
	_screen.dst_ptr = _wnd.buffer_bits;
 

	
 
	return true;
 
}
 

	
 
static const Dimension default_resolutions[] = {
 
	{  640,  480 },
 
	{  800,  600 },
 
@@ -1183,6 +1057,21 @@ void VideoDriver_Win32Base::MainLoop()
 
	}
 
}
 

	
 
void VideoDriver_Win32Base::ClientSizeChanged(int w, int h)
 
{
 
	/* Allocate backing store of the new size. */
 
	if (this->AllocateBackingStore(w, h)) {
 
		/* Mark all palette colours dirty. */
 
		_cur_palette.first_dirty = 0;
 
		_cur_palette.count_dirty = 256;
 
		_local_palette = _cur_palette;
 

	
 
		BlitterFactory::GetCurrentBlitter()->PostResize();
 

	
 
		GameSizeChanged();
 
	}
 
}
 

	
 
bool VideoDriver_Win32Base::ChangeResolution(int w, int h)
 
{
 
	std::unique_lock<std::recursive_mutex> lock;
 
@@ -1303,7 +1192,7 @@ const char *VideoDriver_Win32GDI::Start(
 
	_wnd.width_org = _cur_resolution.width;
 
	_wnd.height_org = _cur_resolution.height;
 

	
 
	AllocateDibSection(_cur_resolution.width, _cur_resolution.height);
 
	this->AllocateBackingStore(_cur_resolution.width, _cur_resolution.height);
 
	this->MakeWindow(_fullscreen);
 

	
 
	MarkWholeScreenDirty();
 
@@ -1323,8 +1212,116 @@ void VideoDriver_Win32GDI::Stop()
 
	MyShowCursor(true);
 
}
 

	
 
bool VideoDriver_Win32GDI::AllocateBackingStore(int w, int h, bool force)
 
{
 
	uint bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
 

	
 
	w = std::max(w, 64);
 
	h = std::max(h, 64);
 

	
 
	if (!force && w == _screen.width && h == _screen.height) return false;
 

	
 
	BITMAPINFO *bi = (BITMAPINFO *)alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);
 
	memset(bi, 0, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);
 
	bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 

	
 
	bi->bmiHeader.biWidth = _wnd.width = w;
 
	bi->bmiHeader.biHeight = -(_wnd.height = h);
 

	
 
	bi->bmiHeader.biPlanes = 1;
 
	bi->bmiHeader.biBitCount = bpp;
 
	bi->bmiHeader.biCompression = BI_RGB;
 

	
 
	if (_wnd.dib_sect) DeleteObject(_wnd.dib_sect);
 

	
 
	HDC dc = GetDC(0);
 
	_wnd.dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID **)&_wnd.buffer_bits, nullptr, 0);
 
	if (_wnd.dib_sect == nullptr) usererror("CreateDIBSection failed");
 
	ReleaseDC(0, dc);
 

	
 
	_screen.width = w;
 
	_screen.pitch = (bpp == 8) ? Align(w, 4) : w;
 
	_screen.height = h;
 
	_screen.dst_ptr = _wnd.buffer_bits;
 

	
 
	return true;
 
}
 

	
 
bool VideoDriver_Win32GDI::AfterBlitterChange()
 
{
 
	assert(BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 0);
 
	return AllocateDibSection(_screen.width, _screen.height, true) && this->MakeWindow(_fullscreen);
 
	return this->AllocateBackingStore(_screen.width, _screen.height, true) && this->MakeWindow(_fullscreen);
 
}
 

	
 
void VideoDriver_Win32GDI::PaletteChanged(HWND hWnd)
 
{
 
	HDC hDC = GetWindowDC(hWnd);
 
	HPALETTE hOldPalette = SelectPalette(hDC, _wnd.gdi_palette, FALSE);
 
	UINT nChanged = RealizePalette(hDC);
 

	
 
	SelectPalette(hDC, hOldPalette, TRUE);
 
	ReleaseDC(hWnd, hDC);
 
	if (nChanged != 0) this->MakeDirty(0, 0, _screen.width, _screen.height);
 
}
 

	
 
void VideoDriver_Win32GDI::Paint()
 
{
 
	PerformanceMeasurer framerate(PFE_VIDEO);
 

	
 
	if (IsEmptyRect(_dirty_rect)) return;
 

	
 
	HDC dc = GetDC(_wnd.main_wnd);
 
	HDC dc2 = CreateCompatibleDC(dc);
 

	
 
	HBITMAP old_bmp = (HBITMAP)SelectObject(dc2, _wnd.dib_sect);
 
	HPALETTE old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE);
 

	
 
	if (_cur_palette.count_dirty != 0) {
 
		Blitter *blitter = BlitterFactory::GetCurrentBlitter();
 

	
 
		switch (blitter->UsePaletteAnimation()) {
 
			case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND:
 
				UpdatePalette(dc2, _local_palette.first_dirty, _local_palette.count_dirty);
 
				break;
 

	
 
			case Blitter::PALETTE_ANIMATION_BLITTER:
 
				blitter->PaletteAnimate(_local_palette);
 
				break;
 

	
 
			case Blitter::PALETTE_ANIMATION_NONE:
 
				break;
 

	
 
			default:
 
				NOT_REACHED();
 
		}
 
		_cur_palette.count_dirty = 0;
 
	}
 

	
 
	BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY);
 
	SelectPalette(dc, old_palette, TRUE);
 
	SelectObject(dc2, old_bmp);
 
	DeleteDC(dc2);
 

	
 
	ReleaseDC(_wnd.main_wnd, dc);
 

	
 
	_dirty_rect = {};
 
}
 

	
 
void VideoDriver_Win32GDI::PaintThread()
 
{
 
	/* First tell the main thread we're started */
 
	std::unique_lock<std::recursive_mutex> lock(*_draw_mutex);
 
	_draw_signal->notify_one();
 

	
 
	/* Now wait for the first thing to draw! */
 
	_draw_signal->wait(*_draw_mutex);
 

	
 
	while (_draw_continue) {
 
		this->Paint();
 

	
 
		/* Flush GDI buffer to ensure drawing here doesn't conflict with any GDI usage in the main WndProc. */
 
		GdiFlush();
 

	
 
		_draw_signal->wait(*_draw_mutex);
 
	}
 
}
src/video/win32_v.h
Show inline comments
 
@@ -37,15 +37,20 @@ protected:
 
	void InputLoop() override;
 
	bool LockVideoBuffer() override;
 
	void UnlockVideoBuffer() override;
 
	void Paint() override;
 
	void PaintThread() override;
 
	void CheckPaletteAnim() override;
 

	
 
	bool MakeWindow(bool full_screen);
 

	
 
	/** (Re-)create the backing store. */
 
	virtual bool AllocateBackingStore(int w, int h, bool force = false) = 0;
 
	/** Palette of the window has changed. */
 
	virtual void PaletteChanged(HWND hWnd) = 0;
 

	
 
private:
 
	std::unique_lock<std::recursive_mutex> draw_lock;
 

	
 
	void ClientSizeChanged(int w, int h);
 

	
 
	static void PaintThreadThunk(VideoDriver_Win32Base *drv);
 

	
 
	friend LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
 
@@ -60,6 +65,13 @@ public:
 
	bool AfterBlitterChange() override;
 

	
 
	const char *GetName() const override { return "win32"; }
 

	
 
protected:
 
	void Paint() override;
 
	void PaintThread() override;
 

	
 
	bool AllocateBackingStore(int w, int h, bool force = false) override;
 
	void PaletteChanged(HWND hWnd) override;
 
};
 

	
 
/** The factory for Windows' video driver. */
0 comments (0 inline, 0 general)