summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/configure.json7
-rw-r--r--src/gui/doc/qtgui.qdocconf1
-rw-r--r--src/gui/doc/snippets/textblock-fragments/mainwindow.cpp2
-rw-r--r--src/gui/doc/snippets/textdocument-blocks/mainwindow.cpp2
-rw-r--r--src/gui/image/qpnghandler.cpp2
-rw-r--r--src/gui/image/qxpmhandler.cpp30
-rw-r--r--src/gui/kernel/qguiapplication.cpp7
-rw-r--r--src/gui/kernel/qguiapplication_p.h2
-rw-r--r--src/gui/kernel/qhighdpiscaling.cpp50
-rw-r--r--src/gui/kernel/qhighdpiscaling_p.h37
-rw-r--r--src/gui/kernel/qopenglcontext.cpp3
-rw-r--r--src/gui/kernel/qopenglcontext_p.h5
-rw-r--r--src/gui/kernel/qsimpledrag.cpp14
-rw-r--r--src/gui/opengl/qopenglpaintengine.cpp5
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp6
-rw-r--r--src/gui/painting/qpainter.h6
-rw-r--r--src/gui/painting/qpainterpath.cpp3
-rw-r--r--src/gui/rhi/qrhi.cpp74
-rw-r--r--src/gui/rhi/qrhi_p.h10
-rw-r--r--src/gui/rhi/qrhi_p_p.h4
-rw-r--r--src/gui/rhi/qrhid3d11.cpp38
-rw-r--r--src/gui/rhi/qrhid3d11_p_p.h3
-rw-r--r--src/gui/rhi/qrhigles2.cpp227
-rw-r--r--src/gui/rhi/qrhigles2_p_p.h18
-rw-r--r--src/gui/rhi/qrhimetal.mm8
-rw-r--r--src/gui/rhi/qrhivulkan.cpp26
-rw-r--r--src/gui/rhi/qrhivulkan_p_p.h2
-rw-r--r--src/gui/rhi/qshader.cpp2
-rw-r--r--src/gui/rhi/rhi.pri2
-rw-r--r--src/gui/text/qfont.cpp6
-rw-r--r--src/gui/text/qfontdatabase.cpp27
-rw-r--r--src/gui/text/qtextdocument.cpp33
-rw-r--r--src/gui/text/qtextdocument_p.h1
-rw-r--r--src/gui/text/qtexthtmlparser.cpp11
-rw-r--r--src/gui/text/qtextmarkdownwriter.cpp5
-rw-r--r--src/gui/text/qtextmarkdownwriter_p.h5
-rw-r--r--src/gui/util/qdesktopservices.cpp4
-rw-r--r--src/gui/util/qshaderlanguage_p.h2
-rw-r--r--src/gui/vulkan/vulkan.pri72
39 files changed, 532 insertions, 230 deletions
diff --git a/src/gui/configure.json b/src/gui/configure.json
index c7bafb8925..764e92a729 100644
--- a/src/gui/configure.json
+++ b/src/gui/configure.json
@@ -1357,9 +1357,14 @@
"condition": "features.opengl-desktop || features.opengl-dynamic || features.opengles2",
"output": [ "publicFeature", "feature" ]
},
+ "vkgen": {
+ "label": "vkgen",
+ "condition": "features.xmlstreamreader",
+ "output": [ "privateFeature" ]
+ },
"vulkan": {
"label": "Vulkan",
- "condition": "libs.vulkan",
+ "condition": "features.vkgen && libs.vulkan",
"output": [ "publicFeature" ]
},
"openvg": {
diff --git a/src/gui/doc/qtgui.qdocconf b/src/gui/doc/qtgui.qdocconf
index b8b8a00cd6..049b9ef179 100644
--- a/src/gui/doc/qtgui.qdocconf
+++ b/src/gui/doc/qtgui.qdocconf
@@ -1,4 +1,5 @@
include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
+include($QT_INSTALL_DOCS/config/exampleurl-qtbase.qdocconf)
project = QtGui
description = Qt GUI Reference Documentation
diff --git a/src/gui/doc/snippets/textblock-fragments/mainwindow.cpp b/src/gui/doc/snippets/textblock-fragments/mainwindow.cpp
index bf864ce48d..236d6952e6 100644
--- a/src/gui/doc/snippets/textblock-fragments/mainwindow.cpp
+++ b/src/gui/doc/snippets/textblock-fragments/mainwindow.cpp
@@ -114,7 +114,7 @@ void MainWindow::insertCalendar()
int year = date.year(), month = date.month();
for (int weekDay = 1; weekDay <= 7; ++weekDay) {
- cursor.insertText(QString("%1 ").arg(QDate::shortDayName(weekDay), 3),
+ cursor.insertText(QString("%1 ").arg(QLocale::system().dayName(weekDay), 3),
boldFormat);
}
diff --git a/src/gui/doc/snippets/textdocument-blocks/mainwindow.cpp b/src/gui/doc/snippets/textdocument-blocks/mainwindow.cpp
index a5801da67e..849f0e957f 100644
--- a/src/gui/doc/snippets/textdocument-blocks/mainwindow.cpp
+++ b/src/gui/doc/snippets/textdocument-blocks/mainwindow.cpp
@@ -117,7 +117,7 @@ void MainWindow::insertCalendar()
int year = date.year(), month = date.month();
for (int weekDay = 1; weekDay <= 7; ++weekDay) {
- cursor.insertText(QString("%1 ").arg(QDate::shortDayName(weekDay), 3),
+ cursor.insertText(QString("%1 ").arg(QLocale::system().dayName(weekDay), 3),
boldFormat);
}
diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp
index 39d0807606..864a944fcb 100644
--- a/src/gui/image/qpnghandler.cpp
+++ b/src/gui/image/qpnghandler.cpp
@@ -417,7 +417,7 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scal
}
QSize outSize(width,height);
if (!scaledSize.isEmpty() && quint32(scaledSize.width()) <= width &&
- quint32(scaledSize.height()) <= height && interlace_method == PNG_INTERLACE_NONE) {
+ quint32(scaledSize.height()) <= height && scaledSize != outSize && interlace_method == PNG_INTERLACE_NONE) {
// Do inline downscaling
outSize = scaledSize;
if (doScaledRead)
diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp
index deff56aa58..cf105b250a 100644
--- a/src/gui/image/qxpmhandler.cpp
+++ b/src/gui/image/qxpmhandler.cpp
@@ -1125,8 +1125,6 @@ static bool write_xpm_image(const QImage &sourceImage, QIODevice *device, const
break;
}
- QString line;
-
// write header
QTextStream s(device);
s << "/* XPM */" << Qt::endl
@@ -1137,35 +1135,29 @@ static bool write_xpm_image(const QImage &sourceImage, QIODevice *device, const
QMap<QRgb, int>::Iterator c = colorMap.begin();
while (c != colorMap.end()) {
QRgb color = c.key();
- if (image.format() != QImage::Format_RGB32 && !qAlpha(color))
- line = QString::asprintf("\"%s c None\"",
- xpm_color_name(cpp, *c));
- else
- line = QString::asprintf("\"%s c #%02x%02x%02x\"",
- xpm_color_name(cpp, *c),
- qRed(color),
- qGreen(color),
- qBlue(color));
+ const QString line = image.format() != QImage::Format_RGB32 && !qAlpha(color)
+ ? QString::asprintf("\"%s c None\"", xpm_color_name(cpp, *c))
+ : QString::asprintf("\"%s c #%02x%02x%02x\"", xpm_color_name(cpp, *c),
+ qRed(color), qGreen(color), qBlue(color));
++c;
s << ',' << Qt::endl << line;
}
// write pixels, limit to 4 characters per pixel
- line.truncate(cpp*w);
+ QByteArray line;
for(y=0; y<h; y++) {
+ line.clear();
const QRgb *yp = reinterpret_cast<const QRgb *>(image.constScanLine(y));
- int cc = 0;
for(x=0; x<w; x++) {
int color = (int)(*(yp + x));
const QByteArray chars(xpm_color_name(cpp, colorMap[color]));
- line[cc++] = QLatin1Char(chars[0]);
+ line.append(chars[0]);
if (cpp > 1) {
- line[cc++] = QLatin1Char(chars[1]);
+ line.append(chars[1]);
if (cpp > 2) {
- line[cc++] = QLatin1Char(chars[2]);
- if (cpp > 3) {
- line[cc++] = QLatin1Char(chars[3]);
- }
+ line.append(chars[2]);
+ if (cpp > 3)
+ line.append(chars[3]);
}
}
}
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 7799be77d2..ceb5055a9d 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -1306,6 +1306,7 @@ static void init_plugins(const QList<QByteArray> &pluginList)
}
}
+#if QT_CONFIG(commandlineparser)
void QGuiApplicationPrivate::addQtOptions(QList<QCommandLineOption> *options)
{
QCoreApplicationPrivate::addQtOptions(options);
@@ -1357,6 +1358,7 @@ void QGuiApplicationPrivate::addQtOptions(QList<QCommandLineOption> *options)
QGuiApplication::tr("Alias for --windowtitle."), QStringLiteral("title")));
}
}
+#endif // QT_CONFIG(commandlineparser)
void QGuiApplicationPrivate::createPlatformIntegration()
{
@@ -3260,9 +3262,12 @@ void QGuiApplication::setPalette(const QPalette &pal)
QGuiApplicationPrivate::app_pal = new QPalette(pal);
else
*QGuiApplicationPrivate::app_pal = pal;
+
applicationResourceFlags |= ApplicationPaletteExplicitlySet;
QCoreApplication::setAttribute(Qt::AA_SetPalette);
- emit qGuiApp->paletteChanged(*QGuiApplicationPrivate::app_pal);
+
+ if (qGuiApp)
+ emit qGuiApp->paletteChanged(*QGuiApplicationPrivate::app_pal);
}
void QGuiApplicationPrivate::applyWindowGeometrySpecificationTo(QWindow *window)
diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h
index 2ecde0354a..afca7579ea 100644
--- a/src/gui/kernel/qguiapplication_p.h
+++ b/src/gui/kernel/qguiapplication_p.h
@@ -92,7 +92,9 @@ public:
virtual void notifyLayoutDirectionChange();
virtual void notifyActiveWindowChange(QWindow *previous);
+#if QT_CONFIG(commandlineparser)
void addQtOptions(QList<QCommandLineOption> *options) override;
+#endif
virtual bool shouldQuit() override;
bool shouldQuitInternal(const QWindowList &processedWindows);
diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp
index 93fcb1a216..0fea416404 100644
--- a/src/gui/kernel/qhighdpiscaling.cpp
+++ b/src/gui/kernel/qhighdpiscaling.cpp
@@ -452,52 +452,30 @@ QDpi QHighDpiScaling::logicalDpi()
return m_logicalDpi;
}
-qreal QHighDpiScaling::factor(const QScreen *screen)
+QHighDpiScaling::ScaleAndOrigin QHighDpiScaling::scaleAndOrigin(const QPlatformScreen *platformScreen, QPoint *nativePosition)
{
- // Fast path for when scaling in Qt is not used at all.
if (!m_active)
- return qreal(1.0);
-
- // The effective factor for a given screen is the product of the
- // screen and global sub-factors
- qreal factor = m_factor;
- if (screen)
- factor *= screenSubfactor(screen->handle());
- return factor;
+ return { qreal(1), QPoint() };
+ const QPlatformScreen *actualScreen = nativePosition ?
+ platformScreen->screenForPosition(*nativePosition) : platformScreen;
+ return { m_factor * screenSubfactor(actualScreen), actualScreen->geometry().topLeft() };
}
-qreal QHighDpiScaling::factor(const QPlatformScreen *platformScreen)
+QHighDpiScaling::ScaleAndOrigin QHighDpiScaling::scaleAndOrigin(const QScreen *screen, QPoint *nativePosition)
{
if (!m_active)
- return qreal(1.0);
-
- return m_factor * screenSubfactor(platformScreen);
+ return { qreal(1), QPoint() };
+ if (!screen)
+ return { m_factor, QPoint() }; // the global factor
+ return scaleAndOrigin(screen->handle(), nativePosition);
}
-qreal QHighDpiScaling::factor(const QWindow *window)
+QHighDpiScaling::ScaleAndOrigin QHighDpiScaling::scaleAndOrigin(const QWindow *window, QPoint *nativePosition)
{
if (!m_active)
- return qreal(1.0);
-
- return factor(window ? window->screen() : QGuiApplication::primaryScreen());
-}
-
-QPoint QHighDpiScaling::origin(const QScreen *screen)
-{
- return screen->geometry().topLeft();
-}
-
-QPoint QHighDpiScaling::origin(const QPlatformScreen *platformScreen)
-{
- return platformScreen->geometry().topLeft();
-}
-
-QPoint QHighDpiScaling::origin(const QWindow *window)
-{
- if (window && window->isTopLevel() && window->screen())
- return window->screen()->geometry().topLeft();
-
- return QPoint(0, 0);
+ return { qreal(1), QPoint() };
+ QScreen *screen = window ? window->screen() : QGuiApplication::primaryScreen();
+ return scaleAndOrigin(screen, nativePosition);
}
#endif //QT_NO_HIGHDPISCALING
diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h
index 6e89f85746..50221926c6 100644
--- a/src/gui/kernel/qhighdpiscaling_p.h
+++ b/src/gui/kernel/qhighdpiscaling_p.h
@@ -78,14 +78,23 @@ public:
static void setScreenFactor(QScreen *window, qreal factor);
static bool isActive() { return m_active; }
- static qreal factor(const QWindow *window);
- static qreal factor(const QScreen *screen);
- static qreal factor(const QPlatformScreen *platformScreen);
- static QPoint origin(const QScreen *screen);
- static QPoint origin(const QPlatformScreen *platformScreen);
- static QPoint origin(const QWindow *window);
- static QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen);
+
+ struct ScaleAndOrigin
+ {
+ qreal factor;
+ QPoint origin;
+ };
+ static ScaleAndOrigin scaleAndOrigin(const QPlatformScreen *platformScreen, QPoint *nativePosition = nullptr);
+ static ScaleAndOrigin scaleAndOrigin(const QScreen *screen, QPoint *nativePosition = nullptr);
+ static ScaleAndOrigin scaleAndOrigin(const QWindow *platformScreen, QPoint *nativePosition = nullptr);
+
+ template<typename C>
+ static qreal factor(C *context, QPoint *nativePosition = nullptr) {
+ return scaleAndOrigin(context, nativePosition).factor;
+ }
+
static QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen);
+ static QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen);
static QPoint mapPositionToGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window);
static QPoint mapPositionFromGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window);
static QDpi logicalDpi();
@@ -166,16 +175,26 @@ inline QRegion scale(const QRegion &region, qreal scaleFactor, QPoint origin = Q
return scaled;
}
+template <typename T>
+inline QPoint position(T) { return QPoint(); }
+inline QPoint position(QPoint point) { return point; }
+inline QPoint position(QPointF point) { return point.toPoint(); }
+inline QPoint position(QRect rect) { return rect.center(); }
+inline QPoint position(QRectF rect) { return rect.center().toPoint(); }
+
template <typename T, typename C>
T fromNativePixels(const T &value, const C *context)
{
- return scale(value, qreal(1) / QHighDpiScaling::factor(context), QHighDpiScaling::origin(context));
+ QPoint nativePosition = position(value);
+ QHighDpiScaling::ScaleAndOrigin so = QHighDpiScaling::scaleAndOrigin(context, &nativePosition);
+ return scale(value, qreal(1) / so.factor, so.origin);
}
template <typename T, typename C>
T toNativePixels(const T &value, const C *context)
{
- return scale(value, QHighDpiScaling::factor(context), QHighDpiScaling::origin(context));
+ QHighDpiScaling::ScaleAndOrigin so = QHighDpiScaling::scaleAndOrigin(context);
+ return scale(value, so.factor, so.origin);
}
template <typename T, typename C>
diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp
index a3b2ea5f86..326d2823eb 100644
--- a/src/gui/kernel/qopenglcontext.cpp
+++ b/src/gui/kernel/qopenglcontext.cpp
@@ -1610,8 +1610,7 @@ void QOpenGLSharedResourceGuard::freeResource(QOpenGLContext *context)
QOpenGLMultiGroupSharedResource instance.
*/
QOpenGLMultiGroupSharedResource::QOpenGLMultiGroupSharedResource()
- : active(0),
- m_mutex(QMutex::Recursive)
+ : active(0)
{
#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
qDebug("Creating context group resource object %p.", this);
diff --git a/src/gui/kernel/qopenglcontext_p.h b/src/gui/kernel/qopenglcontext_p.h
index c6ad893ee6..833cfb20c3 100644
--- a/src/gui/kernel/qopenglcontext_p.h
+++ b/src/gui/kernel/qopenglcontext_p.h
@@ -132,7 +132,6 @@ class Q_GUI_EXPORT QOpenGLContextGroupPrivate : public QObjectPrivate
public:
QOpenGLContextGroupPrivate()
: m_context(nullptr)
- , m_mutex(QMutex::Recursive)
, m_refs(0)
{
}
@@ -147,7 +146,7 @@ public:
QOpenGLContext *m_context;
QList<QOpenGLContext *> m_shares;
- QMutex m_mutex;
+ QRecursiveMutex m_mutex;
QHash<QOpenGLMultiGroupSharedResource *, QOpenGLSharedResource *> m_resources;
QAtomicInt m_refs;
@@ -186,7 +185,7 @@ public:
private:
QAtomicInt active;
QList<QOpenGLContextGroup *> m_groups;
- QMutex m_mutex;
+ QRecursiveMutex m_mutex;
};
class QPaintEngineEx;
diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp
index bba2a863a9..d3070a3d1a 100644
--- a/src/gui/kernel/qsimpledrag.cpp
+++ b/src/gui/kernel/qsimpledrag.cpp
@@ -309,11 +309,15 @@ void QBasicDrag::updateCursor(Qt::DropAction action)
m_dndHasSetOverrideCursor = true;
} else {
QCursor *cursor = QGuiApplication::overrideCursor();
- if (!pixmap.isNull()) {
- if (cursor->pixmap().cacheKey() != pixmap.cacheKey())
- QGuiApplication::changeOverrideCursor(QCursor(pixmap));
- } else if (cursorShape != cursor->shape()) {
- QGuiApplication::changeOverrideCursor(QCursor(cursorShape));
+ if (!cursor) {
+ QGuiApplication::changeOverrideCursor(pixmap.isNull() ? QCursor(cursorShape) : QCursor(pixmap));
+ } else {
+ if (!pixmap.isNull()) {
+ if (cursor->pixmap().cacheKey() != pixmap.cacheKey())
+ QGuiApplication::changeOverrideCursor(QCursor(pixmap));
+ } else if (cursorShape != cursor->shape()) {
+ QGuiApplication::changeOverrideCursor(QCursor(cursorShape));
+ }
}
}
#endif
diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp
index 042b9ebd79..c087326068 100644
--- a/src/gui/opengl/qopenglpaintengine.cpp
+++ b/src/gui/opengl/qopenglpaintengine.cpp
@@ -1475,7 +1475,10 @@ void QOpenGL2PaintEngineEx::renderHintsChanged()
if (!QOpenGLContext::currentContext()->isOpenGLES()) {
Q_D(QOpenGL2PaintEngineEx);
if ((state()->renderHints & QPainter::Antialiasing)
- || (state()->renderHints & QPainter::HighQualityAntialiasing))
+#if QT_DEPRECATED_SINCE(5, 14)
+ || (state()->renderHints & QPainter::HighQualityAntialiasing)
+#endif
+ )
d->funcs.glEnable(GL_MULTISAMPLE);
else
d->funcs.glDisable(GL_MULTISAMPLE);
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 64183c2be6..461ad51200 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -904,7 +904,11 @@ void QRasterPaintEngine::renderHintsChanged()
bool was_aa = s->flags.antialiased;
bool was_bilinear = s->flags.bilinear;
- s->flags.antialiased = bool(s->renderHints & (QPainter::Antialiasing | QPainter::HighQualityAntialiasing));
+ s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
+#if QT_DEPRECATED_SINCE(5, 14)
+ if (s->renderHints & QPainter::HighQualityAntialiasing)
+ s->flags.antialiased = true;
+#endif
s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
s->flags.legacy_rounding = !bool(s->renderHints & QPainter::Antialiasing) && bool(s->renderHints & QPainter::Qt4CompatiblePainting);
diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h
index 843f24e3e1..3394da63c7 100644
--- a/src/gui/painting/qpainter.h
+++ b/src/gui/painting/qpainter.h
@@ -89,8 +89,10 @@ public:
Antialiasing = 0x01,
TextAntialiasing = 0x02,
SmoothPixmapTransform = 0x04,
- HighQualityAntialiasing = 0x08,
- NonCosmeticDefaultPen = 0x10,
+#if QT_DEPRECATED_SINCE(5, 14)
+ HighQualityAntialiasing Q_DECL_ENUMERATOR_DEPRECATED_X("Use Antialiasing instead") = 0x08,
+ NonCosmeticDefaultPen Q_DECL_ENUMERATOR_DEPRECATED_X("Default pen is non-cosmetic now") = 0x10,
+#endif
Qt4CompatiblePainting = 0x20,
LosslessImageRendering = 0x40,
};
diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp
index 70ad6bdc97..8801e66b0f 100644
--- a/src/gui/painting/qpainterpath.cpp
+++ b/src/gui/painting/qpainterpath.cpp
@@ -675,8 +675,9 @@ void QPainterPath::reserve(int size)
{
Q_D(QPainterPath);
if ((!d && size > 0) || (d && d->elements.capacity() < size)) {
+ ensureData();
detach();
- d->elements.reserve(size);
+ d_func()->elements.reserve(size);
}
}
diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp
index dbad63c6d1..d7c1607e57 100644
--- a/src/gui/rhi/qrhi.cpp
+++ b/src/gui/rhi/qrhi.cpp
@@ -494,7 +494,31 @@ QT_BEGIN_NAMESPACE
extension. When false, only 16-bit unsigned elements are supported in the
index buffer.
- \value Compute Indicates that compute shaders are supported.
+ \value Compute Indicates that compute shaders, image load/store, and
+ storage buffers are supported.
+
+ \value WideLines Indicates that lines with a width other than 1 are
+ supported. When reported as not supported, the line width set on the
+ graphics pipeline state is ignored. This can always be false with some
+ backends (D3D11, Metal). With Vulkan, the value depends on the
+ implementation.
+
+ \value VertexShaderPointSize Indicates that the size of rasterized points
+ set via \c{gl_PointSize} in the vertex shader is taken into account. When
+ reported as not supported, drawing points with a size other than 1 is not
+ supported. Setting \c{gl_PointSize} in the shader is still valid then, but
+ is ignored. (for example, when generating HLSL, the assignment is silently
+ dropped from the generated code) Note that some APIs (Metal, Vulkan)
+ require the point size to be set in the shader explicitly whenever drawing
+ points, even when the size is 1, as they do not automatically default to 1.
+
+ \value BaseVertex Indicates that \l{QRhiCommandBuffer::drawIndexed()}{drawIndexed()}
+ supports the \c vertexOffset argument. When reported as not supported, the
+ vertexOffset value in an indexed draw is ignored.
+
+ \value BaseInstance Indicates that instanced draw commands support the \c
+ firstInstance argument. When reported as not supported, the firstInstance
+ value is ignored and the instance ID starts from 0.
*/
/*!
@@ -2575,7 +2599,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
{
QRhiShaderResourceBinding b;
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- Q_ASSERT(d->ref.load() == 1);
+ Q_ASSERT(d->ref.loadRelaxed() == 1);
d->binding = binding;
d->stage = stage;
d->type = UniformBuffer;
@@ -2639,7 +2663,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture(
{
QRhiShaderResourceBinding b;
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- Q_ASSERT(d->ref.load() == 1);
+ Q_ASSERT(d->ref.loadRelaxed() == 1);
d->binding = binding;
d->stage = stage;
d->type = SampledTexture;
@@ -2661,7 +2685,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoad(
{
QRhiShaderResourceBinding b;
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- Q_ASSERT(d->ref.load() == 1);
+ Q_ASSERT(d->ref.loadRelaxed() == 1);
d->binding = binding;
d->stage = stage;
d->type = ImageLoad;
@@ -2715,7 +2739,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
{
QRhiShaderResourceBinding b;
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- Q_ASSERT(d->ref.load() == 1);
+ Q_ASSERT(d->ref.loadRelaxed() == 1);
d->binding = binding;
d->stage = stage;
d->type = BufferLoad;
@@ -3805,6 +3829,7 @@ QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRh
static_cast<QRhiVulkanNativeHandles *>(importDevice));
break;
#else
+ Q_UNUSED(importDevice);
qWarning("This build of Qt has no Vulkan support");
break;
#endif
@@ -4467,15 +4492,21 @@ void QRhiCommandBuffer::setStencilRef(quint32 refValue)
Records a non-indexed draw.
The number of vertices is specified in \a vertexCount. For instanced
- drawing set \a instanceCount to a value other than 1. \a firstVertex is
- the index of the first vertex to draw. \a firstInstance is the instance ID
- of the first instance to draw.
+ drawing set \a instanceCount to a value other than 1. \a firstVertex is the
+ index of the first vertex to draw. When drawing multiple instances, the
+ first instance ID is specified by \a firstInstance.
+
+ \note \a firstInstance may not be supported, and is ignored when the
+ QRhi::BaseInstance feature is reported as not supported. The first ID is
+ always 0 in that case.
\note This function can only be called inside a render pass, meaning
between a beginPass() and endPass() call.
*/
void QRhiCommandBuffer::draw(quint32 vertexCount,
- quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
+ quint32 instanceCount,
+ quint32 firstVertex,
+ quint32 firstInstance)
{
m_rhi->draw(this, vertexCount, instanceCount, firstVertex, firstInstance);
}
@@ -4493,17 +4524,27 @@ void QRhiCommandBuffer::draw(quint32 vertexCount,
\l{QRhi::NonFourAlignedEffectiveIndexBufferOffset}{NonFourAlignedEffectiveIndexBufferOffset}
feature will be reported as not-supported.
- For instanced drawing set \a instanceCount to a value other than 1. \a
- firstInstance is the instance ID of the first instance to draw.
+ For instanced drawing set \a instanceCount to a value other than 1. When
+ drawing multiple instances, the first instance ID is specified by \a
+ firstInstance.
+
+ \note \a firstInstance may not be supported, and is ignored when the
+ QRhi::BaseInstance feature is reported as not supported. The first ID is
+ always 0 in that case.
- \a vertexOffset is added to the vertex index.
+ \a vertexOffset (also called \c{base vertex}) is a signed value that is
+ added to the element index before indexing into the vertex buffer. Support
+ for this is not always available, and the value is ignored when the feature
+ QRhi::BaseVertex is reported as unsupported.
\note This function can only be called inside a render pass, meaning
between a beginPass() and endPass() call.
*/
void QRhiCommandBuffer::drawIndexed(quint32 indexCount,
- quint32 instanceCount, quint32 firstIndex,
- qint32 vertexOffset, quint32 firstInstance)
+ quint32 instanceCount,
+ quint32 firstIndex,
+ qint32 vertexOffset,
+ quint32 firstInstance)
{
m_rhi->drawIndexed(this, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
}
@@ -5192,10 +5233,11 @@ int QRhi::ubufAlignment() const
return d->ubufAlignment();
}
+static QBasicAtomicInteger<QRhiGlobalObjectIdGenerator::Type> counter = Q_BASIC_ATOMIC_INITIALIZER(0);
+
QRhiGlobalObjectIdGenerator::Type QRhiGlobalObjectIdGenerator::newId()
{
- static QRhiGlobalObjectIdGenerator inst;
- return ++inst.counter;
+ return counter.fetchAndAddRelaxed(1) + 1;
}
bool QRhiPassResourceTracker::isEmpty() const
diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h
index 0d296d370c..df30817ef4 100644
--- a/src/gui/rhi/qrhi_p.h
+++ b/src/gui/rhi/qrhi_p.h
@@ -1068,6 +1068,9 @@ public:
int sampleCount() const { return m_sampleCount; }
void setSampleCount(int s) { m_sampleCount = s; }
+ float lineWidth() const { return m_lineWidth; }
+ void setLineWidth(float width) { m_lineWidth = width; }
+
QVector<QRhiShaderStage> shaderStages() const { return m_shaderStages; }
void setShaderStages(const QVector<QRhiShaderStage> &stages) { m_shaderStages = stages; }
@@ -1098,6 +1101,7 @@ protected:
quint32 m_stencilReadMask = 0xFF;
quint32 m_stencilWriteMask = 0xFF;
int m_sampleCount = 1;
+ float m_lineWidth = 1.0f;
QVector<QRhiShaderStage> m_shaderStages;
QRhiVertexInputLayout m_vertexInputLayout;
QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
@@ -1312,7 +1316,11 @@ public:
NPOTTextureRepeat,
RedOrAlpha8IsRed,
ElementIndexUint,
- Compute
+ Compute,
+ WideLines,
+ VertexShaderPointSize,
+ BaseVertex,
+ BaseInstance
};
enum BeginFrameFlag {
diff --git a/src/gui/rhi/qrhi_p_p.h b/src/gui/rhi/qrhi_p_p.h
index 4fd01d3ef2..83d521f441 100644
--- a/src/gui/rhi/qrhi_p_p.h
+++ b/src/gui/rhi/qrhi_p_p.h
@@ -52,7 +52,6 @@
#include "qrhiprofiler_p_p.h"
#include <QBitArray>
#include <QAtomicInt>
-#include <QAtomicInteger>
QT_BEGIN_NAMESPACE
@@ -484,9 +483,6 @@ public:
using Type = quint32;
#endif
static Type newId();
-
-private:
- QAtomicInteger<Type> counter;
};
class QRhiPassResourceTracker
diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp
index 7d9c934c18..a8a490eb5c 100644
--- a/src/gui/rhi/qrhid3d11.cpp
+++ b/src/gui/rhi/qrhid3d11.cpp
@@ -39,6 +39,7 @@
#include <QWindow>
#include <QOperatingSystemVersion>
#include <qmath.h>
+#include <private/qsystemlibrary_p.h>
#include <d3dcompiler.h>
#include <comdef.h>
@@ -150,7 +151,8 @@ static QString comErrorMessage(HRESULT hr)
return result;
}
-static inline uint aligned(uint v, uint byteAlign)
+template <class Int>
+static inline Int aligned(Int v, Int byteAlign)
{
return (v + byteAlign - 1) & ~(byteAlign - 1);
}
@@ -377,6 +379,14 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::Compute:
return true;
+ case QRhi::WideLines:
+ return false;
+ case QRhi::VertexShaderPointSize:
+ return false;
+ case QRhi::BaseVertex:
+ return true;
+ case QRhi::BaseInstance:
+ return true;
default:
Q_UNREACHABLE();
return false;
@@ -595,7 +605,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
for (int i = 0; i < dynamicOffsetCount; ++i) {
const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
const uint binding = dynOfs.first;
- Q_ASSERT(aligned(dynOfs.second, 256) == dynOfs.second);
+ Q_ASSERT(aligned(dynOfs.second, quint32(256)) == dynOfs.second);
const uint offsetInConstants = dynOfs.second / 16;
*p++ = binding;
*p++ = offsetInConstants;
@@ -1471,6 +1481,8 @@ void QRhiD3D11::beginPass(QRhiCommandBuffer *cb,
cbD->recordingPass = QD3D11CommandBuffer::RenderPass;
cbD->currentTarget = rt;
+
+ cbD->resetCachedShaderResourceState();
}
void QRhiD3D11::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
@@ -1547,6 +1559,8 @@ void QRhiD3D11::beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch
cbD->commands.append(cmd);
cbD->recordingPass = QD3D11CommandBuffer::ComputePass;
+
+ cbD->resetCachedShaderResourceState();
}
void QRhiD3D11::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
@@ -3205,6 +3219,18 @@ static inline D3D11_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
}
}
+static pD3DCompile resolveD3DCompile()
+{
+ for (const wchar_t *libraryName : {L"D3DCompiler_47", L"D3DCompiler_43"}) {
+ QSystemLibrary library(libraryName);
+ if (library.load()) {
+ if (auto symbol = library.resolve("D3DCompile"))
+ return reinterpret_cast<pD3DCompile>(symbol);
+ }
+ }
+ return nullptr;
+}
+
static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, QString *error)
{
QShaderCode dxbc = shader.shader({ QShader::DxbcShader, 50, shaderVariant });
@@ -3242,9 +3268,15 @@ static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Varian
return QByteArray();
}
+ static const pD3DCompile d3dCompile = resolveD3DCompile();
+ if (d3dCompile == nullptr) {
+ qWarning("Unable to resolve function D3DCompile()");
+ return QByteArray();
+ }
+
ID3DBlob *bytecode = nullptr;
ID3DBlob *errors = nullptr;
- HRESULT hr = D3DCompile(hlslSource.shader().constData(), hlslSource.shader().size(),
+ HRESULT hr = d3dCompile(hlslSource.shader().constData(), hlslSource.shader().size(),
nullptr, nullptr, nullptr,
hlslSource.entryPoint().constData(), target, 0, 0, &bytecode, &errors);
if (FAILED(hr) || !bytecode) {
diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h
index 688f79b3b7..34c9ff70f8 100644
--- a/src/gui/rhi/qrhid3d11_p_p.h
+++ b/src/gui/rhi/qrhid3d11_p_p.h
@@ -482,6 +482,9 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
currentGraphicsPipeline = nullptr;
currentComputePipeline = nullptr;
currentPipelineGeneration = 0;
+ resetCachedShaderResourceState();
+ }
+ void resetCachedShaderResourceState() {
currentGraphicsSrb = nullptr;
currentComputeSrb = nullptr;
currentSrbGeneration = 0;
diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp
index 7c40a36701..22cb030c27 100644
--- a/src/gui/rhi/qrhigles2.cpp
+++ b/src/gui/rhi/qrhigles2.cpp
@@ -175,14 +175,34 @@ QT_BEGIN_NAMESPACE
#define GL_DEPTH_COMPONENT16 0x81A5
#endif
+#ifndef GL_DEPTH_COMPONENT24
+#define GL_DEPTH_COMPONENT24 0x81A6
+#endif
+
#ifndef GL_DEPTH_COMPONENT32F
#define GL_DEPTH_COMPONENT32F 0x8CAC
#endif
+#ifndef GL_STENCIL_INDEX
+#define GL_STENCIL_INDEX 0x1901
+#endif
+
+#ifndef GL_STENCIL_INDEX8
+#define GL_STENCIL_INDEX8 0x8D48
+#endif
+
#ifndef GL_DEPTH24_STENCIL8
#define GL_DEPTH24_STENCIL8 0x88F0
#endif
+#ifndef GL_DEPTH_STENCIL_ATTACHMENT
+#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
+#endif
+
+#ifndef GL_DEPTH_STENCIL
+#define GL_DEPTH_STENCIL 0x84F9
+#endif
+
#ifndef GL_PRIMITIVE_RESTART_FIXED_INDEX
#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69
#endif
@@ -394,10 +414,19 @@ bool QRhiGles2::create(QRhi::Flags flags)
caps.floatFormats = caps.ctxMajor >= 3;
caps.depthTexture = caps.ctxMajor >= 3;
caps.packedDepthStencil = f->hasOpenGLExtension(QOpenGLExtensions::PackedDepthStencil);
+#ifdef Q_OS_WASM
+ caps.needsDepthStencilCombinedAttach = true;
+#else
+ caps.needsDepthStencilCombinedAttach = false;
+#endif
caps.srgbCapableDefaultFramebuffer = f->hasOpenGLExtension(QOpenGLExtensions::SRGBFrameBuffer);
caps.coreProfile = actualFormat.profile() == QSurfaceFormat::CoreProfile;
caps.uniformBuffers = caps.ctxMajor >= 3 && (caps.gles || caps.ctxMinor >= 1);
caps.elementIndexUint = f->hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint);
+ caps.depth24 = f->hasOpenGLExtension(QOpenGLExtensions::Depth24);
+ caps.rgba8Format = f->hasOpenGLExtension(QOpenGLExtensions::Sized8Formats);
+ caps.instancing = caps.ctxMajor >= 3 && (caps.gles || caps.ctxMinor >= 3);
+ caps.baseVertex = caps.ctxMajor >= 3 && caps.ctxMinor >= 2;
nativeHandlesStruct.context = ctx;
@@ -470,6 +499,43 @@ int QRhiGles2::effectiveSampleCount(int sampleCount) const
return s;
}
+static inline bool isPowerOfTwo(int x)
+{
+ // Assumption: x >= 1
+ return x == (x & -x);
+}
+
+QSize QRhiGles2::safeTextureSize(const QSize &pixelSize) const
+{
+ QSize size = pixelSize.isEmpty() ? QSize(1, 1) : pixelSize;
+
+ if (!caps.npotTexture) {
+ if (!isPowerOfTwo(size.width())) {
+ qWarning("Texture width %d is not a power of two, adjusting",
+ size.width());
+ size.setWidth(qNextPowerOfTwo(size.width()));
+ }
+ if (!isPowerOfTwo(size.height())) {
+ qWarning("Texture height %d is not a power of two, adjusting",
+ size.height());
+ size.setHeight(qNextPowerOfTwo(size.height()));
+ }
+ }
+
+ if (size.width() > caps.maxTextureSize) {
+ qWarning("Texture width %d exceeds maximum width %d, adjusting",
+ size.width(), caps.maxTextureSize);
+ size.setWidth(caps.maxTextureSize);
+ }
+ if (size.height() > caps.maxTextureSize) {
+ qWarning("Texture height %d exceeds maximum height %d, adjusting",
+ size.height(), caps.maxTextureSize);
+ size.setHeight(caps.maxTextureSize);
+ }
+
+ return size;
+}
+
QRhiSwapChain *QRhiGles2::createSwapChain()
{
return new QGles2SwapChain(this);
@@ -601,7 +667,7 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
case QRhi::Timestamps:
return false;
case QRhi::Instancing:
- return false;
+ return caps.instancing;
case QRhi::CustomInstanceStepRate:
return false;
case QRhi::PrimitiveRestart:
@@ -618,6 +684,14 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
return caps.elementIndexUint;
case QRhi::Compute:
return false;
+ case QRhi::WideLines:
+ return true;
+ case QRhi::VertexShaderPointSize:
+ return true;
+ case QRhi::BaseVertex:
+ return caps.baseVertex;
+ case QRhi::BaseInstance:
+ return false; // not in ES 3.2, so won't bother
default:
Q_UNREACHABLE();
return false;
@@ -865,8 +939,6 @@ void QRhiGles2::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
void QRhiGles2::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
{
- Q_UNUSED(instanceCount); // no instancing
- Q_UNUSED(firstInstance);
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
@@ -875,15 +947,14 @@ void QRhiGles2::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
cmd.args.draw.ps = cbD->currentPipeline;
cmd.args.draw.vertexCount = vertexCount;
cmd.args.draw.firstVertex = firstVertex;
+ cmd.args.draw.instanceCount = instanceCount;
+ cmd.args.draw.baseInstance = firstInstance;
cbD->commands.append(cmd);
}
void QRhiGles2::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
{
- Q_UNUSED(instanceCount); // no instancing
- Q_UNUSED(firstInstance);
- Q_UNUSED(vertexOffset); // no glDrawElementsBaseVertex
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
@@ -892,6 +963,9 @@ void QRhiGles2::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
cmd.args.drawIndexed.ps = cbD->currentPipeline;
cmd.args.drawIndexed.indexCount = indexCount;
cmd.args.drawIndexed.firstIndex = firstIndex;
+ cmd.args.drawIndexed.instanceCount = instanceCount;
+ cmd.args.drawIndexed.baseInstance = firstInstance;
+ cmd.args.drawIndexed.baseVertex = vertexOffset;
cbD->commands.append(cmd);
}
@@ -1545,13 +1619,14 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
const QVector<QRhiVertexInputBinding> bindings = psD->m_vertexInputLayout.bindings();
const QVector<QRhiVertexInputAttribute> attributes = psD->m_vertexInputLayout.attributes();
for (const QRhiVertexInputAttribute &a : attributes) {
- if (a.binding() != cmd.args.bindVertexBuffer.binding)
+ const int bindingIdx = a.binding();
+ if (bindingIdx != cmd.args.bindVertexBuffer.binding)
continue;
// we do not support more than one vertex buffer
f->glBindBuffer(GL_ARRAY_BUFFER, cmd.args.bindVertexBuffer.buffer);
- const int stride = bindings[a.binding()].stride();
+ const int stride = bindings[bindingIdx].stride();
int size = 1;
GLenum type = GL_FLOAT;
bool normalize = false;
@@ -1590,10 +1665,17 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
default:
break;
}
+
+ const int locationIdx = a.location();
quint32 ofs = a.offset() + cmd.args.bindVertexBuffer.offset;
- f->glVertexAttribPointer(a.location(), size, type, normalize, stride,
+ f->glVertexAttribPointer(locationIdx, size, type, normalize, stride,
reinterpret_cast<const GLvoid *>(quintptr(ofs)));
- f->glEnableVertexAttribArray(a.location());
+ f->glEnableVertexAttribArray(locationIdx);
+ if (bindings[bindingIdx].classification() == QRhiVertexInputBinding::PerInstance
+ && caps.instancing)
+ {
+ f->glVertexAttribDivisor(locationIdx, bindings[bindingIdx].instanceStepRate());
+ }
}
} else {
qWarning("No graphics pipeline active for setVertexInput; ignored");
@@ -1609,21 +1691,53 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
case QGles2CommandBuffer::Command::Draw:
{
QGles2GraphicsPipeline *psD = QRHI_RES(QGles2GraphicsPipeline, cmd.args.draw.ps);
- if (psD)
- f->glDrawArrays(psD->drawMode, cmd.args.draw.firstVertex, cmd.args.draw.vertexCount);
- else
+ if (psD) {
+ if (cmd.args.draw.instanceCount == 1 || !caps.instancing) {
+ f->glDrawArrays(psD->drawMode, cmd.args.draw.firstVertex, cmd.args.draw.vertexCount);
+ } else {
+ f->glDrawArraysInstanced(psD->drawMode, cmd.args.draw.firstVertex, cmd.args.draw.vertexCount,
+ cmd.args.draw.instanceCount);
+ }
+ } else {
qWarning("No graphics pipeline active for draw; ignored");
+ }
}
break;
case QGles2CommandBuffer::Command::DrawIndexed:
{
QGles2GraphicsPipeline *psD = QRHI_RES(QGles2GraphicsPipeline, cmd.args.drawIndexed.ps);
if (psD) {
- quint32 ofs = cmd.args.drawIndexed.firstIndex * indexStride + indexOffset;
- f->glDrawElements(psD->drawMode,
- cmd.args.drawIndexed.indexCount,
- indexType,
- reinterpret_cast<const GLvoid *>(quintptr(ofs)));
+ const GLvoid *ofs = reinterpret_cast<const GLvoid *>(
+ quintptr(cmd.args.drawIndexed.firstIndex * indexStride + indexOffset));
+ if (cmd.args.drawIndexed.instanceCount == 1 || !caps.instancing) {
+ if (cmd.args.drawIndexed.baseVertex != 0 && caps.baseVertex) {
+ f->glDrawElementsBaseVertex(psD->drawMode,
+ cmd.args.drawIndexed.indexCount,
+ indexType,
+ ofs,
+ cmd.args.drawIndexed.baseVertex);
+ } else {
+ f->glDrawElements(psD->drawMode,
+ cmd.args.drawIndexed.indexCount,
+ indexType,
+ ofs);
+ }
+ } else {
+ if (cmd.args.drawIndexed.baseVertex != 0 && caps.baseVertex) {
+ f->glDrawElementsInstancedBaseVertex(psD->drawMode,
+ cmd.args.drawIndexed.indexCount,
+ indexType,
+ ofs,
+ cmd.args.drawIndexed.instanceCount,
+ cmd.args.drawIndexed.baseVertex);
+ } else {
+ f->glDrawElementsInstanced(psD->drawMode,
+ cmd.args.drawIndexed.indexCount,
+ indexType,
+ ofs,
+ cmd.args.drawIndexed.instanceCount);
+ }
+ }
} else {
qWarning("No graphics pipeline active for drawIndexed; ignored");
}
@@ -1849,6 +1963,9 @@ void QRhiGles2::executeBindGraphicsPipeline(QRhiGraphicsPipeline *ps)
f->glDisable(GL_STENCIL_TEST);
}
+ if (psD->topology() == QRhiGraphicsPipeline::Lines || psD->topology() == QRhiGraphicsPipeline::LineStrip)
+ f->glLineWidth(psD->m_lineWidth);
+
f->glUseProgram(psD->program);
}
@@ -2242,43 +2359,51 @@ bool QGles2RenderBuffer::build()
qWarning("RenderBuffer: UsedWithSwapChainOnly is meaningless in combination with Color");
}
- if (m_pixelSize.isEmpty())
- return false;
-
if (!rhiD->ensureContext())
return false;
rhiD->f->glGenRenderbuffers(1, &renderbuffer);
rhiD->f->glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
+ const QSize size = rhiD->safeTextureSize(m_pixelSize);
+
switch (m_type) {
case QRhiRenderBuffer::DepthStencil:
if (rhiD->caps.msaaRenderBuffer && samples > 1) {
- rhiD->f->glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH24_STENCIL8,
- m_pixelSize.width(), m_pixelSize.height());
+ const GLenum storage = rhiD->caps.needsDepthStencilCombinedAttach ? GL_DEPTH_STENCIL : GL_DEPTH24_STENCIL8;
+ rhiD->f->glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, storage,
+ size.width(), size.height());
+ stencilRenderbuffer = 0;
+ } else if (rhiD->caps.packedDepthStencil || rhiD->caps.needsDepthStencilCombinedAttach) {
+ const GLenum storage = rhiD->caps.needsDepthStencilCombinedAttach ? GL_DEPTH_STENCIL : GL_DEPTH24_STENCIL8;
+ rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, storage,
+ size.width(), size.height());
+ stencilRenderbuffer = 0;
} else {
- if (rhiD->caps.packedDepthStencil) {
- rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
- m_pixelSize.width(), m_pixelSize.height());
- stencilRenderbuffer = 0;
- } else {
- rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_ATTACHMENT,
- m_pixelSize.width(), m_pixelSize.height());
- rhiD->f->glGenRenderbuffers(1, &stencilRenderbuffer);
- rhiD->f->glBindRenderbuffer(GL_RENDERBUFFER, stencilRenderbuffer);
- rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_ATTACHMENT,
- m_pixelSize.width(), m_pixelSize.height());
+ GLenum depthStorage = GL_DEPTH_COMPONENT;
+ if (rhiD->caps.gles) {
+ if (rhiD->caps.depth24)
+ depthStorage = GL_DEPTH_COMPONENT24;
+ else
+ depthStorage = GL_DEPTH_COMPONENT16; // plain ES 2.0 only has this
}
+ const GLenum stencilStorage = rhiD->caps.gles ? GL_STENCIL_INDEX8 : GL_STENCIL_INDEX;
+ rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, depthStorage,
+ size.width(), size.height());
+ rhiD->f->glGenRenderbuffers(1, &stencilRenderbuffer);
+ rhiD->f->glBindRenderbuffer(GL_RENDERBUFFER, stencilRenderbuffer);
+ rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, stencilStorage,
+ size.width(), size.height());
}
QRHI_PROF_F(newRenderBuffer(this, false, false, samples));
break;
case QRhiRenderBuffer::Color:
if (rhiD->caps.msaaRenderBuffer && samples > 1)
rhiD->f->glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_RGBA8,
- m_pixelSize.width(), m_pixelSize.height());
+ size.width(), size.height());
else
- rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8,
- m_pixelSize.width(), m_pixelSize.height());
+ rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, rhiD->caps.rgba8Format ? GL_RGBA8 : GL_RGBA4,
+ size.width(), size.height());
QRHI_PROF_F(newRenderBuffer(this, false, false, samples));
break;
default:
@@ -2328,12 +2453,6 @@ void QGles2Texture::release()
rhiD->unregisterResource(this);
}
-static inline bool isPowerOfTwo(int x)
-{
- // Assumption: x >= 1
- return x == (x & -x);
-}
-
bool QGles2Texture::prepareBuild(QSize *adjustedSize)
{
if (texture)
@@ -2343,9 +2462,7 @@ bool QGles2Texture::prepareBuild(QSize *adjustedSize)
if (!rhiD->ensureContext())
return false;
- QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
- if (!rhiD->caps.npotTexture && (!isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height())))
- size = QSize(qNextPowerOfTwo(size.width()), qNextPowerOfTwo(size.height()));
+ const QSize size = rhiD->safeTextureSize(m_pixelSize);
const bool isCube = m_flags.testFlag(CubeMap);
const bool hasMipMaps = m_flags.testFlag(MipMapped);
@@ -2660,11 +2777,19 @@ bool QGles2TextureRenderTarget::build()
if (hasDepthStencil) {
if (m_desc.depthStencilBuffer()) {
QGles2RenderBuffer *depthRbD = QRHI_RES(QGles2RenderBuffer, m_desc.depthStencilBuffer());
- rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRbD->renderbuffer);
- if (depthRbD->stencilRenderbuffer)
- rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRbD->stencilRenderbuffer);
- else // packed
- rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRbD->renderbuffer);
+ if (rhiD->caps.needsDepthStencilCombinedAttach) {
+ rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
+ depthRbD->renderbuffer);
+ } else {
+ rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
+ depthRbD->renderbuffer);
+ if (depthRbD->stencilRenderbuffer)
+ rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
+ depthRbD->stencilRenderbuffer);
+ else // packed
+ rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
+ depthRbD->renderbuffer);
+ }
if (d.colorAttCount == 0) {
d.pixelSize = depthRbD->pixelSize();
d.sampleCount = depthRbD->samples;
diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h
index fe74e2e75b..d6682977ff 100644
--- a/src/gui/rhi/qrhigles2_p_p.h
+++ b/src/gui/rhi/qrhigles2_p_p.h
@@ -324,11 +324,16 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
QRhiGraphicsPipeline *ps;
quint32 vertexCount;
quint32 firstVertex;
+ quint32 instanceCount;
+ quint32 baseInstance;
} draw;
struct {
QRhiGraphicsPipeline *ps;
quint32 indexCount;
quint32 firstIndex;
+ quint32 instanceCount;
+ quint32 baseInstance;
+ qint32 baseVertex;
} drawIndexed;
struct {
QRhiGraphicsPipeline *ps;
@@ -611,6 +616,7 @@ public:
QGles2RenderTargetData *enqueueBindFramebuffer(QRhiRenderTarget *rt, QGles2CommandBuffer *cbD,
bool *wantsColorClear = nullptr, bool *wantsDsClear = nullptr);
int effectiveSampleCount(int sampleCount) const;
+ QSize safeTextureSize(const QSize &size) const;
QOpenGLContext *ctx = nullptr;
bool importedContext = false;
@@ -638,10 +644,15 @@ public:
floatFormats(false),
depthTexture(false),
packedDepthStencil(false),
+ needsDepthStencilCombinedAttach(false),
srgbCapableDefaultFramebuffer(false),
coreProfile(false),
uniformBuffers(false),
- elementIndexUint(false)
+ elementIndexUint(false),
+ depth24(false),
+ rgba8Format(false),
+ instancing(false),
+ baseVertex(false)
{ }
int ctxMajor;
int ctxMinor;
@@ -662,10 +673,15 @@ public:
uint floatFormats : 1;
uint depthTexture : 1;
uint packedDepthStencil : 1;
+ uint needsDepthStencilCombinedAttach : 1;
uint srgbCapableDefaultFramebuffer : 1;
uint coreProfile : 1;
uint uniformBuffers : 1;
uint elementIndexUint : 1;
+ uint depth24 : 1;
+ uint rgba8Format : 1;
+ uint instancing : 1;
+ uint baseVertex : 1;
} caps;
QGles2SwapChain *currentSwapChain = nullptr;
QVector<GLint> supportedCompressedFormats;
diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm
index 214374e0c6..fa537a504b 100644
--- a/src/gui/rhi/qrhimetal.mm
+++ b/src/gui/rhi/qrhimetal.mm
@@ -523,6 +523,14 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::Compute:
return true;
+ case QRhi::WideLines:
+ return false;
+ case QRhi::VertexShaderPointSize:
+ return true;
+ case QRhi::BaseVertex:
+ return true;
+ case QRhi::BaseInstance:
+ return true;
default:
Q_UNREACHABLE();
return false;
diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp
index f6ecd7c00e..7c4eeaf226 100644
--- a/src/gui/rhi/qrhivulkan.cpp
+++ b/src/gui/rhi/qrhivulkan.cpp
@@ -489,6 +489,9 @@ bool QRhiVulkan::create(QRhi::Flags flags)
// elsewhere states that the minimum bufferOffset is 4...
texbufAlign = qMax<VkDeviceSize>(4, physDevProperties.limits.optimalBufferCopyOffsetAlignment);
+ f->vkGetPhysicalDeviceFeatures(physDev, &physDevFeatures);
+ hasWideLines = physDevFeatures.wideLines;
+
if (!importedAllocator) {
VmaVulkanFunctions afuncs;
afuncs.vkGetPhysicalDeviceProperties = wrap_vkGetPhysicalDeviceProperties;
@@ -3489,24 +3492,21 @@ QMatrix4x4 QRhiVulkan::clipSpaceCorrMatrix() const
bool QRhiVulkan::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const
{
- VkPhysicalDeviceFeatures features;
- f->vkGetPhysicalDeviceFeatures(physDev, &features);
-
// Note that with some SDKs the validation layer gives an odd warning about
// BC not being supported, even when our check here succeeds. Not much we
// can do about that.
if (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) {
- if (!features.textureCompressionBC)
+ if (!physDevFeatures.textureCompressionBC)
return false;
}
if (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) {
- if (!features.textureCompressionETC2)
+ if (!physDevFeatures.textureCompressionETC2)
return false;
}
if (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12) {
- if (!features.textureCompressionASTC_LDR)
+ if (!physDevFeatures.textureCompressionASTC_LDR)
return false;
}
@@ -3545,6 +3545,14 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::Compute:
return hasCompute;
+ case QRhi::WideLines:
+ return hasWideLines;
+ case QRhi::VertexShaderPointSize:
+ return true;
+ case QRhi::BaseVertex:
+ return true;
+ case QRhi::BaseInstance:
+ return true;
default:
Q_UNREACHABLE();
return false;
@@ -4059,7 +4067,7 @@ void QRhiVulkan::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
}
void QRhiVulkan::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
- quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
+ quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
{
QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
@@ -4074,7 +4082,7 @@ void QRhiVulkan::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
}
void QRhiVulkan::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
- quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
+ quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
{
QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
@@ -5612,7 +5620,7 @@ bool QVkGraphicsPipeline::build()
rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rastInfo.cullMode = toVkCullMode(m_cullMode);
rastInfo.frontFace = toVkFrontFace(m_frontFace);
- rastInfo.lineWidth = 1.0f;
+ rastInfo.lineWidth = rhiD->hasWideLines ? m_lineWidth : 1.0f;
pipelineInfo.pRasterizationState = &rastInfo;
VkPipelineMultisampleStateCreateInfo msInfo;
diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h
index cec9016603..31e0eaa585 100644
--- a/src/gui/rhi/qrhivulkan_p_p.h
+++ b/src/gui/rhi/qrhivulkan_p_p.h
@@ -783,9 +783,11 @@ public:
QVkAllocator allocator = nullptr;
QVulkanFunctions *f = nullptr;
QVulkanDeviceFunctions *df = nullptr;
+ VkPhysicalDeviceFeatures physDevFeatures;
VkPhysicalDeviceProperties physDevProperties;
VkDeviceSize ubufAlign;
VkDeviceSize texbufAlign;
+ bool hasWideLines = false;
bool debugMarkersAvailable = false;
bool vertexAttribDivisorAvailable = false;
diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp
index 4676ec3f5b..9098180f69 100644
--- a/src/gui/rhi/qshader.cpp
+++ b/src/gui/rhi/qshader.cpp
@@ -389,7 +389,7 @@ QShader QShader::fromSerialized(const QByteArray &data)
QShader bs;
QShaderPrivate *d = QShaderPrivate::get(&bs);
- Q_ASSERT(d->ref.load() == 1); // must be detached
+ Q_ASSERT(d->ref.loadRelaxed() == 1); // must be detached
int intVal;
ds >> intVal;
if (intVal != QSB_VERSION)
diff --git a/src/gui/rhi/rhi.pri b/src/gui/rhi/rhi.pri
index d8607f1024..4297a5602b 100644
--- a/src/gui/rhi/rhi.pri
+++ b/src/gui/rhi/rhi.pri
@@ -40,7 +40,7 @@ win32 {
SOURCES += \
rhi/qrhid3d11.cpp
- LIBS += -ld3d11 -ldxgi -ldxguid -ld3dcompiler
+ LIBS += -ld3d11 -ldxgi -ldxguid
}
# darwin {
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index 5555422b82..97e73f0723 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -208,7 +208,7 @@ QFontPrivate::~QFontPrivate()
scFont = 0;
}
-extern QMutex *qt_fontdatabase_mutex();
+extern QRecursiveMutex *qt_fontdatabase_mutex();
#define QT_FONT_ENGINE_FROM_DATA(data, script) data->engines[script]
@@ -2799,12 +2799,12 @@ void QFontCache::cleanup()
cache->setLocalData(0);
}
-QBasicAtomicInt font_cache_id = Q_BASIC_ATOMIC_INITIALIZER(1);
+static QBasicAtomicInt font_cache_id = Q_BASIC_ATOMIC_INITIALIZER(0);
QFontCache::QFontCache()
: QObject(), total_cost(0), max_cost(min_cost),
current_timestamp(0), fast(false), timer_id(-1),
- m_id(font_cache_id.fetchAndAddRelaxed(1))
+ m_id(font_cache_id.fetchAndAddRelaxed(1) + 1)
{
}
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index 5350a9c5ec..ce6bb0c347 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -451,8 +451,7 @@ class QFontDatabasePrivate
public:
QFontDatabasePrivate()
: count(0), families(0),
- fallbacksCache(64),
- reregisterAppFonts(false)
+ fallbacksCache(64)
{ }
~QFontDatabasePrivate() {
@@ -488,7 +487,6 @@ public:
};
QVector<ApplicationFont> applicationFonts;
int addAppFont(const QByteArray &fontData, const QString &fileName);
- bool reregisterAppFonts;
bool isApplicationFont(const QString &fileName);
void invalidate();
@@ -707,7 +705,7 @@ static QStringList familyList(const QFontDef &req)
}
Q_GLOBAL_STATIC(QFontDatabasePrivate, privateDb)
-Q_GLOBAL_STATIC_WITH_ARGS(QMutex, fontDatabaseMutex, (QMutex::Recursive))
+Q_GLOBAL_STATIC(QRecursiveMutex, fontDatabaseMutex)
// used in qguiapplication.cpp
void qt_cleanupFontDatabase()
@@ -719,8 +717,8 @@ void qt_cleanupFontDatabase()
}
}
-// used in qfontengine_x11.cpp
-QMutex *qt_fontdatabase_mutex()
+// used in qfont.cpp
+QRecursiveMutex *qt_fontdatabase_mutex()
{
return fontDatabaseMutex();
}
@@ -897,15 +895,12 @@ static void initializeDb()
QFontDatabasePrivate *db = privateDb();
// init by asking for the platformfontdb for the first time or after invalidation
- if (!db->count)
+ if (!db->count) {
QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFontDatabase();
-
- if (db->reregisterAppFonts) {
for (int i = 0; i < db->applicationFonts.count(); i++) {
if (!db->applicationFonts.at(i).families.isEmpty())
registerFont(&db->applicationFonts[i]);
}
- db->reregisterAppFonts = false;
}
}
@@ -1033,11 +1028,7 @@ QFontEngine *loadEngine(int script, const QFontDef &request,
static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
{
- QFontDatabasePrivate *db = privateDb();
-
fnt->families = QGuiApplicationPrivate::platformIntegration()->fontDatabase()->addApplicationFont(fnt->data,fnt->fileName);
-
- db->reregisterAppFonts = true;
}
static QtFontStyle *bestStyle(QtFontFoundry *foundry, const QtFontStyle::Key &styleKey,
@@ -2451,13 +2442,18 @@ int QFontDatabasePrivate::addAppFont(const QByteArray &fontData, const QString &
if (font.fileName.isEmpty() && !fontData.isEmpty())
font.fileName = QLatin1String(":qmemoryfonts/") + QString::number(i);
+ bool wasEmpty = privateDb()->count == 0;
registerFont(&font);
if (font.families.isEmpty())
return -1;
applicationFonts[i] = font;
- invalidate();
+ // If the cache has not yet been populated, we need to reload the application font later
+ if (wasEmpty)
+ invalidate();
+ else
+ emit qApp->fontDatabaseChanged();
return i;
}
@@ -2598,7 +2594,6 @@ bool QFontDatabase::removeApplicationFont(int handle)
db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
- db->reregisterAppFonts = true;
db->invalidate();
return true;
}
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index 2ec3f41f42..dc34a96918 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -2306,7 +2306,11 @@ QString QTextHtmlExporter::toHtml(const QByteArray &encoding, ExportMode mode)
if (mode == ExportEntireDocument) {
html += QLatin1String(" style=\"");
- emitFontFamily(defaultCharFormat.fontFamily());
+ QStringList fontFamilies = defaultCharFormat.fontFamilies().toStringList();
+ if (!fontFamilies.isEmpty())
+ emitFontFamily(fontFamilies);
+ else
+ emitFontFamily(defaultCharFormat.fontFamily());
if (defaultCharFormat.hasProperty(QTextFormat::FontPointSize)) {
html += QLatin1String(" font-size:");
@@ -2368,8 +2372,12 @@ bool QTextHtmlExporter::emitCharFormatStyle(const QTextCharFormat &format)
bool attributesEmitted = false;
{
+ const QStringList families = format.fontFamilies().toStringList();
const QString family = format.fontFamily();
- if (!family.isEmpty() && family != defaultCharFormat.fontFamily()) {
+ if (!families.isEmpty() && families != defaultCharFormat.fontFamilies().toStringList()) {
+ emitFontFamily(families);
+ attributesEmitted = true;
+ } else if (!family.isEmpty() && family != defaultCharFormat.fontFamily()) {
emitFontFamily(family);
attributesEmitted = true;
}
@@ -2656,6 +2664,27 @@ void QTextHtmlExporter::emitFontFamily(const QString &family)
html += QLatin1Char(';');
}
+void QTextHtmlExporter::emitFontFamily(const QStringList &families)
+{
+ html += QLatin1String(" font-family:");
+
+ bool first = true;
+ for (const QString &family : families) {
+ QLatin1String quote("\'");
+ if (family.contains(QLatin1Char('\'')))
+ quote = QLatin1String("&quot;");
+
+ if (!first)
+ html += QLatin1String(",");
+ else
+ first = false;
+ html += quote;
+ html += family.toHtmlEscaped();
+ html += quote;
+ }
+ html += QLatin1Char(';');
+}
+
void QTextHtmlExporter::emitMargins(const QString &top, const QString &bottom, const QString &left, const QString &right)
{
html += QLatin1String(" margin-top:");
diff --git a/src/gui/text/qtextdocument_p.h b/src/gui/text/qtextdocument_p.h
index df00fb7d84..f4e7a25f22 100644
--- a/src/gui/text/qtextdocument_p.h
+++ b/src/gui/text/qtextdocument_p.h
@@ -397,6 +397,7 @@ private:
void emitPageBreakPolicy(QTextFormat::PageBreakFlags policy);
void emitFontFamily(const QString &family);
+ void emitFontFamily(const QStringList &families);
void emitBackgroundAttribute(const QTextFormat &format);
QString findUrlForImage(const QTextDocument *doc, qint64 cacheKey, bool isPixmap);
diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp
index 0b1a23f399..1ee317d27c 100644
--- a/src/gui/text/qtexthtmlparser.cpp
+++ b/src/gui/text/qtexthtmlparser.cpp
@@ -1548,7 +1548,16 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes)
n -= 3;
node->charFormat.setProperty(QTextFormat::FontSizeAdjustment, n);
} else if (key == QLatin1String("face")) {
- node->charFormat.setFontFamily(value);
+ if (value.contains(QLatin1Char(','))) {
+ const QStringList values = value.split(QLatin1Char(','));
+ QStringList families;
+ for (const QString &family : values)
+ families << family.trimmed();
+ node->charFormat.setFontFamilies(families);
+ node->charFormat.setFontFamily(families.at(0));
+ } else {
+ node->charFormat.setFontFamily(value);
+ }
} else if (key == QLatin1String("color")) {
QColor c; c.setNamedColor(value);
if (!c.isValid())
diff --git a/src/gui/text/qtextmarkdownwriter.cpp b/src/gui/text/qtextmarkdownwriter.cpp
index f351c8d20b..cbfb092485 100644
--- a/src/gui/text/qtextmarkdownwriter.cpp
+++ b/src/gui/text/qtextmarkdownwriter.cpp
@@ -47,6 +47,9 @@
#include "qtextcursor.h"
#include "qtextimagehandler_p.h"
#include "qloggingcategory.h"
+#if QT_CONFIG(itemmodel)
+#include "qabstractitemmodel.h"
+#endif
QT_BEGIN_NAMESPACE
@@ -70,6 +73,7 @@ bool QTextMarkdownWriter::writeAll(const QTextDocument *document)
return true;
}
+#if QT_CONFIG(itemmodel)
void QTextMarkdownWriter::writeTable(const QAbstractItemModel *table)
{
QVector<int> tableColumnWidths(table->columnCount());
@@ -101,6 +105,7 @@ void QTextMarkdownWriter::writeTable(const QAbstractItemModel *table)
}
m_listInfo.clear();
}
+#endif
void QTextMarkdownWriter::writeFrame(const QTextFrame *frame)
{
diff --git a/src/gui/text/qtextmarkdownwriter_p.h b/src/gui/text/qtextmarkdownwriter_p.h
index 90310250ac..c3076155d0 100644
--- a/src/gui/text/qtextmarkdownwriter_p.h
+++ b/src/gui/text/qtextmarkdownwriter_p.h
@@ -56,16 +56,19 @@
#include "qtextdocument_p.h"
#include "qtextdocumentwriter.h"
-#include "QAbstractTableModel"
QT_BEGIN_NAMESPACE
+class QAbstractItemModel;
+
class Q_GUI_EXPORT QTextMarkdownWriter
{
public:
QTextMarkdownWriter(QTextStream &stream, QTextDocument::MarkdownFeatures features);
bool writeAll(const QTextDocument *document);
+#if QT_CONFIG(itemmodel)
void writeTable(const QAbstractItemModel *table);
+#endif
int writeBlock(const QTextBlock &block, bool table, bool ignoreFormat, bool ignoreEmpty);
void writeFrame(const QTextFrame *frame);
diff --git a/src/gui/util/qdesktopservices.cpp b/src/gui/util/qdesktopservices.cpp
index 8c7cf8682c..ee0ff4c6ef 100644
--- a/src/gui/util/qdesktopservices.cpp
+++ b/src/gui/util/qdesktopservices.cpp
@@ -60,9 +60,9 @@ class QOpenUrlHandlerRegistry : public QObject
{
Q_OBJECT
public:
- inline QOpenUrlHandlerRegistry() : mutex(QMutex::Recursive) {}
+ QOpenUrlHandlerRegistry() = default;
- QMutex mutex;
+ QRecursiveMutex mutex;
struct Handler
{
diff --git a/src/gui/util/qshaderlanguage_p.h b/src/gui/util/qshaderlanguage_p.h
index 3af967b8c6..193f797cc3 100644
--- a/src/gui/util/qshaderlanguage_p.h
+++ b/src/gui/util/qshaderlanguage_p.h
@@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE
namespace QShaderLanguage
{
- Q_GUI_EXPORT Q_NAMESPACE
+ Q_NAMESPACE_EXPORT(Q_GUI_EXPORT)
enum StorageQualifier : char {
Const = 1,
diff --git a/src/gui/vulkan/vulkan.pri b/src/gui/vulkan/vulkan.pri
index 9bd7391235..5c902e8b82 100644
--- a/src/gui/vulkan/vulkan.pri
+++ b/src/gui/vulkan/vulkan.pri
@@ -17,39 +17,45 @@ qtConfig(vulkan) {
QMAKE_USE += vulkan/nolink
}
-# Generate qvulkanfunctions.h, qvulkanfunctions_p.h, qvulkanfunctions_p.cpp
-QMAKE_QVKGEN_INPUT = vulkan/vk.xml
-QMAKE_QVKGEN_LICENSE_HEADER = $$QT_SOURCE_TREE/header.LGPL
-qtPrepareTool(QMAKE_QVKGEN, qvkgen)
-
-qvkgen_h.commands = $$QMAKE_QVKGEN ${QMAKE_FILE_IN} $$shell_quote($$QMAKE_QVKGEN_LICENSE_HEADER) ${QMAKE_FILE_OUT_PATH}/${QMAKE_FILE_OUT_BASE}
-qvkgen_h.output = $$OUT_PWD/vulkan/qvulkanfunctions.h
-qvkgen_h.input = QMAKE_QVKGEN_INPUT
-qtConfig(vulkan): \
- qvkgen_h.variable_out = HEADERS
-else: \
- qvkgen_h.CONFIG += target_predeps no_link
-QMAKE_EXTRA_COMPILERS += qvkgen_h
-
-qvkgen_ph.commands = $$escape_expand(\\n)
-qvkgen_ph.output = $$OUT_PWD/vulkan/qvulkanfunctions_p.h
-qvkgen_ph.input = QMAKE_QVKGEN_INPUT
-qvkgen_ph.depends += $$OUT_PWD/vulkan/qvulkanfunctions.h
-qtConfig(vulkan): \
- qvkgen_ph.variable_out = HEADERS
-else: \
- qvkgen_ph.CONFIG += target_predeps no_link
-QMAKE_EXTRA_COMPILERS += qvkgen_ph
-
-qvkgen_pimpl.commands = $$escape_expand(\\n)
-qvkgen_pimpl.output = $$OUT_PWD/vulkan/qvulkanfunctions_p.cpp
-qvkgen_pimpl.input = QMAKE_QVKGEN_INPUT
-qvkgen_pimpl.depends += $$OUT_PWD/vulkan/qvulkanfunctions_p.h
-qtConfig(vulkan): \
- qvkgen_pimpl.variable_out = SOURCES
-else: \
- qvkgen_pimpl.CONFIG += target_predeps no_link
-QMAKE_EXTRA_COMPILERS += qvkgen_pimpl
+qtConfig(vkgen) {
+ # Generate qvulkanfunctions.h, qvulkanfunctions_p.h, qvulkanfunctions_p.cpp
+ QMAKE_QVKGEN_INPUT = vulkan/vk.xml
+ QMAKE_QVKGEN_LICENSE_HEADER = $$QT_SOURCE_TREE/header.LGPL
+ qtPrepareTool(QMAKE_QVKGEN, qvkgen)
+
+ qvkgen_h.commands = $$QMAKE_QVKGEN ${QMAKE_FILE_IN} $$shell_quote($$QMAKE_QVKGEN_LICENSE_HEADER) ${QMAKE_FILE_OUT_PATH}/${QMAKE_FILE_OUT_BASE}
+ qvkgen_h.output = $$OUT_PWD/vulkan/qvulkanfunctions.h
+ qvkgen_h.input = QMAKE_QVKGEN_INPUT
+ qtConfig(vulkan): \
+ qvkgen_h.variable_out = HEADERS
+ else: \
+ qvkgen_h.CONFIG += target_predeps no_link
+ QMAKE_EXTRA_COMPILERS += qvkgen_h
+
+ qvkgen_ph.commands = $$escape_expand(\\n)
+ qvkgen_ph.output = $$OUT_PWD/vulkan/qvulkanfunctions_p.h
+ qvkgen_ph.input = QMAKE_QVKGEN_INPUT
+ qvkgen_ph.depends += $$OUT_PWD/vulkan/qvulkanfunctions.h
+ qtConfig(vulkan): \
+ qvkgen_ph.variable_out = HEADERS
+ else: \
+ qvkgen_ph.CONFIG += target_predeps no_link
+ QMAKE_EXTRA_COMPILERS += qvkgen_ph
+
+ qvkgen_pimpl.commands = $$escape_expand(\\n)
+ qvkgen_pimpl.output = $$OUT_PWD/vulkan/qvulkanfunctions_p.cpp
+ qvkgen_pimpl.input = QMAKE_QVKGEN_INPUT
+ qvkgen_pimpl.depends += $$OUT_PWD/vulkan/qvulkanfunctions_p.h
+ qtConfig(vulkan): \
+ qvkgen_pimpl.variable_out = SOURCES
+ else: \
+ qvkgen_pimpl.CONFIG += target_predeps no_link
+ QMAKE_EXTRA_COMPILERS += qvkgen_pimpl
+} else {
+ # generate dummy files to make qmake happy
+ write_file($$OUT_PWD/vulkan/qvulkanfunctions.h)
+ write_file($$OUT_PWD/vulkan/qvulkanfunctions_p.h)
+}
# Ensure qvulkanfunctions.h gets installed correctly
targ_headers.CONFIG += no_check_exist