Issue #46: Program does not launch/freezes on Windows 10/Windows Server 2022 (x64)

This commit is contained in:
Jakub Melka 2023-04-22 13:17:42 +02:00
parent 66c6e23346
commit 6224f226b2
8 changed files with 148 additions and 6 deletions

View File

@ -44,7 +44,7 @@ PDFWidget::PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, int
m_verticalScrollBar(nullptr), m_verticalScrollBar(nullptr),
m_proxy(nullptr) m_proxy(nullptr)
{ {
m_drawWidget = createDrawWidget(engine, samplesCount); m_drawWidget = createDrawWidget(getEffectiveRenderer(engine), samplesCount);
m_horizontalScrollBar = new QScrollBar(Qt::Horizontal, this); m_horizontalScrollBar = new QScrollBar(Qt::Horizontal, this);
m_verticalScrollBar = new QScrollBar(Qt::Vertical, this); m_verticalScrollBar = new QScrollBar(Qt::Vertical, this);
@ -90,6 +90,8 @@ void PDFWidget::setDocument(const PDFModifiedDocument& document)
void PDFWidget::updateRenderer(RendererEngine engine, int samplesCount) void PDFWidget::updateRenderer(RendererEngine engine, int samplesCount)
{ {
engine = getEffectiveRenderer(engine);
PDFOpenGLDrawWidget* openglDrawWidget = qobject_cast<PDFOpenGLDrawWidget*>(m_drawWidget->getWidget()); PDFOpenGLDrawWidget* openglDrawWidget = qobject_cast<PDFOpenGLDrawWidget*>(m_drawWidget->getWidget());
PDFDrawWidget* softwareDrawWidget = qobject_cast<PDFDrawWidget*>(m_drawWidget->getWidget()); PDFDrawWidget* softwareDrawWidget = qobject_cast<PDFDrawWidget*>(m_drawWidget->getWidget());
@ -207,6 +209,16 @@ void PDFWidget::addInputInterface(IDrawWidgetInputInterface* inputInterface)
} }
} }
RendererEngine PDFWidget::getEffectiveRenderer(RendererEngine rendererEngine)
{
if (rendererEngine == RendererEngine::OpenGL && !pdf::PDFRendererInfo::isHardwareAccelerationSupported())
{
return RendererEngine::Software;
}
return rendererEngine;
}
PDFFormManager* PDFWidget::getFormManager() const PDFFormManager* PDFWidget::getFormManager() const
{ {
return m_formManager; return m_formManager;
@ -590,10 +602,13 @@ void PDFOpenGLDrawWidget::initializeGL()
} }
void PDFOpenGLDrawWidget::paintGL() void PDFOpenGLDrawWidget::paintGL()
{
if (this->isValid())
{ {
QPainter painter(this); QPainter painter(this);
getPDFWidget()->getDrawWidgetProxy()->draw(&painter, this->rect()); getPDFWidget()->getDrawWidgetProxy()->draw(&painter, this->rect());
} }
}
PDFDrawWidget::PDFDrawWidget(PDFWidget* widget, QWidget* parent) : PDFDrawWidget::PDFDrawWidget(PDFWidget* widget, QWidget* parent) :
BaseClass(widget, parent) BaseClass(widget, parent)

View File

@ -106,6 +106,8 @@ signals:
void pageRenderingErrorsChanged(pdf::PDFInteger pageIndex, int errorsCount); void pageRenderingErrorsChanged(pdf::PDFInteger pageIndex, int errorsCount);
private: private:
RendererEngine getEffectiveRenderer(RendererEngine rendererEngine);
void updateRendererImpl(); void updateRendererImpl();
void onRenderingError(PDFInteger pageIndex, const QList<PDFRenderError>& errors); void onRenderingError(PDFInteger pageIndex, const QList<PDFRenderError>& errors);
void onPageImageChanged(bool all, const std::vector<PDFInteger>& pages); void onPageImageChanged(bool all, const std::vector<PDFInteger>& pages);

View File

@ -29,6 +29,7 @@
#include <QOffscreenSurface> #include <QOffscreenSurface>
#include <QOpenGLPaintDevice> #include <QOpenGLPaintDevice>
#include <QOpenGLFramebufferObject> #include <QOpenGLFramebufferObject>
#include <QOpenGLFunctions>
namespace pdf namespace pdf
{ {
@ -204,6 +205,12 @@ PDFRasterizer::~PDFRasterizer()
void PDFRasterizer::reset(bool useOpenGL, const QSurfaceFormat& surfaceFormat) void PDFRasterizer::reset(bool useOpenGL, const QSurfaceFormat& surfaceFormat)
{ {
if (!PDFRendererInfo::isHardwareAccelerationSupported())
{
m_features.setFlag(FailedOpenGL, true);
m_features.setFlag(ValidOpenGL, false);
}
if (useOpenGL != m_features.testFlag(UseOpenGL) || surfaceFormat != m_surfaceFormat) if (useOpenGL != m_features.testFlag(UseOpenGL) || surfaceFormat != m_surfaceFormat)
{ {
// In either case, we must reset OpenGL // In either case, we must reset OpenGL
@ -927,4 +934,78 @@ PDFRasterizerPool::PDFRasterizerPool(const PDFDocument* document,
} }
} }
PDFCachedItem<PDFRendererInfo::Info> PDFRendererInfo::s_info;
const PDFRendererInfo::Info& PDFRendererInfo::getHardwareAccelerationSupportedInfo()
{
auto getInfo = []()
{
Info info;
QOffscreenSurface surface;
surface.create();
if (!surface.isValid())
{
info.renderer = PDFTranslationContext::tr("Unknown Device");
info.version = PDFTranslationContext::tr("?.?");
info.vendor = PDFTranslationContext::tr("Generic");
return info;
}
QOpenGLContext context;
if (!context.create())
{
info.renderer = PDFTranslationContext::tr("Unknown Device");
info.version = PDFTranslationContext::tr("?.?");
info.vendor = PDFTranslationContext::tr("Generic");
surface.destroy();
return info;
}
if (!context.makeCurrent(&surface))
{
info.renderer = PDFTranslationContext::tr("Unknown Device");
info.version = PDFTranslationContext::tr("?.?");
info.vendor = PDFTranslationContext::tr("Generic");
surface.destroy();
return info;
}
const char* versionStr = reinterpret_cast<const char*>(context.functions()->glGetString(GL_VERSION));
const char* vendorStr = reinterpret_cast<const char*>(context.functions()->glGetString(GL_VENDOR));
const char* rendererStr = reinterpret_cast<const char*>(context.functions()->glGetString(GL_RENDERER));
QString versionString = QString::fromLocal8Bit(versionStr, std::strlen(versionStr));
QString vendorString = QString::fromLocal8Bit(vendorStr, std::strlen(vendorStr));
QString rendererString = QString::fromLocal8Bit(rendererStr, std::strlen(rendererStr));
context.doneCurrent();
surface.destroy();
info.vendor = vendorString;
info.renderer = rendererString;
info.version = versionString;
QStringList versionStrSplitted = versionString.split('.', Qt::KeepEmptyParts);
if (versionStrSplitted.size() >= 2)
{
info.majorOpenGLVersion = versionStrSplitted[0].toInt();
info.minorOpenGLVersion = versionStrSplitted[1].toInt();
}
return info;
};
return s_info.get(getInfo);
}
bool PDFRendererInfo::isHardwareAccelerationSupported()
{
const Info& info = getHardwareAccelerationSupportedInfo();
return std::make_pair(info.majorOpenGLVersion, info.minorOpenGLVersion) >= std::make_pair(REQUIRED_OPENGL_MAJOR_VERSION, REQUIRED_OPENGL_MINOR_VERSION);
}
} // namespace pdf } // namespace pdf

View File

@ -22,6 +22,7 @@
#include "pdfexception.h" #include "pdfexception.h"
#include "pdfoperationcontrol.h" #include "pdfoperationcontrol.h"
#include "pdfmeshqualitysettings.h" #include "pdfmeshqualitysettings.h"
#include "pdfutils.h"
#include <QMutex> #include <QMutex>
#include <QSemaphore> #include <QSemaphore>
@ -44,6 +45,30 @@ class PDFPrecompiledPage;
class PDFAnnotationManager; class PDFAnnotationManager;
class PDFOptionalContentActivity; class PDFOptionalContentActivity;
class PDF4QTLIBSHARED_EXPORT PDFRendererInfo
{
public:
PDFRendererInfo() = delete;
struct Info
{
QString vendor;
QString renderer;
QString version;
int majorOpenGLVersion = 0;
int minorOpenGLVersion = 0;
};
static const Info& getHardwareAccelerationSupportedInfo();
static bool isHardwareAccelerationSupported();
static constexpr int REQUIRED_OPENGL_MAJOR_VERSION = 3;
static constexpr int REQUIRED_OPENGL_MINOR_VERSION = 2;
private:
static PDFCachedItem<Info> s_info;
};
/// Renders the PDF page on the painter, or onto an image. /// Renders the PDF page on the painter, or onto an image.
class PDF4QTLIBSHARED_EXPORT PDFRenderer class PDF4QTLIBSHARED_EXPORT PDFRenderer
{ {
@ -144,8 +169,9 @@ public:
/// Resets the renderer. This function must be called from main GUI thread, /// Resets the renderer. This function must be called from main GUI thread,
/// it cannot be called from deferred threads, because it can create hidden /// it cannot be called from deferred threads, because it can create hidden
/// window (offscreen surface). /// window (offscreen surface). If hardware renderer is required, and
/// \param useOpenGL Use OpenGL for rendering /// none is available, then software renderer is used.
/// \param useOpenGL Use OpenGL for rendering (ignored if not available)
/// \param surfaceFormat Surface format to render /// \param surfaceFormat Surface format to render
void reset(bool useOpenGL, const QSurfaceFormat& surfaceFormat); void reset(bool useOpenGL, const QSurfaceFormat& surfaceFormat);

View File

@ -2028,6 +2028,20 @@ void PDFProgramController::resetSettings()
} }
} }
void PDFProgramController::checkHardwareOpenGLAvailability()
{
if (m_settings->getRendererEngine() == pdf::RendererEngine::OpenGL &&
!pdf::PDFRendererInfo::isHardwareAccelerationSupported())
{
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));
}
}
void PDFProgramController::onActionOptionsTriggered() void PDFProgramController::onActionOptionsTriggered()
{ {
PDFViewerSettingsDialog::OtherSettings otherSettings; PDFViewerSettingsDialog::OtherSettings otherSettings;

View File

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

View File

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

View File

@ -412,8 +412,9 @@ void PDFViewerMainWindowLite::closeEvent(QCloseEvent* event)
void PDFViewerMainWindowLite::showEvent(QShowEvent* event) void PDFViewerMainWindowLite::showEvent(QShowEvent* event)
{ {
Q_UNUSED(event); QMainWindow::showEvent(event);
m_progressTaskbarIndicator->setWindow(windowHandle()); m_progressTaskbarIndicator->setWindow(windowHandle());
QTimer::singleShot(0, this, [this] { m_programController->checkHardwareOpenGLAvailability(); });
} }
void PDFViewerMainWindowLite::dragEnterEvent(QDragEnterEvent* event) void PDFViewerMainWindowLite::dragEnterEvent(QDragEnterEvent* event)