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

@@ -29,24 +29,15 @@ public:
const D3D12Texture& GetBackBuffer(uint32_t index) const; const D3D12Texture& GetBackBuffer(uint32_t index) const;
void Present(uint32_t syncInterval = 1, uint32_t flags = 0) override; void Present(uint32_t syncInterval = 1, uint32_t flags = 0) override;
void Resize(uint32_t width, uint32_t height) override; void Resize(uint32_t width, uint32_t height) override;
void SetFullscreen(bool fullscreen) override;
bool IsFullscreen() const override;
void* GetNativeHandle() override; void* GetNativeHandle() override;
bool ShouldClose() const override;
void SetShouldClose(bool shouldClose) override;
void PollEvents() override;
private: private:
ComPtr<IDXGISwapChain3> m_swapChain; ComPtr<IDXGISwapChain3> m_swapChain;
ComPtr<ID3D12CommandQueue> m_commandQueue; ComPtr<ID3D12CommandQueue> m_commandQueue;
HWND m_windowHandle;
uint32_t m_width; uint32_t m_width;
uint32_t m_height; uint32_t m_height;
uint32_t m_bufferCount; uint32_t m_bufferCount;
std::vector<D3D12Texture> m_backBuffers; std::vector<D3D12Texture> m_backBuffers;
bool m_shouldClose = false;
bool m_fullscreen = false;
}; };
} // namespace RHI } // namespace RHI

View File

@@ -29,8 +29,6 @@ public:
void Shutdown() override; void Shutdown() override;
bool InitializeWithExistingWindow(HWND hwnd); bool InitializeWithExistingWindow(HWND hwnd);
bool CreateRenderWindow(int width, int height, const char* title, bool enableDebug = false);
HWND GetWindow() const { return m_hwnd; }
HDC GetPresentationDC() const { return m_hdc; } HDC GetPresentationDC() const { return m_hdc; }
HGLRC GetGLContext() const { return m_hglrc; } HGLRC GetGLContext() const { return m_hglrc; }
const RHIDeviceInfo& GetDeviceInfoImpl() const { return m_deviceInfo; } const RHIDeviceInfo& GetDeviceInfoImpl() const { return m_deviceInfo; }
@@ -39,9 +37,6 @@ public:
OpenGLUniformBufferManager* GetUniformBufferManager() { return m_uniformBufferManager.get(); } OpenGLUniformBufferManager* GetUniformBufferManager() { return m_uniformBufferManager.get(); }
void SwapBuffers(); void SwapBuffers();
bool PollEvents();
void SetShouldClose(bool shouldClose);
bool ShouldClose() const;
RHIBuffer* CreateBuffer(const BufferDesc& desc) override; RHIBuffer* CreateBuffer(const BufferDesc& desc) override;
RHITexture* CreateTexture(const TextureDesc& desc) override; RHITexture* CreateTexture(const TextureDesc& desc) override;
@@ -74,8 +69,6 @@ private:
RHIDeviceInfo m_deviceInfo; RHIDeviceInfo m_deviceInfo;
RHICapabilities m_capabilities; RHICapabilities m_capabilities;
bool m_initialized = false; bool m_initialized = false;
bool m_ownsWindow = false;
bool m_shouldClose = false;
std::unique_ptr<OpenGLTextureUnitAllocator> m_textureUnitAllocator; std::unique_ptr<OpenGLTextureUnitAllocator> m_textureUnitAllocator;
std::unique_ptr<OpenGLUniformBufferManager> m_uniformBufferManager; std::unique_ptr<OpenGLUniformBufferManager> m_uniformBufferManager;

View File

@@ -37,39 +37,19 @@ public:
void Present(uint32_t syncInterval = 1, uint32_t flags = 0) override; void Present(uint32_t syncInterval = 1, uint32_t flags = 0) override;
void SwapBuffers(); void SwapBuffers();
void Resize(uint32_t width, uint32_t height) override; void Resize(uint32_t width, uint32_t height) override;
void SetVSync(bool enabled);
bool IsVSync() const { return m_vsync; }
void SetFullscreen(bool fullscreen) override;
bool IsFullscreen() const override;
void SetFramebufferSize(int width, int height);
int GetWidth() const { return m_width; }
int GetHeight() const { return m_height; }
int GetFramebufferWidth() const { return m_framebufferWidth; }
int GetFramebufferHeight() const { return m_framebufferHeight; }
HWND GetWindow() const { return m_hwnd; }
HDC GetDC() const { return m_device ? m_device->GetPresentationDC() : nullptr; }
bool ShouldClose() const override;
void SetShouldClose(bool shouldClose) override;
void PollEvents() override;
uint32_t GetCurrentBackBufferIndex() const override; uint32_t GetCurrentBackBufferIndex() const override;
RHITexture* GetCurrentBackBuffer() override; RHITexture* GetCurrentBackBuffer() override;
void* GetNativeHandle() override; void* GetNativeHandle() override;
int GetWidth() const { return m_width; }
int GetHeight() const { return m_height; }
private: private:
OpenGLDevice* m_device = nullptr; OpenGLDevice* m_device = nullptr;
HWND m_hwnd = nullptr; HWND m_hwnd = nullptr;
int m_width = 0; int m_width = 0;
int m_height = 0; int m_height = 0;
int m_framebufferWidth = 0;
int m_framebufferHeight = 0;
bool m_vsync = true;
bool m_shouldClose = false;
bool m_fullscreen = false;
PresentMode m_presentMode = PresentMode::VSync;
OpenGLTexture* m_backBufferTexture = nullptr; OpenGLTexture* m_backBufferTexture = nullptr;
}; };

View File

@@ -17,12 +17,6 @@ public:
virtual RHITexture* GetCurrentBackBuffer() = 0; virtual RHITexture* GetCurrentBackBuffer() = 0;
virtual void Present(uint32_t syncInterval = 1, uint32_t flags = 0) = 0; virtual void Present(uint32_t syncInterval = 1, uint32_t flags = 0) = 0;
virtual void Resize(uint32_t width, uint32_t height) = 0; virtual void Resize(uint32_t width, uint32_t height) = 0;
virtual void SetFullscreen(bool fullscreen) = 0;
virtual bool IsFullscreen() const = 0;
virtual bool ShouldClose() const = 0;
virtual void SetShouldClose(bool shouldClose) = 0;
virtual void PollEvents() = 0;
virtual void* GetNativeHandle() = 0; virtual void* GetNativeHandle() = 0;
}; };

View File

@@ -184,15 +184,17 @@ struct SamplerDesc {
}; };
struct SwapChainDesc { struct SwapChainDesc {
uint32_t width; void* windowHandle = nullptr;
uint32_t height; uint32_t width = 1280;
uint32_t bufferCount; uint32_t height = 720;
uint32_t format; uint32_t bufferCount = 2;
uint32_t refreshRate; Format format = Format::R8G8B8A8_UNorm;
uint32_t sampleCount; uint32_t refreshRateNumerator = 60;
uint32_t sampleQuality; uint32_t refreshRateDenominator = 1;
uint32_t swapEffect; uint32_t sampleCount = 1;
uint32_t flags; uint32_t sampleQuality = 0;
uint32_t swapEffect = 0;
uint32_t flags = 0;
}; };
struct RenderTargetViewDesc { struct RenderTargetViewDesc {
@@ -317,10 +319,6 @@ struct RHIDeviceDesc {
bool enableDebugLayer = false; bool enableDebugLayer = false;
bool enableGPUValidation = false; bool enableGPUValidation = false;
uint32_t adapterIndex = 0; uint32_t adapterIndex = 0;
void* windowHandle = nullptr;
uint32_t width = 1280;
uint32_t height = 720;
std::wstring appName = L"XCEngine";
}; };
struct RHIDeviceInfo { struct RHIDeviceInfo {

View File

@@ -335,7 +335,7 @@ RHIFence* D3D12Device::CreateFence(const FenceDesc& desc) {
RHISwapChain* D3D12Device::CreateSwapChain(const SwapChainDesc& desc) { RHISwapChain* D3D12Device::CreateSwapChain(const SwapChainDesc& desc) {
auto* swapChain = new D3D12SwapChain(); auto* swapChain = new D3D12SwapChain();
HWND hwnd = static_cast<HWND>(m_deviceDesc.windowHandle); HWND hwnd = static_cast<HWND>(desc.windowHandle);
if (swapChain->Initialize(m_factory.Get(), m_commandQueue.Get(), hwnd, if (swapChain->Initialize(m_factory.Get(), m_commandQueue.Get(), hwnd,
desc.width, desc.height, desc.bufferCount)) { desc.width, desc.height, desc.bufferCount)) {
return swapChain; return swapChain;

View File

@@ -5,8 +5,7 @@ namespace XCEngine {
namespace RHI { namespace RHI {
D3D12SwapChain::D3D12SwapChain() D3D12SwapChain::D3D12SwapChain()
: m_windowHandle(nullptr) : m_width(0)
, m_width(0)
, m_height(0) , m_height(0)
, m_bufferCount(2) { , m_bufferCount(2) {
} }
@@ -40,7 +39,6 @@ bool D3D12SwapChain::Initialize(IDXGIFactory4* factory, ID3D12CommandQueue* comm
} }
m_commandQueue = commandQueue; m_commandQueue = commandQueue;
m_windowHandle = windowHandle;
m_width = width; m_width = width;
m_height = height; m_height = height;
m_bufferCount = bufferCount; m_bufferCount = bufferCount;
@@ -102,15 +100,6 @@ void D3D12SwapChain::Resize(uint32_t width, uint32_t height) {
m_height = height; m_height = height;
} }
void D3D12SwapChain::SetFullscreen(bool fullscreen) {
m_fullscreen = fullscreen;
m_swapChain->SetFullscreenState(fullscreen, nullptr);
}
bool D3D12SwapChain::IsFullscreen() const {
return m_fullscreen;
}
void* D3D12SwapChain::GetNativeHandle() { void* D3D12SwapChain::GetNativeHandle() {
return reinterpret_cast<void*>(m_swapChain.Get()); return reinterpret_cast<void*>(m_swapChain.Get());
} }
@@ -119,16 +108,5 @@ RHITexture* D3D12SwapChain::GetCurrentBackBuffer() {
return &GetBackBuffer(GetCurrentBackBufferIndex()); return &GetBackBuffer(GetCurrentBackBufferIndex());
} }
bool D3D12SwapChain::ShouldClose() const {
return m_shouldClose;
}
void D3D12SwapChain::SetShouldClose(bool shouldClose) {
m_shouldClose = shouldClose;
}
void D3D12SwapChain::PollEvents() {
}
} // namespace RHI } // namespace RHI
} // namespace XCEngine } // namespace XCEngine

View File

@@ -20,9 +20,6 @@
#include "XCEngine/RHI/OpenGL/OpenGLResourceView.h" #include "XCEngine/RHI/OpenGL/OpenGLResourceView.h"
#include "XCEngine/Debug/Logger.h" #include "XCEngine/Debug/Logger.h"
static bool s_windowClassRegistered = false;
static const wchar_t kWindowClassName[] = L"XCEngine_OpenGL_WindowClass";
typedef const char* (WINAPI* PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC hdc); typedef const char* (WINAPI* PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC hdc);
typedef BOOL (WINAPI* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats); typedef BOOL (WINAPI* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats);
typedef HGLRC (WINAPI* PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hShareContext, const int* attribList); typedef HGLRC (WINAPI* PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hShareContext, const int* attribList);
@@ -45,9 +42,7 @@ OpenGLDevice::OpenGLDevice()
: m_hwnd(nullptr) : m_hwnd(nullptr)
, m_hdc(nullptr) , m_hdc(nullptr)
, m_hglrc(nullptr) , m_hglrc(nullptr)
, m_initialized(false) , m_initialized(false) {
, m_ownsWindow(false)
, m_shouldClose(false) {
m_textureUnitAllocator = std::make_unique<OpenGLTextureUnitAllocator>(); m_textureUnitAllocator = std::make_unique<OpenGLTextureUnitAllocator>();
m_uniformBufferManager = std::make_unique<OpenGLUniformBufferManager>(); m_uniformBufferManager = std::make_unique<OpenGLUniformBufferManager>();
} }
@@ -61,16 +56,7 @@ bool OpenGLDevice::Initialize(const RHIDeviceDesc& desc) {
return true; return true;
} }
if (desc.windowHandle) { return false;
return InitializeWithExistingWindow(static_cast<HWND>(desc.windowHandle));
}
std::string titleStr = "XCEngine";
if (!desc.appName.empty()) {
titleStr = std::string(desc.appName.begin(), desc.appName.end());
}
return CreateRenderWindow(desc.width, desc.height, titleStr.c_str(), desc.enableDebugLayer);
} }
bool OpenGLDevice::InitializeWithExistingWindow(HWND hwnd) { bool OpenGLDevice::InitializeWithExistingWindow(HWND hwnd) {
@@ -248,52 +234,6 @@ bool OpenGLDevice::InitializeWithExistingWindow(HWND hwnd) {
return true; return true;
} }
bool OpenGLDevice::CreateRenderWindow(int width, int height, const char* title, bool enableDebug) {
if (m_initialized) {
return true;
}
if (!s_windowClassRegistered) {
WNDCLASSEXW wc = {};
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DefWindowProcW;
wc.hInstance = GetModuleHandleW(nullptr);
wc.lpszClassName = kWindowClassName;
if (!RegisterClassExW(&wc)) {
return false;
}
s_windowClassRegistered = true;
}
std::wstring titleW(title ? std::wstring(title, title + strlen(title)) : L"XCEngine");
HWND hwnd = CreateWindowExW(
0,
kWindowClassName,
titleW.c_str(),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
width, height,
nullptr,
nullptr,
GetModuleHandleW(nullptr),
nullptr
);
if (!hwnd) {
return false;
}
m_hwnd = hwnd;
m_ownsWindow = true;
ShowWindow(m_hwnd, SW_SHOWNORMAL);
UpdateWindow(m_hwnd);
return InitializeWithExistingWindow(m_hwnd);
}
void OpenGLDevice::Shutdown() { void OpenGLDevice::Shutdown() {
if (m_hglrc) { if (m_hglrc) {
wglMakeCurrent(nullptr, nullptr); wglMakeCurrent(nullptr, nullptr);
@@ -304,10 +244,6 @@ void OpenGLDevice::Shutdown() {
if (m_hdc && m_hwnd) { if (m_hdc && m_hwnd) {
ReleaseDC(m_hwnd, m_hdc); ReleaseDC(m_hwnd, m_hdc);
m_hdc = nullptr; m_hdc = nullptr;
}
if (m_ownsWindow && m_hwnd) {
DestroyWindow(m_hwnd);
m_hwnd = nullptr; m_hwnd = nullptr;
} }
@@ -319,8 +255,6 @@ void OpenGLDevice::Shutdown() {
} }
m_initialized = false; m_initialized = false;
m_ownsWindow = false;
m_shouldClose = false;
} }
void OpenGLDevice::SwapBuffers() { void OpenGLDevice::SwapBuffers() {
@@ -329,30 +263,6 @@ void OpenGLDevice::SwapBuffers() {
} }
} }
bool OpenGLDevice::PollEvents() {
MSG msg;
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
m_shouldClose = true;
return false;
}
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return !m_shouldClose;
}
void OpenGLDevice::SetShouldClose(bool shouldClose) {
m_shouldClose = shouldClose;
if (m_hwnd && shouldClose) {
PostMessageW(m_hwnd, WM_CLOSE, 0, 0);
}
}
bool OpenGLDevice::ShouldClose() const {
return m_shouldClose;
}
RHIBuffer* OpenGLDevice::CreateBuffer(const BufferDesc& desc) { RHIBuffer* OpenGLDevice::CreateBuffer(const BufferDesc& desc) {
auto* buffer = new OpenGLBuffer(); auto* buffer = new OpenGLBuffer();
OpenGLBufferType bufferType = OpenGLBufferType::Vertex; OpenGLBufferType bufferType = OpenGLBufferType::Vertex;
@@ -416,8 +326,9 @@ RHITexture* OpenGLDevice::CreateTexture(const TextureDesc& desc) {
RHISwapChain* OpenGLDevice::CreateSwapChain(const SwapChainDesc& desc) { RHISwapChain* OpenGLDevice::CreateSwapChain(const SwapChainDesc& desc) {
auto* swapChain = new OpenGLSwapChain(); auto* swapChain = new OpenGLSwapChain();
if (m_hwnd) { HWND hwnd = static_cast<HWND>(desc.windowHandle);
swapChain->Initialize(this, m_hwnd, desc.width, desc.height); if (hwnd) {
swapChain->Initialize(this, hwnd, desc.width, desc.height);
} }
return swapChain; return swapChain;
} }

View File

@@ -6,9 +6,6 @@
#include "XCEngine/RHI/OpenGL/OpenGLSwapChain.h" #include "XCEngine/RHI/OpenGL/OpenGLSwapChain.h"
typedef void (APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int);
static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = nullptr;
namespace XCEngine { namespace XCEngine {
namespace RHI { namespace RHI {
@@ -17,12 +14,6 @@ OpenGLSwapChain::OpenGLSwapChain()
, m_hwnd(nullptr) , m_hwnd(nullptr)
, m_width(0) , m_width(0)
, m_height(0) , m_height(0)
, m_framebufferWidth(0)
, m_framebufferHeight(0)
, m_vsync(true)
, m_shouldClose(false)
, m_fullscreen(false)
, m_presentMode(PresentMode::VSync)
, m_backBufferTexture(nullptr) { , m_backBufferTexture(nullptr) {
} }
@@ -35,23 +26,6 @@ bool OpenGLSwapChain::Initialize(OpenGLDevice* device, HWND window, int width, i
m_hwnd = window; m_hwnd = window;
m_width = width; m_width = width;
m_height = height; m_height = height;
m_presentMode = PresentMode::VSync;
m_vsync = true;
m_shouldClose = false;
if (!wglSwapIntervalEXT) {
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
}
if (wglSwapIntervalEXT) {
wglSwapIntervalEXT(m_vsync ? 1 : 0);
}
RECT rect = { 0, 0, width, height };
::AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
::SetWindowPos(m_hwnd, nullptr, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER);
m_framebufferWidth = width;
m_framebufferHeight = height;
if (!m_backBufferTexture) { if (!m_backBufferTexture) {
m_backBufferTexture = new OpenGLTexture(); m_backBufferTexture = new OpenGLTexture();
@@ -76,41 +50,6 @@ void OpenGLSwapChain::SwapBuffers() {
} }
} }
void OpenGLSwapChain::SetVSync(bool enabled) {
m_vsync = enabled;
if (wglSwapIntervalEXT) {
wglSwapIntervalEXT(enabled ? 1 : 0);
}
}
void OpenGLSwapChain::SetFramebufferSize(int width, int height) {
m_framebufferWidth = width;
m_framebufferHeight = height;
}
bool OpenGLSwapChain::ShouldClose() const {
return m_shouldClose;
}
void OpenGLSwapChain::SetShouldClose(bool shouldClose) {
m_shouldClose = shouldClose;
if (m_hwnd && shouldClose) {
PostMessageW(m_hwnd, WM_CLOSE, 0, 0);
}
}
void OpenGLSwapChain::PollEvents() {
MSG msg;
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
m_shouldClose = true;
break;
}
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
void OpenGLSwapChain::Present(uint32_t syncInterval, uint32_t flags) { void OpenGLSwapChain::Present(uint32_t syncInterval, uint32_t flags) {
if (m_device) { if (m_device) {
::SwapBuffers(m_device->GetPresentationDC()); ::SwapBuffers(m_device->GetPresentationDC());
@@ -120,21 +59,6 @@ void OpenGLSwapChain::Present(uint32_t syncInterval, uint32_t flags) {
void OpenGLSwapChain::Resize(uint32_t width, uint32_t height) { void OpenGLSwapChain::Resize(uint32_t width, uint32_t height) {
m_width = width; m_width = width;
m_height = height; m_height = height;
if (m_hwnd) {
RECT rect = { 0, 0, width, height };
::AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
::SetWindowPos(m_hwnd, nullptr, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER);
}
m_framebufferWidth = width;
m_framebufferHeight = height;
}
void OpenGLSwapChain::SetFullscreen(bool fullscreen) {
m_fullscreen = fullscreen;
}
bool OpenGLSwapChain::IsFullscreen() const {
return m_fullscreen;
} }
uint32_t OpenGLSwapChain::GetCurrentBackBufferIndex() const { uint32_t OpenGLSwapChain::GetCurrentBackBufferIndex() const {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,24 +3,6 @@
using namespace XCEngine::RHI; 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) { TEST_F(OpenGLTestFixture, Device_InitializeWithExistingWindow) {
OpenGLDevice device; OpenGLDevice device;
HWND existingWindow = GetWindow(); HWND existingWindow = GetWindow();
@@ -28,12 +10,11 @@ TEST_F(OpenGLTestFixture, Device_InitializeWithExistingWindow) {
bool result = device.InitializeWithExistingWindow(existingWindow); bool result = device.InitializeWithExistingWindow(existingWindow);
ASSERT_TRUE(result); ASSERT_TRUE(result);
ASSERT_EQ(device.GetWindow(), existingWindow);
} }
TEST_F(OpenGLTestFixture, Device_GetDeviceInfo_ReturnsValid) { TEST_F(OpenGLTestFixture, Device_GetDeviceInfo_ReturnsValid) {
OpenGLDevice device; OpenGLDevice device;
device.CreateRenderWindow(800, 600, "Test", false); device.InitializeWithExistingWindow(GetWindow());
const auto& info = device.GetDeviceInfo(); const auto& info = device.GetDeviceInfo();
@@ -45,19 +26,10 @@ TEST_F(OpenGLTestFixture, Device_GetDeviceInfo_ReturnsValid) {
TEST_F(OpenGLTestFixture, Device_SwapBuffers_NoErrors) { TEST_F(OpenGLTestFixture, Device_SwapBuffers_NoErrors) {
OpenGLDevice device; OpenGLDevice device;
device.CreateRenderWindow(800, 600, "Test", false); device.InitializeWithExistingWindow(GetWindow());
device.SwapBuffers(); device.SwapBuffers();
GLenum error = glGetError(); GLenum error = glGetError();
EXPECT_EQ(error, GL_NO_ERROR); 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 <iostream>
#include <windows.h> #include <windows.h>
#include "XCEngine/RHI/D3D12/D3D12Device.h"
#include "XCEngine/RHI/OpenGL/OpenGLDevice.h"
namespace XCEngine { namespace XCEngine {
namespace RHI { namespace RHI {
@@ -26,15 +29,18 @@ void RHITestFixture::SetUp() {
wc.lpszClassName = L"RHIUnitTestClass"; wc.lpszClassName = L"RHIUnitTestClass";
RegisterClassExW(&wc); 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); CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
RHIDeviceDesc desc = {}; bool initResult = false;
desc.enableDebugLayer = true; if (GetParam() == RHIType::D3D12) {
desc.appName = L"RHIUnitTest"; RHIDeviceDesc desc = {};
desc.windowHandle = hwnd; desc.enableDebugLayer = true;
initResult = mDevice->Initialize(desc);
bool initResult = mDevice->Initialize(desc); } else if (GetParam() == RHIType::OpenGL) {
auto* oglDevice = static_cast<OpenGLDevice*>(mDevice);
initResult = oglDevice->InitializeWithExistingWindow(mWindow);
}
ASSERT_TRUE(initResult); ASSERT_TRUE(initResult);
} }
@@ -44,6 +50,10 @@ void RHITestFixture::TearDown() {
delete mDevice; delete mDevice;
mDevice = nullptr; mDevice = nullptr;
} }
if (mWindow) {
DestroyWindow(mWindow);
mWindow = nullptr;
}
} }
} // namespace RHI } // namespace RHI

View File

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

View File

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

View File

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