diff options
Diffstat (limited to 'src/gui')
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 ®ion, 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("""); + + 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 |