- Simplify OpenGL integration test structure - Enable CTest registration for OpenGL tests - Refactor test fixtures and device enumeration - Minor code cleanup and improvements
197 lines
5.0 KiB
C++
197 lines
5.0 KiB
C++
#include <glad/glad.h>
|
|
#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);
|
|
} |