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,23 +1,23 @@
#include <windows.h>
#include <glad/glad.h>
#include <stdio.h>
#include <stdlib.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/ConsoleLogSink.h"
#include "XCEngine/Containers/String.h"
#pragma comment(lib, "opengl32.lib")
using namespace XCEngine::RHI;
using namespace XCEngine::Debug;
using namespace XCEngine::Containers;
static const int gWidth = 1280;
static const int gHeight = 720;
static HWND gHWND = nullptr;
static HDC gHDC = nullptr;
static HGLRC gHGLRC = nullptr;
void Log(const char* format, ...) {
char buffer[1024];
@@ -28,6 +28,38 @@ void Log(const char* format, ...) {
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) {
switch (msg) {
case WM_CLOSE:
@@ -37,109 +69,6 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM 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) {
Logger::Get().Initialize();
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");
WNDCLASSEX wc = {};
wc.cbSize = sizeof(WNDCLASSEX);
WNDCLASSEXW wc = {};
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = L"OpenGLTest";
wc.lpszClassName = L"XCEngine_OpenGL_Test";
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, L"Failed to register window class", L"Error", MB_OK);
if (!RegisterClassExW(&wc)) {
Log("[ERROR] Failed to register window class");
return -1;
}
RECT rect = { 0, 0, gWidth, gHeight };
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
gHWND = CreateWindowEx(0, L"OpenGLTest", L"OpenGL Integration Test",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
HWND hwnd = CreateWindowExW(
0,
L"XCEngine_OpenGL_Test",
L"OpenGL Integration Test",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
rect.right - rect.left, rect.bottom - rect.top,
NULL, NULL, hInstance, NULL);
NULL, NULL, hInstance, NULL
);
if (!gHWND) {
MessageBox(NULL, L"Failed to create window", L"Error", MB_OK);
RECT clientRect;
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;
}
if (!InitOpenGL()) {
MessageBox(NULL, L"Failed to initialize OpenGL", L"Error", MB_OK);
OpenGLDevice device;
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;
}
fprintf(stderr, "[minimal] InitializeWithExistingWindow succeeded\n");
ShowWindow(gHWND, nShowCmd);
UpdateWindow(gHWND);
ShowWindow(hwnd, nShowCmd);
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 = {};
int frameCount = 0;
const int targetFrameCount = 30;
while (true) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
DispatchMessageW(&msg);
} 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++;
if (frameCount >= targetFrameCount) {
Log("[INFO] Reached target frame count %d - taking screenshot!", targetFrameCount);
SaveScreenshotPPM("minimal.ppm");
SaveScreenshotPPM("minimal.ppm", gWidth, gHeight);
break;
}
}
}
ShutdownOpenGL();
swapChain.Shutdown();
device.Shutdown();
Logger::Get().Shutdown();
Log("[INFO] OpenGL Integration Test Finished");