334 lines
9.5 KiB
Markdown
334 lines
9.5 KiB
Markdown
# 统一渲染架构快速入门
|
||
|
||
## 概述
|
||
|
||
本项目采用统一的渲染架构设计,通过抽象基类 `RenderWidgetBase` 实现对 Vulkan 和 QPainter 两种渲染方式的统一管理。
|
||
|
||
## 核心设计
|
||
|
||
### 三层架构
|
||
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ MainWindow │ ← 使用统一接口
|
||
│ (RenderWidgetBase* m_renderWidget) │
|
||
└──────────────┬──────────────────────┘
|
||
│
|
||
↓
|
||
┌─────────────────────────────────────┐
|
||
│ RenderWidgetBase (基类) │ ← 定义统一接口
|
||
│ - initializeRenderer() │
|
||
│ - setRenderingEnabled() │
|
||
│ - getRenderFrameCount() │
|
||
│ - getRendererType() │
|
||
└──────────────┬──────────────────────┘
|
||
│
|
||
┌───────┴────────┐
|
||
↓ ↓
|
||
┌─────────────┐ ┌─────────────┐
|
||
│VulkanWidget │ │CustomWidget │ ← 具体实现
|
||
│ (Vulkan) │ │ (QPainter) │
|
||
└─────────────┘ └─────────────┘
|
||
```
|
||
|
||
## 编译选项
|
||
|
||
### 使用 Vulkan(默认,如果可用)
|
||
|
||
```bash
|
||
cd ScreenLockDetector
|
||
mkdir -p build && cd build
|
||
cmake .. -DENABLE_VULKAN=ON
|
||
make -j4
|
||
```
|
||
|
||
**结果**:应用将使用 VulkanWidget 进行硬件加速渲染
|
||
|
||
### 使用 QPainter(后备方案)
|
||
|
||
```bash
|
||
cd ScreenLockDetector
|
||
mkdir -p build && cd build
|
||
cmake .. -DENABLE_VULKAN=OFF
|
||
make -j4
|
||
```
|
||
|
||
**结果**:应用将使用 CustomWidget 进行 CPU 绘制
|
||
|
||
### 自动回退
|
||
|
||
如果 Vulkan 头文件不可用,CMake 会自动回退到 QPainter:
|
||
|
||
```bash
|
||
cmake ..
|
||
# 输出:Vulkan headers not found, disabling Vulkan support
|
||
```
|
||
|
||
## 主要改进
|
||
|
||
### 之前的设计问题
|
||
|
||
```cpp
|
||
// ❌ 旧设计:需要维护两个独立的组件
|
||
private:
|
||
CustomWidget *m_customWidget;
|
||
#ifdef ENABLE_VULKAN_WIDGET
|
||
VulkanWidget *m_vulkanWidget;
|
||
#endif
|
||
|
||
QTabWidget *m_tabWidget; // 使用 Tab 切换
|
||
```
|
||
|
||
### 新的统一设计
|
||
|
||
```cpp
|
||
// ✅ 新设计:单一组件指针
|
||
private:
|
||
RenderWidgetBase *m_renderWidget; // 统一接口
|
||
|
||
// 构造函数中根据编译选项创建
|
||
#ifdef ENABLE_VULKAN_WIDGET
|
||
m_renderWidget = new VulkanWidget(this);
|
||
#else
|
||
m_renderWidget = new CustomWidget(this);
|
||
#endif
|
||
```
|
||
|
||
## 统一接口使用示例
|
||
|
||
### 1. 初始化渲染器
|
||
|
||
```cpp
|
||
// 对于 VulkanWidget:内部调用 initializeVulkan()
|
||
// 对于 CustomWidget:直接返回 true(无需初始化)
|
||
bool success = m_renderWidget->initializeRenderer();
|
||
if (!success) {
|
||
qDebug() << "Error:" << m_renderWidget->getLastError();
|
||
}
|
||
```
|
||
|
||
### 2. 控制渲染
|
||
|
||
```cpp
|
||
// 启用渲染(适用于任何渲染器)
|
||
m_renderWidget->setRenderingEnabled(true);
|
||
|
||
// 禁用渲染(适用于任何渲染器)
|
||
m_renderWidget->setRenderingEnabled(false);
|
||
|
||
// 查询状态
|
||
bool isRendering = m_renderWidget->isRenderingEnabled();
|
||
```
|
||
|
||
### 3. 获取状态信息
|
||
|
||
```cpp
|
||
// 获取渲染器类型
|
||
QString type = m_renderWidget->getRendererType();
|
||
// 返回 "Vulkan" 或 "QPainter"
|
||
|
||
// 获取帧数统计
|
||
int frames = m_renderWidget->getRenderFrameCount();
|
||
|
||
// 检查初始化状态
|
||
bool initialized = m_renderWidget->isInitialized();
|
||
```
|
||
|
||
### 4. 错误处理
|
||
|
||
```cpp
|
||
if (!m_renderWidget->isInitialized()) {
|
||
if (!m_renderWidget->initializeRenderer()) {
|
||
QMessageBox::warning(
|
||
this,
|
||
"初始化失败",
|
||
m_renderWidget->getLastError()
|
||
);
|
||
}
|
||
}
|
||
```
|
||
|
||
## 锁屏检测集成
|
||
|
||
无论使用哪种渲染器,锁屏检测的处理逻辑完全一致:
|
||
|
||
```cpp
|
||
void MainWindow::onLockStateChanged(bool locked)
|
||
{
|
||
// 统一的处理逻辑
|
||
if (m_renderWidget) {
|
||
m_renderWidget->setRenderingEnabled(!locked);
|
||
}
|
||
|
||
updateStatusDisplay();
|
||
updateButtonStates();
|
||
}
|
||
```
|
||
|
||
## 添加新渲染器
|
||
|
||
假设要添加 OpenGL 支持:
|
||
|
||
### 1. 创建新类
|
||
|
||
```cpp
|
||
// src/openglwidget.h
|
||
class OpenGLWidget : public RenderWidgetBase
|
||
{
|
||
Q_OBJECT
|
||
public:
|
||
explicit OpenGLWidget(QWidget *parent = nullptr);
|
||
|
||
// 实现所有虚函数
|
||
bool initializeRenderer() override;
|
||
void setRenderingEnabled(bool enabled) override;
|
||
bool isRenderingEnabled() const override;
|
||
int getRenderFrameCount() const override;
|
||
void resetFrameCount() override;
|
||
bool isInitialized() const override;
|
||
QString getLastError() const override;
|
||
QString getRendererType() const override { return "OpenGL"; }
|
||
};
|
||
```
|
||
|
||
### 2. 修改 CMakeLists.txt
|
||
|
||
```cmake
|
||
option(ENABLE_OPENGL "Enable OpenGL support" OFF)
|
||
|
||
if(ENABLE_OPENGL)
|
||
list(APPEND SOURCES src/openglwidget.cpp)
|
||
list(APPEND HEADERS src/openglwidget.h)
|
||
add_definitions(-DENABLE_OPENGL_WIDGET)
|
||
endif()
|
||
```
|
||
|
||
### 3. 修改 MainWindow 构造函数
|
||
|
||
```cpp
|
||
#ifdef ENABLE_VULKAN_WIDGET
|
||
m_renderWidget = new VulkanWidget(this);
|
||
#elif defined(ENABLE_OPENGL_WIDGET)
|
||
m_renderWidget = new OpenGLWidget(this);
|
||
#else
|
||
m_renderWidget = new CustomWidget(this);
|
||
#endif
|
||
```
|
||
|
||
## 运行效果
|
||
|
||
### Vulkan 模式
|
||
|
||
```
|
||
┌──────────────────────────────────────┐
|
||
│ Qt Screen Lock Detection Demo │
|
||
├──────────────────────────────────────┤
|
||
│ │
|
||
│ [Vulkan 硬件加速渲染窗口] │
|
||
│ (旋转的彩色圆圈动画) │
|
||
│ │
|
||
├──────────────────────────────────────┤
|
||
│ [ Enable Rendering ] │
|
||
│ [ Disable Rendering ] │
|
||
│ [ Reset Frame Count ] │
|
||
├──────────────────────────────────────┤
|
||
│ Renderer Type: Vulkan │
|
||
│ Detector Status: Active │
|
||
│ Renderer Status: ✓ Initialized │
|
||
│ Screen Lock Status: 🔓 UNLOCKED │
|
||
│ Rendering Status: ✓ ENABLED │
|
||
│ Frame Count: 1234 frames │
|
||
└──────────────────────────────────────┘
|
||
```
|
||
|
||
### QPainter 模式
|
||
|
||
```
|
||
┌──────────────────────────────────────┐
|
||
│ Qt Screen Lock Detection Demo │
|
||
├──────────────────────────────────────┤
|
||
│ │
|
||
│ [QPainter 2D 渲染窗口] │
|
||
│ (旋转的彩色圆圈动画) │
|
||
│ │
|
||
├──────────────────────────────────────┤
|
||
│ [ Enable Rendering ] │
|
||
│ [ Disable Rendering ] │
|
||
│ [ Reset Frame Count ] │
|
||
├──────────────────────────────────────┤
|
||
│ Renderer Type: QPainter │
|
||
│ Detector Status: Active │
|
||
│ Renderer Status: ✓ Initialized │
|
||
│ Screen Lock Status: 🔓 UNLOCKED │
|
||
│ Rendering Status: ✓ ENABLED │
|
||
│ Frame Count: 1234 frames │
|
||
└──────────────────────────────────────┘
|
||
```
|
||
|
||
## 优势总结
|
||
|
||
### ✅ 代码简化
|
||
- MainWindow 代码减少约 40%
|
||
- 消除了大量重复的控制逻辑
|
||
- 减少了条件编译代码
|
||
|
||
### ✅ 统一界面
|
||
- 不再使用 Tab 切换
|
||
- 单一、简洁的用户界面
|
||
- 自动选择最佳渲染方式
|
||
|
||
### ✅ 易于维护
|
||
- 添加新功能只需修改基类接口
|
||
- 所有实现类自动继承新接口
|
||
- 更容易追踪和修复 bug
|
||
|
||
### ✅ 高可扩展性
|
||
- 可以轻松添加新的渲染后端
|
||
- 可以在运行时切换渲染器(未来功能)
|
||
- 支持插件化架构(未来功能)
|
||
|
||
## 常见问题
|
||
|
||
### Q: 如何知道当前使用的是哪种渲染器?
|
||
|
||
A: 查看应用程序窗口的 "Renderer Type" 标签,或在日志中查看:
|
||
```
|
||
MainWindow initialized with Vulkan renderer
|
||
```
|
||
|
||
### Q: Vulkan 初始化失败怎么办?
|
||
|
||
A: 应用会自动显示错误信息。可以重新编译使用 QPainter:
|
||
```bash
|
||
cmake .. -DENABLE_VULKAN=OFF
|
||
make -j4
|
||
```
|
||
|
||
### Q: 两种渲染器性能差异大吗?
|
||
|
||
A:
|
||
- **Vulkan**: 硬件加速,GPU 渲染,CPU 占用低,适合复杂场景
|
||
- **QPainter**: CPU 渲染,CPU 占用较高,但兼容性最好
|
||
|
||
### Q: 可以在运行时切换渲染器吗?
|
||
|
||
A: 当前版本不支持,但架构设计已经为此功能预留了空间。
|
||
|
||
## 相关文档
|
||
|
||
- [详细设计文档](./unified_rendering_design.md) - 完整的架构设计说明
|
||
- [API 参考](../src/renderwidgetbase.h) - RenderWidgetBase 接口定义
|
||
- [主 README](../README.md) - 项目总体说明
|
||
|
||
## 贡献指南
|
||
|
||
如果您想添加新的渲染后端:
|
||
|
||
1. 创建新类继承 `RenderWidgetBase`
|
||
2. 实现所有虚函数
|
||
3. 在 CMakeLists.txt 中添加编译选项
|
||
4. 在 MainWindow 中添加创建逻辑
|
||
5. 编写测试用例
|
||
6. 更新文档
|
||
|
||
欢迎提交 Pull Request! |