refactor(RHI): 将窗口职责从RHI移到Platform层

- RHIDeviceDesc 删除 windowHandle/width/height/appName
- SwapChainDesc 添加 windowHandle 字段
- RHISwapChain 删除 PollEvents/ShouldClose/SetFullscreen 等窗口相关接口
- OpenGLDevice 删除 CreateRenderWindow,改用 InitializeWithExistingWindow
- 更新所有集成测试使用新API
- 273个单元测试 + 8个集成测试全部通过
This commit is contained in:
2026-03-24 23:00:49 +08:00
parent 9fae910854
commit 7a66913f2b
22 changed files with 66 additions and 379 deletions

View File

@@ -83,9 +83,6 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
bool InitD3D12() {
// Create device
RHIDeviceDesc deviceDesc;
deviceDesc.windowHandle = gHWND;
deviceDesc.width = gWidth;
deviceDesc.height = gHeight;
deviceDesc.adapterIndex = 0;
deviceDesc.enableDebugLayer = false;
deviceDesc.enableGPUValidation = false;

View File

@@ -119,9 +119,6 @@ bool LoadTexture(const char* filename, D3D12Texture& texture, D3D12ResourceView&
bool InitD3D12() {
RHIDeviceDesc deviceDesc;
deviceDesc.windowHandle = gHWND;
deviceDesc.width = gWidth;
deviceDesc.height = gHeight;
deviceDesc.adapterIndex = 0;
deviceDesc.enableDebugLayer = false;
deviceDesc.enableGPUValidation = false;

View File

@@ -186,9 +186,6 @@ bool LoadTexture(const char* filename, D3D12Texture& texture, D3D12ResourceView&
bool InitD3D12() {
RHIDeviceDesc deviceDesc;
deviceDesc.windowHandle = gHWND;
deviceDesc.width = gWidth;
deviceDesc.height = gHeight;
deviceDesc.adapterIndex = 0;
deviceDesc.enableDebugLayer = false;
deviceDesc.enableGPUValidation = false;

View File

@@ -84,9 +84,6 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
bool InitD3D12() {
RHIDeviceDesc deviceDesc;
deviceDesc.windowHandle = gHWND;
deviceDesc.width = gWidth;
deviceDesc.height = gHeight;
deviceDesc.adapterIndex = 0;
deviceDesc.enableDebugLayer = false;
deviceDesc.enableGPUValidation = false;

View File

@@ -86,13 +86,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
RenderDocCapture::Get().SetCaptureFilePath(".\\minimal_frame30");
OpenGLDevice device;
RHIDeviceDesc desc = {};
desc.windowHandle = hwnd;
desc.width = gWidth;
desc.height = gHeight;
desc.appName = L"OpenGL_Minimal_Test";
desc.enableDebugLayer = true;
if (!device.Initialize(desc)) {
if (!device.InitializeWithExistingWindow(hwnd)) {
Log("[ERROR] Failed to initialize OpenGL device");
return -1;
}

View File

@@ -90,13 +90,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
RenderDocCapture::Get().SetCaptureFilePath(".\\quad_frame30");
OpenGLDevice device;
RHIDeviceDesc desc = {};
desc.windowHandle = hwnd;
desc.width = gWidth;
desc.height = gHeight;
desc.appName = L"OpenGL_Quad_Test";
desc.enableDebugLayer = true;
if (!device.Initialize(desc)) {
if (!device.InitializeWithExistingWindow(hwnd)) {
Log("[ERROR] Failed to initialize OpenGL device");
return -1;
}

View File

@@ -169,13 +169,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
RenderDocCapture::Get().SetCaptureFilePath(".\\sphere_frame30");
OpenGLDevice device;
RHIDeviceDesc desc = {};
desc.windowHandle = hwnd;
desc.width = gWidth;
desc.height = gHeight;
desc.appName = L"OpenGL_Sphere_Test";
desc.enableDebugLayer = true;
if (!device.Initialize(desc)) {
if (!device.InitializeWithExistingWindow(hwnd)) {
Log("[ERROR] Failed to initialize OpenGL device");
return -1;
}

View File

@@ -86,13 +86,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
RenderDocCapture::Get().SetCaptureFilePath(".\\triangle_frame30");
OpenGLDevice device;
RHIDeviceDesc desc = {};
desc.windowHandle = hwnd;
desc.width = gWidth;
desc.height = gHeight;
desc.appName = L"OpenGL_Triangle_Test";
desc.enableDebugLayer = true;
if (!device.Initialize(desc)) {
if (!device.InitializeWithExistingWindow(hwnd)) {
Log("[ERROR] Failed to initialize OpenGL device");
return -1;
}

View File

@@ -3,24 +3,6 @@
using namespace XCEngine::RHI;
TEST_F(OpenGLTestFixture, Device_CreateRenderWindow_ValidParams) {
OpenGLDevice device;
bool result = device.CreateRenderWindow(800, 600, "Test Window", false);
ASSERT_TRUE(result);
ASSERT_NE(device.GetWindow(), nullptr);
}
TEST_F(OpenGLTestFixture, Device_CreateRenderWindow_DebugMode) {
OpenGLDevice device;
bool result = device.CreateRenderWindow(640, 480, "Debug Window", true);
ASSERT_TRUE(result);
ASSERT_NE(device.GetWindow(), nullptr);
}
TEST_F(OpenGLTestFixture, Device_InitializeWithExistingWindow) {
OpenGLDevice device;
HWND existingWindow = GetWindow();
@@ -28,12 +10,11 @@ TEST_F(OpenGLTestFixture, Device_InitializeWithExistingWindow) {
bool result = device.InitializeWithExistingWindow(existingWindow);
ASSERT_TRUE(result);
ASSERT_EQ(device.GetWindow(), existingWindow);
}
TEST_F(OpenGLTestFixture, Device_GetDeviceInfo_ReturnsValid) {
OpenGLDevice device;
device.CreateRenderWindow(800, 600, "Test", false);
device.InitializeWithExistingWindow(GetWindow());
const auto& info = device.GetDeviceInfo();
@@ -45,19 +26,10 @@ TEST_F(OpenGLTestFixture, Device_GetDeviceInfo_ReturnsValid) {
TEST_F(OpenGLTestFixture, Device_SwapBuffers_NoErrors) {
OpenGLDevice device;
device.CreateRenderWindow(800, 600, "Test", false);
device.InitializeWithExistingWindow(GetWindow());
device.SwapBuffers();
GLenum error = glGetError();
EXPECT_EQ(error, GL_NO_ERROR);
}
TEST_F(OpenGLTestFixture, Device_PollEvents_ReturnsTrue) {
OpenGLDevice device;
device.CreateRenderWindow(800, 600, "Test", false);
bool result = device.PollEvents();
EXPECT_TRUE(result);
}
}

View File

@@ -3,6 +3,9 @@
#include <iostream>
#include <windows.h>
#include "XCEngine/RHI/D3D12/D3D12Device.h"
#include "XCEngine/RHI/OpenGL/OpenGLDevice.h"
namespace XCEngine {
namespace RHI {
@@ -26,15 +29,18 @@ void RHITestFixture::SetUp() {
wc.lpszClassName = L"RHIUnitTestClass";
RegisterClassExW(&wc);
HWND hwnd = CreateWindowExW(0, L"RHIUnitTestClass", L"RHIUnitTest", WS_OVERLAPPEDWINDOW,
mWindow = CreateWindowExW(0, L"RHIUnitTestClass", L"RHIUnitTest", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
RHIDeviceDesc desc = {};
desc.enableDebugLayer = true;
desc.appName = L"RHIUnitTest";
desc.windowHandle = hwnd;
bool initResult = mDevice->Initialize(desc);
bool initResult = false;
if (GetParam() == RHIType::D3D12) {
RHIDeviceDesc desc = {};
desc.enableDebugLayer = true;
initResult = mDevice->Initialize(desc);
} else if (GetParam() == RHIType::OpenGL) {
auto* oglDevice = static_cast<OpenGLDevice*>(mDevice);
initResult = oglDevice->InitializeWithExistingWindow(mWindow);
}
ASSERT_TRUE(initResult);
}
@@ -44,6 +50,10 @@ void RHITestFixture::TearDown() {
delete mDevice;
mDevice = nullptr;
}
if (mWindow) {
DestroyWindow(mWindow);
mWindow = nullptr;
}
}
} // namespace RHI

View File

@@ -2,6 +2,7 @@
#include <gtest/gtest.h>
#include <string>
#include <windows.h>
#include "XCEngine/RHI/RHIFactory.h"
#include "XCEngine/RHI/RHIDevice.h"
@@ -29,9 +30,11 @@ protected:
RHIDevice* GetDevice() { return mDevice; }
RHIType GetBackendType() const { return GetParam(); }
HWND GetWindowHandle() const { return mWindow; }
private:
RHIDevice* mDevice = nullptr;
HWND mWindow = nullptr;
};
} // namespace RHI

View File

@@ -1,4 +1,5 @@
#include "fixtures/RHITestFixture.h"
#include "XCEngine/RHI/OpenGL/OpenGLDevice.h"
using namespace XCEngine::RHI;
@@ -10,9 +11,15 @@ TEST_P(RHITestFixture, Device_Initialize_Shutdown) {
RHIDevice* device = RHIFactory::CreateRHIDevice(GetBackendType());
ASSERT_NE(device, nullptr);
RHIDeviceDesc desc = {};
desc.enableDebugLayer = true;
bool initResult = device->Initialize(desc);
bool initResult = false;
if (GetBackendType() == RHIType::D3D12) {
RHIDeviceDesc desc = {};
desc.enableDebugLayer = true;
initResult = device->Initialize(desc);
} else if (GetBackendType() == RHIType::OpenGL) {
auto* oglDevice = static_cast<OpenGLDevice*>(device);
initResult = oglDevice->InitializeWithExistingWindow(GetWindowHandle());
}
ASSERT_TRUE(initResult);
device->Shutdown();

View File

@@ -5,15 +5,11 @@ using namespace XCEngine::RHI;
TEST_P(RHITestFixture, SwapChain_Create) {
SwapChainDesc desc = {};
desc.windowHandle = GetWindowHandle();
desc.width = 800;
desc.height = 600;
desc.bufferCount = 2;
desc.format = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
desc.refreshRate = 60;
desc.sampleCount = 1;
desc.sampleQuality = 0;
desc.swapEffect = 0;
desc.flags = 0;
desc.format = Format::R8G8B8A8_UNorm;
RHISwapChain* swapChain = GetDevice()->CreateSwapChain(desc);
ASSERT_NE(swapChain, nullptr);
@@ -24,10 +20,11 @@ TEST_P(RHITestFixture, SwapChain_Create) {
TEST_P(RHITestFixture, SwapChain_GetCurrentBackBufferIndex) {
SwapChainDesc desc = {};
desc.windowHandle = GetWindowHandle();
desc.width = 800;
desc.height = 600;
desc.bufferCount = 2;
desc.format = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
desc.format = Format::R8G8B8A8_UNorm;
RHISwapChain* swapChain = GetDevice()->CreateSwapChain(desc);
ASSERT_NE(swapChain, nullptr);
@@ -41,10 +38,11 @@ TEST_P(RHITestFixture, SwapChain_GetCurrentBackBufferIndex) {
TEST_P(RHITestFixture, SwapChain_GetCurrentBackBuffer) {
SwapChainDesc desc = {};
desc.windowHandle = GetWindowHandle();
desc.width = 800;
desc.height = 600;
desc.bufferCount = 2;
desc.format = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
desc.format = Format::R8G8B8A8_UNorm;
RHISwapChain* swapChain = GetDevice()->CreateSwapChain(desc);
ASSERT_NE(swapChain, nullptr);
@@ -58,10 +56,11 @@ TEST_P(RHITestFixture, SwapChain_GetCurrentBackBuffer) {
TEST_P(RHITestFixture, SwapChain_Resize) {
SwapChainDesc desc = {};
desc.windowHandle = GetWindowHandle();
desc.width = 800;
desc.height = 600;
desc.bufferCount = 2;
desc.format = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
desc.format = Format::R8G8B8A8_UNorm;
RHISwapChain* swapChain = GetDevice()->CreateSwapChain(desc);
ASSERT_NE(swapChain, nullptr);
@@ -71,40 +70,3 @@ TEST_P(RHITestFixture, SwapChain_Resize) {
swapChain->Shutdown();
delete swapChain;
}
TEST_P(RHITestFixture, SwapChain_FullscreenState) {
SwapChainDesc desc = {};
desc.width = 800;
desc.height = 600;
desc.bufferCount = 2;
desc.format = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
RHISwapChain* swapChain = GetDevice()->CreateSwapChain(desc);
ASSERT_NE(swapChain, nullptr);
EXPECT_FALSE(swapChain->IsFullscreen());
swapChain->SetFullscreen(true);
EXPECT_TRUE(swapChain->IsFullscreen());
swapChain->SetFullscreen(false);
swapChain->Shutdown();
delete swapChain;
}
TEST_P(RHITestFixture, SwapChain_ShouldClose) {
SwapChainDesc desc = {};
desc.width = 800;
desc.height = 600;
desc.bufferCount = 2;
desc.format = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
RHISwapChain* swapChain = GetDevice()->CreateSwapChain(desc);
ASSERT_NE(swapChain, nullptr);
EXPECT_FALSE(swapChain->ShouldClose());
swapChain->SetShouldClose(true);
EXPECT_TRUE(swapChain->ShouldClose());
swapChain->Shutdown();
delete swapChain;
}