188 lines
5.2 KiB
C++
188 lines
5.2 KiB
C++
|
|
#include "RHIIntegrationFixture.h"
|
||
|
|
#include <cstdlib>
|
||
|
|
#include <iostream>
|
||
|
|
#include <windows.h>
|
||
|
|
#include <filesystem>
|
||
|
|
|
||
|
|
#include "XCEngine/RHI/D3D12/D3D12Device.h"
|
||
|
|
#include "XCEngine/RHI/D3D12/D3D12SwapChain.h"
|
||
|
|
#include "XCEngine/RHI/D3D12/D3D12Texture.h"
|
||
|
|
#include "XCEngine/RHI/D3D12/D3D12CommandList.h"
|
||
|
|
#include "XCEngine/RHI/RHIFence.h"
|
||
|
|
#include "XCEngine/RHI/RHIScreenshot.h"
|
||
|
|
#include "XCEngine/RHI/RHIEnums.h"
|
||
|
|
|
||
|
|
namespace XCEngine {
|
||
|
|
namespace RHI {
|
||
|
|
namespace Integration {
|
||
|
|
|
||
|
|
void RHIIntegrationFixture::SetUp() {
|
||
|
|
WNDCLASSEXW wc = {};
|
||
|
|
wc.cbSize = sizeof(WNDCLASSEXW);
|
||
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||
|
|
wc.lpfnWndProc = DefWindowProcW;
|
||
|
|
wc.hInstance = GetModuleHandle(nullptr);
|
||
|
|
wc.lpszClassName = L"XCEngine_RHI_Integration_Test";
|
||
|
|
RegisterClassExW(&wc);
|
||
|
|
|
||
|
|
const int width = 1280;
|
||
|
|
const int height = 720;
|
||
|
|
RECT rect = { 0, 0, width, height };
|
||
|
|
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
|
||
|
|
|
||
|
|
mWindow = CreateWindowExW(
|
||
|
|
0,
|
||
|
|
L"XCEngine_RHI_Integration_Test",
|
||
|
|
L"RHI Integration Test",
|
||
|
|
WS_OVERLAPPEDWINDOW,
|
||
|
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
||
|
|
rect.right - rect.left, rect.bottom - rect.top,
|
||
|
|
NULL, NULL, GetModuleHandle(nullptr), NULL
|
||
|
|
);
|
||
|
|
|
||
|
|
ASSERT_NE(mWindow, nullptr);
|
||
|
|
|
||
|
|
mDevice = RHIFactory::CreateRHIDevice(GetParam());
|
||
|
|
ASSERT_NE(mDevice, nullptr);
|
||
|
|
|
||
|
|
bool initResult = false;
|
||
|
|
if (GetParam() == RHIType::D3D12) {
|
||
|
|
RHIDeviceDesc desc = {};
|
||
|
|
desc.enableDebugLayer = false;
|
||
|
|
desc.enableGPUValidation = false;
|
||
|
|
initResult = mDevice->Initialize(desc);
|
||
|
|
} else if (GetParam() == RHIType::OpenGL) {
|
||
|
|
auto* oglDevice = static_cast<OpenGLDevice*>(mDevice);
|
||
|
|
initResult = oglDevice->InitializeWithExistingWindow(mWindow);
|
||
|
|
}
|
||
|
|
ASSERT_TRUE(initResult);
|
||
|
|
|
||
|
|
SwapChainDesc swapDesc = {};
|
||
|
|
swapDesc.windowHandle = mWindow;
|
||
|
|
swapDesc.width = width;
|
||
|
|
swapDesc.height = height;
|
||
|
|
swapDesc.bufferCount = 2;
|
||
|
|
mSwapChain = mDevice->CreateSwapChain(swapDesc);
|
||
|
|
ASSERT_NE(mSwapChain, nullptr);
|
||
|
|
|
||
|
|
CommandQueueDesc queueDesc = {};
|
||
|
|
queueDesc.queueType = static_cast<uint32_t>(CommandQueueType::Direct);
|
||
|
|
mCommandQueue = mDevice->CreateCommandQueue(queueDesc);
|
||
|
|
ASSERT_NE(mCommandQueue, nullptr);
|
||
|
|
|
||
|
|
CommandListDesc cmdDesc = {};
|
||
|
|
cmdDesc.commandListType = static_cast<uint32_t>(CommandQueueType::Direct);
|
||
|
|
mCommandList = mDevice->CreateCommandList(cmdDesc);
|
||
|
|
ASSERT_NE(mCommandList, nullptr);
|
||
|
|
|
||
|
|
mScreenshot = RHIScreenshot::Create(GetParam());
|
||
|
|
ASSERT_NE(mScreenshot, nullptr);
|
||
|
|
|
||
|
|
ShowWindow(mWindow, SW_SHOW);
|
||
|
|
UpdateWindow(mWindow);
|
||
|
|
}
|
||
|
|
|
||
|
|
void RHIIntegrationFixture::BeginRender() {
|
||
|
|
mCurrentBackBufferIndex = mSwapChain->GetCurrentBackBufferIndex();
|
||
|
|
}
|
||
|
|
|
||
|
|
void RHIIntegrationFixture::EndRender() {
|
||
|
|
}
|
||
|
|
|
||
|
|
void RHIIntegrationFixture::TearDown() {
|
||
|
|
if (mScreenshot) {
|
||
|
|
mScreenshot->Shutdown();
|
||
|
|
delete mScreenshot;
|
||
|
|
mScreenshot = nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mCommandList) {
|
||
|
|
mCommandList->Shutdown();
|
||
|
|
delete mCommandList;
|
||
|
|
mCommandList = nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mCommandQueue) {
|
||
|
|
mCommandQueue->Shutdown();
|
||
|
|
delete mCommandQueue;
|
||
|
|
mCommandQueue = nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mSwapChain) {
|
||
|
|
mSwapChain->Shutdown();
|
||
|
|
delete mSwapChain;
|
||
|
|
mSwapChain = nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mDevice) {
|
||
|
|
mDevice->Shutdown();
|
||
|
|
delete mDevice;
|
||
|
|
mDevice = nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mWindow) {
|
||
|
|
DestroyWindow(mWindow);
|
||
|
|
mWindow = nullptr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void RHIIntegrationFixture::WaitForGPU() {
|
||
|
|
if (mDevice == nullptr || mCommandQueue == nullptr) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (GetParam() == RHIType::D3D12) {
|
||
|
|
FenceDesc fenceDesc = {};
|
||
|
|
fenceDesc.initialValue = 0;
|
||
|
|
fenceDesc.flags = 0;
|
||
|
|
auto* fence = mDevice->CreateFence(fenceDesc);
|
||
|
|
if (fence) {
|
||
|
|
mCommandQueue->Signal(fence, 1);
|
||
|
|
fence->Wait(1);
|
||
|
|
|
||
|
|
for (int i = 0; i < 100; i++) {
|
||
|
|
if (fence->GetCompletedValue() >= 1) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
Sleep(10);
|
||
|
|
}
|
||
|
|
|
||
|
|
fence->Shutdown();
|
||
|
|
delete fence;
|
||
|
|
}
|
||
|
|
Sleep(100);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool RHIIntegrationFixture::TakeScreenshot(const char* filename) {
|
||
|
|
if (!mScreenshot || !mDevice || !mSwapChain) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return mScreenshot->Capture(mDevice, mSwapChain, filename);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool RHIIntegrationFixture::CompareWithGoldenTemplate(const char* outputPpm, const char* gtPpm, float threshold) {
|
||
|
|
namespace fs = std::filesystem;
|
||
|
|
|
||
|
|
fs::path exeDir = fs::current_path();
|
||
|
|
fs::path outputPath = exeDir / outputPpm;
|
||
|
|
fs::path gtPath = exeDir / gtPpm;
|
||
|
|
|
||
|
|
if (!fs::exists(outputPath)) {
|
||
|
|
std::cerr << "Output file not found: " << outputPath << std::endl;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!fs::exists(gtPath)) {
|
||
|
|
std::cerr << "Golden template not found: " << gtPath << std::endl;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string cmd = "python compare_ppm.py \"" + outputPath.string() + "\" \"" + gtPath.string() + "\" " + std::to_string(static_cast<int>(threshold));
|
||
|
|
int result = system(cmd.c_str());
|
||
|
|
return result == 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace Integration
|
||
|
|
} // namespace RHI
|
||
|
|
} // namespace XCEngine
|