Files
XCEngine/engine/src/Debug/RenderDocCapture.cpp
ssdfasd 79422cfddd fix: simplify RenderDocCapture usage with TriggerCapture
- Remove BeginCapture/EndCapture complexity for manual frame capture
- Use TriggerCapture for single frame capture (simpler API)
- Move TriggerCapture before Present to ensure frame is captured
- Add SetForegroundWindow/SetFocus before TriggerCapture
- Remove default capture path in Initialize to allow SetCaptureFilePath to work
2026-03-23 19:40:50 +08:00

217 lines
5.6 KiB
C++

#include "XCEngine/Debug/RenderDocCapture.h"
#include "XCEngine/Debug/Logger.h"
#include <cstdio>
#include <cstring>
#include <windows.h>
namespace XCEngine {
namespace Debug {
static const char* RENDERDOC_DLL_PATH = "renderdoc.dll";
RenderDocCapture& RenderDocCapture::Get() {
static RenderDocCapture instance;
return instance;
}
bool RenderDocCapture::Initialize(void* device, void* window) {
if (m_initialized) {
return true;
}
m_device = device;
m_window = window;
if (!LoadRenderDoc()) {
return false;
}
m_api->SetCaptureOptionU32(2, 1);
m_api->SetCaptureOptionU32(8, 1);
m_api->SetCaptureOptionU32(9, 1);
m_initialized = true;
Logger::Get().Info(LogCategory::General, "RenderDocCapture initialized successfully");
return true;
}
void RenderDocCapture::Shutdown() {
if (m_initialized) {
if (IsCapturing()) {
EndCapture();
}
UnloadRenderDoc();
m_initialized = false;
}
}
void RenderDocCapture::SetDevice(void* device) {
m_device = device;
}
void RenderDocCapture::SetWindow(void* window) {
m_window = window;
}
bool RenderDocCapture::LoadRenderDoc() {
char exePath[MAX_PATH];
GetModuleFileNameA(NULL, exePath, MAX_PATH);
char* end = strrchr(exePath, '\\');
if (end) *end = '\0';
strcat_s(exePath, "\\renderdoc.dll");
HMODULE module = LoadLibraryA(exePath);
if (!module) {
DWORD error = GetLastError();
char buf[512];
sprintf(buf, "Failed to load renderdoc.dll from %s, error=%lu", exePath, error);
Logger::Get().Warning(LogCategory::General, buf);
return false;
}
using PFN_RENDERDOC_GetAPI = int (RENDERDOC_CC*)(int version, void** apiOut);
PFN_RENDERDOC_GetAPI GetAPI = (PFN_RENDERDOC_GetAPI)GetProcAddress(module, "RENDERDOC_GetAPI");
if (!GetAPI) {
Logger::Get().Error(LogCategory::General, "Failed to get RENDERDOC_GetAPI");
FreeLibrary(module);
return false;
}
int apiVersion = 10700;
void* apiPtr = nullptr;
int ret = GetAPI(apiVersion, &apiPtr);
if (ret != 1 || !apiPtr) {
char buf[256];
sprintf(buf, "Failed to get RenderDoc API: ret=%d, ptr=%p", ret, apiPtr);
Logger::Get().Error(LogCategory::General, buf);
FreeLibrary(module);
return false;
}
m_renderDocModule = module;
m_api = (RENDERDOC_API_1_7_0*)apiPtr;
m_isLoaded = true;
return true;
}
void RenderDocCapture::UnloadRenderDoc() {
if (m_renderDocModule) {
FreeLibrary(m_renderDocModule);
m_renderDocModule = nullptr;
}
m_api = nullptr;
m_isLoaded = false;
}
bool RenderDocCapture::IsCapturing() const {
if (!m_isLoaded || !m_api) {
return false;
}
return m_api->IsFrameCapturing() != 0;
}
uint32_t RenderDocCapture::GetNumCaptures() const {
if (!m_isLoaded || !m_api) {
return 0;
}
return m_api->GetNumCaptures();
}
bool RenderDocCapture::GetCapture(uint32_t index, RenderDocCaptureInfo* info) const {
if (!m_isLoaded || !m_api || !info) {
return false;
}
uint32_t length = 0;
uint64_t timestamp = 0;
uint32_t result = m_api->GetCapture(index, info->filename, &length, &timestamp);
info->length = length;
info->timestamp = timestamp;
return result == 1;
}
bool RenderDocCapture::BeginCapture(const char* title) {
if (!m_isLoaded || !m_api) {
Logger::Get().Warning(LogCategory::General, "BeginCapture called but RenderDoc not loaded");
return false;
}
if (IsCapturing()) {
Logger::Get().Warning(LogCategory::General, "BeginCapture called while already capturing");
return false;
}
if (!m_device || !m_window) {
Logger::Get().Warning(LogCategory::General, "BeginCapture called with null device or window");
return false;
}
if (title) {
m_api->SetCaptureTitle(title);
}
SetForegroundWindow((HWND)m_window);
SetFocus((HWND)m_window);
m_api->SetActiveWindow(m_device, m_window);
m_api->StartFrameCapture(m_device, m_window);
return true;
}
bool RenderDocCapture::EndCapture() {
if (!m_isLoaded || !m_api) {
Logger::Get().Warning(LogCategory::General, "EndCapture called but RenderDoc not loaded");
return false;
}
if (!IsCapturing()) {
Logger::Get().Warning(LogCategory::General, "EndCapture called but not currently capturing");
return false;
}
m_api->EndFrameCapture(m_device, m_window);
return true;
}
void RenderDocCapture::TriggerCapture() {
if (!m_isLoaded || !m_api) {
return;
}
if (m_window) {
SetForegroundWindow((HWND)m_window);
SetFocus((HWND)m_window);
}
m_api->TriggerCapture();
}
void RenderDocCapture::SetCaptureFilePath(const char* path) {
if (!m_isLoaded || !m_api) {
return;
}
m_api->SetCaptureFilePathTemplate(path);
}
void RenderDocCapture::SetCaptureComments(const char* comments) {
if (!m_isLoaded || !m_api) {
return;
}
m_api->SetCaptureFileComments(nullptr, comments);
}
void RenderDocCapture::SetCaptureOptionU32(uint32_t option, uint32_t value) {
if (!m_isLoaded || !m_api) {
return;
}
m_api->SetCaptureOptionU32(option, value);
}
bool RenderDocCapture::LaunchReplayUI(uint32_t connect, const char* cmdline) {
if (!m_isLoaded || !m_api) {
Logger::Get().Warning(LogCategory::General, "LaunchReplayUI called but RenderDoc not loaded");
return false;
}
m_api->LaunchReplayUI(connect, cmdline);
return true;
}
} // namespace Debug
} // namespace XCEngine