Add OpenGL test infrastructure - Phase 1: Device, Buffer, Fence tests (17 tests)
- Create test directory structure at tests/RHI/OpenGL/ - Implement OpenGLTestFixture with GLFW/GLAD initialization - Add Device tests: CreateRenderWindow, InitializeWithExistingWindow, GetDeviceInfo, SwapBuffers, PollEvents - Add Buffer tests: VertexBuffer, IndexBuffer, UniformBuffer, Dynamic, Bind/Unbind, Map/Unmap - Add Fence tests: Initialize (signaled/unsignaled), Signal, Wait, IsSignaled, GetStatus - Add CMakeLists.txt with proper GLFW/GLAD/GTest linking - Create implementation plan document at docs/OpenGL测试实施计划.md
This commit is contained in:
410
docs/OpenGL测试实施计划.md
Normal file
410
docs/OpenGL测试实施计划.md
Normal file
@@ -0,0 +1,410 @@
|
||||
# OpenGL 测试实施计划
|
||||
|
||||
## 1. 概述
|
||||
|
||||
本文档是 `docs/OpenGL后端测试设计.md` 的实施细化计划,基于设计文档中的 5 阶段实现优先级,结合 D3D12 测试经验(54 个测试)制定。
|
||||
|
||||
### 1.1 目标
|
||||
|
||||
- 搭建完整的 OpenGL 后端测试框架
|
||||
- 实现与 D3D12 对齐的 54+ 个测试用例
|
||||
- 确保 CI 环境可用
|
||||
- 支持无头渲染(headless)测试
|
||||
|
||||
### 1.2 测试组件总览
|
||||
|
||||
| # | 组件 | 测试数量 | 文件 | 优先级 |
|
||||
|---|------|:--------:|------|:------:|
|
||||
| 1 | OpenGLDevice | 6 | test_device.cpp | Phase 1 |
|
||||
| 2 | OpenGLBuffer | 6 | test_buffer.cpp | Phase 1 |
|
||||
| 3 | OpenGLFence | 5 | test_fence.cpp | Phase 1 |
|
||||
| 4 | OpenGLTexture | 5 | test_texture.cpp | Phase 2 |
|
||||
| 5 | OpenGLSampler | 4 | test_sampler.cpp | Phase 2 |
|
||||
| 6 | OpenGLShader | 4 | test_shader.cpp | Phase 3 |
|
||||
| 7 | OpenGLPipelineState | 3 | test_pipeline_state.cpp | Phase 3 |
|
||||
| 8 | OpenGLVertexArray | 4 | test_vertex_array.cpp | Phase 3 |
|
||||
| 9 | OpenGLCommandList | 8 | test_command_list.cpp | Phase 4 |
|
||||
| 10 | OpenGLRenderTargetView | 4 | test_render_target_view.cpp | Phase 4 |
|
||||
| 11 | OpenGLDepthStencilView | 4 | test_depth_stencil_view.cpp | Phase 4 |
|
||||
| 12 | OpenGLSwapChain | 3 | test_swap_chain.cpp | Phase 5 |
|
||||
| **总计** | | **56** | | |
|
||||
|
||||
---
|
||||
|
||||
## 2. 实施阶段
|
||||
|
||||
### Phase 1: 核心基础设施(约 1 天)
|
||||
|
||||
#### 2.1 创建目录结构
|
||||
|
||||
```
|
||||
tests/RHI/OpenGL/
|
||||
├── CMakeLists.txt
|
||||
├── fixtures/
|
||||
│ ├── OpenGLTestFixture.h
|
||||
│ └── OpenGLTestFixture.cpp
|
||||
└── Res/
|
||||
├── Shader/
|
||||
├── Texture/
|
||||
└── Data/
|
||||
```
|
||||
|
||||
#### 2.2 实现测试夹具
|
||||
|
||||
**OpenGLTestFixture** 是所有测试的基础:
|
||||
|
||||
| 功能 | 描述 |
|
||||
|------|------|
|
||||
| `SetUpTestSuite()` | 创建隐藏 GLFW 窗口和 GL 上下文 |
|
||||
| `TearDownTestSuite()` | 销毁窗口,终止 GLFW |
|
||||
| `SetUp()` | 确保上下文激活,清除 GL 错误 |
|
||||
| `TearDown()` | 重置 GL 状态,检查泄漏 |
|
||||
| `CheckGLError()` | 检查并报告 GL 错误 |
|
||||
|
||||
**GL 错误检查宏**:
|
||||
|
||||
```cpp
|
||||
#define GL_CLEAR_ERRORS() do { while (glGetError() != GL_NO_ERROR); } while(0)
|
||||
#define GL_CHECK(call) do { call; ASSERT_TRUE(CheckGLError(__FILE__, __LINE__)); } while(0)
|
||||
#define GL_EXPECT_SUCCESS(call) do { call; EXPECT_EQ(glGetError(), GL_NO_ERROR); } while(0)
|
||||
```
|
||||
|
||||
#### 2.3 OpenGLDevice 测试(6 个)
|
||||
|
||||
| 测试用例 | 验证内容 |
|
||||
|----------|----------|
|
||||
| `CreateRenderWindow_ValidParams` | 窗口创建成功 |
|
||||
| `CreateRenderWindow_DebugMode` | 调试模式创建 |
|
||||
| `InitializeWithExistingWindow` | 现有窗口初始化 |
|
||||
| `GetDeviceInfo_ReturnsValid` | 供应商/渲染器/版本信息 |
|
||||
| `SwapBuffers_NoErrors` | 交换缓冲区无错误 |
|
||||
| `PollEvents_ReturnsTrue` | 事件轮询正常 |
|
||||
|
||||
#### 2.4 OpenGLBuffer 测试(6 个)
|
||||
|
||||
| 测试用例 | 验证内容 |
|
||||
|----------|----------|
|
||||
| `Initialize_VertexBuffer` | 顶点缓冲创建 |
|
||||
| `Initialize_IndexBuffer` | 索引缓冲创建 |
|
||||
| `Initialize_UniformBuffer` | Uniform 缓冲创建 |
|
||||
| `Initialize_Dynamic` | 动态缓冲创建 |
|
||||
| `Bind_Unbind` | 缓冲绑定/解绑 |
|
||||
| `Map_Unmap` | 数据映射操作 |
|
||||
|
||||
#### 2.5 OpenGLFence 测试(5 个)
|
||||
|
||||
| 测试用例 | 验证内容 |
|
||||
|----------|----------|
|
||||
| `Initialize_Unsignaled` | 未 signaled 状态创建 |
|
||||
| `Initialize_Signaled` | signaled 状态创建 |
|
||||
| `Signal_SetsValue` | Signal 设置值 |
|
||||
| `Wait_Blocks` | Wait 阻塞等待 |
|
||||
| `IsSignaled_ReturnsState` | signaled 状态查询 |
|
||||
|
||||
#### 2.6 验证步骤
|
||||
|
||||
```bash
|
||||
# 构建
|
||||
cmake --build build --config Debug
|
||||
|
||||
# 运行测试
|
||||
./build/tests/RHI/OpenGL/Debug/opengl_tests.exe --gtest_filter=OpenGLTestFixture.Device*:OpenGLTestFixture.Buffer*:OpenGLTestFixture.Fence*
|
||||
|
||||
# 预期结果
|
||||
[==========] 17 tests from OpenGLTestFixture
|
||||
[ PASSED ] 17 tests
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: 资源管理(约 1 天)
|
||||
|
||||
#### 2.7 OpenGLTexture 测试(5 个)
|
||||
|
||||
| 测试用例 | 验证内容 |
|
||||
|----------|----------|
|
||||
| `Initialize_2DTexture` | 2D 纹理创建 |
|
||||
| `Initialize_CubeMap` | 立方体纹理创建 |
|
||||
| `Bind_Unbind` | 纹理绑定/解绑 |
|
||||
| `GenerateMipmap` | Mipmap 生成 |
|
||||
| `SetFiltering_SetWrapping` | 过滤/环绕参数 |
|
||||
|
||||
#### 2.8 OpenGLSampler 测试(4 个)
|
||||
|
||||
| 测试用例 | 验证内容 |
|
||||
|----------|----------|
|
||||
| `Initialize_Default` | 默认采样器创建 |
|
||||
| `Initialize_Custom` | 自定义采样器创建 |
|
||||
| `Bind_Unbind` | 采样器绑定/解绑 |
|
||||
| `GetID_ReturnsValid` | 采样器 ID 有效 |
|
||||
|
||||
#### 2.9 验证步骤
|
||||
|
||||
```bash
|
||||
# 运行资源管理测试
|
||||
./build/tests/RHI/OpenGL/Debug/opengl_tests.exe --gtest_filter=OpenGLTestFixture.Texture*:OpenGLTestFixture.Sampler*
|
||||
|
||||
# 预期结果
|
||||
[==========] 9 tests from OpenGLTestFixture
|
||||
[ PASSED ] 9 tests
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: 渲染管线(约 1.5 天)
|
||||
|
||||
#### 2.10 OpenGLShader 测试(4 个)
|
||||
|
||||
| 测试用例 | 验证内容 |
|
||||
|----------|----------|
|
||||
| `Compile_VertexFragment` | 顶点和片段着色器编译 |
|
||||
| `Compile_WithGeometry` | 几何着色器编译 |
|
||||
| `Compile_InvalidSource` | 无效源码编译失败 |
|
||||
| `SetUniforms` | Uniform 设置 (int/float/vec3/mat4) |
|
||||
|
||||
#### 2.11 OpenGLPipelineState 测试(3 个)
|
||||
|
||||
| 测试用例 | 验证内容 |
|
||||
|----------|----------|
|
||||
| `SetDepthStencilState` | 深度/模板状态设置 |
|
||||
| `SetBlendState` | 混合状态设置 |
|
||||
| `SetViewport_SetScissor` | 视口/裁剪矩形 |
|
||||
|
||||
#### 2.12 OpenGLVertexArray 测试(4 个)
|
||||
|
||||
| 测试用例 | 验证内容 |
|
||||
|----------|----------|
|
||||
| `Initialize_CreatesVAO` | VAO 创建 |
|
||||
| `AddVertexBuffer` | 顶点缓冲添加 |
|
||||
| `SetIndexBuffer` | 索引缓冲设置 |
|
||||
| `Bind_Unbind` | VAO 绑定/解绑 |
|
||||
|
||||
#### 2.13 验证步骤
|
||||
|
||||
```bash
|
||||
# 运行渲染管线测试
|
||||
./build/tests/RHI/OpenGL/Debug/opengl_tests.exe --gtest_filter=OpenGLTestFixture.Shader*:OpenGLTestFixture.PipelineState*:OpenGLTestFixture.VertexArray*
|
||||
|
||||
# 预期结果
|
||||
[==========] 11 tests from OpenGLTestFixture
|
||||
[ PASSED ] 11 tests
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: 命令与视图(约 1.5 天)
|
||||
|
||||
#### 2.14 OpenGLCommandList 测试(8 个)
|
||||
|
||||
| 测试用例 | 验证内容 |
|
||||
|----------|----------|
|
||||
| `Clear_ColorBuffer` | 清除颜色缓冲 |
|
||||
| `Clear_DepthStencil` | 清除深度/模板 |
|
||||
| `SetVertexBuffer` | 设置顶点缓冲 |
|
||||
| `SetIndexBuffer` | 设置索引缓冲 |
|
||||
| `Draw_Triangles` | 绘制三角形 |
|
||||
| `DrawIndexed_Indices` | 索引绘制 |
|
||||
| `DrawInstanced` | 实例化绘制 |
|
||||
| `Dispatch_ComputeShader` | 计算着色器分发 |
|
||||
|
||||
#### 2.15 OpenGLRenderTargetView 测试(4 个)
|
||||
|
||||
| 测试用例 | 验证内容 |
|
||||
|----------|----------|
|
||||
| `Initialize_Texture2D` | 2D 纹理 RTV 创建 |
|
||||
| `Initialize_Default` | 默认帧缓冲 RTV |
|
||||
| `Bind_Unbind` | RTV 绑定/解绑 |
|
||||
| `Clear_Color` | 清除颜色 |
|
||||
|
||||
#### 2.16 OpenGLDepthStencilView 测试(4 个)
|
||||
|
||||
| 测试用例 | 验证内容 |
|
||||
|----------|----------|
|
||||
| `Initialize_Texture2D` | 2D 纹理 DSV 创建 |
|
||||
| `Initialize_DepthOnly` | 仅深度 DSV |
|
||||
| `Bind_Unbind` | DSV 绑定/解绑 |
|
||||
| `ClearDepthStencil` | 清除深度/模板 |
|
||||
|
||||
#### 2.17 验证步骤
|
||||
|
||||
```bash
|
||||
# 运行命令与视图测试
|
||||
./build/tests/RHI/OpenGL/Debug/opengl_tests.exe --gtest_filter=OpenGLTestFixture.CommandList*:OpenGLTestFixture.RenderTargetView*:OpenGLTestFixture.DepthStencilView*
|
||||
|
||||
# 预期结果
|
||||
[==========] 16 tests from OpenGLTestFixture
|
||||
[ PASSED ] 16 tests
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 5: 窗口管理(约 0.5 天)
|
||||
|
||||
#### 2.18 OpenGLSwapChain 测试(3 个)
|
||||
|
||||
| 测试用例 | 验证内容 |
|
||||
|----------|----------|
|
||||
| `Initialize_Window` | 交换链初始化 |
|
||||
| `Present_VSync` | 垂直同步显示 |
|
||||
| `Resize_ChangesSize` | 调整大小 |
|
||||
|
||||
#### 2.19 验证步骤
|
||||
|
||||
```bash
|
||||
# 运行窗口管理测试
|
||||
./build/tests/RHI/OpenGL/Debug/opengl_tests.exe --gtest_filter=OpenGLTestFixture.SwapChain*
|
||||
|
||||
# 预期结果
|
||||
[==========] 3 tests from OpenGLTestFixture
|
||||
[ PASSED ] 3 tests
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 完整验证
|
||||
|
||||
### 3.1 运行所有测试
|
||||
|
||||
```bash
|
||||
# 完整测试
|
||||
cmake --build build --config Debug
|
||||
ctest --test-dir build -C Debug --output-on-failure
|
||||
|
||||
# 预期结果
|
||||
[==========] 56 tests from 1 test suite.
|
||||
[ PASSED ] 56 tests
|
||||
```
|
||||
|
||||
### 3.2 测试分类统计
|
||||
|
||||
| 分类 | 数量 | 占比 |
|
||||
|------|:----:|:----:|
|
||||
| 初始化测试 | 18 | 32% |
|
||||
| 绑定/解绑测试 | 10 | 18% |
|
||||
| 数据操作测试 | 8 | 14% |
|
||||
| 状态设置测试 | 10 | 18% |
|
||||
| 绘制/执行测试 | 10 | 18% |
|
||||
|
||||
---
|
||||
|
||||
## 4. CI 配置
|
||||
|
||||
### 4.1 GitHub Actions
|
||||
|
||||
```yaml
|
||||
# .github/workflows/opengl-tests.yml
|
||||
name: OpenGL Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure
|
||||
run: cmake -B build -S . -G "Visual Studio 17 2022"
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build --config Debug
|
||||
|
||||
- name: Run Tests
|
||||
run: ctest --test-dir build -C Debug --output-on-failure
|
||||
```
|
||||
|
||||
### 4.2 Linux CI(可选)
|
||||
|
||||
Linux 下需要配置 Mesa 软件渲染:
|
||||
|
||||
```yaml
|
||||
- name: Run Tests
|
||||
env:
|
||||
MESA_GL_VERSION_OVERRIDE: 4.6
|
||||
MESA_GALLIUM_DRIVER: llvmpipe
|
||||
run: ctest --test-dir build -C Debug --output-on-failure
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 任务清单
|
||||
|
||||
### 阶段 1:基础设施
|
||||
|
||||
- [ ] 1.1 创建 `tests/RHI/OpenGL/CMakeLists.txt`
|
||||
- [ ] 1.2 创建 `tests/RHI/OpenGL/fixtures/OpenGLTestFixture.h`
|
||||
- [ ] 1.3 创建 `tests/RHI/OpenGL/fixtures/OpenGLTestFixture.cpp`
|
||||
- [ ] 1.4 实现 `test_device.cpp`(6 个测试)
|
||||
- [ ] 1.5 实现 `test_buffer.cpp`(6 个测试)
|
||||
- [ ] 1.6 实现 `test_fence.cpp`(5 个测试)
|
||||
- [ ] 1.7 构建验证(17 个测试)
|
||||
|
||||
### 阶段 2:资源管理
|
||||
|
||||
- [ ] 2.1 实现 `test_texture.cpp`(5 个测试)
|
||||
- [ ] 2.2 实现 `test_sampler.cpp`(4 个测试)
|
||||
- [ ] 2.3 构建验证(9 个测试)
|
||||
|
||||
### 阶段 3:渲染管线
|
||||
|
||||
- [ ] 3.1 实现 `test_shader.cpp`(4 个测试)
|
||||
- [ ] 3.2 实现 `test_pipeline_state.cpp`(3 个测试)
|
||||
- [ ] 3.3 实现 `test_vertex_array.cpp`(4 个测试)
|
||||
- [ ] 3.4 构建验证(11 个测试)
|
||||
|
||||
### 阶段 4:命令与视图
|
||||
|
||||
- [ ] 4.1 实现 `test_command_list.cpp`(8 个测试)
|
||||
- [ ] 4.2 实现 `test_render_target_view.cpp`(4 个测试)
|
||||
- [ ] 4.3 实现 `test_depth_stencil_view.cpp`(4 个测试)
|
||||
- [ ] 4.4 构建验证(16 个测试)
|
||||
|
||||
### 阶段 5:窗口管理
|
||||
|
||||
- [ ] 5.1 实现 `test_swap_chain.cpp`(3 个测试)
|
||||
- [ ] 5.2 完整测试验证(56 个测试)
|
||||
- [ ] 5.3 提交并推送
|
||||
|
||||
---
|
||||
|
||||
## 6. 关键注意事项
|
||||
|
||||
### 6.1 窗口依赖
|
||||
|
||||
- OpenGL 必须有 GLFW 窗口上下文
|
||||
- 使用 `GLFW_VISIBLE = GLFW_FALSE` 创建隐藏窗口
|
||||
- 每个测试前 `glfwMakeContextCurrent()`
|
||||
|
||||
### 6.2 GL 状态污染
|
||||
|
||||
- OpenGL 状态是全局的,必须隔离
|
||||
- `TearDown()` 中重置所有 GL 状态
|
||||
- 测试结束后 `glBindBuffer(..., 0)` 等
|
||||
|
||||
### 6.3 错误检查
|
||||
|
||||
- 使用 `GL_CHECK()` 宏验证每个 GL 调用
|
||||
- 测试开始时 `GL_CLEAR_ERRORS()`
|
||||
- 捕获 GL 错误并转换为测试失败
|
||||
|
||||
### 6.4 与 D3D12 对齐
|
||||
|
||||
- 保持相同的测试数量级(54+)
|
||||
- 使用相同的 TEST_F 宏
|
||||
- 遵循相同的命名约定
|
||||
|
||||
---
|
||||
|
||||
## 7. 后续工作
|
||||
|
||||
- [ ] 资源泄漏检测工具
|
||||
- [ ] 性能基准测试
|
||||
- [ ] 截图对比测试
|
||||
- [ ] Linux CI 配置
|
||||
- [ ] macOS 支持
|
||||
|
||||
---
|
||||
|
||||
**文档版本**:1.0
|
||||
**创建日期**:2026年3月17日
|
||||
**基于文档**:`docs/OpenGL后端测试设计.md`、`tests/RHI/D3D12/`
|
||||
@@ -39,6 +39,7 @@ add_subdirectory(threading)
|
||||
add_subdirectory(debug)
|
||||
add_subdirectory(D3D12)
|
||||
add_subdirectory(RHI/D3D12)
|
||||
add_subdirectory(RHI/OpenGL)
|
||||
|
||||
# ============================================================
|
||||
# Test Summary
|
||||
|
||||
49
tests/RHI/OpenGL/CMakeLists.txt
Normal file
49
tests/RHI/OpenGL/CMakeLists.txt
Normal file
@@ -0,0 +1,49 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
project(OpenGLEngineTests)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
get_filename_component(PROJECT_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../.. ABSOLUTE)
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/tests/OpenGL/package/include/)
|
||||
include_directories(${PROJECT_ROOT_DIR}/engine/include)
|
||||
include_directories(${PROJECT_ROOT_DIR}/engine/src)
|
||||
|
||||
link_directories(${CMAKE_SOURCE_DIR}/tests/OpenGL/package/lib/)
|
||||
|
||||
find_package(GTest REQUIRED)
|
||||
|
||||
set(TEST_SOURCES
|
||||
${CMAKE_SOURCE_DIR}/tests/OpenGL/package/src/glad.c
|
||||
fixtures/OpenGLTestFixture.cpp
|
||||
test_device.cpp
|
||||
test_buffer.cpp
|
||||
test_fence.cpp
|
||||
)
|
||||
|
||||
add_executable(opengl_engine_tests ${TEST_SOURCES})
|
||||
|
||||
target_link_libraries(opengl_engine_tests PRIVATE
|
||||
opengl32
|
||||
glfw3
|
||||
XCEngine
|
||||
GTest::gtest
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
target_include_directories(opengl_engine_tests PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/fixtures
|
||||
${PROJECT_ROOT_DIR}/engine/include
|
||||
${PROJECT_ROOT_DIR}/engine/src
|
||||
)
|
||||
|
||||
target_compile_definitions(opengl_engine_tests PRIVATE
|
||||
TEST_RESOURCES_DIR="${PROJECT_ROOT_DIR}/tests/RHI/OpenGL/Res"
|
||||
)
|
||||
|
||||
enable_testing()
|
||||
add_test(NAME OpenGLEngineTests COMMAND opengl_engine_tests)
|
||||
138
tests/RHI/OpenGL/fixtures/OpenGLTestFixture.cpp
Normal file
138
tests/RHI/OpenGL/fixtures/OpenGLTestFixture.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
#include "OpenGLTestFixture.h"
|
||||
|
||||
using namespace XCEngine::RHI;
|
||||
|
||||
GLFWwindow* OpenGLTestFixture::m_window = nullptr;
|
||||
bool OpenGLTestFixture::m_contextInitialized = false;
|
||||
OpenGLDevice* OpenGLTestFixture::m_device = nullptr;
|
||||
|
||||
void OpenGLTestFixture::SetUpTestSuite() {
|
||||
if (!glfwInit()) {
|
||||
GTEST_SKIP() << "Failed to initialize GLFW";
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
m_window = glfwCreateWindow(640, 480, "OpenGL Tests", nullptr, nullptr);
|
||||
if (!m_window) {
|
||||
GTEST_SKIP() << "Failed to create GLFW window";
|
||||
glfwTerminate();
|
||||
return;
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(m_window);
|
||||
|
||||
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
|
||||
GTEST_SKIP() << "Failed to initialize GLAD";
|
||||
glfwDestroyWindow(m_window);
|
||||
m_window = nullptr;
|
||||
glfwTerminate();
|
||||
return;
|
||||
}
|
||||
|
||||
m_contextInitialized = true;
|
||||
|
||||
m_device = new OpenGLDevice();
|
||||
m_device->CreateRenderWindow(640, 480, "Test Window", false);
|
||||
}
|
||||
|
||||
void OpenGLTestFixture::TearDownTestSuite() {
|
||||
if (m_device) {
|
||||
delete m_device;
|
||||
m_device = nullptr;
|
||||
}
|
||||
|
||||
if (m_window) {
|
||||
glfwDestroyWindow(m_window);
|
||||
m_window = nullptr;
|
||||
}
|
||||
glfwTerminate();
|
||||
m_contextInitialized = false;
|
||||
}
|
||||
|
||||
void OpenGLTestFixture::SetUp() {
|
||||
if (!m_window || !m_contextInitialized) {
|
||||
GTEST_SKIP() << "OpenGL context not available";
|
||||
return;
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(m_window);
|
||||
ClearGLErrors();
|
||||
}
|
||||
|
||||
void OpenGLTestFixture::TearDown() {
|
||||
GLenum error = glGetError();
|
||||
if (error != GL_NO_ERROR) {
|
||||
}
|
||||
|
||||
ResetGLState();
|
||||
}
|
||||
|
||||
void OpenGLTestFixture::MakeContextCurrent() {
|
||||
if (m_window) {
|
||||
glfwMakeContextCurrent(m_window);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLTestFixture::DoneContextCurrent() {
|
||||
glfwMakeContextCurrent(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);
|
||||
}
|
||||
53
tests/RHI/OpenGL/fixtures/OpenGLTestFixture.h
Normal file
53
tests/RHI/OpenGL/fixtures/OpenGLTestFixture.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "XCEngine/RHI/OpenGL/OpenGLDevice.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
|
||||
class OpenGLTestFixture : public ::testing::Test {
|
||||
protected:
|
||||
static void SetUpTestSuite();
|
||||
static void TearDownTestSuite();
|
||||
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
|
||||
GLFWwindow* GetWindow() { return m_window; }
|
||||
void MakeContextCurrent();
|
||||
void DoneContextCurrent();
|
||||
|
||||
void ClearGLErrors();
|
||||
bool CheckGLError(const char* file, int line);
|
||||
const char* GetGLErrorString(GLenum error);
|
||||
void ResetGLState();
|
||||
|
||||
private:
|
||||
static GLFWwindow* m_window;
|
||||
static bool m_contextInitialized;
|
||||
static OpenGLDevice* m_device;
|
||||
};
|
||||
|
||||
} // namespace RHI
|
||||
} // namespace XCEngine
|
||||
|
||||
#define GL_CLEAR_ERRORS() \
|
||||
do { while (glGetError() != GL_NO_ERROR); } while(0)
|
||||
|
||||
#define GL_CHECK(call) \
|
||||
do { \
|
||||
call; \
|
||||
ASSERT_TRUE(XCEngine::RHI::OpenGLTestFixture::CheckGLError(__FILE__, __LINE__)) \
|
||||
<< "GL error after " << #call; \
|
||||
} while(0)
|
||||
|
||||
#define GL_EXPECT_SUCCESS(call) \
|
||||
do { \
|
||||
call; \
|
||||
EXPECT_EQ(glGetError(), GL_NO_ERROR) \
|
||||
<< "GL error after " << #call; \
|
||||
} while(0)
|
||||
89
tests/RHI/OpenGL/test_buffer.cpp
Normal file
89
tests/RHI/OpenGL/test_buffer.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#include "fixtures/OpenGLTestFixture.h"
|
||||
#include "XCEngine/RHI/OpenGL/OpenGLBuffer.h"
|
||||
|
||||
using namespace XCEngine::RHI;
|
||||
|
||||
TEST_F(OpenGLTestFixture, Buffer_Initialize_VertexBuffer) {
|
||||
OpenGLBuffer buffer;
|
||||
float vertices[] = { 0.0f, 0.0f, 0.5f, 0.5f };
|
||||
|
||||
bool result = buffer.InitializeVertexBuffer(vertices, sizeof(vertices));
|
||||
|
||||
ASSERT_TRUE(result);
|
||||
EXPECT_NE(buffer.GetID(), 0u);
|
||||
EXPECT_EQ(buffer.GetSize(), sizeof(vertices));
|
||||
EXPECT_EQ(buffer.GetType(), OpenGLBufferType::Vertex);
|
||||
|
||||
buffer.Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(OpenGLTestFixture, Buffer_Initialize_IndexBuffer) {
|
||||
OpenGLBuffer buffer;
|
||||
unsigned int indices[] = { 0, 1, 2 };
|
||||
|
||||
bool result = buffer.InitializeIndexBuffer(indices, sizeof(indices));
|
||||
|
||||
ASSERT_TRUE(result);
|
||||
EXPECT_NE(buffer.GetID(), 0u);
|
||||
EXPECT_EQ(buffer.GetSize(), sizeof(indices));
|
||||
|
||||
buffer.Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(OpenGLTestFixture, Buffer_Initialize_UniformBuffer) {
|
||||
OpenGLBuffer buffer;
|
||||
float data[16] = {};
|
||||
|
||||
bool result = buffer.Initialize(OpenGLBufferType::Uniform, sizeof(data), data, true);
|
||||
|
||||
ASSERT_TRUE(result);
|
||||
EXPECT_TRUE(buffer.IsDynamic());
|
||||
EXPECT_EQ(buffer.GetType(), OpenGLBufferType::Uniform);
|
||||
|
||||
buffer.Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(OpenGLTestFixture, Buffer_Initialize_Dynamic) {
|
||||
OpenGLBuffer buffer;
|
||||
|
||||
bool result = buffer.Initialize(OpenGLBufferType::CopyRead, 256, nullptr, true);
|
||||
|
||||
ASSERT_TRUE(result);
|
||||
EXPECT_TRUE(buffer.IsDynamic());
|
||||
EXPECT_EQ(buffer.GetSize(), 256u);
|
||||
|
||||
buffer.Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(OpenGLTestFixture, Buffer_Bind_Unbind) {
|
||||
OpenGLBuffer buffer;
|
||||
buffer.InitializeVertexBuffer(nullptr, 16);
|
||||
|
||||
buffer.Bind();
|
||||
GLint boundBuffer = 0;
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &boundBuffer);
|
||||
EXPECT_EQ(boundBuffer, static_cast<GLint>(buffer.GetID()));
|
||||
|
||||
buffer.Unbind();
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &boundBuffer);
|
||||
EXPECT_EQ(boundBuffer, 0);
|
||||
|
||||
buffer.Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(OpenGLTestFixture, Buffer_Map_Unmap) {
|
||||
OpenGLBuffer buffer;
|
||||
buffer.Initialize(OpenGLBufferType::CopyRead, 256, nullptr, true);
|
||||
|
||||
void* mappedData = buffer.Map();
|
||||
ASSERT_NE(mappedData, nullptr);
|
||||
|
||||
memset(mappedData, 0xAB, 256);
|
||||
|
||||
buffer.Unmap();
|
||||
|
||||
GLenum error = glGetError();
|
||||
EXPECT_EQ(error, GL_NO_ERROR);
|
||||
|
||||
buffer.Shutdown();
|
||||
}
|
||||
63
tests/RHI/OpenGL/test_device.cpp
Normal file
63
tests/RHI/OpenGL/test_device.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "fixtures/OpenGLTestFixture.h"
|
||||
#include "XCEngine/RHI/OpenGL/OpenGLDevice.h"
|
||||
|
||||
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) {
|
||||
OpenGLDevice device;
|
||||
GLFWwindow* existingWindow = GetWindow();
|
||||
|
||||
bool result = device.InitializeWithExistingWindow(existingWindow);
|
||||
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(device.GetWindow(), existingWindow);
|
||||
}
|
||||
|
||||
TEST_F(OpenGLTestFixture, Device_GetDeviceInfo_ReturnsValid) {
|
||||
OpenGLDevice device;
|
||||
device.CreateRenderWindow(800, 600, "Test", false);
|
||||
|
||||
const auto& info = device.GetDeviceInfo();
|
||||
|
||||
EXPECT_FALSE(info.vendor.empty());
|
||||
EXPECT_FALSE(info.renderer.empty());
|
||||
EXPECT_GE(info.majorVersion, 3);
|
||||
EXPECT_GE(info.minorVersion, 0);
|
||||
}
|
||||
|
||||
TEST_F(OpenGLTestFixture, Device_SwapBuffers_NoErrors) {
|
||||
OpenGLDevice device;
|
||||
device.CreateRenderWindow(800, 600, "Test", false);
|
||||
|
||||
device.SwapBuffers();
|
||||
|
||||
GLenum error = glGetError();
|
||||
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);
|
||||
}
|
||||
61
tests/RHI/OpenGL/test_fence.cpp
Normal file
61
tests/RHI/OpenGL/test_fence.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
#include "fixtures/OpenGLTestFixture.h"
|
||||
#include "XCEngine/RHI/OpenGL/OpenGLFence.h"
|
||||
|
||||
using namespace XCEngine::RHI;
|
||||
|
||||
TEST_F(OpenGLTestFixture, Fence_Initialize_Unsignaled) {
|
||||
OpenGLFence fence;
|
||||
|
||||
bool result = fence.Initialize(false);
|
||||
|
||||
ASSERT_TRUE(result);
|
||||
EXPECT_EQ(fence.GetStatus(), FenceStatus::Unsignaled);
|
||||
|
||||
fence.Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(OpenGLTestFixture, Fence_Initialize_Signaled) {
|
||||
OpenGLFence fence;
|
||||
|
||||
bool result = fence.Initialize(true);
|
||||
|
||||
ASSERT_TRUE(result);
|
||||
|
||||
fence.Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(OpenGLTestFixture, Fence_Signal_Wait) {
|
||||
OpenGLFence fence;
|
||||
fence.Initialize(false);
|
||||
|
||||
fence.Signal(1);
|
||||
|
||||
fence.Wait(1);
|
||||
|
||||
EXPECT_TRUE(fence.IsSignaled());
|
||||
EXPECT_EQ(fence.GetCompletedValue(), 1u);
|
||||
|
||||
fence.Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(OpenGLTestFixture, Fence_IsSignaled_ReturnsState) {
|
||||
OpenGLFence fence;
|
||||
fence.Initialize(false);
|
||||
|
||||
fence.Signal(1);
|
||||
fence.Wait(1);
|
||||
|
||||
EXPECT_TRUE(fence.IsSignaled());
|
||||
|
||||
fence.Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(OpenGLTestFixture, Fence_GetStatus_ReturnsCorrect) {
|
||||
OpenGLFence fence;
|
||||
fence.Initialize(false);
|
||||
|
||||
FenceStatus status = fence.GetStatus();
|
||||
EXPECT_TRUE(status == FenceStatus::Signaled || status == FenceStatus::Unsignaled);
|
||||
|
||||
fence.Shutdown();
|
||||
}
|
||||
Reference in New Issue
Block a user