Skip to content

Commit

Permalink
[添加Vulkan图形渲染支持]:引入Vulkan图形渲染框架,更新依赖和示例工程
Browse files Browse the repository at this point in the history
- 在`action.yml`中添加了安装Vulkan SDK的步骤
- `CMakeLists.txt`文件更新了`find_package`以包含`Qt6::Gui`模块,并添加了对Vulkan的查找
- `README.md`中新增了`QVulkanWindow`相关的编译和旋转问题的文档说明
- `examples/graphics/CMakeLists.txt`和`graphics.pro`中添加了新文件`vulkanviewer.cc`和`vulkanviewer.hpp`,并更新了链接库
- `mainwindow.cpp`中新增了对`VulkanViewer`的引用和相关UI组件
- 新增了`vulkanviewer.cc`和`vulkanviewer.hpp`文件,实现了基于Vulkan的图像查看器
- `src/gpugraphics/CMakeLists.txt`中添加了Vulkan相关源文件和资源,并更新了链接库
- `gpugraphics.pro`中添加了Vulkan相关的头文件和源文件
- 更新了`shader.qrc`,添加了Vulkan着色器文件
- 新增了`vulkan.frag`和`vulkan.vert`着色器文件,实现了Vulkan渲染的着色器程序
- 新增了`vulkanrenderer.cc`和`vulkanrenderer.hpp`,实现了Vulkan渲染器
- 新增了`vulkanview.cc`和`vulkanview.hpp`,实现了Vulkan视图窗口
  • Loading branch information
RealChuan committed Aug 14, 2024
1 parent 50ec75f commit 9ac4565
Show file tree
Hide file tree
Showing 17 changed files with 1,682 additions and 14 deletions.
5 changes: 5 additions & 0 deletions .github/actions/install-dependencies/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,8 @@ runs:
version: ${{ inputs.qt_ver }}
modules: ${{ inputs.qt_modules }}
cache: 'true'

- name: Install Vulkan SDK
uses: humbletim/install-vulkan-sdk@main
with:
cache: true
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ project(

include(cmake/common.cmake)

find_package(Qt6 REQUIRED COMPONENTS Widgets Network Core5Compat Concurrent
find_package(Qt6 REQUIRED COMPONENTS Gui Widgets Network Core5Compat Concurrent
OpenGLWidgets)

qt_standard_project_setup()
Expand All @@ -32,6 +32,10 @@ find_package(crashpad CONFIG REQUIRED)
if(crashpad_FOUND)
message(STATUS "found crashpad")
endif()
find_package(Vulkan REQUIRED)
if(Vulkan_FOUND)
message(STATUS "found Vulkan")
endif()

find_package(GIF REQUIRED)
if(GIF_FOUND)
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@

## 效果图更新会不太及时

## QVulkanWindow

### 问题

#### 编译

1. [cmake](.github/workflows/cmake.yml):在MacOS下会找不到QVulkanWindow相关的头文件,编译无法通过;
2. [qmake](.github/workflows/qmake.yml)
1. 在MacOS下会找不到QVulkanWindowRenderer相关的头文件,编译无法通过;
2. 在Ubuntu下会找不到QVulkanInstance相关的头文件,编译无法通过:

#### 旋转

1. 跟OpenGL看图界面类似,在旋转任意角度的时候,纹理的宽高比会变化,导致显示不正常;

## 看图界面

<div align=center>
Expand Down
5 changes: 4 additions & 1 deletion examples/graphics/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ set(PROJECT_SOURCES
subtitlsplicingwidget.cc
subtitlsplicingwidget.hpp
viewer.cc
viewer.hpp)
viewer.hpp
vulkanviewer.cc
vulkanviewer.hpp)

qt_add_executable(Qt-Graphics MANUAL_FINALIZATION ${PROJECT_SOURCES})

Expand All @@ -48,6 +50,7 @@ target_link_libraries(
thirdparty
dump
utils
Qt6::Gui
Qt6::Widgets
Qt6::OpenGLWidgets
Qt6::Network
Expand Down
6 changes: 4 additions & 2 deletions examples/graphics/graphics.pro
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ SOURCES += \
selectionwidget.cc \
stretchparamssettingdailog.cc \
subtitlsplicingwidget.cc \
viewer.cc
viewer.cc \
vulkanviewer.cc

HEADERS += \
capturewidget.hpp \
Expand All @@ -58,4 +59,5 @@ HEADERS += \
selectionwidget.hpp \
stretchparamssettingdailog.hpp \
subtitlsplicingwidget.hpp \
viewer.hpp
viewer.hpp \
vulkanviewer.hpp
15 changes: 11 additions & 4 deletions examples/graphics/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "openglviewer.hpp"
#include "recordwidget.hpp"
#include "subtitlsplicingwidget.hpp"
#include "vulkanviewer.hpp"

#include <utils/utils.h>

Expand All @@ -19,19 +20,22 @@ class MainWindow::MainWindowPrivate
drawWidget = new DrawWidget(q_ptr);
imageViewer = new ImageViewer(q_ptr);
openglViewer = new OpenglViewer(q_ptr);
vulkanViewer = new VulkanViewer(q_ptr);
subtitlSplicingWidget = new SubtitlSplicingWidget(q_ptr);
stackedWidget = new QStackedWidget(q_ptr);
stackedWidget->addWidget(imageViewer);
stackedWidget->addWidget(drawWidget);
stackedWidget->addWidget(subtitlSplicingWidget);
stackedWidget->addWidget(openglViewer);
stackedWidget->addWidget(vulkanViewer);
}
~MainWindowPrivate() {}

QWidget *q_ptr;
DrawWidget *drawWidget;
ImageViewer *imageViewer;
OpenglViewer *openglViewer;
VulkanViewer *vulkanViewer;
SubtitlSplicingWidget *subtitlSplicingWidget;
QStackedWidget *stackedWidget;
};
Expand Down Expand Up @@ -69,13 +73,16 @@ void MainWindow::setupUI()

void MainWindow::initMenuBar()
{
auto menu = new QMenu(tr("Select Widget"), this);
menu->addAction(tr("ImageViewer"), this, [this] {
auto *menu = new QMenu(tr("Select Widget"), this);
menu->addAction(tr("Image Viewer"), this, [this] {
d_ptr->stackedWidget->setCurrentWidget(d_ptr->imageViewer);
});
menu->addAction(tr("OpenglViewer"), this, [this] {
menu->addAction(tr("Opengl Viewer"), this, [this] {
d_ptr->stackedWidget->setCurrentWidget(d_ptr->openglViewer);
});
menu->addAction(tr("Vulakn Viewer"), this, [this] {
d_ptr->stackedWidget->setCurrentWidget(d_ptr->vulkanViewer);
});
menu->addAction(tr("Draw"), this, [this] {
d_ptr->stackedWidget->setCurrentWidget(d_ptr->drawWidget);
});
Expand All @@ -93,4 +100,4 @@ void MainWindow::initMenuBar()
auto recordWidget = new RecordWidget;
recordWidget->show();
});
}
}
198 changes: 198 additions & 0 deletions examples/graphics/vulkanviewer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
#include "vulkanviewer.hpp"
#include "imagelistmodel.h"

#include <gpugraphics/vulkanrenderer.hpp>
#include <gpugraphics/vulkanview.hpp>
#include <utils/utils.h>

#include <QtWidgets>

class VulkanViewer::VulkanViewerPrivate
{
public:
explicit VulkanViewerPrivate(VulkanViewer *q)
: q_ptr(q)
, vulkanViewPtr(new GpuGraphics::VulkanView)
{
urlLabel = new QLabel("-", q_ptr);
urlLabel->setWordWrap(true);
sizeLabel = new QLabel("-", q_ptr);
fileSizeLabel = new QLabel("-", q_ptr);
scaleLabel = new QLabel("-", q_ptr);
imageListView = new ImageListView(q_ptr);
imageListView->setFixedHeight(120);
}

VulkanViewer *q_ptr;

QScopedPointer<GpuGraphics::VulkanView> vulkanViewPtr;

QLabel *urlLabel;
QLabel *fileSizeLabel;
QLabel *sizeLabel;
QLabel *scaleLabel;
ImageInfoList imageInfoList;
ImageListView *imageListView;

QAtomicInteger<qint64> taskCount = 0;
};

VulkanViewer::VulkanViewer(QWidget *parent)
: Viewer(parent)
, d_ptr(new VulkanViewerPrivate(this))
{
setupUI();
buildConnect();
}

VulkanViewer::~VulkanViewer()
{
clearThumbnail();
}

auto VulkanViewer::setImage(const QFileInfo &info, const QImage &image, const qint64 taskCount)
-> bool
{
if (taskCount != d_ptr->taskCount.loadRelaxed()) {
return false;
}
QMetaObject::invokeMethod(
this, [=] { onImageLoaded(info, image); }, Qt::QueuedConnection);
return true;
}

void VulkanViewer::onOpenImage()
{
QString imageFilters(tr("Images (*.bmp *.gif *.jpg *.jpeg *.png *.svg *.tiff *.webp *.icns "
"*.bitmap *.graymap *.pixmap *.tga *.xbitmap *.xpixmap)"));
//qDebug() << imageFilters;
const auto path = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation)
.value(0, QDir::homePath());
const auto filename = QFileDialog::getOpenFileName(this, tr("Open Image"), path, imageFilters);
if (filename.isEmpty()) {
return;
}

d_ptr->vulkanViewPtr->setImageUrl(filename);
}

void VulkanViewer::onScaleFactorChanged(qreal factor)
{
const auto info = QString::number(factor * 100, 'f', 2) + QLatin1Char('%');
d_ptr->scaleLabel->setText(info);
}

void VulkanViewer::onImageSizeChanged(const QSize &size)
{
QString imageSizeText;
if (size.isValid()) {
imageSizeText = QString::fromLatin1("%1x%2").arg(size.width()).arg(size.height());
}
d_ptr->sizeLabel->setText(imageSizeText);
}

void VulkanViewer::onImageChanged(const QString &url)
{
d_ptr->urlLabel->setText(url);
d_ptr->fileSizeLabel->setText(Utils::convertBytesToString(QFile(url).size()));

for (const ImageInfo &image : std::as_const(d_ptr->imageInfoList)) {
if (image.fileInfo().absoluteFilePath() == url) {
return;
}
}
clearThumbnail();
startImageLoadThread(url);
}

void VulkanViewer::onChangedImage(int index)
{
if (index < 0 || index >= d_ptr->imageInfoList.size()) {
return;
}
const ImageInfo &info = d_ptr->imageInfoList.at(index);
d_ptr->vulkanViewPtr->setImageUrl(info.fileInfo().absoluteFilePath());
}

void VulkanViewer::onImageLoaded(const QFileInfo &fileInfo, const QImage &image)
{
if (image.isNull()) {
return;
}
d_ptr->imageInfoList.append(ImageInfo(fileInfo, image));
d_ptr->imageListView->setImageInfoList(d_ptr->imageInfoList);
}

void VulkanViewer::setupUI()
{
auto *splitter = new QSplitter(Qt::Horizontal, this);
splitter->addWidget(QWidget::createWindowContainer(d_ptr->vulkanViewPtr.data()));
splitter->addWidget(toolWidget());
splitter->setStretchFactor(0, 1);
splitter->setStretchFactor(1, 1);
splitter->setSizes({INT_MAX, 1});

auto *layout = new QVBoxLayout(this);
layout->setContentsMargins(QMargins());
layout->addWidget(splitter);
layout->addWidget(d_ptr->imageListView);
}

auto VulkanViewer::toolWidget() -> QWidget *
{
auto *openImageButton = new QPushButton(tr("Open Picture"), this);
connect(openImageButton, &QPushButton::clicked, this, &VulkanViewer::onOpenImage);

auto *infoBox = new QGroupBox(tr("Image Information"), this);
auto *gridLayout = new QGridLayout(infoBox);
gridLayout->addWidget(new QLabel(tr("Url: "), this), 0, 0, 1, 1);
gridLayout->addWidget(d_ptr->urlLabel, 0, 1, 1, 1);
gridLayout->addWidget(new QLabel(tr("File Size: "), this), 1, 0, 1, 1);
gridLayout->addWidget(d_ptr->fileSizeLabel, 1, 1, 1, 1);
gridLayout->addWidget(new QLabel(tr("Image Size: "), this), 2, 0, 1, 1);
gridLayout->addWidget(d_ptr->sizeLabel, 2, 1, 1, 1);
gridLayout->addWidget(new QLabel(tr("Scaling Ratio:"), this), 3, 0, 1, 1);
gridLayout->addWidget(d_ptr->scaleLabel, 3, 1, 1, 1);

auto *widget = new QWidget(this);
widget->setMaximumWidth(300);
auto *rightLayout = new QVBoxLayout(widget);
rightLayout->addWidget(openImageButton);
rightLayout->addWidget(infoBox);
rightLayout->addStretch();

return widget;
}

void VulkanViewer::buildConnect()
{
connect(d_ptr->vulkanViewPtr.data(),
&GpuGraphics::VulkanView::scaleFactorChanged,
this,
&VulkanViewer::onScaleFactorChanged);
connect(d_ptr->vulkanViewPtr.data(),
&GpuGraphics::VulkanView::imageSizeChanged,
this,
&VulkanViewer::onImageSizeChanged);
connect(d_ptr->vulkanViewPtr.data(),
&GpuGraphics::VulkanView::imageUrlChanged,
this,
&VulkanViewer::onImageChanged);
connect(d_ptr->imageListView, &ImageListView::changeItem, this, &VulkanViewer::onChangedImage);
}

void VulkanViewer::startImageLoadThread(const QString &url)
{
d_ptr->taskCount.ref();
QThreadPool::globalInstance()->start(
new ImageLoadRunnable(url, this, d_ptr->taskCount.loadAcquire()));
}

void VulkanViewer::clearThumbnail()
{
if (d_ptr->imageInfoList.isEmpty()) {
return;
}
d_ptr->imageInfoList.clear();
d_ptr->imageListView->setImageInfoList(d_ptr->imageInfoList);
}
39 changes: 39 additions & 0 deletions examples/graphics/vulkanviewer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#ifndef VULKANVIEWER_HPP
#define VULKANVIEWER_HPP

#include "viewer.hpp"

class VulkanViewer : public Viewer
{
Q_OBJECT
public:
explicit VulkanViewer(QWidget *parent = nullptr);
~VulkanViewer() override;

auto setImage(const QFileInfo &info, const QImage &image, const qint64 taskCount)
-> bool override;

signals:
void imageReady(const QImage &);

private slots:
void onOpenImage();

void onScaleFactorChanged(qreal factor);
void onImageSizeChanged(const QSize &size);
void onImageChanged(const QString &url);
void onChangedImage(int index);
void onImageLoaded(const QFileInfo &fileInfo, const QImage &image);

private:
void setupUI();
auto toolWidget() -> QWidget *;
void buildConnect();
void startImageLoadThread(const QString &url);
void clearThumbnail();

class VulkanViewerPrivate;
QScopedPointer<VulkanViewerPrivate> d_ptr;
};

#endif // VULKANVIEWER_HPP
Loading

0 comments on commit 9ac4565

Please sign in to comment.