#include #include "OpenGLTestFixture.h" using namespace XCEngine::RHI; static bool s_windowClassRegistered = false; static const wchar_t kWindowClassName[] = L"XCEngine_Test_WindowClass"; void OpenGLTestFixture::SetUp() { 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)) { GTEST_SKIP() << "Failed to register window class"; return; } s_windowClassRegistered = true; } m_hwnd = CreateWindowExW( 0, 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; } ShowWindow(m_hwnd, SW_HIDE); m_hdc = GetDC(m_hwnd); 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) { 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->InitializeWithExistingWindow(m_hwnd); m_ownsWindow = true; ClearGLErrors(); } void OpenGLTestFixture::TearDown() { ResetGLState(); if (m_device) { delete m_device; m_device = nullptr; } if (m_hglrc) { wglMakeCurrent(nullptr, 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() { if (m_hdc && m_hglrc) { wglMakeCurrent(m_hdc, m_hglrc); } } void OpenGLTestFixture::DoneContextCurrent() { wglMakeCurrent(nullptr, nullptr); } void OpenGLTestFixture::ClearGLErrors() { while (glGetError() != GL_NO_ERROR); } bool OpenGLTestFixture::CheckGLError(const char* file, int line) { GLenum error = glGetError(); if (error != GL_NO_ERROR) { ADD_FAILURE() << "OpenGL Error: " << error << " (" << GetGLErrorString(error) << ")" << " at " << file << ":" << line; return false; } return true; } const char* OpenGLTestFixture::GetGLErrorString(GLenum error) { switch (error) { case GL_NO_ERROR: return "GL_NO_ERROR"; case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; case GL_INVALID_VALUE: return "GL_INVALID_VALUE"; case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION"; case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; default: return "Unknown error"; } } void OpenGLTestFixture::ResetGLState() { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_UNIFORM_BUFFER, 0); glUseProgram(0); glBindVertexArray(0); glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindRenderbuffer(GL_RENDERBUFFER, 0); glActiveTexture(GL_TEXTURE0); for (int i = 0; i < 16; ++i) { glBindTexture(GL_TEXTURE_2D, 0); } glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); glDisable(GL_BLEND); glDisable(GL_CULL_FACE); glDisable(GL_SCISSOR_TEST); glDepthFunc(GL_LESS); glStencilFunc(GL_ALWAYS, 0, 0xFF); glBlendFunc(GL_ONE, GL_ZERO); }