From 003d6ed63055cf0f021b2e3c98bcfd72071682ba Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Mon, 23 Mar 2026 21:43:32 +0800 Subject: [PATCH] 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 --- .../XCEngine/RHI/OpenGL/OpenGLDevice.h | 26 ++--- .../XCEngine/RHI/OpenGL/OpenGLSwapChain.h | 31 +++--- engine/src/RHI/OpenGL/OpenGLDevice.cpp | 94 +++++++++---------- engine/src/RHI/OpenGL/OpenGLSwapChain.cpp | 54 +++-------- tests/RHI/OpenGL/integration/minimal/main.cpp | 50 +++++----- 5 files changed, 108 insertions(+), 147 deletions(-) diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLDevice.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLDevice.h index 91fef9d0..719bc647 100644 --- a/engine/include/XCEngine/RHI/OpenGL/OpenGLDevice.h +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLDevice.h @@ -1,11 +1,11 @@ #pragma once #include +#include #include "../RHIDevice.h" #include "../RHICapabilities.h" -struct HWND__; struct HDC__; struct HGLRC__; @@ -13,9 +13,10 @@ namespace XCEngine { namespace RHI { using HWND = HWND__*; -using HDC = HDC__*; using HGLRC = HGLRC__*; +class OpenGLSwapChain; + class OpenGLDevice : public RHIDevice { public: OpenGLDevice(); @@ -24,12 +25,11 @@ public: bool Initialize(const RHIDeviceDesc& desc) override; void Shutdown() override; - bool CreateRenderWindow(int width, int height, const char* title, bool enableDebug = false); bool InitializeWithExistingWindow(HWND hwnd); - + bool CreateRenderWindow(int width, int height, const char* title, bool enableDebug = false); HWND GetWindow() const { return m_hwnd; } - HDC GetDC() const { return m_hdc; } - HGLRC GetContext() const { return m_hglrc; } + HDC GetPresentationDC() const { return m_hdc; } + HGLRC GetGLContext() const { return m_hglrc; } const RHIDeviceInfo& GetDeviceInfoImpl() const { return m_deviceInfo; } void SwapBuffers(); @@ -54,14 +54,16 @@ public: void* GetNativeHandle() const; private: - HWND m_hwnd; - HDC m_hdc; - HGLRC m_hglrc; + friend class OpenGLSwapChain; + + HWND m_hwnd = nullptr; + HDC m_hdc = nullptr; + HGLRC m_hglrc = nullptr; RHIDeviceInfo m_deviceInfo; RHICapabilities m_capabilities; - bool m_initialized; - bool m_ownsWindow; - bool m_shouldClose; + bool m_initialized = false; + bool m_ownsWindow = false; + bool m_shouldClose = false; }; } // namespace RHI diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLSwapChain.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLSwapChain.h index cf8b6d0e..88856e50 100644 --- a/engine/include/XCEngine/RHI/OpenGL/OpenGLSwapChain.h +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLSwapChain.h @@ -4,6 +4,7 @@ #include "../RHISwapChain.h" #include "OpenGLTexture.h" +#include "OpenGLDevice.h" struct HWND__; struct HDC__; @@ -11,9 +12,6 @@ struct HDC__; namespace XCEngine { namespace RHI { -using HWND = HWND__*; -using HDC = HDC__*; - enum class PresentMode { Immediate, VSync, @@ -33,8 +31,7 @@ public: OpenGLSwapChain(); ~OpenGLSwapChain() override; - bool Initialize(HWND window, bool vsync = true); - bool Initialize(HWND window, int width, int height, PresentMode mode = PresentMode::VSync); + bool Initialize(OpenGLDevice* device, HWND window, int width, int height); void Shutdown() override; void Present(uint32_t syncInterval = 1, uint32_t flags = 0) override; @@ -52,7 +49,7 @@ public: int GetFramebufferHeight() const { return m_framebufferHeight; } HWND GetWindow() const { return m_hwnd; } - HDC GetDC() const { return m_hdc; } + HDC GetDC() const { return m_device ? m_device->GetPresentationDC() : nullptr; } bool ShouldClose() const override; void SetShouldClose(bool shouldClose) override; @@ -63,17 +60,17 @@ public: void* GetNativeHandle() override; private: - HWND m_hwnd; - HDC m_hdc; - int m_width; - int m_height; - int m_framebufferWidth; - int m_framebufferHeight; - bool m_vsync; - bool m_shouldClose; - bool m_fullscreen; - PresentMode m_presentMode; - OpenGLTexture* m_backBufferTexture; + OpenGLDevice* m_device = nullptr; + HWND m_hwnd = nullptr; + int m_width = 0; + int m_height = 0; + int m_framebufferWidth = 0; + int m_framebufferHeight = 0; + bool m_vsync = true; + bool m_shouldClose = false; + bool m_fullscreen = false; + PresentMode m_presentMode = PresentMode::VSync; + OpenGLTexture* m_backBufferTexture = nullptr; }; } // namespace RHI diff --git a/engine/src/RHI/OpenGL/OpenGLDevice.cpp b/engine/src/RHI/OpenGL/OpenGLDevice.cpp index b9c59cab..79de9d4d 100644 --- a/engine/src/RHI/OpenGL/OpenGLDevice.cpp +++ b/engine/src/RHI/OpenGL/OpenGLDevice.cpp @@ -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; } diff --git a/engine/src/RHI/OpenGL/OpenGLSwapChain.cpp b/engine/src/RHI/OpenGL/OpenGLSwapChain.cpp index c93b67ee..6b60cdc8 100644 --- a/engine/src/RHI/OpenGL/OpenGLSwapChain.cpp +++ b/engine/src/RHI/OpenGL/OpenGLSwapChain.cpp @@ -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()); } } diff --git a/tests/RHI/OpenGL/integration/minimal/main.cpp b/tests/RHI/OpenGL/integration/minimal/main.cpp index 1cda8429..827e1d3a 100644 --- a/tests/RHI/OpenGL/integration/minimal/main.cpp +++ b/tests/RHI/OpenGL/integration/minimal/main.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "XCEngine/RHI/OpenGL/OpenGLDevice.h" #include "XCEngine/RHI/OpenGL/OpenGLSwapChain.h" @@ -42,18 +43,15 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { - // Set RenderDoc environment variables for global capture _putenv_s("RENDERDOC_CAPTUREINTERACTIVE", "0"); _putenv_s("RENDERDOC_CAPTUREFRAMESTART", "0"); - // Initialize logger Logger::Get().Initialize(); Logger::Get().AddSink(std::make_unique()); Logger::Get().SetMinimumLevel(LogLevel::Debug); Log("[INFO] OpenGL Integration Test Starting"); - // Register window class WNDCLASSEXW wc = {}; wc.cbSize = sizeof(WNDCLASSEXW); wc.style = CS_HREDRAW | CS_VREDRAW; @@ -66,11 +64,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine return -1; } - // Calculate full window size from client area size RECT rect = { 0, 0, gWidth, gHeight }; AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); - // Create window HWND hwnd = CreateWindowExW( 0, L"XCEngine_OpenGL_Test", @@ -89,35 +85,37 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine RenderDocCapture::Get().Initialize(nullptr, hwnd); RenderDocCapture::Get().SetCaptureFilePath(".\\minimal_frame30"); - // Initialize OpenGL device with existing window OpenGLDevice device; - if (!device.InitializeWithExistingWindow(hwnd)) { + RHIDeviceDesc desc = {}; + desc.windowHandle = hwnd; + desc.width = gWidth; + desc.height = gHeight; + desc.appName = L"OpenGL_Minimal_Test"; + desc.enableDebugLayer = true; + if (!device.Initialize(desc)) { Log("[ERROR] Failed to initialize OpenGL device"); return -1; } - RenderDocCapture::Get().SetDevice(device.GetContext()); + RenderDocCapture::Get().SetDevice(device.GetGLContext()); ShowWindow(hwnd, nShowCmd); UpdateWindow(hwnd); - // Log OpenGL device info Log("[INFO] OpenGL Device: %S", device.GetDeviceInfo().renderer.c_str()); Log("[INFO] OpenGL Version: %S", device.GetDeviceInfo().version.c_str()); - // Create swap chain for rendering OpenGLSwapChain swapChain; - swapChain.Initialize(hwnd, gWidth, gHeight); + swapChain.Initialize(&device, hwnd, gWidth, gHeight); - // Create command list for rendering commands OpenGLCommandList commandList; - // Main render loop MSG msg = {}; int frameCount = 0; - const int targetFrameCount = 30; + const int captureStartFrame = 25; + const int captureEndFrame = 35; - while (frameCount < targetFrameCount) { + while (frameCount < captureEndFrame) { if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { break; @@ -125,34 +123,30 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine TranslateMessage(&msg); DispatchMessageW(&msg); } else { - wglMakeCurrent(device.GetDC(), device.GetContext()); + wglMakeCurrent(device.GetPresentationDC(), device.GetGLContext()); commandList.SetViewport(0, 0, gWidth, gHeight); commandList.Clear(1.0f, 0.0f, 0.0f, 1.0f, 1 | 2); - if (frameCount >= targetFrameCount - 1) { - if (RenderDocCapture::Get().BeginCapture("OpenGL_Minimal_Test")) { - Log("[INFO] RenderDoc capture started"); - } - } - swapChain.Present(0, 0); frameCount++; - if (frameCount >= targetFrameCount) { - if (RenderDocCapture::Get().EndCapture()) { - Log("[INFO] RenderDoc capture ended"); - } + if (frameCount == captureStartFrame) { + RenderDocCapture::Get().BeginCapture("OpenGL_Minimal_Test"); + Log("[INFO] RenderDoc capture started at frame %d", frameCount); + } + + if (frameCount == captureEndFrame) { + RenderDocCapture::Get().EndCapture(); + Log("[INFO] RenderDoc capture ended at frame %d", frameCount); break; } } } - // Take screenshot after target frame count is reached Log("[INFO] Taking screenshot!"); OpenGLScreenshot::Capture(device, swapChain, "minimal.ppm"); - // Shutdown in reverse order of initialization RenderDocCapture::Get().Shutdown(); swapChain.Shutdown(); device.Shutdown();