mirror of https://github.com/PCSX2/pcsx2.git
ContextWGL: Use pbuffers when we don't have a surface
Fixes context restore error tripping when confirming shutdown while fullscreen in Qt.
This commit is contained in:
parent
771b1490d2
commit
5c88c585a0
|
@ -13,10 +13,10 @@
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "common/PrecompiledHeader.h"
|
#include "common/GL/ContextWGL.h"
|
||||||
|
#include "common/Assertions.h"
|
||||||
#include "common/Console.h"
|
#include "common/Console.h"
|
||||||
#include "ContextWGL.h"
|
#include "common/ScopedGuard.h"
|
||||||
|
|
||||||
static void* GetProcAddressCallback(const char* name)
|
static void* GetProcAddressCallback(const char* name)
|
||||||
{
|
{
|
||||||
|
@ -43,8 +43,7 @@ namespace GL
|
||||||
if (m_rc)
|
if (m_rc)
|
||||||
wglDeleteContext(m_rc);
|
wglDeleteContext(m_rc);
|
||||||
|
|
||||||
if (m_dc)
|
ReleaseDC();
|
||||||
ReleaseDC(GetHWND(), m_dc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Context> ContextWGL::Create(const WindowInfo& wi, const Version* versions_to_try,
|
std::unique_ptr<Context> ContextWGL::Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||||
|
@ -66,7 +65,7 @@ namespace GL
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.Error("PBuffer not implemented");
|
Console.Error("ContextWGL must always start with a valid surface.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,11 +101,7 @@ namespace GL
|
||||||
{
|
{
|
||||||
const bool was_current = (wglGetCurrentContext() == m_rc);
|
const bool was_current = (wglGetCurrentContext() == m_rc);
|
||||||
|
|
||||||
if (m_dc)
|
ReleaseDC();
|
||||||
{
|
|
||||||
ReleaseDC(GetHWND(), m_dc);
|
|
||||||
m_dc = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
m_wi = new_wi;
|
m_wi = new_wi;
|
||||||
if (!InitializeDC())
|
if (!InitializeDC())
|
||||||
|
@ -187,7 +182,7 @@ namespace GL
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ContextWGL::InitializeDC()
|
HDC ContextWGL::GetDCAndSetPixelFormat(HWND hwnd)
|
||||||
{
|
{
|
||||||
PIXELFORMATDESCRIPTOR pfd = {};
|
PIXELFORMATDESCRIPTOR pfd = {};
|
||||||
pfd.nSize = sizeof(pfd);
|
pfd.nSize = sizeof(pfd);
|
||||||
|
@ -200,26 +195,154 @@ namespace GL
|
||||||
pfd.cBlueBits = 8;
|
pfd.cBlueBits = 8;
|
||||||
pfd.cColorBits = 24;
|
pfd.cColorBits = 24;
|
||||||
|
|
||||||
m_dc = GetDC(GetHWND());
|
HDC hDC = ::GetDC(hwnd);
|
||||||
if (!m_dc)
|
if (!hDC)
|
||||||
{
|
{
|
||||||
Console.Error("GetDC() failed: 0x%08X", GetLastError());
|
Console.Error("GetDC() failed: 0x%08X", GetLastError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int pf = ChoosePixelFormat(m_dc, &pfd);
|
if (!m_pixel_format.has_value())
|
||||||
if (pf == 0)
|
|
||||||
{
|
{
|
||||||
Console.Error("ChoosePixelFormat() failed: 0x%08X", GetLastError());
|
const int pf = ChoosePixelFormat(hDC, &pfd);
|
||||||
return false;
|
if (pf == 0)
|
||||||
|
{
|
||||||
|
Console.Error("ChoosePixelFormat() failed: 0x%08X", GetLastError());
|
||||||
|
::ReleaseDC(hwnd, hDC);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pixel_format = pf;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SetPixelFormat(m_dc, pf, &pfd))
|
if (!SetPixelFormat(hDC, m_pixel_format.value(), &pfd))
|
||||||
{
|
{
|
||||||
Console.Error("SetPixelFormat() failed: 0x%08X", GetLastError());
|
Console.Error("SetPixelFormat() failed: 0x%08X", GetLastError());
|
||||||
|
::ReleaseDC(hwnd, hDC);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return hDC;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ContextWGL::InitializeDC()
|
||||||
|
{
|
||||||
|
if (m_wi.type == WindowInfo::Type::Win32)
|
||||||
|
{
|
||||||
|
m_dc = GetDCAndSetPixelFormat(GetHWND());
|
||||||
|
if (!m_dc)
|
||||||
|
{
|
||||||
|
Console.Error("Failed to get DC for window");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (m_wi.type == WindowInfo::Type::Surfaceless)
|
||||||
|
{
|
||||||
|
return CreatePBuffer();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.Error("Unknown window info type %u", static_cast<unsigned>(m_wi.type));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextWGL::ReleaseDC()
|
||||||
|
{
|
||||||
|
if (m_pbuffer)
|
||||||
|
{
|
||||||
|
wglReleasePbufferDCARB(m_pbuffer, m_dc);
|
||||||
|
m_dc = {};
|
||||||
|
|
||||||
|
wglDestroyPbufferARB(m_pbuffer);
|
||||||
|
m_pbuffer = {};
|
||||||
|
|
||||||
|
::ReleaseDC(m_dummy_window, m_dummy_dc);
|
||||||
|
m_dummy_dc = {};
|
||||||
|
|
||||||
|
DestroyWindow(m_dummy_window);
|
||||||
|
m_dummy_window = {};
|
||||||
|
}
|
||||||
|
else if (m_dc)
|
||||||
|
{
|
||||||
|
::ReleaseDC(GetHWND(), m_dc);
|
||||||
|
m_dc = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ContextWGL::CreatePBuffer()
|
||||||
|
{
|
||||||
|
static bool window_class_registered = false;
|
||||||
|
static const wchar_t* window_class_name = L"ContextWGLPBuffer";
|
||||||
|
|
||||||
|
if (!window_class_registered)
|
||||||
|
{
|
||||||
|
WNDCLASSEXW wc = {};
|
||||||
|
wc.cbSize = sizeof(WNDCLASSEXW);
|
||||||
|
wc.style = 0;
|
||||||
|
wc.lpfnWndProc = DefWindowProcW;
|
||||||
|
wc.cbClsExtra = 0;
|
||||||
|
wc.cbWndExtra = 0;
|
||||||
|
wc.hInstance = GetModuleHandle(nullptr);
|
||||||
|
wc.hIcon = NULL;
|
||||||
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||||
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||||
|
wc.lpszMenuName = NULL;
|
||||||
|
wc.lpszClassName = window_class_name;
|
||||||
|
wc.hIconSm = NULL;
|
||||||
|
|
||||||
|
if (!RegisterClassExW(&wc))
|
||||||
|
{
|
||||||
|
Console.Error("(ContextWGL::CreatePBuffer) RegisterClassExW() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
window_class_registered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND hwnd = CreateWindowExW(0, window_class_name, window_class_name, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
|
||||||
|
if (!hwnd)
|
||||||
|
{
|
||||||
|
Console.Error("(ContextWGL::CreatePBuffer) CreateWindowEx() failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScopedGuard hwnd_guard([hwnd]() { DestroyWindow(hwnd); });
|
||||||
|
|
||||||
|
HDC hdc = GetDCAndSetPixelFormat(hwnd);
|
||||||
|
if (!hdc)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ScopedGuard hdc_guard([hdc, hwnd]() { ::ReleaseDC(hwnd, hdc); });
|
||||||
|
|
||||||
|
static constexpr const int pb_attribs[] = {0, 0};
|
||||||
|
|
||||||
|
pxAssertRel(m_pixel_format.has_value(), "Has pixel format for pbuffer");
|
||||||
|
HPBUFFERARB pbuffer = wglCreatePbufferARB(hdc, m_pixel_format.value(), 1, 1, pb_attribs);
|
||||||
|
if (!pbuffer)
|
||||||
|
{
|
||||||
|
Console.Error("(ContextWGL::CreatePBuffer) wglCreatePbufferARB() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedGuard pbuffer_guard([pbuffer]() { wglDestroyPbufferARB(pbuffer); });
|
||||||
|
|
||||||
|
m_dc = wglGetPbufferDCARB(pbuffer);
|
||||||
|
if (!m_dc)
|
||||||
|
{
|
||||||
|
Console.Error("(ContextWGL::CreatePbuffer) wglGetPbufferDCARB() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dummy_window = hwnd;
|
||||||
|
m_dummy_dc = hdc;
|
||||||
|
m_pbuffer = pbuffer;
|
||||||
|
|
||||||
|
pbuffer_guard.Cancel();
|
||||||
|
hdc_guard.Cancel();
|
||||||
|
hwnd_guard.Cancel();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#endif
|
#endif
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace GL
|
namespace GL
|
||||||
{
|
{
|
||||||
|
@ -48,12 +49,24 @@ namespace GL
|
||||||
private:
|
private:
|
||||||
__fi HWND GetHWND() const { return static_cast<HWND>(m_wi.window_handle); }
|
__fi HWND GetHWND() const { return static_cast<HWND>(m_wi.window_handle); }
|
||||||
|
|
||||||
|
HDC GetDCAndSetPixelFormat(HWND hwnd);
|
||||||
|
|
||||||
bool Initialize(const Version* versions_to_try, size_t num_versions_to_try);
|
bool Initialize(const Version* versions_to_try, size_t num_versions_to_try);
|
||||||
bool InitializeDC();
|
bool InitializeDC();
|
||||||
|
void ReleaseDC();
|
||||||
|
bool CreatePBuffer();
|
||||||
bool CreateAnyContext(HGLRC share_context, bool make_current);
|
bool CreateAnyContext(HGLRC share_context, bool make_current);
|
||||||
bool CreateVersionContext(const Version& version, HGLRC share_context, bool make_current);
|
bool CreateVersionContext(const Version& version, HGLRC share_context, bool make_current);
|
||||||
|
|
||||||
HDC m_dc = {};
|
HDC m_dc = {};
|
||||||
HGLRC m_rc = {};
|
HGLRC m_rc = {};
|
||||||
|
|
||||||
|
// Can't change pixel format once it's set for a RC.
|
||||||
|
std::optional<int> m_pixel_format;
|
||||||
|
|
||||||
|
// Dummy window for creating a PBuffer off when we're surfaceless.
|
||||||
|
HWND m_dummy_window = {};
|
||||||
|
HDC m_dummy_dc = {};
|
||||||
|
HPBUFFERARB m_pbuffer = {};
|
||||||
};
|
};
|
||||||
} // namespace GL
|
} // namespace GL
|
|
@ -688,10 +688,7 @@ void EmuThread::releaseHostDisplay()
|
||||||
ImGuiManager::Shutdown();
|
ImGuiManager::Shutdown();
|
||||||
|
|
||||||
if (s_host_display)
|
if (s_host_display)
|
||||||
{
|
|
||||||
s_host_display->DestroyRenderSurface();
|
|
||||||
s_host_display->DestroyRenderDevice();
|
s_host_display->DestroyRenderDevice();
|
||||||
}
|
|
||||||
|
|
||||||
emit onDestroyDisplayRequested();
|
emit onDestroyDisplayRequested();
|
||||||
|
|
||||||
|
|
|
@ -326,9 +326,9 @@ void VulkanHostDisplay::DestroyRenderDevice()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
g_vulkan_context->WaitForGPUIdle();
|
g_vulkan_context->WaitForGPUIdle();
|
||||||
|
m_swap_chain.reset();
|
||||||
|
|
||||||
Vulkan::ShaderCache::Destroy();
|
Vulkan::ShaderCache::Destroy();
|
||||||
DestroyRenderSurface();
|
|
||||||
Vulkan::Context::Destroy();
|
Vulkan::Context::Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue