OpenGL: Refactor integration test and enable CTest framework

- Simplify OpenGL integration test structure
- Enable CTest registration for OpenGL tests
- Refactor test fixtures and device enumeration
- Minor code cleanup and improvements
This commit is contained in:
2026-03-20 19:05:50 +08:00
parent 45fd25dce3
commit 572e0e9bd5
29 changed files with 446 additions and 295 deletions

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include <string> #include <string>
#include <GLFW/glfw3.h>
#include "../RHIBuffer.h" #include "../RHIBuffer.h"

View File

@@ -1,6 +1,5 @@
#pragma once #pragma once
#include <GLFW/glfw3.h>
#include <vector> #include <vector>
#include <cstdint> #include <cstdint>

View File

@@ -1,6 +1,5 @@
#pragma once #pragma once
#include <GLFW/glfw3.h>
#include <cstdint> #include <cstdint>
namespace XCEngine { namespace XCEngine {

View File

@@ -1,14 +1,21 @@
#pragma once #pragma once
#include <string> #include <string>
#include <GLFW/glfw3.h>
#include "../RHIDevice.h" #include "../RHIDevice.h"
#include "../RHICapabilities.h" #include "../RHICapabilities.h"
struct HWND__;
struct HDC__;
struct HGLRC__;
namespace XCEngine { namespace XCEngine {
namespace RHI { namespace RHI {
using HWND = HWND__*;
using HDC = HDC__*;
using HGLRC = HGLRC__*;
class OpenGLDevice : public RHIDevice { class OpenGLDevice : public RHIDevice {
public: public:
OpenGLDevice(); OpenGLDevice();
@@ -18,9 +25,11 @@ public:
void Shutdown() override; void Shutdown() override;
bool CreateRenderWindow(int width, int height, const char* title, bool enableDebug = false); bool CreateRenderWindow(int width, int height, const char* title, bool enableDebug = false);
bool InitializeWithExistingWindow(GLFWwindow* window); bool InitializeWithExistingWindow(HWND hwnd);
GLFWwindow* GetWindow() const { return m_window; } HWND GetWindow() const { return m_hwnd; }
HDC GetDC() const { return m_hdc; }
HGLRC GetContext() const { return m_hglrc; }
const RHIDeviceInfo& GetDeviceInfoImpl() const { return m_deviceInfo; } const RHIDeviceInfo& GetDeviceInfoImpl() const { return m_deviceInfo; }
void SwapBuffers(); void SwapBuffers();
@@ -45,11 +54,14 @@ public:
void* GetNativeHandle() const; void* GetNativeHandle() const;
private: private:
GLFWwindow* m_window; HWND m_hwnd;
HDC m_hdc;
HGLRC m_hglrc;
RHIDeviceInfo m_deviceInfo; RHIDeviceInfo m_deviceInfo;
RHICapabilities m_capabilities; RHICapabilities m_capabilities;
bool m_initialized; bool m_initialized;
bool m_ownsWindow; bool m_ownsWindow;
bool m_shouldClose;
}; };
} // namespace RHI } // namespace RHI

View File

@@ -1,6 +1,5 @@
#pragma once #pragma once
#include <GLFW/glfw3.h>
#include <cstdint> #include <cstdint>
#include "../RHIFence.h" #include "../RHIFence.h"

View File

@@ -1,6 +1,5 @@
#pragma once #pragma once
#include <GLFW/glfw3.h>
#include <cstdint> #include <cstdint>
#include <string> #include <string>

View File

@@ -1,6 +1,5 @@
#pragma once #pragma once
#include <GLFW/glfw3.h>
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>

View File

@@ -1,7 +1,5 @@
#pragma once #pragma once
#include <GLFW/glfw3.h>
#include "../RHISampler.h" #include "../RHISampler.h"
#include "../RHITypes.h" #include "../RHITypes.h"

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include <string> #include <string>
#include <GLFW/glfw3.h>
#include <vector> #include <vector>
#include "../RHIShader.h" #include "../RHIShader.h"

View File

@@ -1,13 +1,18 @@
#pragma once #pragma once
#include <GLFW/glfw3.h>
#include <cstdint> #include <cstdint>
#include "../RHISwapChain.h" #include "../RHISwapChain.h"
struct HWND__;
struct HDC__;
namespace XCEngine { namespace XCEngine {
namespace RHI { namespace RHI {
using HWND = HWND__*;
using HDC = HDC__*;
enum class PresentMode { enum class PresentMode {
Immediate, Immediate,
VSync, VSync,
@@ -27,8 +32,8 @@ public:
OpenGLSwapChain(); OpenGLSwapChain();
~OpenGLSwapChain() override; ~OpenGLSwapChain() override;
bool Initialize(GLFWwindow* window, bool vsync = true); bool Initialize(HWND window, bool vsync = true);
bool Initialize(GLFWwindow* window, int width, int height, PresentMode mode = PresentMode::VSync); bool Initialize(HWND window, int width, int height, PresentMode mode = PresentMode::VSync);
void Shutdown() override; void Shutdown() override;
void Present(uint32_t syncInterval = 1, uint32_t flags = 0) override; void Present(uint32_t syncInterval = 1, uint32_t flags = 0) override;
@@ -45,7 +50,8 @@ public:
int GetFramebufferWidth() const { return m_framebufferWidth; } int GetFramebufferWidth() const { return m_framebufferWidth; }
int GetFramebufferHeight() const { return m_framebufferHeight; } int GetFramebufferHeight() const { return m_framebufferHeight; }
GLFWwindow* GetWindow() const { return m_window; } HWND GetWindow() const { return m_hwnd; }
HDC GetDC() const { return m_hdc; }
bool ShouldClose() const override; bool ShouldClose() const override;
void SetShouldClose(bool shouldClose) override; void SetShouldClose(bool shouldClose) override;
@@ -56,12 +62,14 @@ public:
void* GetNativeHandle() override; void* GetNativeHandle() override;
private: private:
GLFWwindow* m_window; HWND m_hwnd;
HDC m_hdc;
int m_width; int m_width;
int m_height; int m_height;
int m_framebufferWidth; int m_framebufferWidth;
int m_framebufferHeight; int m_framebufferHeight;
bool m_vsync; bool m_vsync;
bool m_shouldClose;
PresentMode m_presentMode; PresentMode m_presentMode;
}; };

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include <string> #include <string>
#include <GLFW/glfw3.h>
#include <vector> #include <vector>
#include "../RHITexture.h" #include "../RHITexture.h"

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include <string> #include <string>
#include <GLFW/glfw3.h>
#include <vector> #include <vector>
namespace XCEngine { namespace XCEngine {

View File

@@ -1,7 +1,5 @@
#define GLFW_INCLUDE_NONE
#include "XCEngine/RHI/OpenGL/OpenGLBuffer.h" #include "XCEngine/RHI/OpenGL/OpenGLBuffer.h"
#include <glad/glad.h> #include <glad/glad.h>
#include <GLFW/glfw3.h>
namespace XCEngine { namespace XCEngine {
namespace RHI { namespace RHI {

View File

@@ -1,7 +1,5 @@
#define GLFW_INCLUDE_NONE
#include "XCEngine/RHI/OpenGL/OpenGLCommandList.h" #include "XCEngine/RHI/OpenGL/OpenGLCommandList.h"
#include <glad/glad.h> #include <glad/glad.h>
#include <GLFW/glfw3.h>
namespace XCEngine { namespace XCEngine {
namespace RHI { namespace RHI {

View File

@@ -1,7 +1,5 @@
#define GLFW_INCLUDE_NONE
#include "XCEngine/RHI/OpenGL/OpenGLDepthStencilView.h" #include "XCEngine/RHI/OpenGL/OpenGLDepthStencilView.h"
#include <glad/glad.h> #include <glad/glad.h>
#include <GLFW/glfw3.h>
namespace XCEngine { namespace XCEngine {
namespace RHI { namespace RHI {

View File

@@ -1,4 +1,10 @@
#define GLFW_INCLUDE_NONE #define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <stdio.h>
#include <glad/glad.h>
#include <windows.h>
#include "XCEngine/RHI/OpenGL/OpenGLDevice.h" #include "XCEngine/RHI/OpenGL/OpenGLDevice.h"
#include "XCEngine/RHI/OpenGL/OpenGLBuffer.h" #include "XCEngine/RHI/OpenGL/OpenGLBuffer.h"
#include "XCEngine/RHI/OpenGL/OpenGLTexture.h" #include "XCEngine/RHI/OpenGL/OpenGLTexture.h"
@@ -9,16 +15,20 @@
#include "XCEngine/RHI/OpenGL/OpenGLCommandList.h" #include "XCEngine/RHI/OpenGL/OpenGLCommandList.h"
#include "XCEngine/RHI/OpenGL/OpenGLCommandQueue.h" #include "XCEngine/RHI/OpenGL/OpenGLCommandQueue.h"
#include "XCEngine/RHI/OpenGL/OpenGLSwapChain.h" #include "XCEngine/RHI/OpenGL/OpenGLSwapChain.h"
#include <glad/glad.h>
#include <GLFW/glfw3.h> static bool s_windowClassRegistered = false;
static const wchar_t kWindowClassName[] = L"XCEngine_OpenGL_WindowClass";
namespace XCEngine { namespace XCEngine {
namespace RHI { namespace RHI {
OpenGLDevice::OpenGLDevice() OpenGLDevice::OpenGLDevice()
: m_window(nullptr) : m_hwnd(nullptr)
, m_hdc(nullptr)
, m_hglrc(nullptr)
, m_initialized(false) , m_initialized(false)
, m_ownsWindow(false) { , m_ownsWindow(false)
, m_shouldClose(false) {
} }
OpenGLDevice::~OpenGLDevice() { OpenGLDevice::~OpenGLDevice() {
@@ -31,7 +41,7 @@ bool OpenGLDevice::Initialize(const RHIDeviceDesc& desc) {
} }
if (desc.windowHandle) { if (desc.windowHandle) {
return InitializeWithExistingWindow(static_cast<GLFWwindow*>(desc.windowHandle)); return InitializeWithExistingWindow(static_cast<HWND>(desc.windowHandle));
} }
std::string titleStr = "XCEngine"; std::string titleStr = "XCEngine";
@@ -47,42 +57,121 @@ bool OpenGLDevice::CreateRenderWindow(int width, int height, const char* title,
return true; return true;
} }
static bool glfwInitialized = false; if (!s_windowClassRegistered) {
if (!glfwInitialized) { WNDCLASSEXW wc = {};
glfwInit(); wc.cbSize = sizeof(WNDCLASSEXW);
glfwInitialized = true; wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DefWindowProcW;
wc.hInstance = GetModuleHandleW(nullptr);
wc.lpszClassName = kWindowClassName;
if (!RegisterClassExW(&wc)) {
return false;
}
s_windowClassRegistered = true;
} }
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); std::wstring titleW(title ? std::wstring(title, title + strlen(title)) : L"XCEngine");
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
m_window = glfwCreateWindow(width, height, title, nullptr, nullptr); HWND hwnd = CreateWindowExW(
if (!m_window) { 0,
kWindowClassName,
titleW.c_str(),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
width, height,
nullptr,
nullptr,
GetModuleHandleW(nullptr),
nullptr
);
if (!hwnd) {
return false; return false;
} }
glfwSetWindowShouldClose(m_window, GLFW_FALSE); m_hwnd = hwnd;
m_ownsWindow = true; m_ownsWindow = true;
return InitializeWithExistingWindow(m_window);
ShowWindow(m_hwnd, SW_SHOWNORMAL);
UpdateWindow(m_hwnd);
return InitializeWithExistingWindow(m_hwnd);
} }
bool OpenGLDevice::InitializeWithExistingWindow(GLFWwindow* window) { bool OpenGLDevice::InitializeWithExistingWindow(HWND hwnd) {
if (m_initialized) { if (m_initialized) {
return true; return true;
} }
m_window = window; if (!hwnd) {
if (!m_window) { fprintf(stderr, "[OpenGLDevice] ERROR: hwnd is null\n");
return false; return false;
} }
glfwMakeContextCurrent(m_window); m_hwnd = hwnd;
m_hdc = ::GetDC(m_hwnd);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { if (!m_hdc) {
fprintf(stderr, "[OpenGLDevice] ERROR: GetDC failed\n");
return false; return false;
} }
fprintf(stderr, "[OpenGLDevice] GetDC succeeded\n");
PIXELFORMATDESCRIPTOR pfd = {};
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;
int pixelFormat = ChoosePixelFormat(m_hdc, &pfd);
if (!pixelFormat) {
fprintf(stderr, "[OpenGLDevice] ERROR: ChoosePixelFormat failed\n");
ReleaseDC(m_hwnd, m_hdc);
m_hdc = nullptr;
return false;
}
fprintf(stderr, "[OpenGLDevice] ChoosePixelFormat succeeded\n");
if (!SetPixelFormat(m_hdc, pixelFormat, &pfd)) {
fprintf(stderr, "[OpenGLDevice] ERROR: SetPixelFormat failed\n");
ReleaseDC(m_hwnd, m_hdc);
m_hdc = nullptr;
return false;
}
fprintf(stderr, "[OpenGLDevice] SetPixelFormat succeeded\n");
m_hglrc = wglCreateContext(m_hdc);
if (!m_hglrc) {
fprintf(stderr, "[OpenGLDevice] ERROR: wglCreateContext failed\n");
ReleaseDC(m_hwnd, m_hdc);
m_hdc = nullptr;
return false;
}
fprintf(stderr, "[OpenGLDevice] wglCreateContext succeeded\n");
if (!wglMakeCurrent(m_hdc, m_hglrc)) {
fprintf(stderr, "[OpenGLDevice] ERROR: wglMakeCurrent failed\n");
wglDeleteContext(m_hglrc);
ReleaseDC(m_hwnd, m_hdc);
m_hglrc = nullptr;
m_hdc = nullptr;
return false;
}
fprintf(stderr, "[OpenGLDevice] wglMakeCurrent succeeded\n");
if (!gladLoadGL()) {
fprintf(stderr, "[OpenGLDevice] ERROR: gladLoadGL failed\n");
wglMakeCurrent(nullptr, nullptr);
wglDeleteContext(m_hglrc);
ReleaseDC(m_hwnd, m_hdc);
m_hglrc = nullptr;
m_hdc = nullptr;
return false;
}
fprintf(stderr, "[OpenGLDevice] gladLoadGL succeeded\n");
const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR)); const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
const char* renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER)); const char* renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
@@ -135,33 +224,55 @@ bool OpenGLDevice::InitializeWithExistingWindow(GLFWwindow* window) {
} }
void OpenGLDevice::Shutdown() { void OpenGLDevice::Shutdown() {
if (m_ownsWindow && m_window) { if (m_hglrc) {
glfwDestroyWindow(m_window); wglMakeCurrent(nullptr, nullptr);
wglDeleteContext(m_hglrc);
m_hglrc = nullptr;
} }
m_window = nullptr;
if (m_hdc && m_hwnd) {
ReleaseDC(m_hwnd, m_hdc);
m_hdc = nullptr;
}
if (m_ownsWindow && m_hwnd) {
DestroyWindow(m_hwnd);
m_hwnd = nullptr;
}
m_initialized = false; m_initialized = false;
m_ownsWindow = false; m_ownsWindow = false;
m_shouldClose = false;
} }
void OpenGLDevice::SwapBuffers() { void OpenGLDevice::SwapBuffers() {
if (m_window) { if (m_hdc) {
glfwSwapBuffers(m_window); ::SwapBuffers(m_hdc);
} }
} }
bool OpenGLDevice::PollEvents() { bool OpenGLDevice::PollEvents() {
glfwPollEvents(); MSG msg;
return !glfwWindowShouldClose(m_window); 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) { void OpenGLDevice::SetShouldClose(bool shouldClose) {
if (m_window) { m_shouldClose = shouldClose;
glfwSetWindowShouldClose(m_window, shouldClose ? GLFW_TRUE : GLFW_FALSE); if (m_hwnd && shouldClose) {
PostMessageW(m_hwnd, WM_CLOSE, 0, 0);
} }
} }
bool OpenGLDevice::ShouldClose() const { bool OpenGLDevice::ShouldClose() const {
return m_window && glfwWindowShouldClose(m_window) == GLFW_TRUE; return m_shouldClose;
} }
RHIBuffer* OpenGLDevice::CreateBuffer(const BufferDesc& desc) { RHIBuffer* OpenGLDevice::CreateBuffer(const BufferDesc& desc) {
@@ -169,10 +280,10 @@ RHIBuffer* OpenGLDevice::CreateBuffer(const BufferDesc& desc) {
OpenGLBufferType bufferType = OpenGLBufferType::Vertex; OpenGLBufferType bufferType = OpenGLBufferType::Vertex;
switch (desc.bufferType) { switch (desc.bufferType) {
case 1: // Index buffer case 1:
bufferType = OpenGLBufferType::Index; bufferType = OpenGLBufferType::Index;
break; break;
case 2: // Constant buffer case 2:
bufferType = OpenGLBufferType::Uniform; bufferType = OpenGLBufferType::Uniform;
break; break;
default: default:
@@ -210,8 +321,8 @@ 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_window) { if (m_hwnd) {
swapChain->Initialize(m_window, desc.width, desc.height); swapChain->Initialize(m_hwnd, desc.width, desc.height);
} }
return swapChain; return swapChain;
} }

View File

@@ -1,7 +1,5 @@
#define GLFW_INCLUDE_NONE
#include "XCEngine/RHI/OpenGL/OpenGLFence.h" #include "XCEngine/RHI/OpenGL/OpenGLFence.h"
#include <glad/glad.h> #include <glad/glad.h>
#include <GLFW/glfw3.h>
namespace XCEngine { namespace XCEngine {
namespace RHI { namespace RHI {

View File

@@ -1,7 +1,5 @@
#define GLFW_INCLUDE_NONE
#include "XCEngine/RHI/OpenGL/OpenGLRenderTargetView.h" #include "XCEngine/RHI/OpenGL/OpenGLRenderTargetView.h"
#include <glad/glad.h> #include <glad/glad.h>
#include <GLFW/glfw3.h>
namespace XCEngine { namespace XCEngine {
namespace RHI { namespace RHI {

View File

@@ -1,7 +1,5 @@
#define GLFW_INCLUDE_NONE
#include "XCEngine/RHI/OpenGL/OpenGLSampler.h" #include "XCEngine/RHI/OpenGL/OpenGLSampler.h"
#include <glad/glad.h> #include <glad/glad.h>
#include <GLFW/glfw3.h>
namespace XCEngine { namespace XCEngine {
namespace RHI { namespace RHI {

View File

@@ -1,7 +1,5 @@
#define GLFW_INCLUDE_NONE
#include "XCEngine/RHI/OpenGL/OpenGLShader.h" #include "XCEngine/RHI/OpenGL/OpenGLShader.h"
#include <glad/glad.h> #include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <iostream> #include <iostream>

View File

@@ -1,28 +1,26 @@
#define GLFW_INCLUDE_NONE #define WIN32_LEAN_AND_MEAN
#include "XCEngine/RHI/OpenGL/OpenGLSwapChain.h" #define NOMINMAX
#include <GLFW/glfw3.h>
#include <glad/glad.h> #include <glad/glad.h>
#include <windows.h>
#include "XCEngine/RHI/OpenGL/OpenGLSwapChain.h"
typedef void (APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int);
static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = nullptr;
namespace XCEngine { namespace XCEngine {
namespace RHI { namespace RHI {
static int ToGLFWPresentMode(PresentMode mode) {
switch (mode) {
case PresentMode::Immediate: return 0;
case PresentMode::VSync: return 1;
case PresentMode::Mailbox: return -1;
case PresentMode::Fifo: return 1;
default: return 1;
}
}
OpenGLSwapChain::OpenGLSwapChain() OpenGLSwapChain::OpenGLSwapChain()
: m_window(nullptr) : m_hwnd(nullptr)
, m_hdc(nullptr)
, m_width(0) , m_width(0)
, m_height(0) , m_height(0)
, m_framebufferWidth(0) , m_framebufferWidth(0)
, m_framebufferHeight(0) , m_framebufferHeight(0)
, m_vsync(true) , m_vsync(true)
, m_shouldClose(false)
, m_presentMode(PresentMode::VSync) { , m_presentMode(PresentMode::VSync) {
} }
@@ -30,57 +28,73 @@ OpenGLSwapChain::~OpenGLSwapChain() {
Shutdown(); Shutdown();
} }
bool OpenGLSwapChain::Initialize(GLFWwindow* window, bool vsync) { bool OpenGLSwapChain::Initialize(HWND window, bool vsync) {
m_window = window; m_hwnd = window;
m_hdc = ::GetDC(m_hwnd);
m_vsync = vsync; m_vsync = vsync;
m_presentMode = vsync ? PresentMode::VSync : PresentMode::Immediate; m_presentMode = vsync ? PresentMode::VSync : PresentMode::Immediate;
m_shouldClose = false;
int w, h; if (!wglSwapIntervalEXT) {
glfwGetFramebufferSize(window, &w, &h); wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
m_framebufferWidth = w; }
m_framebufferHeight = h; if (wglSwapIntervalEXT) {
wglSwapIntervalEXT(vsync ? 1 : 0);
}
glfwGetWindowSize(window, &w, &h); RECT rect;
m_width = w; ::GetClientRect(m_hwnd, &rect);
m_height = h; m_width = rect.right - rect.left;
m_height = rect.bottom - rect.top;
glfwSwapInterval(m_vsync ? 1 : 0); m_framebufferWidth = m_width;
m_framebufferHeight = m_height;
return true; return true;
} }
bool OpenGLSwapChain::Initialize(GLFWwindow* window, int width, int height, PresentMode mode) { bool OpenGLSwapChain::Initialize(HWND window, int width, int height, PresentMode mode) {
m_window = window; m_hwnd = window;
m_hdc = ::GetDC(m_hwnd);
m_width = width; m_width = width;
m_height = height; m_height = height;
m_presentMode = mode; m_presentMode = mode;
m_vsync = (mode == PresentMode::VSync || mode == PresentMode::Fifo); m_vsync = (mode == PresentMode::VSync || mode == PresentMode::Fifo);
m_shouldClose = false;
glfwSetWindowSize(window, width, height); if (!wglSwapIntervalEXT) {
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
}
if (wglSwapIntervalEXT) {
wglSwapIntervalEXT(m_vsync ? 1 : 0);
}
int w, h; ::SetWindowPos(m_hwnd, nullptr, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER);
glfwGetFramebufferSize(window, &w, &h);
m_framebufferWidth = w;
m_framebufferHeight = h;
glfwSwapInterval(m_vsync ? 1 : 0); m_framebufferWidth = width;
m_framebufferHeight = height;
return true; return true;
} }
void OpenGLSwapChain::Shutdown() { void OpenGLSwapChain::Shutdown() {
m_window = nullptr; if (m_hdc && m_hwnd) {
::ReleaseDC(m_hwnd, m_hdc);
m_hdc = nullptr;
}
m_hwnd = nullptr;
} }
void OpenGLSwapChain::SwapBuffers() { void OpenGLSwapChain::SwapBuffers() {
if (m_window) { if (m_hdc) {
glfwSwapBuffers(m_window); ::SwapBuffers(m_hdc);
} }
} }
void OpenGLSwapChain::SetVSync(bool enabled) { void OpenGLSwapChain::SetVSync(bool enabled) {
m_vsync = enabled; m_vsync = enabled;
glfwSwapInterval(enabled ? 1 : 0); if (wglSwapIntervalEXT) {
wglSwapIntervalEXT(enabled ? 1 : 0);
}
} }
void OpenGLSwapChain::SetFramebufferSize(int width, int height) { void OpenGLSwapChain::SetFramebufferSize(int width, int height) {
@@ -89,33 +103,42 @@ void OpenGLSwapChain::SetFramebufferSize(int width, int height) {
} }
bool OpenGLSwapChain::ShouldClose() const { bool OpenGLSwapChain::ShouldClose() const {
return m_window && glfwWindowShouldClose(m_window); return m_shouldClose;
} }
void OpenGLSwapChain::SetShouldClose(bool shouldClose) { void OpenGLSwapChain::SetShouldClose(bool shouldClose) {
if (m_window) { m_shouldClose = shouldClose;
glfwSetWindowShouldClose(m_window, shouldClose ? GLFW_TRUE : GLFW_FALSE); if (m_hwnd && shouldClose) {
PostMessageW(m_hwnd, WM_CLOSE, 0, 0);
} }
} }
void OpenGLSwapChain::PollEvents() { void OpenGLSwapChain::PollEvents() {
glfwPollEvents(); 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_window) { if (m_hdc) {
glfwSwapBuffers(m_window); ::SwapBuffers(m_hdc);
} }
} }
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;
glfwSetWindowSize(m_window, width, height); if (m_hwnd) {
int w, h; ::SetWindowPos(m_hwnd, nullptr, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER);
glfwGetFramebufferSize(m_window, &w, &h); }
m_framebufferWidth = w; m_framebufferWidth = width;
m_framebufferHeight = h; m_framebufferHeight = height;
} }
void OpenGLSwapChain::SetFullscreen(bool fullscreen) { void OpenGLSwapChain::SetFullscreen(bool fullscreen) {

View File

@@ -1,7 +1,5 @@
#define GLFW_INCLUDE_NONE
#include "XCEngine/RHI/OpenGL/OpenGLTexture.h" #include "XCEngine/RHI/OpenGL/OpenGLTexture.h"
#include <glad/glad.h> #include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stb_image.h> #include <stb_image.h>
#include <iostream> #include <iostream>

View File

@@ -1,7 +1,5 @@
#define GLFW_INCLUDE_NONE
#include "XCEngine/RHI/OpenGL/OpenGLVertexArray.h" #include "XCEngine/RHI/OpenGL/OpenGLVertexArray.h"
#include <glad/glad.h> #include <glad/glad.h>
#include <GLFW/glfw3.h>
namespace XCEngine { namespace XCEngine {
namespace RHI { namespace RHI {

View File

@@ -24,7 +24,6 @@ target_include_directories(OpenGL_Minimal PRIVATE
target_link_libraries(OpenGL_Minimal PRIVATE target_link_libraries(OpenGL_Minimal PRIVATE
opengl32 opengl32
${PACKAGE_DIR}/lib/glfw3.lib
XCEngine XCEngine
) )

View File

@@ -1,23 +1,23 @@
#include <windows.h>
#include <glad/glad.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <glad/glad.h>
#include <windows.h>
#include "XCEngine/RHI/OpenGL/OpenGLDevice.h"
#include "XCEngine/RHI/OpenGL/OpenGLSwapChain.h"
#include "XCEngine/Debug/Logger.h" #include "XCEngine/Debug/Logger.h"
#include "XCEngine/Debug/ConsoleLogSink.h" #include "XCEngine/Debug/ConsoleLogSink.h"
#include "XCEngine/Containers/String.h" #include "XCEngine/Containers/String.h"
#pragma comment(lib, "opengl32.lib") #pragma comment(lib, "opengl32.lib")
using namespace XCEngine::RHI;
using namespace XCEngine::Debug; using namespace XCEngine::Debug;
using namespace XCEngine::Containers; using namespace XCEngine::Containers;
static const int gWidth = 1280; static const int gWidth = 1280;
static const int gHeight = 720; static const int gHeight = 720;
static HWND gHWND = nullptr;
static HDC gHDC = nullptr;
static HGLRC gHGLRC = nullptr;
void Log(const char* format, ...) { void Log(const char* format, ...) {
char buffer[1024]; char buffer[1024];
@@ -28,6 +28,38 @@ void Log(const char* format, ...) {
Logger::Get().Debug(LogCategory::Rendering, String(buffer)); Logger::Get().Debug(LogCategory::Rendering, String(buffer));
} }
void SaveScreenshotPPM(const char* filename, int width, int height) {
unsigned char* pixels = (unsigned char*)malloc(width * height * 3);
if (!pixels) {
Log("[ERROR] Failed to allocate pixel buffer");
return;
}
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
FILE* f = fopen(filename, "wb");
if (!f) {
Log("[ERROR] Failed to open file for screenshot: %s", filename);
free(pixels);
return;
}
fprintf(f, "P6\n%d %d\n255\n", width, height);
unsigned char* row = (unsigned char*)malloc(width * 3);
for (int y = height - 1; y >= 0; y--) {
memcpy(row, pixels + y * width * 3, width * 3);
fwrite(row, 1, width * 3, f);
}
free(row);
free(pixels);
fclose(f);
Log("[INFO] Screenshot saved to %s", filename);
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) { switch (msg) {
case WM_CLOSE: case WM_CLOSE:
@@ -37,109 +69,6 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
return DefWindowProc(hwnd, msg, wParam, lParam); return DefWindowProc(hwnd, msg, wParam, lParam);
} }
bool InitOpenGL() {
gHDC = GetDC(gHWND);
if (!gHDC) {
Log("[ERROR] Failed to get DC");
return false;
}
PIXELFORMATDESCRIPTOR pfd = {};
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;
int pixelFormat = ChoosePixelFormat(gHDC, &pfd);
if (!pixelFormat) {
Log("[ERROR] Failed to choose pixel format");
return false;
}
if (!SetPixelFormat(gHDC, pixelFormat, &pfd)) {
Log("[ERROR] Failed to set pixel format");
return false;
}
gHGLRC = wglCreateContext(gHDC);
if (!gHGLRC) {
Log("[ERROR] Failed to create GL context");
return false;
}
if (!wglMakeCurrent(gHDC, gHGLRC)) {
Log("[ERROR] Failed to make GL context current");
return false;
}
if (!gladLoadGL()) {
Log("[ERROR] Failed to load OpenGL functions");
return false;
}
Log("[INFO] OpenGL initialized: %s", glGetString(GL_RENDERER));
Log("[INFO] OpenGL Version: %s", glGetString(GL_VERSION));
glViewport(0, 0, gWidth, gHeight);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
return true;
}
void ShutdownOpenGL() {
if (gHGLRC) {
wglDeleteContext(gHGLRC);
gHGLRC = nullptr;
}
if (gHDC) {
ReleaseDC(gHWND, gHDC);
gHDC = nullptr;
}
}
void SaveScreenshotPPM(const char* filename) {
unsigned char* pixels = (unsigned char*)malloc(gWidth * gHeight * 3);
if (!pixels) {
Log("[ERROR] Failed to allocate pixel buffer");
return;
}
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, gWidth, gHeight, GL_RGB, GL_UNSIGNED_BYTE, pixels);
FILE* f = fopen(filename, "wb");
if (!f) {
Log("[ERROR] Failed to open file for screenshot: %s", filename);
free(pixels);
return;
}
fprintf(f, "P6\n%d %d\n255\n", gWidth, gHeight);
unsigned char* row = (unsigned char*)malloc(gWidth * 3);
for (int y = gHeight - 1; y >= 0; y--) {
memcpy(row, pixels + y * gWidth * 3, gWidth * 3);
fwrite(row, 1, gWidth * 3, f);
}
free(row);
free(pixels);
fclose(f);
Log("[INFO] Screenshot saved to %s", filename);
}
void RenderFrame() {
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
SwapBuffers(gHDC);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
Logger::Get().Initialize(); Logger::Get().Initialize();
Logger::Get().AddSink(std::make_unique<ConsoleLogSink>()); Logger::Get().AddSink(std::make_unique<ConsoleLogSink>());
@@ -147,63 +76,86 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
Log("[INFO] OpenGL Integration Test Starting"); Log("[INFO] OpenGL Integration Test Starting");
WNDCLASSEX wc = {}; WNDCLASSEXW wc = {};
wc.cbSize = sizeof(WNDCLASSEX); wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = CS_HREDRAW | CS_VREDRAW; wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc; wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance; wc.hInstance = hInstance;
wc.lpszClassName = L"OpenGLTest"; wc.lpszClassName = L"XCEngine_OpenGL_Test";
if (!RegisterClassEx(&wc)) { if (!RegisterClassExW(&wc)) {
MessageBox(NULL, L"Failed to register window class", L"Error", MB_OK); Log("[ERROR] Failed to register window class");
return -1; return -1;
} }
RECT rect = { 0, 0, gWidth, gHeight }; RECT rect = { 0, 0, gWidth, gHeight };
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
gHWND = CreateWindowEx(0, L"OpenGLTest", L"OpenGL Integration Test", HWND hwnd = CreateWindowExW(
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 0,
L"XCEngine_OpenGL_Test",
L"OpenGL Integration Test",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
rect.right - rect.left, rect.bottom - rect.top, rect.right - rect.left, rect.bottom - rect.top,
NULL, NULL, hInstance, NULL); NULL, NULL, hInstance, NULL
);
if (!gHWND) { RECT clientRect;
MessageBox(NULL, L"Failed to create window", L"Error", MB_OK); GetClientRect(hwnd, &clientRect);
fprintf(stderr, "[minimal] Window client area: %ldx%ld\n", clientRect.right, clientRect.bottom);
if (!hwnd) {
Log("[ERROR] Failed to create window");
return -1; return -1;
} }
if (!InitOpenGL()) { OpenGLDevice device;
MessageBox(NULL, L"Failed to initialize OpenGL", L"Error", MB_OK); fprintf(stderr, "[minimal] About to call InitializeWithExistingWindow\n");
if (!device.InitializeWithExistingWindow(hwnd)) {
fprintf(stderr, "[minimal] InitializeWithExistingWindow returned false\n");
Log("[ERROR] Failed to initialize OpenGL device");
return -1; return -1;
} }
fprintf(stderr, "[minimal] InitializeWithExistingWindow succeeded\n");
ShowWindow(gHWND, nShowCmd); ShowWindow(hwnd, nShowCmd);
UpdateWindow(gHWND); UpdateWindow(hwnd);
Log("[INFO] OpenGL Device: %S", device.GetDeviceInfo().renderer.c_str());
Log("[INFO] OpenGL Version: %S", device.GetDeviceInfo().version.c_str());
OpenGLSwapChain swapChain;
swapChain.Initialize(hwnd, gWidth, gHeight);
MSG msg = {}; MSG msg = {};
int frameCount = 0; int frameCount = 0;
const int targetFrameCount = 30; const int targetFrameCount = 30;
while (true) { while (true) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) { if (msg.message == WM_QUIT) {
break; break;
} }
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessageW(&msg);
} else { } else {
RenderFrame(); glViewport(0, 0, gWidth, gHeight);
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
swapChain.Present(0, 0);
frameCount++; frameCount++;
if (frameCount >= targetFrameCount) { if (frameCount >= targetFrameCount) {
Log("[INFO] Reached target frame count %d - taking screenshot!", targetFrameCount); Log("[INFO] Reached target frame count %d - taking screenshot!", targetFrameCount);
SaveScreenshotPPM("minimal.ppm"); SaveScreenshotPPM("minimal.ppm", gWidth, gHeight);
break; break;
} }
} }
} }
ShutdownOpenGL(); swapChain.Shutdown();
device.Shutdown();
Logger::Get().Shutdown(); Logger::Get().Shutdown();
Log("[INFO] OpenGL Integration Test Finished"); Log("[INFO] OpenGL Integration Test Finished");

View File

@@ -8,8 +8,6 @@ include_directories(${CMAKE_SOURCE_DIR}/tests/OpenGL/package/include/)
include_directories(${PROJECT_ROOT_DIR}/engine/include) include_directories(${PROJECT_ROOT_DIR}/engine/include)
include_directories(${PROJECT_ROOT_DIR}/engine/src) include_directories(${PROJECT_ROOT_DIR}/engine/src)
link_directories(${CMAKE_SOURCE_DIR}/tests/OpenGL/package/lib/)
find_package(GTest REQUIRED) find_package(GTest REQUIRED)
set(TEST_SOURCES set(TEST_SOURCES
@@ -33,7 +31,6 @@ add_executable(opengl_engine_tests ${TEST_SOURCES})
target_link_libraries(opengl_engine_tests PRIVATE target_link_libraries(opengl_engine_tests PRIVATE
opengl32 opengl32
glfw3
XCEngine XCEngine
GTest::gtest GTest::gtest
GTest::gtest_main GTest::gtest_main

View File

@@ -1,45 +1,107 @@
#include <glad/glad.h>
#include "OpenGLTestFixture.h" #include "OpenGLTestFixture.h"
using namespace XCEngine::RHI; using namespace XCEngine::RHI;
static bool s_glfwInitialized = false; static bool s_windowClassRegistered = false;
static bool s_gladInitialized = false; static const wchar_t kWindowClassName[] = L"XCEngine_Test_WindowClass";
void OpenGLTestFixture::SetUp() { void OpenGLTestFixture::SetUp() {
if (!s_glfwInitialized) { if (!s_windowClassRegistered) {
if (!glfwInit()) { WNDCLASSEXW wc = {};
GTEST_SKIP() << "Failed to initialize GLFW"; wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DefWindowProcW;
wc.hInstance = GetModuleHandleW(nullptr);
wc.lpszClassName = kWindowClassName;
if (!RegisterClassExW(&wc)) {
GTEST_SKIP() << "Failed to register window class";
return; return;
} }
s_windowClassRegistered = true;
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
s_glfwInitialized = true;
} }
m_window = glfwCreateWindow(640, 480, "OpenGL Tests", nullptr, nullptr); m_hwnd = CreateWindowExW(
if (!m_window) { 0,
GTEST_SKIP() << "Failed to create GLFW window"; kWindowClassName,
L"OpenGL Tests",
WS_POPUP,
0, 0,
640, 480,
nullptr,
nullptr,
GetModuleHandleW(nullptr),
nullptr
);
if (!m_hwnd) {
GTEST_SKIP() << "Failed to create window";
return; return;
} }
glfwMakeContextCurrent(m_window); ShowWindow(m_hwnd, SW_HIDE);
m_hdc = GetDC(m_hwnd);
if (!s_gladInitialized) { PIXELFORMATDESCRIPTOR pfd = {};
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
GTEST_SKIP() << "Failed to initialize GLAD"; pfd.nVersion = 1;
glfwDestroyWindow(m_window); pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
m_window = nullptr; pfd.iPixelType = PFD_TYPE_RGBA;
return; pfd.cColorBits = 32;
} pfd.cDepthBits = 24;
s_gladInitialized = true; pfd.cStencilBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;
int pixelFormat = ChoosePixelFormat(m_hdc, &pfd);
if (!pixelFormat) {
ReleaseDC(m_hwnd, m_hdc);
DestroyWindow(m_hwnd);
m_hwnd = nullptr;
GTEST_SKIP() << "Failed to choose pixel format";
return;
}
if (!SetPixelFormat(m_hdc, pixelFormat, &pfd)) {
ReleaseDC(m_hwnd, m_hdc);
DestroyWindow(m_hwnd);
m_hwnd = nullptr;
GTEST_SKIP() << "Failed to set pixel format";
return;
}
m_hglrc = wglCreateContext(m_hdc);
if (!m_hglrc) {
ReleaseDC(m_hwnd, m_hdc);
DestroyWindow(m_hwnd);
m_hwnd = nullptr;
GTEST_SKIP() << "Failed to create GL context";
return;
}
if (!wglMakeCurrent(m_hdc, m_hglrc)) {
wglDeleteContext(m_hglrc);
ReleaseDC(m_hwnd, m_hdc);
DestroyWindow(m_hwnd);
m_hglrc = nullptr;
m_hwnd = nullptr;
GTEST_SKIP() << "Failed to make GL context current";
return;
}
if (!gladLoadGLLoader((GLADloadproc)wglGetProcAddress)) {
wglMakeCurrent(nullptr, nullptr);
wglDeleteContext(m_hglrc);
ReleaseDC(m_hwnd, m_hdc);
DestroyWindow(m_hwnd);
m_hglrc = nullptr;
m_hwnd = nullptr;
GTEST_SKIP() << "Failed to load OpenGL functions";
return;
} }
m_device = new OpenGLDevice(); m_device = new OpenGLDevice();
m_device->CreateRenderWindow(640, 480, "Test Window", false); m_device->InitializeWithExistingWindow(m_hwnd);
m_ownsWindow = true;
ClearGLErrors(); ClearGLErrors();
} }
@@ -52,20 +114,31 @@ void OpenGLTestFixture::TearDown() {
m_device = nullptr; m_device = nullptr;
} }
if (m_window) { if (m_hglrc) {
glfwDestroyWindow(m_window); wglMakeCurrent(nullptr, nullptr);
m_window = nullptr; wglDeleteContext(m_hglrc);
m_hglrc = nullptr;
}
if (m_hdc && m_hwnd) {
ReleaseDC(m_hwnd, m_hdc);
m_hdc = nullptr;
}
if (m_ownsWindow && m_hwnd) {
DestroyWindow(m_hwnd);
m_hwnd = nullptr;
} }
} }
void OpenGLTestFixture::MakeContextCurrent() { void OpenGLTestFixture::MakeContextCurrent() {
if (m_window) { if (m_hdc && m_hglrc) {
glfwMakeContextCurrent(m_window); wglMakeCurrent(m_hdc, m_hglrc);
} }
} }
void OpenGLTestFixture::DoneContextCurrent() { void OpenGLTestFixture::DoneContextCurrent() {
glfwMakeContextCurrent(nullptr); wglMakeCurrent(nullptr, nullptr);
} }
void OpenGLTestFixture::ClearGLErrors() { void OpenGLTestFixture::ClearGLErrors() {

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include <windows.h>
#include <glad/glad.h> #include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "XCEngine/RHI/OpenGL/OpenGLDevice.h" #include "XCEngine/RHI/OpenGL/OpenGLDevice.h"
@@ -14,7 +14,9 @@ protected:
void SetUp() override; void SetUp() override;
void TearDown() override; void TearDown() override;
GLFWwindow* GetWindow() { return m_window; } HWND GetWindow() { return m_hwnd; }
HDC GetDC() { return m_hdc; }
HGLRC GetContext() { return m_hglrc; }
void MakeContextCurrent(); void MakeContextCurrent();
void DoneContextCurrent(); void DoneContextCurrent();
@@ -24,8 +26,11 @@ protected:
void ResetGLState(); void ResetGLState();
private: private:
GLFWwindow* m_window = nullptr; HWND m_hwnd = nullptr;
HDC m_hdc = nullptr;
HGLRC m_hglrc = nullptr;
OpenGLDevice* m_device = nullptr; OpenGLDevice* m_device = nullptr;
bool m_ownsWindow = false;
}; };
} // namespace RHI } // namespace RHI

View File

@@ -23,7 +23,7 @@ TEST_F(OpenGLTestFixture, Device_CreateRenderWindow_DebugMode) {
TEST_F(OpenGLTestFixture, Device_InitializeWithExistingWindow) { TEST_F(OpenGLTestFixture, Device_InitializeWithExistingWindow) {
OpenGLDevice device; OpenGLDevice device;
GLFWwindow* existingWindow = GetWindow(); HWND existingWindow = GetWindow();
bool result = device.InitializeWithExistingWindow(existingWindow); bool result = device.InitializeWithExistingWindow(existingWindow);