Issue #123: Alternative software rendering backend

This commit is contained in:
Jakub Melka
2024-02-04 18:05:38 +01:00
parent 87cedf01dc
commit d314683d38
48 changed files with 872 additions and 761 deletions

View File

@ -86,10 +86,6 @@ GENERATE_EXPORT_HEADER(Pdf4QtViewer
PDF4QTVIEWERLIBSHARED_EXPORT
EXPORT_FILE_NAME "${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR}/pdf4qtviewer_export.h")
if(PDF4QT_ENABLE_OPENGL)
target_link_libraries(Pdf4QtViewer PRIVATE Qt6::OpenGLWidgets)
endif()
target_link_libraries(Pdf4QtViewer PRIVATE Pdf4QtLibCore Pdf4QtLibWidgets Qt6::Core Qt6::Gui Qt6::Widgets Qt6::PrintSupport Qt6::TextToSpeech Qt6::Xml Qt6::Svg)
target_include_directories(Pdf4QtViewer INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(Pdf4QtViewer PUBLIC ${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR})

View File

@ -2298,24 +2298,6 @@ void PDFProgramController::resetSettings()
}
}
void PDFProgramController::checkHardwareOpenGLAvailability()
{
if (m_settings->getRendererEngine() == pdf::RendererEngine::OpenGL &&
!pdf::PDFRendererInfo::isHardwareAccelerationSupported())
{
#ifdef PDF4QT_ENABLE_OPENGL
pdf::PDFRendererInfo::Info info = pdf::PDFRendererInfo::getHardwareAccelerationSupportedInfo();
QMessageBox::warning(m_mainWindow, tr("Warning"),
tr("Hardware acceleration is not supported on this device. "
"OpenGL version at least 3.2 is required. Software rendering is used instead. "
"Available OpenGL is %1 using %2. You can turn off hardware acceleration "
"in 'Tools' menu using 'Options' item to stop displaying this message.").arg(info.version, info.renderer));
#else
QMessageBox::warning(m_mainWindow, tr("Warning"), tr("Hardware acceleration is not enabled in this build."));
#endif
}
}
void PDFProgramController::onActionOptionsTriggered()
{
PDFViewerSettingsDialog::OtherSettings otherSettings;

View File

@ -297,8 +297,6 @@ public:
void writeSettings();
void resetSettings();
void checkHardwareOpenGLAvailability();
void performPrint();
void performSave();
void performSaveAs();

View File

@ -299,7 +299,7 @@ void PDFRenderToImagesDialog::on_buttonBox_clicked(QAbstractButton* button)
m_cms = m_proxy->getCMSManager()->getCurrentCMS();
m_rasterizerPool = new pdf::PDFRasterizerPool(m_document, m_proxy->getFontCache(), m_proxy->getCMSManager(),
m_optionalContentActivity, m_proxy->getFeatures(), m_proxy->getMeshQualitySettings(),
pdf::PDFRasterizerPool::getDefaultRasterizerCount(), m_proxy->isUsingOpenGL(), m_proxy->getSurfaceFormat(), this);
pdf::PDFRasterizerPool::getDefaultRasterizerCount(), m_proxy->getRendererEngine(), this);
connect(m_rasterizerPool, &pdf::PDFRasterizerPool::renderError, this, &PDFRenderToImagesDialog::onRenderError);
auto process = [this]()

View File

@ -543,7 +543,6 @@ void PDFViewerMainWindow::showEvent(QShowEvent* event)
{
QMainWindow::showEvent(event);
m_progressTaskbarIndicator->setWindow(windowHandle());
QTimer::singleShot(0, this, [this] { m_programController->checkHardwareOpenGLAvailability(); });
}
void PDFViewerMainWindow::dragEnterEvent(QDragEnterEvent* event)

View File

@ -432,7 +432,6 @@ void PDFViewerMainWindowLite::showEvent(QShowEvent* event)
{
QMainWindow::showEvent(event);
m_progressTaskbarIndicator->setWindow(windowHandle());
QTimer::singleShot(0, this, [this] { m_programController->checkHardwareOpenGLAvailability(); });
}
void PDFViewerMainWindowLite::dragEnterEvent(QDragEnterEvent* event)

View File

@ -43,7 +43,7 @@ void PDFViewerSettings::readSettings(QSettings& settings, const pdf::PDFCMSSetti
settings.beginGroup("ViewerSettings");
m_settings.m_directory = settings.value("defaultDirectory", QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)).toString();
m_settings.m_features = static_cast<pdf::PDFRenderer::Features>(settings.value("rendererFeaturesv2", static_cast<int>(pdf::PDFRenderer::getDefaultFeatures())).toInt());
m_settings.m_rendererEngine = static_cast<pdf::RendererEngine>(settings.value("renderingEngine", static_cast<int>(pdf::RendererEngine::OpenGL)).toInt());
m_settings.m_rendererEngine = static_cast<pdf::RendererEngine>(settings.value("renderingEngine", static_cast<int>(pdf::RendererEngine::Blend2D)).toInt());
m_settings.m_multisampleAntialiasing = settings.value("msaa", defaultSettings.m_multisampleAntialiasing).toBool();
m_settings.m_rendererSamples = settings.value("rendererSamples", defaultSettings.m_rendererSamples).toInt();
m_settings.m_prefetchPages = settings.value("prefetchPages", defaultSettings.m_prefetchPages).toBool();
@ -271,7 +271,7 @@ void PDFViewerSettings::setColorTolerance(pdf::PDFReal colorTolerance)
PDFViewerSettings::Settings::Settings() :
m_features(pdf::PDFRenderer::getDefaultFeatures()),
m_rendererEngine(pdf::RendererEngine::OpenGL),
m_rendererEngine(pdf::RendererEngine::Blend2D),
m_multisampleAntialiasing(true),
m_rendererSamples(16),
m_prefetchPages(true),

View File

@ -52,8 +52,6 @@ public:
pdf::PDFRenderer::Features m_features;
QString m_directory;
pdf::RendererEngine m_rendererEngine;
bool m_multisampleAntialiasing;
int m_rendererSamples;
bool m_prefetchPages;
pdf::PDFReal m_preferredMeshResolutionRatio;
pdf::PDFReal m_minimalMeshResolutionRatio;

View File

@ -102,8 +102,8 @@ PDFViewerSettingsDialog::PDFViewerSettingsDialog(const PDFViewerSettings::Settin
font.setPointSize(font.pointSize() * 1.5);
ui->optionsPagesWidget->setFont(font);
ui->renderingEngineComboBox->addItem(tr("Software"), static_cast<int>(pdf::RendererEngine::Software));
ui->renderingEngineComboBox->addItem(tr("Hardware accelerated (OpenGL)"), static_cast<int>(pdf::RendererEngine::OpenGL));
ui->renderingEngineComboBox->addItem(tr("Software | QPainter"), static_cast<int>(pdf::RendererEngine::QPainter));
ui->renderingEngineComboBox->addItem(tr("Software | Blend2D | Multithreaded"), static_cast<int>(pdf::RendererEngine::Blend2D));
for (int i : { 1, 2, 4, 8, 16 })
{
@ -279,29 +279,6 @@ void PDFViewerSettingsDialog::loadData()
ui->renderingEngineComboBox->setCurrentIndex(ui->renderingEngineComboBox->findData(static_cast<int>(m_settings.m_rendererEngine)));
// Engine
if (m_settings.m_rendererEngine == pdf::RendererEngine::OpenGL)
{
ui->multisampleAntialiasingCheckBox->setEnabled(true);
ui->multisampleAntialiasingCheckBox->setChecked(m_settings.m_multisampleAntialiasing);
if (m_settings.m_multisampleAntialiasing)
{
ui->multisampleAntialiasingSamplesCountComboBox->setEnabled(true);
ui->multisampleAntialiasingSamplesCountComboBox->setCurrentIndex(ui->multisampleAntialiasingSamplesCountComboBox->findData(m_settings.m_rendererSamples));
}
else
{
ui->multisampleAntialiasingSamplesCountComboBox->setEnabled(false);
ui->multisampleAntialiasingSamplesCountComboBox->setCurrentIndex(-1);
}
}
else
{
ui->multisampleAntialiasingCheckBox->setEnabled(false);
ui->multisampleAntialiasingCheckBox->setChecked(false);
ui->multisampleAntialiasingSamplesCountComboBox->setEnabled(false);
ui->multisampleAntialiasingSamplesCountComboBox->setCurrentIndex(-1);
}
ui->prefetchPagesCheckBox->setChecked(m_settings.m_prefetchPages);
ui->multithreadingComboBox->setCurrentIndex(ui->multithreadingComboBox->findData(static_cast<int>(m_settings.m_multithreadingStrategy)));

View File

@ -35,7 +35,7 @@
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>6</number>
<number>0</number>
</property>
<widget class="QWidget" name="enginePage">
<layout class="QVBoxLayout" name="enginePageLayout">
@ -59,47 +59,16 @@
<layout class="QVBoxLayout" name="engineSettingsGroupBoxLayout">
<item>
<layout class="QGridLayout" name="engineSettingsGridLayout">
<item row="1" column="1">
<widget class="QCheckBox" name="multisampleAntialiasingCheckBox">
<item row="2" column="0">
<widget class="QLabel" name="multithreadingLabel">
<property name="text">
<string>Enable</string>
<string>Multithreading strategy</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="renderingEngineComboBox"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="multisampleAntialiasingLabel">
<property name="text">
<string>Multisample antialiasing (MSAA)</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="multisampleAntialiasingSamplesCountComboBox"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="prefetchPagesLabel">
<property name="text">
<string>Prefetch pages</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="multisampleAntiailasingSamplesLabel">
<property name="text">
<string>MSAA Samples count</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="prefetchPagesCheckBox">
<property name="text">
<string>Enable</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="renderingEngineLabel">
<property name="text">
@ -107,22 +76,29 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="multithreadingLabel">
<item row="1" column="0">
<widget class="QLabel" name="prefetchPagesLabel">
<property name="text">
<string>Multithreading strategy</string>
<string>Prefetch pages</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="2" column="1">
<widget class="QComboBox" name="multithreadingComboBox"/>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="prefetchPagesCheckBox">
<property name="text">
<string>Enable</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="engineInfoLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Choose a rendering method based on your needs. Although &lt;span style=&quot; font-weight:600;&quot;&gt;Software Rendering&lt;/span&gt; is slower than the hardware-accelerated &lt;span style=&quot; font-weight:600;&quot;&gt;OpenGL Rendering&lt;/span&gt;, it can be utilized when OpenGL is not available on your platform. The default (and recommended) method is OpenGL Rendering. &lt;/p&gt;&lt;p&gt;OpenGL rendering employs &lt;span style=&quot; font-weight:600;&quot;&gt;Multisample Antialiasing (MSAA)&lt;/span&gt;, ensuring high-quality image rendering. You have the option to enable or disable this feature. However, disabling it might lead to inferior image quality. The Samples Count sets the number of samples per pixel used to determine pixel color. It can be set to 1, 2, 4, 8, or 16. Most modern GPUs support at least a value of 8. If your GPU doesn't support the desired sample count, lower this value. &lt;/p&gt;&lt;p&gt;The &lt;span style=&quot; font-weight:600;&quot;&gt;Prefetch Pages&lt;/span&gt; feature pre-renders pages adjacent to the currently viewed pages, minimizing flickering during scrolling. Prefetched pages are stored in the page cache. &lt;/p&gt;&lt;p&gt;The &lt;span style=&quot; font-weight:600;&quot;&gt;Multithreading Strategy&lt;/span&gt; determines how the program will utilize CPU cores. With the &lt;span style=&quot; font-weight:600;&quot;&gt;Single Thread&lt;/span&gt; strategy, only one CPU core is used for rendering a page. This results in longer processing times, but each page is independently compiled/drawn in its own thread. Alternatively, there are two multithreading strategies: Load Balanced and Maximum Threads. Load Balanced only parallelizes pages without processing individual page content. In contrast, the Maximum Threads strategy spawns as many threads as possible for operations to achieve optimal performance. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select a rendering method tailored to your application's requirements. Software Rendering, utilizing QPainter, is a versatile choice that guarantees compatibility across all platforms. It's particularly useful in scenarios where direct access to hardware acceleration isn't crucial. QPainter, part of the Qt framework, excels in rendering 2D graphics with support for various painting styles, image processing, and intricate graphical transformations, making it an excellent tool for applications that require detailed and sophisticated 2D graphics without relying on hardware acceleration.&lt;/p&gt;&lt;p&gt;On the other hand, for applications that demand high-performance rendering, leveraging the Blend2D library offers a compelling alternative. Blend2D is a high-performance 2D vector graphics engine that utilizes multi-threading to accelerate the rendering process. It does not rely on QPainter or hardware acceleration but instead offers a software-based rendering solution optimized for speed and quality. Blend2D's advanced anti-aliasing techniques ensure crisp and clear image quality, making it suitable for applications where rendering performance and image quality are paramount.&lt;/p&gt;&lt;p&gt;The Prefetch Pages feature is a strategy that can be applied regardless of the rendering method chosen. By pre-rendering pages adjacent to the currently viewed content, this approach minimizes flickering and enhances the smoothness of transitions during scrolling, improving the overall user experience.&lt;/p&gt;&lt;p&gt;When it comes to optimizing the rendering process, the choice of multithreading strategy plays a crucial role. A Single Thread strategy, where rendering tasks are executed sequentially on a single CPU core, might be preferable in environments where simplicity and predictability are key. For more demanding applications, employing a Multi-threading strategy can significantly improve rendering times. Strategies like Load Balanced distribute the workload evenly across CPU cores without delving into content-specific processing, offering a good performance boost. The Maximum Threads strategy takes full advantage of available CPU resources by allocating as many threads as possible to the rendering tasks, achieving optimal performance and minimizing rendering times.&lt;/p&gt;&lt;p&gt;This delineation between using QPainter for software rendering and Blend2D for high-performance, multi-threaded rendering allows developers to choose the most appropriate rendering pathway based on their specific performance requirements and the graphical complexity of their application.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>