Replace pDsp with WindowInfo

This commit is contained in:
Connor McLaughlin 2021-07-08 23:37:13 +10:00 committed by refractionpcsx2
parent 114d78d378
commit 0f5ed59e50
31 changed files with 424 additions and 1000 deletions

View File

@ -183,7 +183,7 @@ void DEV9shutdown()
delete dev9.ata;
}
s32 DEV9open(void* pDsp)
s32 DEV9open()
{
DevCon.WriteLn("DEV9: DEV9open");
LoadConf();

View File

@ -727,7 +727,7 @@ extern void DEV9configure();
void FLASHinit();
s32 DEV9init();
void DEV9close();
s32 DEV9open(void* pDsp);
s32 DEV9open();
void DEV9shutdown();
u32 FLASHread32(u32 addr, int size);
void FLASHwrite32(u32 addr, u32 value, int size);

View File

@ -143,10 +143,9 @@ void GSclose()
}
}
int _GSopen(void** dsp, const char* title, GSRendererType renderer, int threads = -1)
int _GSopen(const WindowInfo& wi, const char* title, GSRendererType renderer, int threads = -1)
{
GSDevice* dev = NULL;
ASSERT(dsp != nullptr);
// Fresh start up or config file changed
if (renderer == GSRendererType::Undefined)
@ -187,23 +186,8 @@ int _GSopen(void** dsp, const char* title, GSRendererType renderer, int threads
case GSRendererType::OGL_HW:
case GSRendererType::OGL_SW:
#if defined(__unix__)
// Note: EGL code use GLX otherwise maybe it could be also compatible with Windows
// Yes OpenGL code isn't complicated enough !
switch (GSWndEGL::SelectPlatform())
{
#if GS_EGL_X11
case EGL_PLATFORM_X11_KHR:
wnds.push_back(std::make_shared<GSWndEGL_X11>());
break;
#endif
#if GS_EGL_WL
case EGL_PLATFORM_WAYLAND_KHR:
wnds.push_back(std::make_shared<GSWndEGL_WL>());
break;
#endif
default:
break;
}
if (std::shared_ptr<GSWndEGL> wnd = GSWndEGL::CreateForPlatform(wi); wnd)
wnds.push_back(std::move(wnd));
#elif defined(__APPLE__)
// No windows available for macOS at the moment
#else
@ -220,17 +204,14 @@ int _GSopen(void** dsp, const char* title, GSRendererType renderer, int threads
#endif
break;
}
#if defined(__unix__)
void* win_handle = (void*)((uptr*)(dsp) + 1);
#else
void* win_handle = *dsp;
#endif
for (auto& wnd : wnds)
{
try
{
wnd->Attach(win_handle, false);
if (!wnd->Attach(wi))
continue;
window = wnd; // Previous code will throw if window isn't supported
break;
}
@ -353,7 +334,7 @@ void GSosdMonitor(const char* key, const char* value, uint32 color)
s_gs->m_dev->m_osd.Monitor(key, value);
}
int GSopen2(void** dsp, uint32 flags)
int GSopen2(const WindowInfo& wi, uint32 flags)
{
static bool stored_toggle_state = false;
const bool toggle_state = !!(flags & 4);
@ -395,7 +376,7 @@ int GSopen2(void** dsp, uint32 flags)
}
stored_toggle_state = toggle_state;
int retval = _GSopen(dsp, "", current_renderer);
int retval = _GSopen(wi, "", current_renderer);
gsopen_done = true;
@ -545,23 +526,6 @@ void GSvsync(int field)
{
try
{
#ifdef _WIN32
if (s_gs->m_wnd->IsManaged())
{
MSG msg;
memset(&msg, 0, sizeof(msg));
while (msg.message != WM_QUIT && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
#endif
s_gs->VSync(field);
}
catch (GSRecoverableError)
@ -792,251 +756,6 @@ void GSsetExclusive(int enabled)
}
}
#if defined(__unix__) || defined(__APPLE__)
inline unsigned long timeGetTime()
{
struct timespec t;
clock_gettime(CLOCK_REALTIME, &t);
return (unsigned long)(t.tv_sec * 1000 + t.tv_nsec / 1000000);
}
// Note
void GSReplay(char* lpszCmdLine, int renderer)
{
GLLoader::in_replayer = true;
// Required by multithread driver
#ifndef __APPLE__
XInitThreads();
#endif
GSinit();
GSRendererType m_renderer;
// Allow to easyly switch between SW/HW renderer -> this effectively removes the ability to select the renderer by function args
m_renderer = static_cast<GSRendererType>(theApp.GetConfigI("Renderer"));
if (m_renderer != GSRendererType::OGL_HW && m_renderer != GSRendererType::OGL_SW)
{
fprintf(stderr, "wrong renderer selected %d\n", static_cast<int>(m_renderer));
return;
}
struct Packet
{
uint8 type, param;
uint32 size, addr;
std::vector<uint8> buff;
};
std::list<Packet*> packets;
std::vector<uint8> buff;
uint8 regs[0x2000];
GSsetBaseMem(regs);
s_vsync = theApp.GetConfigI("vsync");
int finished = theApp.GetConfigI("linux_replay");
bool repack_dump = (finished < 0);
if (theApp.GetConfigI("dump"))
{
fprintf(stderr, "Dump is enabled. Replay will be disabled\n");
finished = 1;
}
long frame_number = 0;
void* hWnd = NULL;
int err = _GSopen((void**)&hWnd, "", m_renderer);
if (err != 0)
{
fprintf(stderr, "Error failed to GSopen\n");
return;
}
if (s_gs->m_wnd == NULL)
return;
{ // Read .gs content
std::string f(lpszCmdLine);
bool is_xz = (f.size() >= 4) && (f.compare(f.size() - 3, 3, ".xz") == 0);
if (is_xz)
f.replace(f.end() - 6, f.end(), "_repack.gs");
else
f.replace(f.end() - 3, f.end(), "_repack.gs");
GSDumpFile* file = is_xz ? (GSDumpFile*)new GSDumpLzma(lpszCmdLine, repack_dump ? f.c_str() : nullptr) : (GSDumpFile*)new GSDumpRaw(lpszCmdLine, repack_dump ? f.c_str() : nullptr);
uint32 crc;
file->Read(&crc, 4);
GSsetGameCRC(crc, 0);
freezeData fd;
file->Read(&fd.size, 4);
fd.data = new u8[fd.size];
file->Read(fd.data, fd.size);
GSfreeze(FreezeAction::Load, &fd);
delete[] fd.data;
file->Read(regs, 0x2000);
uint8 type;
while (file->Read(&type, 1))
{
Packet* p = new Packet();
p->type = type;
switch (type)
{
case 0:
file->Read(&p->param, 1);
file->Read(&p->size, 4);
switch (p->param)
{
case 0:
p->buff.resize(0x4000);
p->addr = 0x4000 - p->size;
file->Read(&p->buff[p->addr], p->size);
break;
case 1:
case 2:
case 3:
p->buff.resize(p->size);
file->Read(&p->buff[0], p->size);
break;
}
break;
case 1:
file->Read(&p->param, 1);
frame_number++;
break;
case 2:
file->Read(&p->size, 4);
break;
case 3:
p->buff.resize(0x2000);
file->Read(&p->buff[0], 0x2000);
break;
}
packets.push_back(p);
if (repack_dump && frame_number > -finished)
break;
}
delete file;
}
sleep(2);
frame_number = 0;
// Init vsync stuff
GSvsync(1);
while (finished > 0)
{
for (auto i = packets.begin(); i != packets.end(); i++)
{
Packet* p = *i;
switch (p->type)
{
case 0:
switch (p->param)
{
case 0:
GSgifTransfer1(&p->buff[0], p->addr);
break;
case 1:
GSgifTransfer2(&p->buff[0], p->size / 16);
break;
case 2:
GSgifTransfer3(&p->buff[0], p->size / 16);
break;
case 3:
GSgifTransfer(&p->buff[0], p->size / 16);
break;
}
break;
case 1:
GSvsync(p->param);
frame_number++;
break;
case 2:
if (buff.size() < p->size)
buff.resize(p->size);
GSreadFIFO2(&buff[0], p->size / 16);
break;
case 3:
memcpy(regs, &p->buff[0], 0x2000);
break;
}
}
if (finished >= 200)
{
; // Nop for Nvidia Profiler
}
else if (finished > 90)
{
sleep(1);
}
else
{
finished--;
}
}
static_cast<GSDeviceOGL*>(s_gs->m_dev)->GenerateProfilerData();
#ifdef ENABLE_OGL_DEBUG_MEM_BW
unsigned long total_frame_nb = std::max(1l, frame_number) << 10;
fprintf(stderr, "memory bandwith. T: %f KB/f. V: %f KB/f. U: %f KB/f\n",
(float)g_real_texture_upload_byte / (float)total_frame_nb,
(float)g_vertex_upload_byte / (float)total_frame_nb,
(float)g_uniform_upload_byte / (float)total_frame_nb);
#endif
for (auto i = packets.begin(); i != packets.end(); i++)
{
delete *i;
}
packets.clear();
sleep(2);
GSclose();
GSshutdown();
}
#endif
std::string format(const char* fmt, ...)
{
va_list args;

View File

@ -1765,6 +1765,7 @@ enum class CRCHackLevel : int8
};
struct HostKeyEvent;
struct WindowInfo;
#ifdef ENABLE_ACCURATE_BUFFER_EMULATION
const GSVector2i default_rt_size(2048, 2048);
@ -1776,10 +1777,10 @@ void GSsetBaseMem(uint8* mem);
int GSinit();
void GSshutdown();
void GSclose();
int _GSopen(void** dsp, const char* title, GSRendererType renderer, int threads);
int _GSopen(const WindowInfo& wi, const char* title, GSRendererType renderer, int threads);
void GSosdLog(const char* utf8, uint32 color);
void GSosdMonitor(const char* key, const char* value, uint32 color);
int GSopen2(void** dsp, uint32 flags);
int GSopen2(const WindowInfo & wi, uint32 flags);
void GSreset();
void GSgifSoftReset(uint32 mask);
void GSwriteCSR(uint32 csr);

View File

@ -399,10 +399,6 @@ void GSRenderer::VSync(int field)
std::string s;
#ifdef GSTITLEINFO_API_FORCE_VERBOSE
if (1) //force verbose reply
#else
if (m_wnd->IsManaged())
#endif
{
//GS owns the window's title, be verbose.
static const char* aspect_ratio_names[static_cast<int>(AspectRatioType::MaxCount)] = { "Stretch", "4:3", "16:9" };
@ -438,41 +434,29 @@ void GSRenderer::VSync(int field)
s += format(" | %d%% CPU", sum);
}
}
else
#else
{
// Satisfy PCSX2's request for title info: minimal verbosity due to more external title text
s = format("%dx%d | %s", GetInternalResolution().x, GetInternalResolution().y, theApp.m_gs_interlace[m_interlace].name.c_str());
}
#endif
if (m_capture.IsCapturing())
{
s += " | Recording...";
}
if (m_wnd->IsManaged())
{
m_wnd->SetWindowText(s.c_str());
}
else
{
// note: do not use TryEnterCriticalSection. It is unnecessary code complication in
// an area that absolutely does not matter (even if it were 100 times slower, it wouldn't
// be noticeable). Besides, these locks are extremely short -- overhead of conditional
// is way more expensive than just waiting for the CriticalSection in 1 of 10,000,000 tries. --air
// note: do not use TryEnterCriticalSection. It is unnecessary code complication in
// an area that absolutely does not matter (even if it were 100 times slower, it wouldn't
// be noticeable). Besides, these locks are extremely short -- overhead of conditional
// is way more expensive than just waiting for the CriticalSection in 1 of 10,000,000 tries. --air
std::lock_guard<std::mutex> lock(m_pGSsetTitle_Crit);
std::lock_guard<std::mutex> lock(m_pGSsetTitle_Crit);
strncpy(m_GStitleInfoBuffer, s.c_str(), countof(m_GStitleInfoBuffer) - 1);
strncpy(m_GStitleInfoBuffer, s.c_str(), countof(m_GStitleInfoBuffer) - 1);
m_GStitleInfoBuffer[sizeof(m_GStitleInfoBuffer) - 1] = 0; // make sure null terminated even if text overflows
}
}
else
{
// [TODO]
// We don't have window title rights, or the window has no title,
// so let's use actual OSD!
m_GStitleInfoBuffer[sizeof(m_GStitleInfoBuffer) - 1] = 0; // make sure null terminated even if text overflows
}
if (m_frameskip)

View File

@ -16,38 +16,25 @@
#pragma once
#include "PrecompiledHeader.h"
#include "common/WindowInfo.h"
#include "GS/GS.h"
#include "GS/GSVector.h"
class GSWnd
{
protected:
bool m_managed; // set true when we're attached to a 3rdparty window that's amanged by the emulator
public:
GSWnd()
: m_managed(false)
{
}
virtual ~GSWnd() {}
GSWnd() = default;
virtual ~GSWnd() = default;
virtual bool Create(const std::string& title, int w, int h) = 0;
virtual bool Attach(void* handle, bool managed = true) = 0;
virtual bool Attach(const WindowInfo& wi) = 0;
virtual void Detach() = 0;
bool IsManaged() const { return m_managed; }
virtual void* GetDisplay() = 0;
virtual void* GetHandle() = 0;
virtual GSVector4i GetClientRect() = 0;
virtual bool SetWindowText(const char* title) = 0;
virtual void AttachContext() {}
virtual void DetachContext() {}
virtual void Show() = 0;
virtual void Hide() = 0;
virtual void HideFrame() = 0;
virtual void Flip() {}
virtual void SetVSync(int vsync) {}
};
@ -75,24 +62,9 @@ public:
, m_vsync(0)
{
}
virtual ~GSWndGL() {}
virtual ~GSWndGL() override = default;
virtual bool Create(const std::string& title, int w, int h) = 0;
virtual bool Attach(void* handle, bool managed = true) = 0;
virtual void Detach() = 0;
virtual void* GetDisplay() = 0;
virtual void* GetHandle() = 0;
virtual GSVector4i GetClientRect() = 0;
virtual bool SetWindowText(const char* title) = 0;
virtual void AttachContext() = 0;
virtual void DetachContext() = 0;
virtual void* GetProcAddress(const char* name, bool opt = false) = 0;
virtual void Show() = 0;
virtual void Hide() = 0;
virtual void HideFrame() = 0;
virtual void Flip() = 0;
virtual void SetVSync(int vsync) final;
void SetVSync(int vsync) final;
};

View File

@ -19,7 +19,6 @@
#ifdef _WIN32
GSWndDX::GSWndDX()
: m_hWnd(NULL)
, m_frame(true)
{
}
@ -27,136 +26,20 @@ GSWndDX::~GSWndDX()
{
}
LRESULT CALLBACK GSWndDX::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
bool GSWndDX::Attach(const WindowInfo& wi)
{
GSWndDX* wnd = NULL;
if (wi.type != WindowInfo::Type::Win32)
return false;
if (message == WM_NCCREATE)
{
wnd = (GSWndDX*)((LPCREATESTRUCT)lParam)->lpCreateParams;
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)wnd);
wnd->m_hWnd = hWnd;
}
else
{
wnd = (GSWndDX*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
}
if (wnd == NULL)
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
return wnd->OnMessage(message, wParam, lParam);
}
LRESULT GSWndDX::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CLOSE:
Hide();
// DestroyWindow(m_hWnd);
return 0;
case WM_DESTROY:
// This kills the emulator when GS is closed, which *really* isn't desired behavior,
// especially in STGS mode (worked in MTGS mode since it only quit the thread, but even
// that wasn't needed).
//PostQuitMessage(0);
return 0;
default:
break;
}
return DefWindowProc((HWND)m_hWnd, message, wParam, lParam);
}
bool GSWndDX::Create(const std::string& title, int w, int h)
{
if (m_hWnd)
throw GSRecoverableError();
m_managed = true;
WNDCLASS wc;
memset(&wc, 0, sizeof(wc));
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc = WndProc;
wc.hInstance = theApp.GetModuleHandle();
// TODO: wc.hIcon = ;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszClassName = L"GSWndDX";
if (!GetClassInfo(wc.hInstance, wc.lpszClassName, &wc))
{
if (!RegisterClass(&wc))
{
throw GSRecoverableError();
}
}
DWORD style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW | WS_BORDER;
GSVector4i r;
GetWindowRect(GetDesktopWindow(), r);
bool remote = !!GetSystemMetrics(SM_REMOTESESSION);
if (w <= 0 || h <= 0 || remote)
{
w = r.width() / 3;
h = r.width() / 4;
if (!remote)
{
w *= 2;
h *= 2;
}
}
r.left = (r.left + r.right - w) / 2;
r.top = (r.top + r.bottom - h) / 2;
r.right = r.left + w;
r.bottom = r.top + h;
AdjustWindowRect(r, style, FALSE);
std::wstring tmp = std::wstring(title.begin(), title.end());
m_hWnd = CreateWindow(wc.lpszClassName, tmp.c_str(), style, r.left, r.top, r.width(), r.height(), NULL, NULL, wc.hInstance, (LPVOID)this);
if (!m_hWnd)
throw GSRecoverableError();
return true;
}
bool GSWndDX::Attach(void* handle, bool managed)
{
// TODO: subclass
m_hWnd = (HWND)handle;
m_managed = managed;
m_hWnd = static_cast<HWND>(wi.window_handle);
return true;
}
void GSWndDX::Detach()
{
if (m_hWnd && m_managed)
{
// close the window, since it's under GS care. It's not taking messages anyway, and
// that means its big, ugly, and in the way.
DestroyWindow(m_hWnd);
}
m_hWnd = NULL;
m_managed = true;
m_hWnd = {};
}
GSVector4i GSWndDX::GetClientRect()
@ -167,50 +50,4 @@ GSVector4i GSWndDX::GetClientRect()
return r;
}
// Returns FALSE if the window has no title, or if th window title is under the strict
// management of the emulator.
bool GSWndDX::SetWindowText(const char* title)
{
if (!m_managed)
return false;
const size_t tmp_size = strlen(title) + 1;
std::wstring tmp(tmp_size, L'#');
mbstowcs(&tmp[0], title, tmp_size);
::SetWindowText(m_hWnd, tmp.c_str());
return m_frame;
}
void GSWndDX::Show()
{
if (!m_managed)
return;
SetForegroundWindow(m_hWnd);
ShowWindow(m_hWnd, SW_SHOWNORMAL);
UpdateWindow(m_hWnd);
}
void GSWndDX::Hide()
{
if (!m_managed)
return;
ShowWindow(m_hWnd, SW_HIDE);
}
void GSWndDX::HideFrame()
{
if (!m_managed)
return;
SetWindowLong(m_hWnd, GWL_STYLE, GetWindowLong(m_hWnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME));
SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
SetMenu(m_hWnd, NULL);
m_frame = false;
}
#endif

View File

@ -17,30 +17,18 @@
#include "GSWnd.h"
#ifdef _WIN32
class GSWndDX : public GSWnd
class GSWndDX final : public GSWnd
{
HWND m_hWnd;
bool m_frame;
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
public:
GSWndDX();
virtual ~GSWndDX();
~GSWndDX() override;
bool Create(const std::string& title, int w, int h);
bool Attach(void* handle, bool managed = true);
void Detach();
bool Attach(const WindowInfo& wi) override;
void Detach() override;
void* GetDisplay() { return m_hWnd; }
void* GetHandle() { return m_hWnd; }
GSVector4i GetClientRect();
bool SetWindowText(const char* title);
void Show();
void Hide();
void HideFrame();
void* GetHandle() override { return m_hWnd; }
GSVector4i GetClientRect() override;
};
#endif

View File

@ -18,15 +18,14 @@
#if defined(__unix__)
// static method
int GSWndEGL::SelectPlatform()
std::shared_ptr<GSWndEGL> GSWndEGL::CreateForPlatform(const WindowInfo& wi)
{
// Check the supported extension
const char* client_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
if (!client_extensions)
{
fprintf(stderr, "EGL: Client extension not supported\n");
return 0;
return nullptr;
}
fprintf(stdout, "EGL: Supported extensions: %s\n", client_extensions);
@ -34,28 +33,27 @@ int GSWndEGL::SelectPlatform()
if (!strstr(client_extensions, "EGL_EXT_platform_base"))
{
fprintf(stderr, "EGL: Dynamic platform selection isn't supported\n");
return 0;
return nullptr;
}
// Finally we can select the platform
#if GS_EGL_X11
if (strstr(client_extensions, "EGL_EXT_platform_x11"))
if (strstr(client_extensions, "EGL_EXT_platform_x11") && wi.type == WindowInfo::Type::X11)
{
fprintf(stdout, "EGL: select X11 platform\n");
return EGL_PLATFORM_X11_KHR;
return std::make_shared<GSWndEGL_X11>();
}
#endif
#if GS_EGL_WL
if (strstr(client_extensions, "EGL_EXT_platform_wayland"))
if (strstr(client_extensions, "EGL_EXT_platform_wayland") && wi.type == WindowInfo::Type::Wayland)
{
fprintf(stdout, "EGL: select Wayland platform\n");
return EGL_PLATFORM_WAYLAND_KHR;
return std::make_shared<GSWndEGL_WL>();
}
#endif
fprintf(stderr, "EGL: no compatible platform found\n");
return 0;
fprintf(stderr, "EGL: no compatible platform found for wintype %u\n", static_cast<unsigned>(wi.type));
return nullptr;
}
@ -103,7 +101,7 @@ void GSWndEGL::CreateContext(int major, int minor)
m_eglSurface = eglCreatePlatformWindowSurface(m_eglDisplay, eglConfig, m_native_window, nullptr);
if (m_eglSurface == EGL_NO_SURFACE)
{
fprintf(stderr, "EGL: Failed to get a window surface\n");
fprintf(stderr, "EGL: Failed to get a window surface (0x%x)\n", eglGetError());
throw GSRecoverableError();
}
@ -169,11 +167,11 @@ void GSWndEGL::BindAPI()
}
}
bool GSWndEGL::Attach(void* handle, bool managed)
bool GSWndEGL::Attach(const WindowInfo& wi)
{
m_managed = managed;
m_native_window = AttachNativeWindow(handle);
m_native_window = AttachNativeWindow(wi);
if (!m_native_window)
return false;
OpenEGLDisplay();
@ -198,25 +196,6 @@ void GSWndEGL::Detach()
DestroyNativeResources();
}
bool GSWndEGL::Create(const std::string& title, int w, int h)
{
if (w <= 0 || h <= 0)
{
w = theApp.GetConfigI("ModeWidth");
h = theApp.GetConfigI("ModeHeight");
}
m_managed = true;
OpenEGLDisplay();
m_native_window = CreateNativeWindow(w, h);
FullContextInit();
return true;
}
void* GSWndEGL::GetProcAddress(const char* name, bool opt)
{
void* ptr = (void*)eglGetProcAddress(name);
@ -267,9 +246,7 @@ void GSWndEGL::OpenEGLDisplay()
// We only need a native display when we manage the window ourself.
// By default, EGL will create its own native display. This way the driver knows
// that display will be thread safe and so it can enable multithread optimization.
void* native_display = (m_managed) ? CreateNativeDisplay() : nullptr;
// Create an EGL display from the native display
void* native_display = nullptr;
m_eglDisplay = eglGetPlatformDisplay(m_platform, native_display, nullptr);
if (m_eglDisplay == EGL_NO_DISPLAY)
{
@ -290,84 +267,21 @@ void GSWndEGL::OpenEGLDisplay()
#if GS_EGL_X11
GSWndEGL_X11::GSWndEGL_X11()
: GSWndEGL(EGL_PLATFORM_X11_KHR), m_NativeDisplay(nullptr), m_NativeWindow(0)
: GSWndEGL(EGL_PLATFORM_X11_KHR), m_NativeWindow(0)
{
}
void* GSWndEGL_X11::CreateNativeDisplay()
void* GSWndEGL_X11::AttachNativeWindow(const WindowInfo& wi)
{
if (m_NativeDisplay == nullptr)
m_NativeDisplay = XOpenDisplay(nullptr);
if (wi.type != WindowInfo::Type::X11)
return nullptr;
return (void*)m_NativeDisplay;
}
void* GSWndEGL_X11::CreateNativeWindow(int w, int h)
{
const int depth = 0, x = 0, y = 0, border_width = 1;
#if 0
// Old X code in case future code will still require it
m_NativeWindow = XCreateSimpleWindow(m_NativeDisplay, DefaultRootWindow(m_NativeDisplay), 0, 0, w, h, 0, 0, 0);
XMapWindow (m_NativeDisplay, m_NativeWindow);
#endif
if (m_NativeDisplay == nullptr)
{
fprintf(stderr, "EGL X11: display wasn't created before the window\n");
throw GSRecoverableError();
}
xcb_connection_t* c = XGetXCBConnection(m_NativeDisplay);
const xcb_setup_t* setup = xcb_get_setup(c);
xcb_screen_t* screen = (xcb_setup_roots_iterator(setup)).data;
m_NativeWindow = xcb_generate_id(c);
if (m_NativeWindow == 0)
{
fprintf(stderr, "EGL X11: failed to create the native window\n");
throw GSRecoverableError();
}
xcb_create_window(c, depth, m_NativeWindow, screen->root, x, y, w, h,
border_width, InputOutput, screen->root_visual, 0, nullptr);
xcb_map_window(c, m_NativeWindow);
xcb_flush(c);
return (void*)&m_NativeWindow;
}
void* GSWndEGL_X11::AttachNativeWindow(void* handle)
{
m_NativeWindow = *(Window*)handle;
return handle;
m_NativeWindow = reinterpret_cast<Window>(wi.window_handle);
return &m_NativeWindow;
}
void GSWndEGL_X11::DestroyNativeResources()
{
if (m_NativeDisplay)
{
XCloseDisplay(m_NativeDisplay);
m_NativeDisplay = nullptr;
}
}
bool GSWndEGL_X11::SetWindowText(const char* title)
{
if (!m_managed)
return true;
xcb_connection_t* c = XGetXCBConnection(m_NativeDisplay);
xcb_change_property(c, XCB_PROP_MODE_REPLACE, m_NativeWindow,
XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
strlen(title), title);
return true;
}
#endif
@ -378,43 +292,36 @@ bool GSWndEGL_X11::SetWindowText(const char* title)
#if GS_EGL_WL
GSWndEGL_WL::GSWndEGL_WL()
: GSWndEGL(EGL_PLATFORM_WAYLAND_KHR), m_NativeDisplay(nullptr), m_NativeWindow(nullptr)
: GSWndEGL(EGL_PLATFORM_WAYLAND_KHR), m_NativeWindow(nullptr)
{
}
void* GSWndEGL_WL::CreateNativeDisplay()
void* GSWndEGL_WL::AttachNativeWindow(const WindowInfo& wi)
{
if (m_NativeDisplay == nullptr)
m_NativeDisplay = wl_display_connect(NULL);
if (wi.type != WindowInfo::Type::Wayland)
return nullptr;
return (void*)m_NativeDisplay;
}
m_NativeWindow = wl_egl_window_create(static_cast<wl_surface*>(wi.window_handle),
static_cast<int>(wi.surface_width),
static_cast<int>(wi.surface_height));
if (!m_NativeWindow)
{
std::fprintf(stderr, "Failed to create walyand EGL window\n");
return nullptr;
}
void* GSWndEGL_WL::CreateNativeWindow(int w, int h)
{
return nullptr;
}
void* GSWndEGL_WL::AttachNativeWindow(void* handle)
{
m_NativeWindow = (wl_egl_window*)handle;
return handle;
return m_NativeWindow;
}
void GSWndEGL_WL::DestroyNativeResources()
{
if (m_NativeDisplay)
if (m_NativeWindow)
{
wl_display_disconnect(m_NativeDisplay);
m_NativeDisplay = nullptr;
wl_egl_window_destroy(m_NativeWindow);
m_NativeWindow = nullptr;
}
}
bool GSWndEGL_WL::SetWindowText(const char* title)
{
return true;
}
#endif
#endif

View File

@ -46,35 +46,21 @@ public:
GSWndEGL(int platform);
virtual ~GSWndEGL(){};
bool Create(const std::string& title, int w, int h) final;
bool Attach(void* handle, bool managed = true) final;
static std::shared_ptr<GSWndEGL> CreateForPlatform(const WindowInfo& wi);
bool Attach(const WindowInfo& wi) final;
void Detach() final;
virtual void* CreateNativeDisplay() = 0;
virtual void* CreateNativeWindow(int w, int h) = 0; // GSopen1/PSX API
virtual void* AttachNativeWindow(void* handle) = 0;
virtual void* AttachNativeWindow(const WindowInfo& wi) = 0;
virtual void DestroyNativeResources() = 0;
GSVector4i GetClientRect();
virtual bool SetWindowText(const char* title) = 0; // GSopen1/PSX API
void AttachContext() final;
void DetachContext() final;
void* GetProcAddress(const char* name, bool opt = false) final;
void Flip() final;
// Deprecated API
void Show() final {}
void Hide() final {}
void HideFrame() final {} // DX9 API
virtual void* GetDisplay() = 0; // GSopen1 API
virtual void* GetHandle() = 0; // DX API
// Static to allow to query supported the platform
// before object creation
static int SelectPlatform();
};
#if GS_EGL_X11
@ -83,24 +69,18 @@ public:
#include <X11/Xlib.h>
#include <X11/Xlib-xcb.h>
class GSWndEGL_X11 : public GSWndEGL
class GSWndEGL_X11 final : public GSWndEGL
{
Display* m_NativeDisplay;
Window m_NativeWindow;
public:
GSWndEGL_X11();
virtual ~GSWndEGL_X11(){};
virtual ~GSWndEGL_X11() final = default;
void* GetDisplay() final { return (void*)m_NativeDisplay; }
void* GetHandle() final { return (void*)&m_NativeWindow; }
void* GetHandle() final { return reinterpret_cast<void*>(m_NativeWindow); }
void* CreateNativeDisplay() final;
void* CreateNativeWindow(int w, int h) final;
void* AttachNativeWindow(void* handle) final;
void* AttachNativeWindow(const WindowInfo& wi) final;
void DestroyNativeResources() final;
bool SetWindowText(const char* title) final;
};
#endif
@ -113,24 +93,18 @@ public:
#include <wayland-client-protocol.h>
#include <wayland-egl.h>
class GSWndEGL_WL : public GSWndEGL
class GSWndEGL_WL final : public GSWndEGL
{
wl_display* m_NativeDisplay;
wl_egl_window* m_NativeWindow;
public:
GSWndEGL_WL();
virtual ~GSWndEGL_WL(){};
virtual ~GSWndEGL_WL() final = default;
void* GetDisplay() final { return (void*)m_NativeDisplay; }
void* GetHandle() final { return (void*)m_NativeWindow; }
void* GetHandle() final { return reinterpret_cast<void*>(m_NativeWindow); }
void* CreateNativeDisplay() final;
void* CreateNativeWindow(int w, int h) final;
void* AttachNativeWindow(void* handle) final;
void* AttachNativeWindow(const WindowInfo& wi) final;
void DestroyNativeResources() final;
bool SetWindowText(const char* title) final;
};
#endif

View File

@ -41,23 +41,6 @@ GSWndWGL::GSWndWGL()
{
}
// Used by GSReplay. Perhaps the stuff used by GSReplay can be moved out? That way all
// the GSOpen 1 stuff can be removed. But that'll take a bit of thinking.
LRESULT CALLBACK GSWndWGL::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CLOSE:
// This takes place before GSClose, so don't destroy the Window so we can clean up.
ShowWindow(hWnd, SW_HIDE);
// DestroyWindow(hWnd);
return 0;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
void GSWndWGL::CreateContext(int major, int minor)
{
if (!m_NativeDisplay || !m_NativeWindow)
@ -156,10 +139,12 @@ void GSWndWGL::PopulateWndGlFunction()
}
}
bool GSWndWGL::Attach(void* handle, bool managed)
bool GSWndWGL::Attach(const WindowInfo& wi)
{
m_NativeWindow = (HWND)handle;
m_managed = managed;
if (wi.type != WindowInfo::Type::Win32)
return false;
m_NativeWindow = static_cast<HWND>(wi.window_handle);
OpenWGLDisplay();
@ -181,13 +166,6 @@ void GSWndWGL::Detach()
m_context = NULL;
CloseWGLDisplay();
// Used by GSReplay.
if (m_NativeWindow && m_managed)
{
DestroyWindow(m_NativeWindow);
m_NativeWindow = NULL;
}
}
void GSWndWGL::OpenWGLDisplay()
@ -235,77 +213,6 @@ void GSWndWGL::CloseWGLDisplay()
m_NativeDisplay = NULL;
}
//TODO: GSopen 1 => Drop?
// Used by GSReplay. At least for now.
// More or less copy pasted from GSWndDX::Create and GSWndWGL::Attach with a few
// modifications
bool GSWndWGL::Create(const std::string& title, int w, int h)
{
if (m_NativeWindow)
return false;
m_managed = true;
WNDCLASS wc;
memset(&wc, 0, sizeof(wc));
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.hInstance = theApp.GetModuleHandle();
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszClassName = L"GSWndOGL";
if (!GetClassInfo(wc.hInstance, wc.lpszClassName, &wc))
{
if (!RegisterClass(&wc))
{
return false;
}
}
DWORD style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW | WS_BORDER;
GSVector4i r;
GetWindowRect(GetDesktopWindow(), r);
// Old GSOpen ModeWidth and ModeHeight are not necessary with this.
bool remote = !!GetSystemMetrics(SM_REMOTESESSION);
if (w <= 0 || h <= 0 || remote)
{
w = r.width() / 3;
h = r.width() / 4;
if (!remote)
{
w *= 2;
h *= 2;
}
}
r.left = (r.left + r.right - w) / 2;
r.top = (r.top + r.bottom - h) / 2;
r.right = r.left + w;
r.bottom = r.top + h;
AdjustWindowRect(r, style, FALSE);
std::wstring tmp = std::wstring(title.begin(), title.end());
m_NativeWindow = CreateWindow(wc.lpszClassName, tmp.c_str(), style, r.left, r.top, r.width(), r.height(), NULL, NULL, wc.hInstance, (LPVOID)this);
if (m_NativeWindow == NULL)
return false;
OpenWGLDisplay();
FullContextInit();
return true;
}
//Same as DX
GSVector4i GSWndWGL::GetClientRect()
{
@ -360,42 +267,4 @@ void GSWndWGL::Flip()
SwapBuffers(m_NativeDisplay);
}
void GSWndWGL::Show()
{
if (!m_managed)
return;
// Used by GSReplay
SetForegroundWindow(m_NativeWindow);
ShowWindow(m_NativeWindow, SW_SHOWNORMAL);
UpdateWindow(m_NativeWindow);
}
void GSWndWGL::Hide()
{
}
void GSWndWGL::HideFrame()
{
}
// Returns FALSE if the window has no title, or if th window title is under the strict
// management of the emulator.
bool GSWndWGL::SetWindowText(const char* title)
{
if (!m_managed)
return false;
const size_t tmp_size = strlen(title) + 1;
std::wstring tmp(tmp_size, L'#');
mbstowcs(&tmp[0], title, tmp_size);
// Used by GSReplay.
::SetWindowText(m_NativeWindow, tmp.c_str());
return true;
}
#endif

View File

@ -17,7 +17,7 @@
#ifdef _WIN32
class GSWndWGL : public GSWndGL
class GSWndWGL final : public GSWndGL
{
HWND m_NativeWindow;
HDC m_NativeDisplay;
@ -35,29 +35,21 @@ class GSWndWGL : public GSWndGL
void SetSwapInterval();
bool HasLateVsyncSupport() { return m_has_late_vsync; }
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
public:
GSWndWGL();
virtual ~GSWndWGL() {}
~GSWndWGL() override = default;
bool Create(const std::string& title, int w, int h);
bool Attach(void* handle, bool managed = true);
void Detach();
bool Attach(const WindowInfo& wi) override;
void Detach() override;
void* GetDisplay() { return m_NativeWindow; }
void* GetHandle() { return m_NativeWindow; }
GSVector4i GetClientRect();
bool SetWindowText(const char* title);
void* GetHandle() override { return m_NativeWindow; }
GSVector4i GetClientRect() override;
void AttachContext();
void DetachContext();
void* GetProcAddress(const char* name, bool opt);
void AttachContext() override;
void DetachContext() override;
void* GetProcAddress(const char* name, bool opt) override;
void Show();
void Hide();
void HideFrame();
void Flip();
void Flip() override;
};
#endif

View File

@ -25,6 +25,8 @@
#include "Elfheader.h"
#include "gui/Dialogs/ModalPopups.h"
#include "common/WindowInfo.h"
extern WindowInfo g_gs_window_info;
// Uncomment this to enable profiling of the GS RingBufferCopy function.
//#define PCSX2_GSRING_SAMPLING_STATS
@ -237,7 +239,7 @@ void SysMtgsThread::OpenGS()
memcpy(RingBuffer.Regs, PS2MEM_GS, sizeof(PS2MEM_GS));
GSsetBaseMem(RingBuffer.Regs);
pxAssertMsg((GSopen2((void**)pDsp, 1 | (renderswitch ? 4 : 0)) == 0), "GS failed to open!");
pxAssertMsg((GSopen2(g_gs_window_info, 1 | (renderswitch ? 4 : 0)) == 0), "GS failed to open!");
GSsetVsync(EmuConfig.GS.GetVsync());

View File

@ -18,6 +18,9 @@
#include <fcntl.h>
#include <stdarg.h>
// NOTE: Must come first because of the None enum
#include "common/WindowInfo.h"
#include "keyboard.h"
#include "PAD.h"
#include "state_management.h"
@ -109,7 +112,7 @@ void PADshutdown()
CloseLogging();
}
s32 PADopen(void* pDsp)
s32 PADopen(const WindowInfo& wi)
{
memset(&event, 0, sizeof(event));
g_key_status.Init();
@ -119,7 +122,7 @@ s32 PADopen(void* pDsp)
#if defined(__unix__) || defined(__APPLE__)
EnumerateDevices();
#endif
return _PADopen(pDsp);
return _PADopen(wi);
}
void PADsetLogDir(const char* dir)

View File

@ -31,13 +31,15 @@ enum PadOptions
PADOPTION_MOUSE_R = 0x40,
};
struct WindowInfo;
extern FILE* padLog;
extern void initLogging();
extern HostKeyEvent event;
extern MtQueue<HostKeyEvent> g_ev_fifo;
s32 _PADopen(void* pDsp);
s32 _PADopen(const WindowInfo& wi);
void _PADclose();
void PADsetMode(int pad, int mode);
@ -45,7 +47,7 @@ void SysMessage(char* fmt, ...);
s32 PADinit();
void PADshutdown();
s32 PADopen(void* pDsp);
s32 PADopen(const WindowInfo& wi);
void PADsetLogDir(const char* dir);
void PADclose();
s32 PADsetSlot(u8 port, u8 slot);

View File

@ -262,6 +262,9 @@ void UpdateKeyboardInput()
g_ev_fifo.consume_all(AnalyzeKeyEvent);
// keyboard input
if (!GSdsp)
return;
while (XPending(GSdsp) > 0)
{
XNextEvent(GSdsp, &E);

View File

@ -14,6 +14,8 @@
*/
#include "gui/AppCoreThread.h"
#include "common/WindowInfo.h"
#include "Global.h"
#include "Device.h"
#include "keyboard.h"
@ -42,11 +44,14 @@ static void SysMessage(const char* fmt, ...)
dialog.ShowModal();
}
s32 _PADopen(void* pDsp)
s32 _PADopen(const WindowInfo& wi)
{
#ifndef __APPLE__
GSdsp = *(Display**)pDsp;
GSwin = (Window) * (((u32*)pDsp) + 1);
if (wi.type != WindowInfo::Type::X11)
return -1;
GSdsp = static_cast<Display*>(wi.display_connection);
GSwin = reinterpret_cast<Window>(wi.window_handle);
#endif
return 0;
@ -65,7 +70,7 @@ void PADupdate(int pad)
// Emulate an user activity
static int count = 0;
count++;
if ((count & 0xFFF) == 0)
if ((count & 0xFFF) == 0 && GSdsp)
{
// 1 call every 4096 Vsync is enough
XResetScreenSaver(GSdsp);

View File

@ -15,6 +15,7 @@
#include "PrecompiledHeader.h"
#include "Global.h"
#include "Common/WindowInfo.h"
#include <fstream>
#include <iomanip>
@ -34,17 +35,17 @@
#include "KeyboardQueue.h"
#include "DualShock3.h"
#ifndef PCSX2_CORE
#include "gui/AppCoreThread.h"
#endif
#define WMA_FORCE_UPDATE (WM_APP + 0x537)
#define FORCE_UPDATE_WPARAM ((WPARAM)0x74328943)
#define FORCE_UPDATE_LPARAM ((LPARAM)0x89437437)
#ifdef __linux__
Display* GSdsp;
Window GSwin;
#else
HWND hWnd;
static WindowInfo s_window_info;
#ifdef _WIN32
HWND hWndTop;
WndProcEater hWndGSProc;
@ -483,7 +484,8 @@ void Update(unsigned int port, unsigned int slot)
if (!updateQueued)
{
updateQueued = 1;
PostMessage(hWnd, WMA_FORCE_UPDATE, FORCE_UPDATE_WPARAM, FORCE_UPDATE_LPARAM);
PostMessage(static_cast<HWND>(s_window_info.window_handle),
WMA_FORCE_UPDATE, FORCE_UPDATE_WPARAM, FORCE_UPDATE_LPARAM);
}
}
else
@ -963,67 +965,52 @@ ExtraWndProcResult StatusWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa
}
#endif
#ifndef PCSX2_CORE
void PADconfigure()
{
ScopedCoreThreadPause paused_core(SystemsMask::System_PAD);
Configure();
paused_core.AllowResume();
}
#endif
s32 PADopen(void* pDsp)
s32 PADopen(const WindowInfo& wi)
{
if (openCount++)
return 0;
miceEnabled = !config.mouseUnfocus;
#ifdef _MSC_VER
if (!hWnd)
if (wi.type != WindowInfo::Type::Win32)
{
if (IsWindow((HWND)pDsp))
{
hWnd = (HWND)pDsp;
}
else if (pDsp && !IsBadReadPtr(pDsp, 4) && IsWindow(*(HWND*)pDsp))
{
hWnd = *(HWND*)pDsp;
}
else
{
openCount = 0;
MessageBoxA(GetActiveWindow(),
"Invalid Window handle passed to PAD.\n"
"\n"
"Either your emulator or gs plugin is buggy,\n"
"Despite the fact the emulator is about to\n"
"blame PAD for failing to initialize.",
"Non-PAD Error", MB_OK | MB_ICONERROR);
return -1;
}
hWndTop = GetAncestor(hWnd, GA_ROOT);
if (!hWndGSProc.SetWndHandle(hWnd))
{
openCount = 0;
return -1;
}
// Implements most hacks, as well as enabling/disabling mouse
// capture when focus changes.
updateQueued = 0;
hWndGSProc.Eat(StatusWndProc, 0);
if (hWnd != hWndTop)
{
if (!hWndTopProc.SetWndHandle(hWndTop))
{
openCount = 0;
return -1;
}
}
windowThreadId = GetWindowThreadProcessId(hWndTop, 0);
openCount = 0;
MessageBoxA(GetActiveWindow(),
"Invalid Window handle passed to PAD.\n"
"\n"
"Either your emulator or gs plugin is buggy,\n"
"Despite the fact the emulator is about to\n"
"blame PAD for failing to initialize.",
"Non-PAD Error", MB_OK | MB_ICONERROR);
return -1;
}
const HWND hWnd = static_cast<HWND>(wi.window_handle);
hWndTop = GetAncestor(hWnd, GA_ROOT);
if (!hWndGSProc.SetWndHandle(hWnd))
{
openCount = 0;
return -1;
}
// Implements most hacks, as well as enabling/disabling mouse
// capture when focus changes.
updateQueued = 0;
hWndGSProc.Eat(StatusWndProc, 0);
windowThreadId = GetWindowThreadProcessId(hWndTop, 0);
s_window_info = wi;
#endif
for (int port = 0; port < 2; port++)
{
@ -1049,10 +1036,6 @@ s32 PADopen(void* pDsp)
// activeWindow = GetActiveWindow() == hWnd;
// activeWindow = (GetAncestor(hWnd, GA_ROOT) == GetAncestor(GetForegroundWindow(), GA_ROOT));
#else
// Not used so far
GSdsp = *(Display**)pDsp;
GSwin = (Window) * (((uptr*)pDsp) + 1);
#endif
activeWindow = 1;
UpdateEnabledDevices();
@ -1068,8 +1051,7 @@ void PADclose()
hWndGSProc.Release();
hWndTopProc.Release();
dm->ReleaseInput();
hWnd = 0;
hWndTop = 0;
s_window_info = WindowInfo();
#else
R_ClearKeyQueue();
#endif

View File

@ -36,6 +36,7 @@
#include "SaveState.h"
struct HostKeyEvent;
struct WindowInfo;
struct PadDataS
{
@ -49,12 +50,14 @@ struct PadDataS
void PADupdate(int pad);
void PADshutdown();
s32 PADinit();
s32 PADopen(void* pDsp);
s32 PADopen(const WindowInfo& wi);
void PADclose();
u8 PADstartPoll(int pad);
u8 PADpoll(u8 value);
HostKeyEvent* PADkeyEvent();
#ifndef PCSX2_CORE
void PADconfigure();
#endif
s32 PADfreeze(FreezeAction mode, freezeData* data);
s32 PADsetSlot(u8 port, u8 slot);
void PADsetSettingsDir(const char* dir);

View File

@ -20,8 +20,6 @@
#include "common/StringHelpers.h"
extern uptr gsWindowHandle;
void SysMessage(const char* fmt, ...)
{
va_list list;
@ -32,8 +30,9 @@ void SysMessage(const char* fmt, ...)
vsprintf_s(tmp, fmt, list);
va_end(list);
swprintf_s(wtmp, L"%S", tmp);
MessageBox((!!gsWindowHandle) ? (HWND)gsWindowHandle : GetActiveWindow(), wtmp,
L"SPU2 System Message", MB_OK | MB_SETFOREGROUND);
// TODO: Move this into app/host.
MessageBox(NULL, wtmp, L"SPU2 System Message", MB_OK | MB_SETFOREGROUND);
}
void SysMessage(const wchar_t* fmt, ...)
@ -43,8 +42,7 @@ void SysMessage(const wchar_t* fmt, ...)
wxString wtmp;
wtmp.PrintfV(fmt, list);
va_end(list);
MessageBox((!!gsWindowHandle) ? (HWND)gsWindowHandle : GetActiveWindow(), wtmp,
L"SPU2 System Message", MB_OK | MB_SETFOREGROUND);
MessageBox(NULL, wtmp, L"SPU2 System Message", MB_OK | MB_SETFOREGROUND);
}
//////

View File

@ -250,7 +250,7 @@ static INT_PTR CALLBACK DebugProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lP
#endif
uptr gsWindowHandle = 0;
s32 SPU2open(void* pDsp)
s32 SPU2open()
{
ScopedLock lock(mtx_SPU2Status);
if (IsOpened)
@ -258,11 +258,6 @@ s32 SPU2open(void* pDsp)
FileLog("[%10d] SPU2 Open\n", Cycles);
if (pDsp != nullptr)
gsWindowHandle = *(uptr*)pDsp;
else
gsWindowHandle = 0;
#ifdef _MSC_VER
#ifdef PCSX2_DEVBUILD // Define may not be needed but not tested yet. Better make sure.
if (IsDevBuild && VisualDebug())

View File

@ -28,7 +28,7 @@ enum class PS2Modes
s32 SPU2init();
s32 SPU2reset(PS2Modes isRunningPSXMode);
s32 SPU2open(void* pDsp);
s32 SPU2open();
void SPU2close();
void SPU2shutdown();
void SPU2write(u32 mem, u16 value);

View File

@ -19,6 +19,9 @@
#include "IopBios.h"
#include "R5900.h"
#include "common/WindowInfo.h"
extern WindowInfo g_gs_window_info;
#include "Counters.h"
#include "GS.h"
#include "Elfheader.h"
@ -323,11 +326,11 @@ void SysCoreThread::TearDownSystems(SystemsMask systemsToTearDown)
void SysCoreThread::OnResumeInThread(SystemsMask systemsToReinstate)
{
GetMTGS().WaitForOpen();
if (systemsToReinstate & System_DEV9) DEV9open((void*)pDsp);
if (systemsToReinstate & System_USB) USBopen((void*)pDsp);
if (systemsToReinstate & System_DEV9) DEV9open();
if (systemsToReinstate & System_USB) USBopen(g_gs_window_info);
if (systemsToReinstate & System_FW) FWopen();
if (systemsToReinstate & System_SPU2) SPU2open((void*)pDsp);
if (systemsToReinstate & System_PAD) PADopen((void*)pDsp);
if (systemsToReinstate & System_SPU2) SPU2open();
if (systemsToReinstate & System_PAD) PADopen(g_gs_window_info);
if (systemsToReinstate & System_MCD) FileMcd_EmuOpen();
}

View File

@ -21,6 +21,7 @@
#include "PrecompiledHeader.h"
#include "common/pxStreams.h"
#include "common/WindowInfo.h"
#include "USB.h"
#include "qemu-usb/USBinternal.h"
#include "qemu-usb/desc.h"
@ -67,7 +68,7 @@ int64_t usb_bit_time;
s64 clocks = 0;
s64 remaining = 0;
#if _WIN32
#if defined(_WIN32)
HWND gsWnd = nullptr;
#elif defined(__linux__)
#include "gtk.h"
@ -243,7 +244,7 @@ void USBshutdown()
usb_opened = false;
}
s32 USBopen(void* pDsp)
s32 USBopen(const WindowInfo& wi)
{
if (conf.Log && !usbLog)
@ -252,29 +253,25 @@ s32 USBopen(void* pDsp)
//if(usbLog) setvbuf(usbLog, NULL, _IONBF, 0);
}
#if _WIN32
HWND hWnd = 0;
if (IsWindow((HWND)pDsp))
void* window_handle_for_init = nullptr;
#if defined(_WIN32)
if (wi.type == WindowInfo::Type::Win32)
{
hWnd = (HWND)pDsp;
gsWnd = static_cast<HWND>(wi.window_handle);
window_handle_for_init = wi.window_handle;
}
else if (pDsp && !IsBadReadPtr(pDsp, 4) && IsWindow(*(HWND*)pDsp))
{
hWnd = *(HWND*)pDsp;
}
gsWnd = hWnd;
pDsp = gsWnd;
#elif defined(__linux__)
g_GSdsp = (Display*)((uptr*)pDsp)[0];
g_GSwin = (Window)((uptr*)pDsp)[1];
if (wi.type == WindowInfo::Type::X11)
{
g_GSdsp = static_cast<Display*>(wi.display_connection);
g_GSwin = reinterpret_cast<Window>(wi.window_handle);
window_handle_for_init = reinterpret_cast<void*>(g_GSwin);
}
#endif
try
{
shared::Initialize(pDsp);
shared::Initialize(window_handle_for_init);
}
catch (std::runtime_error& e)
{
@ -298,6 +295,12 @@ void USBclose()
CloseDevice(1);
shared::Uninitialize();
usb_opened = false;
#if defined(_WIN32)
gsWnd = {};
#elif defined(__linux__)
g_GSdsp = nullptr;
g_GSwin = {};
#endif
}
u8 USBread8(u32 addr)

View File

@ -22,6 +22,8 @@
#include "SaveState.h"
struct WindowInfo;
// ---------------------------------------------------------------------
#define USBdefs
@ -38,7 +40,7 @@ s32 USBinit();
void USBasync(u32 cycles);
void USBshutdown();
void USBclose();
s32 USBopen(void* pDsp);
s32 USBopen(const WindowInfo& wi);
s32 USBfreeze(FreezeAction mode, freezeData* data);
u8 USBread8(u32 addr);

View File

@ -26,7 +26,7 @@ s32 USBinit() { return 0; }
void USBasync(u32 cycles) {}
void USBshutdown() {}
void USBclose() {}
s32 USBopen(void* pDsp) { return 0; }
s32 USBopen(const WindowInfo& wi) { return 0; }
s32 USBfreeze(FreezeAction mode, freezeData* data) { return 0; }
u8 USBread8(u32 addr) { return 0; }

View File

@ -15,7 +15,8 @@
#pragma once
#include "gui/wxAppWithHelpers.h"
#include "wxAppWithHelpers.h"
#include "common/WindowInfo.h"
#include <wx/fileconf.h>
#include <wx/apptrait.h>
@ -39,7 +40,8 @@ struct HostKeyEvent;
#include "System.h"
#include "System/SysThreads.h"
extern uptr pDsp[2];
// TODO: Not the best location for this, but it needs to be accessed by MTGS etc.
extern WindowInfo g_gs_window_info;
typedef void FnType_OnThreadComplete(const wxCommandEvent& evt);
typedef void (Pcsx2App::*FnPtr_Pcsx2App)();

View File

@ -73,7 +73,7 @@ wxIMPLEMENT_APP(Pcsx2App);
std::unique_ptr<AppConfig> g_Conf;
uptr pDsp[2];
WindowInfo g_gs_window_info;
// Returns a string message telling the user to consult guides for obtaining a legal BIOS.
// This message is in a function because it's used as part of several dialogs in PCSX2 (there
@ -864,39 +864,12 @@ void Pcsx2App::OpenGsPanel()
pxAssertDev( !gsopen_done, "GS must be closed prior to opening a new Gs Panel!" );
#ifdef __WXGTK__
// The x window/display are actually very deeper in the widget. You need both display and window
// because unlike window there are unrelated. One could think it would be easier to send directly the GdkWindow.
// Unfortunately there is a race condition between gui and gs threads when you called the
// GDK_WINDOW_* macro. To be safe I think it is best to do here. -- Gregory
gsFrame->ShowFullScreen(g_Conf->GSWindow.IsFullscreen);
wxApp::ProcessPendingEvents();
// GTK_PIZZA is an internal interface of wx, therefore they decide to
// remove it on wx 3. I tryed to replace it with gtk_widget_get_window but
// unfortunately it creates a gray box in the middle of the window on some
// users.
GtkWidget *child_window = GTK_WIDGET(gsFrame->GetViewport()->GetHandle());
gtk_widget_realize(child_window); // create the widget to allow to use GDK_WINDOW_* macro
gtk_widget_set_double_buffered(child_window, false); // Disable the widget double buffer, you will use the opengl one
GdkWindow* draw_window = gtk_widget_get_window(child_window);
#if GTK_MAJOR_VERSION < 3
Window Xwindow = GDK_WINDOW_XWINDOW(draw_window);
#else
Window Xwindow = GDK_WINDOW_XID(draw_window);
#endif
Display* XDisplay = GDK_WINDOW_XDISPLAY(draw_window);
pDsp[0] = (uptr)XDisplay;
pDsp[1] = (uptr)Xwindow;
#else
pDsp[0] = (uptr)gsFrame->GetViewport()->GetHandle();
pDsp[1] = NULL;
#endif
gsFrame->ShowFullScreen( g_Conf->GSWindow.IsFullscreen );
std::optional<WindowInfo> wi = gsFrame->GetViewport()->GetWindowInfo();
pxAssertDev(wi.has_value(), "GS frame has a valid native window");
g_gs_window_info = std::move(*wi);
#ifndef DISABLE_RECORDING
// Enable New & Play after the first game load of the session

View File

@ -775,7 +775,7 @@ void Dialogs::GSDumpDialog::GSThread::ExecuteTaskInThread()
}
GSsetBaseMem((u8*)regs);
if (GSopen2((void**)pDsp, (renderer_override<<24)) != 0)
if (GSopen2(g_gs_window_info, (renderer_override<<24)) != 0)
{
OnStop();
return;

View File

@ -43,6 +43,20 @@
#include <sstream>
#include <iomanip>
#ifdef __WXGTK__
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
// Junk X11 macros...
#ifdef DisableScreenSaver
#undef DisableScreenSaver
#endif
#endif
#ifdef GDK_WINDOWING_WAYLAND
#include <gdk/gdkwayland.h>
#endif
//#define GSWindowScaleDebug
static const KeyAcceleratorCode FULLSCREEN_TOGGLE_ACCELERATOR_GSPANEL=KeyAcceleratorCode( WXK_RETURN ).Alt();
@ -229,6 +243,10 @@ GSPanel::GSPanel( wxWindow* parent )
GSPanel::~GSPanel()
{
//CoreThread.Suspend( false ); // Just in case...!
#ifdef WAYLAND_API
WaylandDestroySubsurface();
#endif
}
void GSPanel::DoShowMouse()
@ -243,6 +261,74 @@ void GSPanel::DoShowMouse()
m_HideMouseTimer.Start( 1750, true );
}
std::optional<WindowInfo> GSPanel::GetWindowInfo()
{
WindowInfo ret;
const wxSize gs_vp_size(GetClientSize());
ret.surface_scale = static_cast<float>(GetContentScaleFactor());
ret.surface_width = static_cast<u32>(gs_vp_size.GetWidth());
ret.surface_height = static_cast<u32>(gs_vp_size.GetHeight());
#if defined(_WIN32)
ret.type = WindowInfo::Type::Win32;
ret.window_handle = GetHandle();
#elif defined(__WXGTK__)
GtkWidget* child_window = GTK_WIDGET(GetHandle());
// create the widget to allow to use GDK_WINDOW_* macro
gtk_widget_realize(child_window);
// Disable the widget double buffer, you will use the opengl one
gtk_widget_set_double_buffered(child_window, false);
GdkWindow* draw_window = gtk_widget_get_window(child_window);
// TODO: Do we even want to support GTK2?
#if GTK_MAJOR_VERSION < 3
ret.type = WindowInfo::Type::X11;
ret.display_connection = GDK_WINDOW_XDISPLAY(draw_window);
ret.window_handle = reinterpret_cast<void*>(GDK_WINDOW_XWINDOW(draw_window));
#else
#ifdef GDK_WINDOWING_X11
if (GDK_IS_X11_WINDOW(draw_window))
{
ret.type = WindowInfo::Type::X11;
ret.display_connection = GDK_WINDOW_XDISPLAY(draw_window);
ret.window_handle = reinterpret_cast<void*>(GDK_WINDOW_XID(draw_window));
// GTK/X11 seems to not scale coordinates?
ret.surface_width = static_cast<u32>(ret.surface_width * ret.surface_scale);
ret.surface_height = static_cast<u32>(ret.surface_height * ret.surface_scale);
}
#endif // GDK_WINDOWING_X11
#if defined(GDK_WINDOWING_WAYLAND) && defined(WAYLAND_API)
if (GDK_IS_WAYLAND_WINDOW(draw_window))
{
wl_display* display = gdk_wayland_display_get_wl_display(gdk_window_get_display(draw_window));
wl_surface* parent_surface = gdk_wayland_window_get_wl_surface(draw_window);
if (!m_wl_child_surface && !WaylandCreateSubsurface(display, parent_surface))
return std::nullopt;
ret.type = WindowInfo::Type::Wayland;
ret.display_connection = display;
ret.window_handle = m_wl_child_surface;
}
#endif // GDK_WINDOWING_WAYLAND
#endif // GTK_MAJOR_VERSION >= 3
#elif defined(__WXOSX__)
ret.type = WindowInfo::Type::MacOS;
ret.window_handle = GetHandle();
#endif
if (ret.type == WindowInfo::Type::Surfaceless)
{
Console.Error("Unknown window type for GSFrame.");
return std::nullopt;
}
return ret;
}
void GSPanel::OnResize(wxSizeEvent& event)
{
@ -475,6 +561,103 @@ void GSPanel::OnLeftDclick(wxMouseEvent& evt)
DirectKeyCommand(FULLSCREEN_TOGGLE_ACCELERATOR_GSPANEL);
}
#if defined(__WXGTK__) && defined(GDK_WINDOWING_WAYLAND) && defined(WAYLAND_API)
void GSPanel::WaylandGlobalRegistryAddHandler(void* data, wl_registry* registry, uint32_t id, const char* interface, uint32_t version)
{
GSPanel* pnl = static_cast<GSPanel*>(data);
if (std::strcmp(interface, wl_compositor_interface.name) == 0)
{
pnl->m_wl_compositor = static_cast<wl_compositor*>(wl_registry_bind(registry, id, &wl_compositor_interface, wl_compositor_interface.version));
}
else if (std::strcmp(interface, wl_subcompositor_interface.name) == 0)
{
pnl->m_wl_subcompositor = static_cast<wl_subcompositor*>(wl_registry_bind(registry, id, &wl_subcompositor_interface, wl_subcompositor_interface.version));
}
}
void GSPanel::WaylandGlobalRegistryRemoveHandler(void* data, wl_registry* registry, uint32_t id)
{
}
bool GSPanel::WaylandCreateSubsurface(wl_display* display, wl_surface* surface)
{
static constexpr wl_registry_listener registry_listener = {
&GSPanel::WaylandGlobalRegistryAddHandler,
&GSPanel::WaylandGlobalRegistryRemoveHandler
};
wl_registry* registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, this);
wl_display_flush(display);
wl_display_roundtrip(display);
if (!m_wl_compositor || !m_wl_subcompositor)
{
Console.Error("Missing wl_compositor or wl_subcompositor");
return false;
}
wl_registry_destroy(registry);
m_wl_child_surface = wl_compositor_create_surface(m_wl_compositor);
if (!m_wl_child_surface)
{
Console.Error("Failed to create compositor surface");
return false;
}
wl_region* input_region = wl_compositor_create_region(m_wl_compositor);
if (!input_region)
{
Console.Error("Failed to create input region");
return false;
}
wl_surface_set_input_region(m_wl_child_surface, input_region);
wl_region_destroy(input_region);
m_wl_child_subsurface = wl_subcompositor_get_subsurface(m_wl_subcompositor, m_wl_child_surface, surface);
if (!m_wl_child_subsurface)
{
Console.Error("Failed to create subsurface");
return false;
}
// we want to present asynchronously to the surrounding window
wl_subsurface_set_desync(m_wl_child_subsurface);
return true;
}
void GSPanel::WaylandDestroySubsurface()
{
if (m_wl_child_subsurface)
{
wl_subsurface_destroy(m_wl_child_subsurface);
m_wl_child_subsurface = nullptr;
}
if (m_wl_child_surface)
{
wl_surface_destroy(m_wl_child_surface);
m_wl_child_surface = nullptr;
}
if (m_wl_subcompositor)
{
wl_subcompositor_destroy(m_wl_subcompositor);
m_wl_subcompositor = nullptr;
}
if (m_wl_compositor)
{
wl_compositor_destroy(m_wl_compositor);
m_wl_compositor = nullptr;
}
}
#endif
// --------------------------------------------------------------------------------------
// GSFrame Implementation
// --------------------------------------------------------------------------------------

View File

@ -18,7 +18,13 @@
#include "AppCommon.h"
#include "CpuUsageProvider.h"
#include "common/WindowInfo.h"
#include <memory>
#include <optional>
#ifdef WAYLAND_API
#include <wayland-client.h>
#endif
// --------------------------------------------------------------------------------------
// GSPanel
@ -41,6 +47,8 @@ public:
GSPanel( wxWindow* parent );
virtual ~GSPanel();
std::optional<WindowInfo> GetWindowInfo();
void DoShowMouse();
void DirectKeyCommand( wxKeyEvent& evt );
void DirectKeyCommand( const KeyAcceleratorCode& kac );
@ -67,6 +75,20 @@ protected:
void OnLeftDclick( wxMouseEvent& evt );
void UpdateScreensaver();
private:
#ifdef WAYLAND_API
static void WaylandGlobalRegistryAddHandler(void* data, wl_registry* registry, uint32_t id, const char* interface, uint32_t version);
static void WaylandGlobalRegistryRemoveHandler(void* data, wl_registry* registry, uint32_t id);
bool WaylandCreateSubsurface(wl_display* display, wl_surface* parent_surface);
void WaylandDestroySubsurface();
wl_compositor* m_wl_compositor = nullptr;
wl_subcompositor* m_wl_subcompositor = nullptr;
wl_surface* m_wl_child_surface = nullptr;
wl_subsurface* m_wl_child_subsurface = nullptr;
#endif
};