2026-03-23 17:11:01 +08:00
|
|
|
#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_api->SetCaptureFilePathTemplate(".\\captures");
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-23 17:47:43 +08:00
|
|
|
void RenderDocCapture::SetDevice(void* device) {
|
|
|
|
|
m_device = device;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-23 17:11:01 +08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-23 17:47:43 +08:00
|
|
|
uint32_t RenderDocCapture::GetNumCaptures() const {
|
|
|
|
|
if (!m_isLoaded || !m_api) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return m_api->GetNumCaptures();
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-23 17:11:01 +08:00
|
|
|
void RenderDocCapture::BeginCapture(const char* title) {
|
|
|
|
|
if (!m_isLoaded || !m_api) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (title) {
|
|
|
|
|
m_api->SetCaptureTitle(title);
|
|
|
|
|
}
|
2026-03-23 18:35:49 +08:00
|
|
|
|
|
|
|
|
SetForegroundWindow((HWND)m_window);
|
|
|
|
|
SetFocus((HWND)m_window);
|
|
|
|
|
|
|
|
|
|
m_api->SetActiveWindow(m_device, m_window);
|
|
|
|
|
m_api->StartFrameCapture(m_device, m_window);
|
2026-03-23 17:11:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderDocCapture::EndCapture() {
|
|
|
|
|
if (!m_isLoaded || !m_api) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-03-23 18:35:49 +08:00
|
|
|
m_api->EndFrameCapture(m_device, m_window);
|
2026-03-23 17:11:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RenderDocCapture::TriggerCapture() {
|
|
|
|
|
if (!m_isLoaded || !m_api) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Debug
|
|
|
|
|
} // namespace XCEngine
|