Refactor OpenGL SwapChain HDC management

- OpenGLSwapChain now gets HDC from OpenGLDevice instead of creating its own
- Renamed OpenGLDevice::GetContext() to GetGLContext() for clarity
- Renamed OpenGLDevice::GetDC() to GetPresentationDC() for clarity
- OpenGLDevice now owns the HDC/HGLRC lifecycle
- OpenGLSwapChain::Initialize() now takes OpenGLDevice* parameter
- OpenGLSwapChain::Present() uses device's HDC for SwapBuffers
- Updated minimal test to use new API and capture from frame 25-35
- RenderDoc SetDevice now uses GetGLContext() for proper OpenGL hook
This commit is contained in:
2026-03-23 21:43:32 +08:00
parent 0fa4f2e3a8
commit 003d6ed630
5 changed files with 108 additions and 147 deletions

View File

@@ -67,52 +67,6 @@ bool OpenGLDevice::Initialize(const RHIDeviceDesc& desc) {
return CreateRenderWindow(desc.width, desc.height, titleStr.c_str(), desc.enableDebugLayer);
}
bool OpenGLDevice::CreateRenderWindow(int width, int height, const char* title, bool enableDebug) {
if (m_initialized) {
return true;
}
if (!s_windowClassRegistered) {
WNDCLASSEXW wc = {};
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DefWindowProcW;
wc.hInstance = GetModuleHandleW(nullptr);
wc.lpszClassName = kWindowClassName;
if (!RegisterClassExW(&wc)) {
return false;
}
s_windowClassRegistered = true;
}
std::wstring titleW(title ? std::wstring(title, title + strlen(title)) : L"XCEngine");
HWND hwnd = CreateWindowExW(
0,
kWindowClassName,
titleW.c_str(),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
width, height,
nullptr,
nullptr,
GetModuleHandleW(nullptr),
nullptr
);
if (!hwnd) {
return false;
}
m_hwnd = hwnd;
m_ownsWindow = true;
ShowWindow(m_hwnd, SW_SHOWNORMAL);
UpdateWindow(m_hwnd);
return InitializeWithExistingWindow(m_hwnd);
}
bool OpenGLDevice::InitializeWithExistingWindow(HWND hwnd) {
if (m_initialized) {
return true;
@@ -280,6 +234,52 @@ bool OpenGLDevice::InitializeWithExistingWindow(HWND hwnd) {
return true;
}
bool OpenGLDevice::CreateRenderWindow(int width, int height, const char* title, bool enableDebug) {
if (m_initialized) {
return true;
}
if (!s_windowClassRegistered) {
WNDCLASSEXW wc = {};
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DefWindowProcW;
wc.hInstance = GetModuleHandleW(nullptr);
wc.lpszClassName = kWindowClassName;
if (!RegisterClassExW(&wc)) {
return false;
}
s_windowClassRegistered = true;
}
std::wstring titleW(title ? std::wstring(title, title + strlen(title)) : L"XCEngine");
HWND hwnd = CreateWindowExW(
0,
kWindowClassName,
titleW.c_str(),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
width, height,
nullptr,
nullptr,
GetModuleHandleW(nullptr),
nullptr
);
if (!hwnd) {
return false;
}
m_hwnd = hwnd;
m_ownsWindow = true;
ShowWindow(m_hwnd, SW_SHOWNORMAL);
UpdateWindow(m_hwnd);
return InitializeWithExistingWindow(m_hwnd);
}
void OpenGLDevice::Shutdown() {
if (m_hglrc) {
wglMakeCurrent(nullptr, nullptr);
@@ -396,7 +396,7 @@ RHITexture* OpenGLDevice::CreateTexture(const TextureDesc& desc) {
RHISwapChain* OpenGLDevice::CreateSwapChain(const SwapChainDesc& desc) {
auto* swapChain = new OpenGLSwapChain();
if (m_hwnd) {
swapChain->Initialize(m_hwnd, desc.width, desc.height);
swapChain->Initialize(this, m_hwnd, desc.width, desc.height);
}
return swapChain;
}

View File

@@ -13,8 +13,8 @@ namespace XCEngine {
namespace RHI {
OpenGLSwapChain::OpenGLSwapChain()
: m_hwnd(nullptr)
, m_hdc(nullptr)
: m_device(nullptr)
, m_hwnd(nullptr)
, m_width(0)
, m_height(0)
, m_framebufferWidth(0)
@@ -30,42 +30,13 @@ OpenGLSwapChain::~OpenGLSwapChain() {
Shutdown();
}
bool OpenGLSwapChain::Initialize(HWND window, bool vsync) {
bool OpenGLSwapChain::Initialize(OpenGLDevice* device, HWND window, int width, int height) {
m_device = device;
m_hwnd = window;
m_hdc = ::GetDC(m_hwnd);
m_vsync = vsync;
m_presentMode = vsync ? PresentMode::VSync : PresentMode::Immediate;
m_shouldClose = false;
if (!wglSwapIntervalEXT) {
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
}
if (wglSwapIntervalEXT) {
wglSwapIntervalEXT(vsync ? 1 : 0);
}
RECT rect;
::GetClientRect(m_hwnd, &rect);
m_width = rect.right - rect.left;
m_height = rect.bottom - rect.top;
m_framebufferWidth = m_width;
m_framebufferHeight = m_height;
if (!m_backBufferTexture) {
m_backBufferTexture = new OpenGLTexture();
m_backBufferTexture->Initialize(OpenGLTextureType::Texture2D, m_width, m_height, 1, 1, OpenGLFormat::RGBA8, nullptr);
}
return true;
}
bool OpenGLSwapChain::Initialize(HWND window, int width, int height, PresentMode mode) {
m_hwnd = window;
m_hdc = ::GetDC(m_hwnd);
m_width = width;
m_height = height;
m_presentMode = mode;
m_vsync = (mode == PresentMode::VSync || mode == PresentMode::Fifo);
m_presentMode = PresentMode::VSync;
m_vsync = true;
m_shouldClose = false;
if (!wglSwapIntervalEXT) {
@@ -95,16 +66,13 @@ void OpenGLSwapChain::Shutdown() {
delete m_backBufferTexture;
m_backBufferTexture = nullptr;
}
if (m_hdc && m_hwnd) {
::ReleaseDC(m_hwnd, m_hdc);
m_hdc = nullptr;
}
m_hwnd = nullptr;
m_device = nullptr;
}
void OpenGLSwapChain::SwapBuffers() {
if (m_hdc) {
::SwapBuffers(m_hdc);
if (m_device) {
::SwapBuffers(m_device->GetPresentationDC());
}
}
@@ -144,8 +112,8 @@ void OpenGLSwapChain::PollEvents() {
}
void OpenGLSwapChain::Present(uint32_t syncInterval, uint32_t flags) {
if (m_hdc) {
::SwapBuffers(m_hdc);
if (m_device) {
::SwapBuffers(m_device->GetPresentationDC());
}
}