Fix RenderDoc OpenGL capture - pass HGLRC instead of HDC

Critical fix: For OpenGL, RenderDoc requires HGLRC (OpenGL context) as
the device pointer, not HDC. Previously OpenGL test incorrectly passed
HDC which caused capture to silently fail (NumCaptures=0).

Changes:
- OpenGLDevice: Add wglCreateContextAttribsARB support for debug context
- OpenGLDevice: Create OpenGL 4.6 core profile with debug flag
- RenderDocCapture: Pass correct window to SetActiveWindow/StartFrameCapture
- OpenGL test: Pass HGLRC via SetDevice(), use BeginCapture/EndCapture

Fix root cause identified via RenderDoc docs analysis:
  'For OpenGL it must be the HGLRC, GLXContext, or EGLContext'
This commit is contained in:
2026-03-23 18:35:49 +08:00
parent e9f4f2dc49
commit 36683b4bb3
3 changed files with 112 additions and 5 deletions

View File

@@ -11,6 +11,7 @@
#include "XCEngine/RHI/OpenGL/OpenGLScreenshot.h"
#include "XCEngine/Debug/Logger.h"
#include "XCEngine/Debug/ConsoleLogSink.h"
#include "XCEngine/Debug/RenderDocCapture.h"
#include "XCEngine/Containers/String.h"
#pragma comment(lib, "opengl32.lib")
@@ -41,6 +42,10 @@ 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<ConsoleLogSink>());
@@ -81,6 +86,14 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
return -1;
}
// Initialize RenderDoc capture (MUST be before OpenGL init)
// For OpenGL: device=nullptr (will be set via SetDevice), window=hwnd
if (!RenderDocCapture::Get().Initialize(nullptr, hwnd)) {
Log("[WARNING] Failed to initialize RenderDoc, frame capture will not be available");
} else {
RenderDocCapture::Get().SetCaptureFilePath(".\\minimal_frame30");
}
// Initialize OpenGL device with existing window
OpenGLDevice device;
if (!device.InitializeWithExistingWindow(hwnd)) {
@@ -88,6 +101,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
return -1;
}
// Set device for RenderDoc (must be called after OpenGL init)
// For OpenGL, device pointer must be HGLRC, not HDC!
RenderDocCapture::Get().SetDevice(device.GetContext());
ShowWindow(hwnd, nShowCmd);
UpdateWindow(hwnd);
@@ -115,6 +132,13 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
TranslateMessage(&msg);
DispatchMessageW(&msg);
} else {
if (frameCount == targetFrameCount - 1) {
Log("[INFO] Starting RenderDoc capture at frame %d", frameCount + 1);
wglMakeCurrent(device.GetDC(), device.GetContext());
RenderDocCapture::Get().BeginCapture("OpenGL_Minimal_Test");
Log("[INFO] IsCapturing after BeginCapture: %s", RenderDocCapture::Get().IsCapturing() ? "true" : "false");
}
// Set viewport and clear color using encapsulated command list
commandList.SetViewport(0, 0, gWidth, gHeight);
commandList.Clear(1.0f, 0.0f, 0.0f, 1.0f, 1 | 2);
@@ -122,14 +146,21 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
// Present the rendered frame
swapChain.Present(0, 0);
frameCount++;
if (frameCount >= targetFrameCount) {
Log("[INFO] Ending RenderDoc capture at frame %d", frameCount);
RenderDocCapture::Get().EndCapture();
Log("[INFO] NumCaptures: %u", RenderDocCapture::Get().GetNumCaptures());
}
}
}
// Take screenshot after target frame count is reached
Log("[INFO] Reached target frame count %d - taking screenshot!", targetFrameCount);
Log("[INFO] Taking screenshot!");
OpenGLScreenshot::Capture(device, swapChain, "minimal.ppm");
// Shutdown in reverse order of initialization
RenderDocCapture::Get().Shutdown();
swapChain.Shutdown();
device.Shutdown();
Logger::Get().Shutdown();