2026-03-25 19:00:30 +08:00
|
|
|
#include <windows.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
|
|
|
|
|
#include "../fixtures/RHIIntegrationFixture.h"
|
2026-03-25 20:50:49 +08:00
|
|
|
#include "XCEngine/Debug/Logger.h"
|
|
|
|
|
#include "XCEngine/Debug/ConsoleLogSink.h"
|
2026-03-25 19:00:30 +08:00
|
|
|
|
|
|
|
|
using namespace XCEngine::RHI;
|
|
|
|
|
using namespace XCEngine::RHI::Integration;
|
2026-03-25 20:50:49 +08:00
|
|
|
using namespace XCEngine::Debug;
|
2026-03-25 19:00:30 +08:00
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
class MinimalTest : public RHIIntegrationFixture {
|
|
|
|
|
protected:
|
|
|
|
|
void RenderFrame() override;
|
|
|
|
|
};
|
|
|
|
|
|
2026-03-25 21:50:57 +08:00
|
|
|
const char* GetScreenshotFilename(RHIType type) {
|
2026-03-27 12:05:12 +08:00
|
|
|
switch (type) {
|
|
|
|
|
case RHIType::D3D12:
|
|
|
|
|
return "minimal_d3d12.ppm";
|
|
|
|
|
case RHIType::OpenGL:
|
|
|
|
|
return "minimal_opengl.ppm";
|
|
|
|
|
case RHIType::Vulkan:
|
|
|
|
|
return "minimal_vulkan.ppm";
|
|
|
|
|
default:
|
|
|
|
|
return "minimal_unknown.ppm";
|
|
|
|
|
}
|
2026-03-25 21:50:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int GetComparisonThreshold(RHIType type) {
|
|
|
|
|
return type == RHIType::OpenGL ? 5 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 19:00:30 +08:00
|
|
|
void MinimalTest::RenderFrame() {
|
|
|
|
|
RHICommandList* cmdList = GetCommandList();
|
|
|
|
|
RHICommandQueue* cmdQueue = GetCommandQueue();
|
|
|
|
|
|
2026-03-25 20:50:49 +08:00
|
|
|
Log("[TEST] RenderFrame: calling Reset");
|
2026-03-25 19:00:30 +08:00
|
|
|
cmdList->Reset();
|
2026-03-25 20:50:49 +08:00
|
|
|
|
|
|
|
|
Log("[TEST] RenderFrame: calling SetRenderTargetForClear");
|
|
|
|
|
SetRenderTargetForClear();
|
2026-03-25 19:00:30 +08:00
|
|
|
|
|
|
|
|
Viewport viewport = { 0.0f, 0.0f, 1280.0f, 720.0f, 0.0f, 1.0f };
|
|
|
|
|
Rect scissorRect = { 0, 0, 1280, 720 };
|
|
|
|
|
cmdList->SetViewport(viewport);
|
|
|
|
|
cmdList->SetScissorRect(scissorRect);
|
|
|
|
|
|
|
|
|
|
float clearColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
|
2026-03-25 20:50:49 +08:00
|
|
|
Log("[TEST] RenderFrame: calling Clear");
|
2026-03-25 19:00:30 +08:00
|
|
|
cmdList->Clear(clearColor[0], clearColor[1], clearColor[2], clearColor[3], 1);
|
|
|
|
|
|
2026-03-25 20:50:49 +08:00
|
|
|
Log("[TEST] RenderFrame: calling EndRender");
|
|
|
|
|
EndRender();
|
|
|
|
|
|
|
|
|
|
Log("[TEST] RenderFrame: calling Close");
|
2026-03-25 19:00:30 +08:00
|
|
|
cmdList->Close();
|
2026-03-25 20:50:49 +08:00
|
|
|
|
|
|
|
|
Log("[TEST] RenderFrame: calling ExecuteCommandLists");
|
2026-03-25 19:00:30 +08:00
|
|
|
void* cmdLists[] = { cmdList };
|
|
|
|
|
cmdQueue->ExecuteCommandLists(1, cmdLists);
|
2026-03-25 20:50:49 +08:00
|
|
|
|
|
|
|
|
Log("[TEST] RenderFrame: done");
|
2026-03-25 19:00:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_P(MinimalTest, RenderClear) {
|
|
|
|
|
RHICommandQueue* cmdQueue = GetCommandQueue();
|
|
|
|
|
RHISwapChain* swapChain = GetSwapChain();
|
|
|
|
|
const int targetFrameCount = 30;
|
2026-03-25 21:50:57 +08:00
|
|
|
const char* screenshotFilename = GetScreenshotFilename(GetBackendType());
|
|
|
|
|
const int comparisonThreshold = GetComparisonThreshold(GetBackendType());
|
2026-03-25 19:00:30 +08:00
|
|
|
|
|
|
|
|
for (int frameCount = 0; frameCount <= targetFrameCount; ++frameCount) {
|
|
|
|
|
if (frameCount > 0) {
|
|
|
|
|
cmdQueue->WaitForPreviousFrame();
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 20:50:49 +08:00
|
|
|
Log("[TEST] MainLoop: frame %d", frameCount);
|
2026-03-25 19:00:30 +08:00
|
|
|
BeginRender();
|
|
|
|
|
RenderFrame();
|
|
|
|
|
|
|
|
|
|
if (frameCount >= targetFrameCount) {
|
|
|
|
|
cmdQueue->WaitForIdle();
|
2026-03-25 21:50:57 +08:00
|
|
|
Log("[TEST] MainLoop: frame %d reached, capturing %s", frameCount, screenshotFilename);
|
|
|
|
|
ASSERT_TRUE(TakeScreenshot(screenshotFilename));
|
|
|
|
|
ASSERT_TRUE(CompareWithGoldenTemplate(screenshotFilename, "GT.ppm", static_cast<float>(comparisonThreshold)));
|
|
|
|
|
Log("[TEST] MainLoop: frame %d compare passed", frameCount);
|
2026-03-25 19:00:30 +08:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 20:50:49 +08:00
|
|
|
Log("[TEST] MainLoop: calling Present, index before=%d", swapChain->GetCurrentBackBufferIndex());
|
2026-03-25 19:00:30 +08:00
|
|
|
swapChain->Present(0, 0);
|
2026-03-25 20:50:49 +08:00
|
|
|
Log("[TEST] MainLoop: Present done, index after=%d", swapChain->GetCurrentBackBufferIndex());
|
2026-03-25 19:00:30 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
INSTANTIATE_TEST_SUITE_P(D3D12, MinimalTest, ::testing::Values(RHIType::D3D12));
|
|
|
|
|
INSTANTIATE_TEST_SUITE_P(OpenGL, MinimalTest, ::testing::Values(RHIType::OpenGL));
|
2026-03-27 12:05:12 +08:00
|
|
|
#if defined(XCENGINE_SUPPORT_VULKAN)
|
|
|
|
|
INSTANTIATE_TEST_SUITE_P(Vulkan, MinimalTest, ::testing::Values(RHIType::Vulkan));
|
|
|
|
|
#endif
|
2026-03-25 19:00:30 +08:00
|
|
|
|
|
|
|
|
GTEST_API_ int main(int argc, char** argv) {
|
2026-03-25 20:50:49 +08:00
|
|
|
Logger::Get().Initialize();
|
|
|
|
|
Logger::Get().AddSink(std::make_unique<ConsoleLogSink>());
|
|
|
|
|
Logger::Get().SetMinimumLevel(LogLevel::Debug);
|
|
|
|
|
|
2026-03-25 19:00:30 +08:00
|
|
|
testing::InitGoogleTest(&argc, argv);
|
|
|
|
|
return RUN_ALL_TESTS();
|
2026-03-25 20:50:49 +08:00
|
|
|
}
|