2010-08-09 13:28:56 +00:00
|
|
|
#undef interface
|
|
|
|
#define interface struct
|
|
|
|
#include <d3d9.h>
|
|
|
|
#undef interface
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
static LRESULT CALLBACK VideoDirect3D_WindowProcedure(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
|
|
|
return DefWindowProc(hwnd, msg, wparam, lparam);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct VideoDirect3D : Video {
|
|
|
|
VideoDirect3D() {
|
|
|
|
POINT point = {0, 0};
|
|
|
|
HMONITOR monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY);
|
|
|
|
MONITORINFOEX information = {};
|
|
|
|
information.cbSize = sizeof(MONITORINFOEX);
|
|
|
|
GetMonitorInfo(monitor, &information);
|
|
|
|
monitorWidth = information.rcMonitor.right - information.rcMonitor.left;
|
|
|
|
monitorHeight = information.rcMonitor.bottom - information.rcMonitor.top;
|
|
|
|
|
|
|
|
WNDCLASS windowClass = {};
|
|
|
|
windowClass.cbClsExtra = 0;
|
|
|
|
windowClass.cbWndExtra = 0;
|
|
|
|
windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
|
|
|
windowClass.hCursor = LoadCursor(0, IDC_ARROW);
|
|
|
|
windowClass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
|
|
|
|
windowClass.hInstance = GetModuleHandle(0);
|
|
|
|
windowClass.lpfnWndProc = VideoDirect3D_WindowProcedure;
|
|
|
|
windowClass.lpszClassName = L"VideoDirect3D_Window";
|
|
|
|
windowClass.lpszMenuName = 0;
|
|
|
|
windowClass.style = CS_HREDRAW | CS_VREDRAW;
|
|
|
|
RegisterClass(&windowClass);
|
|
|
|
|
|
|
|
settings.exclusiveHandle = CreateWindowEx(WS_EX_TOPMOST, L"VideoDirect3D_Window", L"", WS_POPUP,
|
|
|
|
information.rcMonitor.left, information.rcMonitor.top, monitorWidth, monitorHeight,
|
|
|
|
nullptr, nullptr, GetModuleHandle(0), nullptr);
|
|
|
|
}
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
~VideoDirect3D() {
|
|
|
|
term();
|
|
|
|
DestroyWindow(settings.exclusiveHandle);
|
|
|
|
}
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
LPDIRECT3D9 context = nullptr;
|
|
|
|
LPDIRECT3DDEVICE9 device = nullptr;
|
|
|
|
LPDIRECT3DVERTEXBUFFER9 vertexBuffer = nullptr;
|
|
|
|
D3DPRESENT_PARAMETERS presentation = {};
|
|
|
|
D3DCAPS9 capabilities = {};
|
|
|
|
LPDIRECT3DTEXTURE9 texture = nullptr;
|
|
|
|
LPDIRECT3DSURFACE9 surface = nullptr;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2015-06-12 13:14:38 +00:00
|
|
|
bool lost = true;
|
2017-07-09 02:23:17 +00:00
|
|
|
uint windowWidth;
|
|
|
|
uint windowHeight;
|
|
|
|
uint textureWidth;
|
|
|
|
uint textureHeight;
|
|
|
|
uint monitorWidth;
|
|
|
|
uint monitorHeight;
|
|
|
|
|
|
|
|
struct Vertex {
|
|
|
|
float x, y, z, rhw; //screen coordinates
|
|
|
|
float u, v; //texture coordinates
|
2010-08-09 13:28:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct {
|
2017-07-09 02:23:17 +00:00
|
|
|
uint32_t textureUsage;
|
|
|
|
uint32_t texturePool;
|
|
|
|
uint32_t vertexUsage;
|
|
|
|
uint32_t vertexPool;
|
2010-08-09 13:28:56 +00:00
|
|
|
uint32_t filter;
|
|
|
|
} flags;
|
|
|
|
|
|
|
|
struct {
|
2017-07-09 02:23:17 +00:00
|
|
|
bool exclusive = false;
|
2015-06-12 13:14:38 +00:00
|
|
|
HWND handle = nullptr;
|
|
|
|
bool synchronize = false;
|
2017-07-09 02:23:17 +00:00
|
|
|
uint filter = Video::FilterLinear;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
HWND exclusiveHandle = nullptr;
|
|
|
|
uint width;
|
|
|
|
uint height;
|
2010-08-09 13:28:56 +00:00
|
|
|
} settings;
|
|
|
|
|
2015-06-12 13:14:38 +00:00
|
|
|
auto cap(const string& name) -> bool {
|
2017-07-09 02:23:17 +00:00
|
|
|
if(name == Video::Exclusive) return true;
|
2010-08-09 13:28:56 +00:00
|
|
|
if(name == Video::Handle) return true;
|
|
|
|
if(name == Video::Synchronize) return true;
|
|
|
|
if(name == Video::Filter) return true;
|
2013-04-09 13:31:46 +00:00
|
|
|
if(name == Video::Shader) return false;
|
2010-08-09 13:28:56 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-06-12 13:14:38 +00:00
|
|
|
auto get(const string& name) -> any {
|
2017-07-09 02:23:17 +00:00
|
|
|
if(name == Video::Exclusive) return settings.exclusive;
|
2010-08-09 13:28:56 +00:00
|
|
|
if(name == Video::Handle) return (uintptr_t)settings.handle;
|
|
|
|
if(name == Video::Synchronize) return settings.synchronize;
|
|
|
|
if(name == Video::Filter) return settings.filter;
|
2015-06-12 13:14:38 +00:00
|
|
|
return {};
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-06-12 13:14:38 +00:00
|
|
|
auto set(const string& name, const any& value) -> bool {
|
2017-07-09 02:23:17 +00:00
|
|
|
if(name == Video::Exclusive && value.is<bool>()) {
|
|
|
|
settings.exclusive = value.get<bool>();
|
|
|
|
if(context) init();
|
2010-08-09 13:28:56 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
if(name == Video::Handle && value.is<uintptr>()) {
|
|
|
|
settings.handle = (HWND)value.get<uintptr>();
|
2010-08-09 13:28:56 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
if(name == Video::Synchronize && value.is<bool>()) {
|
|
|
|
settings.synchronize = value.get<bool>();
|
2010-08-09 13:28:56 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
if(name == Video::Filter && value.is<uint>()) {
|
|
|
|
settings.filter = value.get<uint>();
|
|
|
|
if(context) updateFilter();
|
|
|
|
return true;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-06-12 13:14:38 +00:00
|
|
|
auto recover() -> bool {
|
2010-08-09 13:28:56 +00:00
|
|
|
if(!device) return false;
|
|
|
|
|
|
|
|
if(lost) {
|
2017-07-09 02:23:17 +00:00
|
|
|
if(vertexBuffer) { vertexBuffer->Release(); vertexBuffer = nullptr; }
|
|
|
|
if(surface) { surface->Release(); surface = nullptr; }
|
|
|
|
if(texture) { texture->Release(); texture = nullptr; }
|
2010-08-09 13:28:56 +00:00
|
|
|
if(device->Reset(&presentation) != D3D_OK) return false;
|
|
|
|
}
|
|
|
|
lost = false;
|
|
|
|
|
|
|
|
device->SetDialogBoxMode(false);
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
|
2010-08-09 13:28:56 +00:00
|
|
|
device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
|
|
|
device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
|
2010-08-09 13:28:56 +00:00
|
|
|
device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
|
|
|
device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
|
|
|
|
|
|
|
device->SetRenderState(D3DRS_LIGHTING, false);
|
2017-07-09 02:23:17 +00:00
|
|
|
device->SetRenderState(D3DRS_ZENABLE, false);
|
2010-08-09 13:28:56 +00:00
|
|
|
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
2010-08-09 13:28:56 +00:00
|
|
|
device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
|
|
|
device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
device->SetVertexShader(nullptr);
|
|
|
|
device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
device->CreateVertexBuffer(sizeof(Vertex) * 4, flags.vertexUsage, D3DFVF_XYZRHW | D3DFVF_TEX1,
|
|
|
|
(D3DPOOL)flags.vertexPool, &vertexBuffer, nullptr);
|
|
|
|
textureWidth = 0;
|
|
|
|
textureHeight = 0;
|
2010-08-09 13:28:56 +00:00
|
|
|
resize(settings.width = 256, settings.height = 256);
|
2017-07-09 02:23:17 +00:00
|
|
|
updateFilter();
|
2010-08-09 13:28:56 +00:00
|
|
|
clear();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
auto resize(uint width, uint height) -> void {
|
|
|
|
if(textureWidth >= width && textureHeight >= height) return;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
textureWidth = bit::round(max(width, textureWidth));
|
|
|
|
textureHeight = bit::round(max(height, textureHeight));
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
if(capabilities.MaxTextureWidth < textureWidth || capabilities.MaxTextureWidth < textureHeight) return;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
if(texture) texture->Release();
|
2017-07-09 02:23:17 +00:00
|
|
|
device->CreateTexture(textureWidth, textureHeight, 1, flags.textureUsage, D3DFMT_X8R8G8B8,
|
|
|
|
(D3DPOOL)flags.texturePool, &texture, nullptr);
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
auto updateFilter() -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
if(!device) return;
|
|
|
|
if(lost && !recover()) return;
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
flags.filter = settings.filter == Video::FilterNearest ? D3DTEXF_POINT : D3DTEXF_LINEAR;
|
2010-08-09 13:28:56 +00:00
|
|
|
device->SetSamplerState(0, D3DSAMP_MINFILTER, flags.filter);
|
|
|
|
device->SetSamplerState(0, D3DSAMP_MAGFILTER, flags.filter);
|
|
|
|
}
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
//(x,y) screen coordinates, in pixels
|
|
|
|
//(u,v) texture coordinates, betweeen 0.0 (top, left) to 1.0 (bottom, right)
|
|
|
|
auto setVertex(
|
2010-08-09 13:28:56 +00:00
|
|
|
uint32_t px, uint32_t py, uint32_t pw, uint32_t ph,
|
|
|
|
uint32_t tw, uint32_t th,
|
|
|
|
uint32_t x, uint32_t y, uint32_t w, uint32_t h
|
2015-06-12 13:14:38 +00:00
|
|
|
) -> void {
|
2017-07-09 02:23:17 +00:00
|
|
|
Vertex vertex[4];
|
2010-08-09 13:28:56 +00:00
|
|
|
vertex[0].x = vertex[2].x = (double)(x - 0.5);
|
|
|
|
vertex[1].x = vertex[3].x = (double)(x + w - 0.5);
|
|
|
|
vertex[0].y = vertex[1].y = (double)(y - 0.5);
|
|
|
|
vertex[2].y = vertex[3].y = (double)(y + h - 0.5);
|
|
|
|
|
|
|
|
//Z-buffer and RHW are unused for 2D blit, set to normal values
|
|
|
|
vertex[0].z = vertex[1].z = vertex[2].z = vertex[3].z = 0.0;
|
|
|
|
vertex[0].rhw = vertex[1].rhw = vertex[2].rhw = vertex[3].rhw = 1.0;
|
|
|
|
|
|
|
|
double rw = (double)w / (double)pw * (double)tw;
|
|
|
|
double rh = (double)h / (double)ph * (double)th;
|
|
|
|
vertex[0].u = vertex[2].u = (double)(px ) / rw;
|
|
|
|
vertex[1].u = vertex[3].u = (double)(px + w) / rw;
|
|
|
|
vertex[0].v = vertex[1].v = (double)(py ) / rh;
|
|
|
|
vertex[2].v = vertex[3].v = (double)(py + h) / rh;
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
LPDIRECT3DVERTEXBUFFER9* vertexPointer = nullptr;
|
|
|
|
vertexBuffer->Lock(0, sizeof(Vertex) * 4, (void**)&vertexPointer, 0);
|
|
|
|
memory::copy(vertexPointer, vertex, sizeof(Vertex) * 4);
|
|
|
|
vertexBuffer->Unlock();
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
device->SetStreamSource(0, vertexBuffer, 0, sizeof(Vertex));
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-06-12 13:14:38 +00:00
|
|
|
auto clear() -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
if(lost && !recover()) return;
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
D3DSURFACE_DESC surfaceDescription;
|
|
|
|
texture->GetLevelDesc(0, &surfaceDescription);
|
2010-08-09 13:28:56 +00:00
|
|
|
texture->GetSurfaceLevel(0, &surface);
|
|
|
|
|
|
|
|
if(surface) {
|
|
|
|
device->ColorFill(surface, 0, D3DCOLOR_XRGB(0x00, 0x00, 0x00));
|
|
|
|
surface->Release();
|
2012-03-31 08:17:36 +00:00
|
|
|
surface = nullptr;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//clear primary display and all backbuffers
|
2017-07-09 02:23:17 +00:00
|
|
|
for(uint n : range(3)) {
|
2010-08-09 13:28:56 +00:00
|
|
|
device->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0x00, 0x00, 0x00), 1.0f, 0);
|
|
|
|
device->Present(0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool {
|
2010-08-09 13:28:56 +00:00
|
|
|
if(lost && !recover()) return false;
|
|
|
|
|
|
|
|
if(width != settings.width || height != settings.height) {
|
|
|
|
resize(settings.width = width, settings.height = height);
|
|
|
|
}
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
D3DSURFACE_DESC surfaceDescription;
|
|
|
|
texture->GetLevelDesc(0, &surfaceDescription);
|
2010-08-09 13:28:56 +00:00
|
|
|
texture->GetSurfaceLevel(0, &surface);
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
D3DLOCKED_RECT lockedRectangle;
|
|
|
|
surface->LockRect(&lockedRectangle, 0, D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD);
|
|
|
|
pitch = lockedRectangle.Pitch;
|
|
|
|
return data = (uint32_t*)lockedRectangle.pBits;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-06-12 13:14:38 +00:00
|
|
|
auto unlock() -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
surface->UnlockRect();
|
|
|
|
surface->Release();
|
2012-03-31 08:17:36 +00:00
|
|
|
surface = nullptr;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-06-12 13:14:38 +00:00
|
|
|
auto refresh() -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
if(lost && !recover()) return;
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
RECT rectangle;
|
|
|
|
GetClientRect(settings.handle, &rectangle);
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
//if output size changed, driver must be re-initialized.
|
|
|
|
//failure to do so causes scaling issues on some video drivers.
|
2017-07-09 02:23:17 +00:00
|
|
|
if(windowWidth != rectangle.right || windowHeight != rectangle.bottom) init();
|
|
|
|
|
|
|
|
device->BeginScene();
|
|
|
|
uint x = 0, y = 0;
|
|
|
|
if(settings.exclusive) {
|
|
|
|
//center output in exclusive mode fullscreen window
|
|
|
|
x = (monitorWidth - windowWidth) / 2;
|
|
|
|
y = (monitorHeight - windowHeight) / 2;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
2017-07-09 02:23:17 +00:00
|
|
|
setVertex(0, 0, settings.width, settings.height, textureWidth, textureHeight, x, y, windowWidth, windowHeight);
|
|
|
|
device->SetTexture(0, texture);
|
|
|
|
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
|
|
|
|
device->EndScene();
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
if(settings.synchronize) {
|
Update to v088r15 release.
byuu says:
Changelog:
- default placement of presentation window optimized for 1024x768
displays or larger (sorry if yours is smaller, move the window
yourself.)
- Direct3D waits until a previous Vblank ends before waiting for the
next Vblank to begin (fixes video timing analysis, and ---really---
fast computers.)
- Window::setVisible(false) clears modality, but also fixed in Browser
code as well (fixes loading images on Windows hanging)
- Browser won't consume full CPU resources (but timing analysis will,
I don't want stalls to affect the results.)
- closing settings window while analyzing stops analysis
- you can load the SGB BIOS without a game (why the hell you would want
to ...)
- escape closes the Browser window (it won't close other dialogs, it has
to be hooked up per-window)
- just for fun, joypad hat up/down moves in Browser file list, any
joypad button loads selected game [not very useful, lacks repeat, and
there aren't GUI load file open buttons]
- Super Scope and Justifier crosshairs render correctly (probably
doesn't belong in the core, but it's not something I suspect people
want to do themselves ...)
- you can load GB, SGB, GB, SGB ... without problems (not happy with how
I did this, but I don't want to add an Interface::setInterface()
function yet)
- PAL timing works as I want now (if you want 50fps on a 60hz monitor,
you must not use sync video) [needed to update the DSP frequency when
toggling video/audio sync]
- not going to save input port selection for now (lot of work), but it
will properly keep your port setting across cartridge loads at least
[just goes to controller on emulator restart]
- SFC overscan on and off both work as expected now (off centers image,
on shows entire image)
- laevateinn compiles properly now
- ethos goes to ~/.config/bsnes now that target-ui is dead [honestly,
I recommend deleting the old folder and starting over]
- Emulator::Interface callbacks converted to virtual binding structure
that GUI inherits from (simplifies binding callbacks)
- this breaks Super Game Boy for a bit, I need to rethink
system-specific bindings without direct inheritance
Timing analysis works spectacularly well on Windows, too. You won't get
your 100% perfect rate (unless maybe you leave the analysis running
overnight?), but it'll get really freaking close this way.
2012-05-07 23:29:03 +00:00
|
|
|
D3DRASTER_STATUS status;
|
2017-07-09 02:23:17 +00:00
|
|
|
while(true) { //wait for a previous vblank to finish, if necessary
|
Update to v088r15 release.
byuu says:
Changelog:
- default placement of presentation window optimized for 1024x768
displays or larger (sorry if yours is smaller, move the window
yourself.)
- Direct3D waits until a previous Vblank ends before waiting for the
next Vblank to begin (fixes video timing analysis, and ---really---
fast computers.)
- Window::setVisible(false) clears modality, but also fixed in Browser
code as well (fixes loading images on Windows hanging)
- Browser won't consume full CPU resources (but timing analysis will,
I don't want stalls to affect the results.)
- closing settings window while analyzing stops analysis
- you can load the SGB BIOS without a game (why the hell you would want
to ...)
- escape closes the Browser window (it won't close other dialogs, it has
to be hooked up per-window)
- just for fun, joypad hat up/down moves in Browser file list, any
joypad button loads selected game [not very useful, lacks repeat, and
there aren't GUI load file open buttons]
- Super Scope and Justifier crosshairs render correctly (probably
doesn't belong in the core, but it's not something I suspect people
want to do themselves ...)
- you can load GB, SGB, GB, SGB ... without problems (not happy with how
I did this, but I don't want to add an Interface::setInterface()
function yet)
- PAL timing works as I want now (if you want 50fps on a 60hz monitor,
you must not use sync video) [needed to update the DSP frequency when
toggling video/audio sync]
- not going to save input port selection for now (lot of work), but it
will properly keep your port setting across cartridge loads at least
[just goes to controller on emulator restart]
- SFC overscan on and off both work as expected now (off centers image,
on shows entire image)
- laevateinn compiles properly now
- ethos goes to ~/.config/bsnes now that target-ui is dead [honestly,
I recommend deleting the old folder and starting over]
- Emulator::Interface callbacks converted to virtual binding structure
that GUI inherits from (simplifies binding callbacks)
- this breaks Super Game Boy for a bit, I need to rethink
system-specific bindings without direct inheritance
Timing analysis works spectacularly well on Windows, too. You won't get
your 100% perfect rate (unless maybe you leave the analysis running
overnight?), but it'll get really freaking close this way.
2012-05-07 23:29:03 +00:00
|
|
|
device->GetRasterStatus(0, &status);
|
2017-07-09 02:23:17 +00:00
|
|
|
if(!status.InVBlank) break;
|
Update to v088r15 release.
byuu says:
Changelog:
- default placement of presentation window optimized for 1024x768
displays or larger (sorry if yours is smaller, move the window
yourself.)
- Direct3D waits until a previous Vblank ends before waiting for the
next Vblank to begin (fixes video timing analysis, and ---really---
fast computers.)
- Window::setVisible(false) clears modality, but also fixed in Browser
code as well (fixes loading images on Windows hanging)
- Browser won't consume full CPU resources (but timing analysis will,
I don't want stalls to affect the results.)
- closing settings window while analyzing stops analysis
- you can load the SGB BIOS without a game (why the hell you would want
to ...)
- escape closes the Browser window (it won't close other dialogs, it has
to be hooked up per-window)
- just for fun, joypad hat up/down moves in Browser file list, any
joypad button loads selected game [not very useful, lacks repeat, and
there aren't GUI load file open buttons]
- Super Scope and Justifier crosshairs render correctly (probably
doesn't belong in the core, but it's not something I suspect people
want to do themselves ...)
- you can load GB, SGB, GB, SGB ... without problems (not happy with how
I did this, but I don't want to add an Interface::setInterface()
function yet)
- PAL timing works as I want now (if you want 50fps on a 60hz monitor,
you must not use sync video) [needed to update the DSP frequency when
toggling video/audio sync]
- not going to save input port selection for now (lot of work), but it
will properly keep your port setting across cartridge loads at least
[just goes to controller on emulator restart]
- SFC overscan on and off both work as expected now (off centers image,
on shows entire image)
- laevateinn compiles properly now
- ethos goes to ~/.config/bsnes now that target-ui is dead [honestly,
I recommend deleting the old folder and starting over]
- Emulator::Interface callbacks converted to virtual binding structure
that GUI inherits from (simplifies binding callbacks)
- this breaks Super Game Boy for a bit, I need to rethink
system-specific bindings without direct inheritance
Timing analysis works spectacularly well on Windows, too. You won't get
your 100% perfect rate (unless maybe you leave the analysis running
overnight?), but it'll get really freaking close this way.
2012-05-07 23:29:03 +00:00
|
|
|
}
|
2017-07-09 02:23:17 +00:00
|
|
|
while(true) { //wait for next vblank to begin
|
2010-08-09 13:28:56 +00:00
|
|
|
device->GetRasterStatus(0, &status);
|
2017-07-09 02:23:17 +00:00
|
|
|
if(status.InVBlank) break;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(device->Present(0, 0, 0, 0) == D3DERR_DEVICELOST) lost = true;
|
|
|
|
}
|
|
|
|
|
2015-06-12 13:14:38 +00:00
|
|
|
auto init() -> bool {
|
2017-07-09 02:23:17 +00:00
|
|
|
term();
|
|
|
|
|
|
|
|
RECT rectangle;
|
|
|
|
GetClientRect(settings.handle, &rectangle);
|
|
|
|
windowWidth = rectangle.right;
|
|
|
|
windowHeight = rectangle.bottom;
|
|
|
|
|
|
|
|
context = Direct3DCreate9(D3D_SDK_VERSION);
|
|
|
|
if(!context) return false;
|
|
|
|
|
|
|
|
memory::fill(&presentation, sizeof(presentation));
|
|
|
|
presentation.Flags = D3DPRESENTFLAG_VIDEO;
|
|
|
|
presentation.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
|
|
|
presentation.BackBufferCount = 1;
|
|
|
|
presentation.MultiSampleType = D3DMULTISAMPLE_NONE;
|
|
|
|
presentation.MultiSampleQuality = 0;
|
2010-08-09 13:28:56 +00:00
|
|
|
presentation.EnableAutoDepthStencil = false;
|
|
|
|
presentation.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
|
2017-07-09 02:23:17 +00:00
|
|
|
presentation.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
|
|
|
|
|
|
|
if(!settings.exclusive) {
|
|
|
|
presentation.hDeviceWindow = settings.handle;
|
|
|
|
presentation.Windowed = true;
|
|
|
|
presentation.BackBufferFormat = D3DFMT_UNKNOWN;
|
|
|
|
presentation.BackBufferWidth = 0;
|
|
|
|
presentation.BackBufferHeight = 0;
|
|
|
|
|
|
|
|
ShowWindow(settings.exclusiveHandle, SW_HIDE);
|
|
|
|
if(context->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, settings.handle,
|
|
|
|
D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentation, &device) != D3D_OK) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
presentation.hDeviceWindow = settings.exclusiveHandle;
|
|
|
|
presentation.Windowed = false;
|
|
|
|
presentation.BackBufferFormat = D3DFMT_X8R8G8B8;
|
|
|
|
presentation.BackBufferWidth = monitorWidth;
|
|
|
|
presentation.BackBufferHeight = monitorHeight;
|
|
|
|
presentation.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
|
|
|
|
|
|
|
|
ShowWindow(settings.exclusiveHandle, SW_SHOWNORMAL);
|
|
|
|
if(context->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, settings.exclusiveHandle,
|
|
|
|
D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentation, &device) != D3D_OK) {
|
|
|
|
return false;
|
|
|
|
}
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
device->GetDeviceCaps(&capabilities);
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2017-07-09 02:23:17 +00:00
|
|
|
if(capabilities.Caps2 & D3DCAPS2_DYNAMICTEXTURES) {
|
|
|
|
flags.textureUsage = D3DUSAGE_DYNAMIC;
|
|
|
|
flags.texturePool = D3DPOOL_DEFAULT;
|
|
|
|
flags.vertexUsage = D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC;
|
|
|
|
flags.vertexPool = D3DPOOL_DEFAULT;
|
2010-08-09 13:28:56 +00:00
|
|
|
} else {
|
2017-07-09 02:23:17 +00:00
|
|
|
flags.textureUsage = 0;
|
|
|
|
flags.texturePool = D3DPOOL_MANAGED;
|
|
|
|
flags.vertexUsage = D3DUSAGE_WRITEONLY;
|
|
|
|
flags.vertexPool = D3DPOOL_MANAGED;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lost = false;
|
2017-07-09 02:23:17 +00:00
|
|
|
return recover();
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-06-12 13:14:38 +00:00
|
|
|
auto term() -> void {
|
2017-07-09 02:23:17 +00:00
|
|
|
if(vertexBuffer) { vertexBuffer->Release(); vertexBuffer = nullptr; }
|
|
|
|
if(surface) { surface->Release(); surface = nullptr; }
|
|
|
|
if(texture) { texture->Release(); texture = nullptr; }
|
|
|
|
if(device) { device->Release(); device = nullptr; }
|
|
|
|
if(context) { context->Release(); context = nullptr; }
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
};
|