Page prefetching, bugfixing

This commit is contained in:
Jakub Melka 2019-12-15 17:46:58 +01:00
parent 618f334e5d
commit 3cd2dd5104
10 changed files with 94 additions and 24 deletions

View File

@ -92,7 +92,7 @@ void PDFAsynchronousPageCompiler::reset()
start();
}
const PDFPrecompiledPage* PDFAsynchronousPageCompiler::getPrecompiledCache(PDFInteger pageIndex, bool compile)
const PDFPrecompiledPage* PDFAsynchronousPageCompiler::getCompiledPage(PDFInteger pageIndex, bool compile)
{
if (m_state != State::Active || !m_proxy->getDocument())
{
@ -115,9 +115,8 @@ const PDFPrecompiledPage* PDFAsynchronousPageCompiler::getPrecompiledCache(PDFIn
CompileTask& task = m_tasks[pageIndex];
task.taskFuture = QtConcurrent::run(compilePage);
task.taskWatcher = new QFutureWatcher<PDFPrecompiledPage>(this);
task.taskWatcher->setFuture(task.taskFuture);
connect(task.taskWatcher, &QFutureWatcher<PDFPrecompiledPage>::finished, this, &PDFAsynchronousPageCompiler::onPageCompiled);
onPageCompiled();
task.taskWatcher->setFuture(task.taskFuture);
}
return page;

View File

@ -66,7 +66,7 @@ public:
/// task is performed.
/// \param pageIndex Index of page
/// \param compile Compile the page, if it is not found in the cache
const PDFPrecompiledPage* getPrecompiledCache(PDFInteger pageIndex, bool compile);
const PDFPrecompiledPage* getCompiledPage(PDFInteger pageIndex, bool compile);
signals:
void pageImageChanged(bool all, const std::vector<PDFInteger>& pages);

View File

@ -606,7 +606,7 @@ void PDFDrawWidgetProxy::draw(QPainter* painter, QRect rect)
// Clear the page space by white color
painter->fillRect(placedRect, Qt::white);
const PDFPrecompiledPage* compiledPage = m_compiler->getPrecompiledCache(item.pageIndex, true);
const PDFPrecompiledPage* compiledPage = m_compiler->getCompiledPage(item.pageIndex, true);
if (compiledPage && compiledPage->isValid())
{
QElapsedTimer timer;
@ -676,7 +676,7 @@ QImage PDFDrawWidgetProxy::drawThumbnailImage(PDFInteger pageIndex, int pixelSiz
if (imageSize.isValid())
{
const PDFPrecompiledPage* compiledPage = m_compiler->getPrecompiledCache(pageIndex, true);
const PDFPrecompiledPage* compiledPage = m_compiler->getCompiledPage(pageIndex, true);
if (compiledPage && compiledPage->isValid())
{
// Rasterize the image.
@ -957,6 +957,41 @@ void PDFDrawWidgetProxy::updateRenderer(bool useOpenGL, const QSurfaceFormat& su
m_rasterizer->reset(useOpenGL, surfaceFormat);
}
void PDFDrawWidgetProxy::prefetchPages(PDFInteger pageIndex)
{
// Determine number of pages, which should be prefetched. In case of two or more pages,
// we need to prefetch more pages (for example, two for two columns/two pages display mode).
int prefetchCount = 0;
switch (m_controller->getPageLayout())
{
case PageLayout::OneColumn:
case PageLayout::SinglePage:
prefetchCount = 1;
break;
case PageLayout::TwoPagesLeft:
case PageLayout::TwoPagesRight:
case PageLayout::TwoColumnLeft:
case PageLayout::TwoColumnRight:
prefetchCount = 2;
break;
default:
Q_ASSERT(false);
break;
}
if (const PDFDocument* document = getDocument())
{
const PDFInteger pageCount = document->getCatalog()->getPageCount();
const PDFInteger pageEnd = qMin(pageCount, pageIndex + prefetchCount + 1);
for (PDFInteger i = pageIndex + 1; i < pageEnd; ++i)
{
m_compiler->getCompiledPage(i, true);
}
}
}
void PDFDrawWidgetProxy::onHorizontalScrollbarValueChanged(int value)
{
if (!m_updateDisabled && !m_horizontalScrollbar->isHidden())

View File

@ -260,6 +260,10 @@ public:
/// \param surfaceFormat Surface format for OpenGL rendering
void updateRenderer(bool useOpenGL, const QSurfaceFormat& surfaceFormat);
/// Prefetches (prerenders) pages after page with pageIndex, i.e., prepares
/// for non-flickering scroll operation.
void prefetchPages(PDFInteger pageIndex);
static constexpr PDFReal ZOOM_STEP = 1.2;
const PDFDocument* getDocument() const { return m_controller->getDocument(); }

View File

@ -241,7 +241,7 @@ QImage PDFRasterizer::render(const PDFPage* page, const PDFPrecompiledPage* comp
compiledPage->draw(&painter, page->getCropBox(), matrix, features);
}
// Convert the image into format Format_ARGB32_Premultiplied for fast drawing.
// Jakub Melka: Convert the image into format Format_ARGB32_Premultiplied for fast drawing.
// If this format is used, then no image conversion is performed while drawing.
if (image.format() != QImage::Format_ARGB32_Premultiplied)
{
@ -304,13 +304,15 @@ void PDFRasterizer::releaseOpenGL()
if (m_surface)
{
Q_ASSERT(m_context);
Q_ASSERT(m_fbo);
// Delete framebuffer
m_context->makeCurrent(m_surface);
delete m_fbo;
m_fbo = nullptr;
m_context->doneCurrent();
if (m_fbo)
{
m_context->makeCurrent(m_surface);
delete m_fbo;
m_fbo = nullptr;
m_context->doneCurrent();
}
// Delete OpenGL context
delete m_context;

View File

@ -633,6 +633,12 @@ void PDFViewerMainWindow::updateUI(bool fullUpdate)
if (!currentPages.empty())
{
m_pageNumberSpinBox->setValue(currentPages.front() + 1);
// Prefetch pages, if it is enabled
if (m_settings->isPagePrefetchingEnabled())
{
m_pdfWidget->getDrawWidgetProxy()->prefetchPages(currentPages.back());
}
}
m_sidebarWidget->setCurrentPages(currentPages);

View File

@ -36,6 +36,7 @@ void PDFViewerSettings::readSettings(QSettings& settings)
m_settings.m_rendererEngine = static_cast<pdf::RendererEngine>(settings.value("renderingEngine", static_cast<int>(pdf::RendererEngine::OpenGL)).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();
m_settings.m_preferredMeshResolutionRatio = settings.value("preferredMeshResolutionRatio", defaultSettings.m_preferredMeshResolutionRatio).toDouble();
m_settings.m_minimalMeshResolutionRatio = settings.value("minimalMeshResolutionRatio", defaultSettings.m_minimalMeshResolutionRatio).toDouble();
m_settings.m_colorTolerance = settings.value("colorTolerance", defaultSettings.m_colorTolerance).toDouble();
@ -54,6 +55,7 @@ void PDFViewerSettings::writeSettings(QSettings& settings)
settings.setValue("renderingEngine", static_cast<int>(m_settings.m_rendererEngine));
settings.setValue("msaa", m_settings.m_multisampleAntialiasing);
settings.setValue("rendererSamples", m_settings.m_rendererSamples);
settings.setValue("prefetchPages", m_settings.m_prefetchPages);
settings.setValue("preferredMeshResolutionRatio", m_settings.m_preferredMeshResolutionRatio);
settings.setValue("minimalMeshResolutionRatio", m_settings.m_minimalMeshResolutionRatio);
settings.setValue("colorTolerance", m_settings.m_colorTolerance);

View File

@ -43,6 +43,7 @@ public:
m_rendererEngine(pdf::RendererEngine::OpenGL),
m_multisampleAntialiasing(true),
m_rendererSamples(16),
m_prefetchPages(true),
m_preferredMeshResolutionRatio(0.02),
m_minimalMeshResolutionRatio(0.005),
m_colorTolerance(0.01),
@ -57,6 +58,7 @@ public:
pdf::RendererEngine m_rendererEngine;
bool m_multisampleAntialiasing;
int m_rendererSamples;
bool m_prefetchPages;
pdf::PDFReal m_preferredMeshResolutionRatio;
pdf::PDFReal m_minimalMeshResolutionRatio;
pdf::PDFReal m_colorTolerance;
@ -82,6 +84,7 @@ public:
int getRendererSamples() const;
void setRendererSamples(int rendererSamples);
bool isPagePrefetchingEnabled() const { return m_settings.m_prefetchPages; }
bool isMultisampleAntialiasingEnabled() const { return m_settings.m_multisampleAntialiasing; }
pdf::PDFReal getPreferredMeshResolutionRatio() const { return m_settings.m_preferredMeshResolutionRatio; }

View File

@ -133,6 +133,7 @@ void PDFViewerSettingsDialog::loadData()
ui->multisampleAntialiasingSamplesCountComboBox->setEnabled(false);
ui->multisampleAntialiasingSamplesCountComboBox->setCurrentIndex(-1);
}
ui->prefetchPagesCheckBox->setChecked(m_settings.m_prefetchPages);
// Rendering
ui->antialiasingCheckBox->setChecked(m_settings.m_features.testFlag(pdf::PDFRenderer::Antialiasing));
@ -173,6 +174,10 @@ void PDFViewerSettingsDialog::saveData()
{
m_settings.m_rendererSamples = ui->multisampleAntialiasingSamplesCountComboBox->currentData().toInt();
}
else if (sender == ui->prefetchPagesCheckBox)
{
m_settings.m_prefetchPages = ui->prefetchPagesCheckBox->isChecked();
}
else if (sender == ui->antialiasingCheckBox)
{
m_settings.m_features.setFlag(pdf::PDFRenderer::Antialiasing, ui->antialiasingCheckBox->isChecked());

View File

@ -26,7 +26,7 @@
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="enginePage">
<layout class="QVBoxLayout" name="enginePageLayout">
@ -50,16 +50,6 @@
<layout class="QVBoxLayout" name="engineSettingsGroupBoxLayout">
<item>
<layout class="QGridLayout" name="engineSettingsGridLayout">
<item row="0" column="0">
<widget class="QLabel" name="renderingEngineLabel">
<property name="text">
<string>Rendering engine</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="renderingEngineComboBox"/>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="multisampleAntialiasingCheckBox">
<property name="text">
@ -84,12 +74,36 @@
<item row="2" column="1">
<widget class="QComboBox" name="multisampleAntialiasingSamplesCountComboBox"/>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="renderingEngineComboBox"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="renderingEngineLabel">
<property name="text">
<string>Rendering engine</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="prefetchPagesLabel">
<property name="text">
<string>Prefetch pages</string>
</property>
</widget>
</item>
<item row="3" 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;Select rendering method according to your needs. &lt;span style=&quot; font-weight:600;&quot;&gt;Software rendering&lt;/span&gt; is much slower than hardware accelerated rendering using &lt;span style=&quot; font-weight:600;&quot;&gt;OpenGL rendering&lt;/span&gt;, but it works when OpenGL is not available at your platform. OpenGL rendering is selected as default and is recommended.&lt;/p&gt;&lt;p&gt;OpenGL rendering uses&lt;span style=&quot; font-weight:600;&quot;&gt; multisample antialiasing (MSAA)&lt;/span&gt;, which provides good quality antialiasing. You can turn this feature on or off, but without antialiasing, bad quality image can occur. Samples count affect how much samples per pixel are considered to determine pixel color. It can be a value 1, 2, 4, 8, and 16. Most modern GPUs support at least value 8. Lower this value, if your GPU doesn't support the desired sample count.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select rendering method according to your needs. &lt;span style=&quot; font-weight:600;&quot;&gt;Software rendering&lt;/span&gt; is much slower than hardware accelerated rendering using &lt;span style=&quot; font-weight:600;&quot;&gt;OpenGL rendering&lt;/span&gt;, but it works when OpenGL is not available at your platform. OpenGL rendering is selected as default and is recommended.&lt;/p&gt;&lt;p&gt;OpenGL rendering uses&lt;span style=&quot; font-weight:600;&quot;&gt; multisample antialiasing (MSAA)&lt;/span&gt;, which provides good quality antialiasing. You can turn this feature on or off, but without antialiasing, bad quality image can occur. Samples count affect how much samples per pixel are considered to determine pixel color. It can be a value 1, 2, 4, 8, and 16. Most modern GPUs support at least value 8. Lower this value, if your GPU doesn't support the desired sample count.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Prefetch pages &lt;/span&gt;prefetches (pre-renders) pages next to currently viewed pages, to avoid flickering during scrolling. Prefetched pages are stored in the page cache.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>