mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-02-23 22:52:34 +01:00
byuu says: Changelog: - ruby/video: cleaned up Direct3D9 driver and fixed catastrophic memory leak - ruby/video: added fullscreen exclusive mode support to the Direct3D9 driver¹ - ruby/video: minor cosmetic code cleanups to various drivers - tomoko: added support to always allow input when in fullscreen exclusive mode - tomoko: fixed window to not remove resizability flag when exiting fullscreen mode ¹: I am assuming that exclusive mode will try to capture the primary monitor. I don't know what will happen in multi-monitor setups, however, as I don't use such a setup here. Also, I am using `D3DPRESENT_DISCARD` instead of `D3DPRESENT_FLIP`. I'm not sure if this will prove better or worse, but I've heard it will waste less memory, and having a BackBufferCount of 1 should still result in page flipping anyway. The difference is supposedly just that you can't rely on the back buffer being a valid copy of the previous frame like you can with FLIP. Lastly, if you want Vsync, you can edit the configuration file to enable that, and then turn off audio sync. Errata: "pause emulation when focus is lost" is not working with exclusive mode. I need to add a check to never auto-pause when in exclusive mode. Thanks to bun for catching that one.
104 lines
2.7 KiB
C++
104 lines
2.7 KiB
C++
#include <assert.h>
|
|
|
|
struct VideoGDI : Video {
|
|
~VideoGDI() { term(); }
|
|
|
|
struct Device {
|
|
HBITMAP bitmap = nullptr;
|
|
HDC dc = nullptr;
|
|
BITMAPINFO info = {};
|
|
} device;
|
|
|
|
struct Settings {
|
|
HWND handle = nullptr;
|
|
|
|
uint32_t* buffer = nullptr;
|
|
uint width = 0;
|
|
uint height = 0;
|
|
} settings;
|
|
|
|
auto cap(const string& name) -> bool {
|
|
if(name == Video::Handle) return true;
|
|
return false;
|
|
}
|
|
|
|
auto get(const string& name) -> any {
|
|
if(name == Video::Handle) return (uintptr_t)settings.handle;
|
|
return {};
|
|
}
|
|
|
|
auto set(const string& name, const any& value) -> bool {
|
|
if(name == Video::Handle && value.is<uintptr>()) {
|
|
settings.handle = (HWND)value.get<uintptr>();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool {
|
|
if(!settings.buffer || settings.width != width || settings.height != height) {
|
|
if(settings.buffer) {
|
|
delete[] settings.buffer;
|
|
DeleteObject(device.bitmap);
|
|
DeleteObject(device.dc);
|
|
}
|
|
settings.buffer = new uint32_t[width * height]();
|
|
settings.width = width;
|
|
settings.height = height;
|
|
|
|
HDC hdc = GetDC(settings.handle);
|
|
device.dc = CreateCompatibleDC(hdc);
|
|
assert(device.dc);
|
|
device.bitmap = CreateCompatibleBitmap(hdc, width, height);
|
|
assert(device.bitmap);
|
|
SelectObject(device.dc, device.bitmap);
|
|
ReleaseDC(settings.handle, hdc);
|
|
|
|
memory::fill(&device.info, sizeof(BITMAPINFO));
|
|
device.info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
device.info.bmiHeader.biWidth = width;
|
|
device.info.bmiHeader.biHeight = -height;
|
|
device.info.bmiHeader.biPlanes = 1;
|
|
device.info.bmiHeader.biBitCount = 32;
|
|
device.info.bmiHeader.biCompression = BI_RGB;
|
|
device.info.bmiHeader.biSizeImage = width * height * sizeof(uint32_t);
|
|
}
|
|
|
|
data = settings.buffer;
|
|
pitch = settings.width * sizeof(uint32_t);
|
|
return true;
|
|
}
|
|
|
|
auto unlock() -> void {}
|
|
|
|
auto clear() -> void {}
|
|
|
|
auto refresh() -> void {
|
|
RECT rc;
|
|
GetClientRect(settings.handle, &rc);
|
|
|
|
SetDIBits(device.dc, device.bitmap, 0, settings.height, (void*)settings.buffer, &device.info, DIB_RGB_COLORS);
|
|
HDC hdc = GetDC(settings.handle);
|
|
StretchBlt(hdc, rc.left, rc.top, rc.right, rc.bottom, device.dc, 0, 0, settings.width, settings.height, SRCCOPY);
|
|
ReleaseDC(settings.handle, hdc);
|
|
}
|
|
|
|
auto init() -> bool {
|
|
settings.width = 0;
|
|
settings.height = 0;
|
|
return true;
|
|
}
|
|
|
|
auto term() -> void {
|
|
if(settings.buffer) {
|
|
delete[] settings.buffer;
|
|
DeleteObject(device.bitmap);
|
|
DeleteDC(device.dc);
|
|
settings.buffer = nullptr;
|
|
device.bitmap = nullptr;
|
|
device.dc = nullptr;
|
|
}
|
|
}
|
|
};
|