From 240c2ef60e854575dced056d916f8a8922905e8f Mon Sep 17 00:00:00 2001 From: Andrea Bernabei Date: Tue, 31 May 2016 14:21:44 +0100 Subject: Flickable: fix minXExtent/minYExtent when content is smaller than view At the moment, defining leftMargin (or topMargin) and contentWidth (or contentHeight) so that "leftMargin+contentWidth < flickable.width" (or topMargin+contentHeight < flickable.height) leads to widthRatio (or heightRatio) having value != 1. The value should, however, be 1, as the content is completely visible inside the view, margins included. As a sideeffect, under the assumptions described above, it will now not be possible to scroll the leftMargin (or topMargin) out of screen, something which was possible (and it shouldn't have) before this fix. Task-number: QTBUG-53726 Change-Id: I22426c8038e90a2cfc7445914206eae0e781a3fb Reviewed-by: Robin Burchell Reviewed-by: Albert Astals Cid Reviewed-by: Shawn Rutledge --- src/quick/items/qquickflickable.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/quick') diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 32d445dbc5..b0980cd2c1 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -1580,13 +1580,13 @@ qreal QQuickFlickable::minXExtent() const qreal QQuickFlickable::maxXExtent() const { Q_D(const QQuickFlickable); - return qMin(0, width() - vWidth() - d->hData.endMargin); + return qMin(minXExtent(), width() - vWidth() - d->hData.endMargin); } /* returns -ve */ qreal QQuickFlickable::maxYExtent() const { Q_D(const QQuickFlickable); - return qMin(0, height() - vHeight() - d->vData.endMargin); + return qMin(minYExtent(), height() - vHeight() - d->vData.endMargin); } void QQuickFlickable::componentComplete() -- cgit v1.2.3 From 506ae2dba8270341cbe3ee6435baf472b0d1abed Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 30 Jun 2016 16:54:13 +0200 Subject: Fix crash in QQuickShaderEffect::updatePaintNode When having a ShaderEffect and an Image sharing the texture via supportsAtlasTextures This used to work fine in 5.4 but 38cab579a0c5398b7621221fd8609bc43cf1f3c5 removed the check for the provider not being null Change-Id: I18cb969dbf8011ea01543cc079214e8ecbb66623 Reviewed-by: Frederik Gladhorn --- src/quick/items/qquickshadereffect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/quick') diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp index 94fa7e92e3..690433af4b 100644 --- a/src/quick/items/qquickshadereffect.cpp +++ b/src/quick/items/qquickshadereffect.cpp @@ -1054,7 +1054,7 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa bool geometryUsesTextureSubRect = false; if (m_supportsAtlasTextures && material->textureProviders.size() == 1) { QSGTextureProvider *provider = material->textureProviders.at(0); - if (provider->texture()) { + if (provider && provider->texture()) { srcRect = provider->texture()->normalizedTextureSubRect(); geometryUsesTextureSubRect = true; } -- cgit v1.2.3 From d7ebaa1611758a9677809d77e0b11f501c103f8d Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Wed, 6 Jul 2016 12:19:18 +0200 Subject: Doc: Added definition of enum value ItemAntialiasingHasChanged Error message: Undocumented enum item 'ItemAntialiasingHasChanged' in QQuickItem::ItemChange Change-Id: I0ea7bf4ba9cdf7fb69a9794694113c6501066d75 Reviewed-by: Martin Smith --- src/quick/items/qquickitem.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/quick') diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 5676bdb13a..aaa7ce04b9 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2102,6 +2102,9 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus) \value ItemDevicePixelRatioHasChanged The device pixel ratio of the screen the item is on has changed. ItemChangedData::realValue contains the new device pixel ratio. + + \value ItemAntialiasingHasChanged The antialiasing has changed. The current + (boolean) value can be found in QQuickItem::antialiasing. */ /*! -- cgit v1.2.3 From 1e18a4f985f6ec4a0191a2e0cc087b13d29b1719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Tue, 28 Jun 2016 11:34:59 +0100 Subject: macOS: Use sRGB when doing native font rendering into FBO Otherwise text appears too dark. A similar bug was fixed in the past for QQuickWidget (which also uses FBO). Now this fixes it for ShaderEffectSource and QQuickItem::grabImage() too. Change-Id: Ia0e176372b9ba8282972f8d60f87f02747291ffe Task-Id: QTBUG-52906 Reviewed-by: Sean Harmer --- src/quick/scenegraph/qsgdefaultlayer.cpp | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'src/quick') diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp index fa69f911dd..99735564ef 100644 --- a/src/quick/scenegraph/qsgdefaultlayer.cpp +++ b/src/quick/scenegraph/qsgdefaultlayer.cpp @@ -42,6 +42,29 @@ DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY) #endif DEFINE_BOOL_CONFIG_OPTION(qmlFboFlushBeforeDetach, QML_FBO_FLUSH_BEFORE_DETACH) + + +static QOpenGLFramebufferObject *createFramebuffer(const QSize &size, + QOpenGLFramebufferObjectFormat format) +{ +#ifdef Q_OS_MACOS + QOpenGLContext *context = QOpenGLContext::currentContext(); + if (context->hasExtension("GL_ARB_framebuffer_sRGB") + && context->hasExtension("GL_EXT_texture_sRGB") + && context->hasExtension("GL_EXT_texture_sRGB_decode")) + format.setInternalTextureFormat(GL_SRGB8_ALPHA8_EXT); +#endif + QOpenGLFramebufferObject *fbo = new QOpenGLFramebufferObject(size, format); +#ifdef Q_OS_MACOS + if (format.internalTextureFormat() == GL_SRGB8_ALPHA8_EXT) { + QOpenGLFunctions *funcs = context->functions(); + funcs->glBindTexture(GL_TEXTURE_2D, fbo->texture()); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); + } +#endif + return fbo; +} + namespace { class BindableFbo : public QSGBindable @@ -324,7 +347,7 @@ void QSGDefaultLayer::grab() format.setInternalTextureFormat(m_format); format.setSamples(m_context->openglContext()->format().samples()); - m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); + m_secondaryFbo = createFramebuffer(m_size, format); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { QOpenGLFramebufferObjectFormat format; @@ -333,14 +356,14 @@ void QSGDefaultLayer::grab() if (m_recursive) { deleteFboLater = true; delete m_secondaryFbo; - m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); + m_secondaryFbo = createFramebuffer(m_size, format); funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { delete m_fbo; delete m_secondaryFbo; - m_fbo = new QOpenGLFramebufferObject(m_size, format); + m_fbo = createFramebuffer(m_size, format); m_secondaryFbo = 0; funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); @@ -354,7 +377,7 @@ void QSGDefaultLayer::grab() Q_ASSERT(m_fbo); Q_ASSERT(!m_multisampling); - m_secondaryFbo = new QOpenGLFramebufferObject(m_size, m_fbo->format()); + m_secondaryFbo = createFramebuffer(m_size, m_fbo->format()); funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); } -- cgit v1.2.3 From e4f7ab42c6c4f19eed76d9d0de5accda5835a3a8 Mon Sep 17 00:00:00 2001 From: Daniel d'Andrada Date: Wed, 6 Jul 2016 17:01:35 -0300 Subject: QQuickWindow: Fill out timestamps in QHoverEvents sent to QQuickItems Task-number: QTBUG-54600 Change-Id: Ie24c44e2f68aae55ff1146c13c3dfc25349b7a29 Reviewed-by: Frederik Gladhorn Reviewed-by: Robin Burchell Reviewed-by: Shawn Rutledge --- src/quick/items/qquickwindow.cpp | 28 +++++++++++++++------------- src/quick/items/qquickwindow_p.h | 6 +++--- 2 files changed, 18 insertions(+), 16 deletions(-) (limited to 'src/quick') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 14e7915dba..de1b5f236e 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -661,10 +661,10 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e lastMousePosition = me->windowPos(); bool accepted = me->isAccepted(); - bool delivered = deliverHoverEvent(contentItem, me->windowPos(), last, me->modifiers(), accepted); + bool delivered = deliverHoverEvent(contentItem, me->windowPos(), last, me->modifiers(), me->timestamp(), accepted); if (!delivered) { //take care of any exits - accepted = clearHover(); + accepted = clearHover(me->timestamp()); } me->setAccepted(accepted); break; @@ -1397,7 +1397,7 @@ QQuickItem *QQuickWindow::mouseGrabberItem() const } -bool QQuickWindowPrivate::clearHover() +bool QQuickWindowPrivate::clearHover(ulong timestamp) { Q_Q(QQuickWindow); if (hoverItems.isEmpty()) @@ -1407,7 +1407,7 @@ bool QQuickWindowPrivate::clearHover() bool accepted = false; foreach (QQuickItem* item, hoverItems) - accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted; + accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), timestamp, true) || accepted; hoverItems.clear(); return accepted; } @@ -1657,13 +1657,15 @@ void QQuickWindow::mouseDoubleClickEvent(QMouseEvent *event) bool QQuickWindowPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos, - Qt::KeyboardModifiers modifiers, bool accepted) + Qt::KeyboardModifiers modifiers, ulong timestamp, + bool accepted) { Q_Q(QQuickWindow); const QTransform transform = QQuickItemPrivate::get(item)->windowToItemTransform(); //create copy of event QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers); + hoverEvent.setTimestamp(timestamp); hoverEvent.setAccepted(accepted); QSet hasFiltered; @@ -1699,10 +1701,10 @@ void QQuickWindow::mouseMoveEvent(QMouseEvent *event) d->lastMousePosition = event->windowPos(); bool accepted = event->isAccepted(); - bool delivered = d->deliverHoverEvent(d->contentItem, event->windowPos(), last, event->modifiers(), accepted); + bool delivered = d->deliverHoverEvent(d->contentItem, event->windowPos(), last, event->modifiers(), event->timestamp(), accepted); if (!delivered) { //take care of any exits - accepted = d->clearHover(); + accepted = d->clearHover(event->timestamp()); } event->setAccepted(accepted); return; @@ -1712,7 +1714,7 @@ void QQuickWindow::mouseMoveEvent(QMouseEvent *event) } bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos, - Qt::KeyboardModifiers modifiers, bool &accepted) + Qt::KeyboardModifiers modifiers, ulong timestamp, bool &accepted) { Q_Q(QQuickWindow); QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); @@ -1728,7 +1730,7 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce QQuickItem *child = children.at(ii); if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled) continue; - if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted)) + if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, timestamp, accepted)) return true; } @@ -1737,7 +1739,7 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce if (item->contains(p)) { if (!hoverItems.isEmpty() && hoverItems[0] == item) { //move - accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted); + accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, timestamp, accepted); } else { QList itemsToHover; QQuickItem* parent = item; @@ -1748,12 +1750,12 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce // Leaving from previous hovered items until we reach the item or one of its ancestors. while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) { QQuickItem *hoverLeaveItem = hoverItems.takeFirst(); - sendHoverEvent(QEvent::HoverLeave, hoverLeaveItem, scenePos, lastScenePos, modifiers, accepted); + sendHoverEvent(QEvent::HoverLeave, hoverLeaveItem, scenePos, lastScenePos, modifiers, timestamp, accepted); } if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item // ### Shouldn't we send moves for the parent items as well? - accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted); + accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, timestamp, accepted); } else { // Enter items that are not entered yet. int startIdx = -1; @@ -1772,7 +1774,7 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce // itemToHoverPrivate->window here prevents that case. if (itemToHoverPrivate->window == q && itemToHoverPrivate->hoverEnabled) { hoverItems.prepend(itemToHover); - sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted); + sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, timestamp, accepted); } } } diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 33aa021d98..be7252d335 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -155,14 +155,14 @@ public: bool deliverTouchCancelEvent(QTouchEvent *); void deliverDelayedTouchEvent(); void flushDelayedTouchEvent(); - bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool &accepted); + bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, ulong timestamp, bool &accepted); bool deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet *acceptedNewPoints, const QSet &matchingNewPoints, const QList &matchingPoints, QSet *filtered); QTouchEvent *touchEventForItemBounds(QQuickItem *target, const QTouchEvent &originalEvent); QTouchEvent *touchEventWithPoints(const QTouchEvent &event, const QList &newPoints); bool sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event, QSet *filtered); bool sendHoverEvent(QEvent::Type, QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, - Qt::KeyboardModifiers modifiers, bool accepted); - bool clearHover(); + Qt::KeyboardModifiers modifiers, ulong timestamp, bool accepted); + bool clearHover(ulong timestamp = 0); #ifndef QT_NO_DRAGANDDROP void deliverDragEvent(QQuickDragGrabber *, QEvent *); bool deliverDragEvent(QQuickDragGrabber *, QQuickItem *, QDragMoveEvent *); -- cgit v1.2.3 From a1f6409d1c34238405bbd73d067a39091bf844f7 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Thu, 7 Jul 2016 13:21:05 +0200 Subject: Fix missing closing parenthesis in TextEdit docs Change-Id: Ib1872e6353a49bc12a6a714a79873e8c0a7032f7 Reviewed-by: Robin Burchell --- src/quick/items/qquicktextedit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/quick') diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 8282c09770..3ab7f358ff 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -1435,8 +1435,8 @@ void QQuickTextEdit::setSelectByKeyboard(bool on) If true, the user can use the mouse to select text in some platform-specific way. Note that for some platforms this may - not be an appropriate interaction (eg. may conflict with how - the text needs to behave inside a Flickable. + not be an appropriate interaction; it may conflict with how + the text needs to behave inside a Flickable, for example. */ bool QQuickTextEdit::selectByMouse() const { -- cgit v1.2.3 From 50cc3c20047b88e763dc21ec3c5d8b28c7ecb2d4 Mon Sep 17 00:00:00 2001 From: Joni Poikelin Date: Thu, 14 Jul 2016 08:55:08 +0300 Subject: Avoid crashing when failing to query GL_EXTENSIONS Change-Id: Ice542d53c4eb9f34745e2d06dd03c32de7a9817e Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/util/qsgatlastexture.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/quick') diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index 832510148c..1a1f0d37f7 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -151,13 +151,13 @@ Atlas::Atlas(const QSize &size) wrongfullyReportsBgra8888Support = false; const char *ext = (const char *) QOpenGLContext::currentContext()->functions()->glGetString(GL_EXTENSIONS); - if (!wrongfullyReportsBgra8888Support + if (ext && !wrongfullyReportsBgra8888Support && (strstr(ext, "GL_EXT_bgra") || strstr(ext, "GL_EXT_texture_format_BGRA8888") || strstr(ext, "GL_IMG_texture_format_BGRA8888"))) { m_internalFormat = m_externalFormat = GL_BGRA; #ifdef Q_OS_IOS - } else if (strstr(ext, "GL_APPLE_texture_format_BGRA8888")) { + } else if (ext && strstr(ext, "GL_APPLE_texture_format_BGRA8888")) { m_internalFormat = GL_RGBA; m_externalFormat = GL_BGRA; #endif // IOS -- cgit v1.2.3 From b08a4c2f421494b515dc7ef6f50d33e37e18eb91 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Tue, 12 Jul 2016 19:29:39 +0200 Subject: Remove vsync sleep before rendering first frame The QSGRenderThread slept for up to one vsync interval before the first frame was rendered. This happened when the QSGRenderContext was not yet initialized and thus a sync could not result in changes. With LTTNG and custom trace points this latency was easily visible before the first frame swap. With perf it can also be checked, when one does: QSG_RENDER_LOOP=threaded perf trace record -m 10M \ -e syscalls:sys_enter_nanosleep,syscalls:sys_enter_ioctl \ --call-graph dwarf qml main.qml ... [ perf record: Captured and wrote 116.731 MB perf.data (14309 samples) ] Then afterwards have a look at the output of perf script --comms QSGRenderThread And you will notice the sleep directly at the start, followed by the bulk of ioctl required to setup the OpenGL contexts: QSGRenderThread 10875 [001] 13940.801449: syscalls:sys_enter_nanosleep: rqtp: 0x7f1ab954cd60, rmtp: 0x7f1ab954cd60 7f1ada3997fd __nanosleep+0x2d (/usr/lib/libpthread-2.23.so) 7f1ada9683ed qt_nanosleep+0x2d (/home/milian/projects/compiled/qt5-5.7-opt/lib/libQt5Core.so.5.7.0) 7f1ada8c73b8 QThread::msleep+0x38 (/home/milian/projects/compiled/qt5-5.7-opt/lib/libQt5Core.so.5.7.0) 7f1abb594320 QSGRenderThread::syncAndRender+0x320 (/home/milian/projects/compiled/qt5-5.7-opt/lib/libQt5Quick.so.5.7.0) 7f1abb598b0c QSGRenderThread::run+0x19c (/home/milian/projects/compiled/qt5-5.7-opt/lib/libQt5Quick.so.5.7.0) 7f1ada8c7f89 QThreadPrivate::start+0x149 (/home/milian/projects/compiled/qt5-5.7-opt/lib/libQt5Core.so.5.7.0) 7f1ada390484 start_thread+0xc4 (/usr/lib/libpthread-2.23.so) 7f1ad982e6dd __clone+0x6d (/usr/lib/libc-2.23.so) ... ioctl follow This change here checks the validity of the render context before sleeping, thereby removing the vsync latency before rendering the first frame. Note that simply skipping the calls to `syncAndRender` from `run` is not an option, as those also trigger the expose event that is required for the initialization to happen eventually. [ChangeLog][QtQuick] The threaded scene graph renderer does not sleep up to one vsync interval before the first frame anymore. Change-Id: If7474d5420e0d4a1d05ccb664c7c6932fa989127 Reviewed-by: Gunnar Sletta Reviewed-by: Ulf Hermann --- src/quick/scenegraph/qsgthreadedrenderloop.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/quick') diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 8d6bea9e67..ceb3caa53f 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -593,7 +593,7 @@ void QSGRenderThread::syncAndRender() #endif Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame); - if (!syncResultedInChanges && !repaintRequested) { + if (!syncResultedInChanges && !repaintRequested && sgrc->isValid()) { qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- no changes, render aborted"; int waitTime = vsyncDelta - (int) waitTimer.elapsed(); if (waitTime > 0) -- cgit v1.2.3 From 0a87552e8122cdda58160da2dd549da411d9093c Mon Sep 17 00:00:00 2001 From: Dan Cape Date: Wed, 7 Oct 2015 15:46:14 -0400 Subject: Fix QQuickItem's setAcceptedMouseButtons function When using setAcceptedMouseButtons to only allow the LeftButton, the user can click the LeftButton and while still holding it press the RightButton. There would be a press event sent for both. To resolve this, a check needed to be added to ensure the acceptedMouseButtons are checked when a second press comes in. [ChangeLog][QtQuick][QQuickItem] Fixed issue with mouse button events being sent even when they were disabled by setAcceptedMouseButtons. Change-Id: I064f3ff56ede12b1572e172be326eb337e280750 Task-number: QTBUG-31861 Reviewed-by: Frederik Gladhorn Reviewed-by: Robin Burchell Reviewed-by: Shawn Rutledge --- src/quick/items/qquickwindow.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/quick') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index de1b5f236e..8a2471b34f 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1584,6 +1584,12 @@ bool QQuickWindowPrivate::deliverMouseEvent(QMouseEvent *event) } if (mouseGrabberItem) { + if (event->button() != Qt::NoButton + && mouseGrabberItem->acceptedMouseButtons() + && !(mouseGrabberItem->acceptedMouseButtons() & event->button())) { + event->ignore(); + return false; + } QPointF localPos = mouseGrabberItem->mapFromScene(event->windowPos()); QScopedPointer me(cloneMouseEvent(event, &localPos)); me->accept(); -- cgit v1.2.3 From 1943ef3b06d3f95a4e6c4d24f771cee8db02d342 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 22 Jul 2016 19:38:10 -0700 Subject: Work around ICC bug about C++11 noexcept inheritance qquickitemanimation.cpp(213): error #809: exception specification for virtual function "QQuickParentAnimationData::~QQuickParentAnimationData" is incompatible with that of overridden function "QAbstractAnimationAction::~QAbstractAnimationAction" Change-Id: I149e0540c00745fe8119fffd1463cb59e590b6b8 Reviewed-by: Simon Hausmann --- src/quick/items/qquickitemanimation.cpp | 42 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'src/quick') diff --git a/src/quick/items/qquickitemanimation.cpp b/src/quick/items/qquickitemanimation.cpp index 9d140b3156..6b48ca5bf9 100644 --- a/src/quick/items/qquickitemanimation.cpp +++ b/src/quick/items/qquickitemanimation.cpp @@ -194,6 +194,27 @@ QPointF QQuickParentAnimationPrivate::computeTransformOrigin(QQuickItem::Transfo } } +struct QQuickParentAnimationData : public QAbstractAnimationAction +{ + QQuickParentAnimationData() : reverse(false) {} + ~QQuickParentAnimationData() { qDeleteAll(pc); } + + QQuickStateActions actions; + //### reverse should probably apply on a per-action basis + bool reverse; + QList pc; + void doAction() Q_DECL_OVERRIDE + { + for (int ii = 0; ii < actions.count(); ++ii) { + const QQuickStateAction &action = actions.at(ii); + if (reverse) + action.event->reverse(); + else + action.event->execute(); + } + } +}; + QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &actions, QQmlProperties &modified, TransitionDirection direction, @@ -201,27 +222,6 @@ QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &act { Q_D(QQuickParentAnimation); - struct QQuickParentAnimationData : public QAbstractAnimationAction - { - QQuickParentAnimationData() : reverse(false) {} - ~QQuickParentAnimationData() { qDeleteAll(pc); } - - QQuickStateActions actions; - //### reverse should probably apply on a per-action basis - bool reverse; - QList pc; - void doAction() Q_DECL_OVERRIDE - { - for (int ii = 0; ii < actions.count(); ++ii) { - const QQuickStateAction &action = actions.at(ii); - if (reverse) - action.event->reverse(); - else - action.event->execute(); - } - } - }; - QQuickParentAnimationData *data = new QQuickParentAnimationData; QQuickParentAnimationData *viaData = new QQuickParentAnimationData; -- cgit v1.2.3 From 007ae316a62670eeff8b08526fad9110fff0bbd4 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 14 Jul 2016 12:09:23 +0200 Subject: QML: Unify property reads/writes and use accessors Pass property reads/writes through utility functions in QQmlProperty, which in turn will try to use accessors when available (and no interceptors have to be called). Change-Id: I60ecfc202b6024bfe4a33206a46299787b152546 Reviewed-by: Simon Hausmann --- src/quick/designer/qquickdesignercustomobjectdata.cpp | 4 ++-- src/quick/util/qquickanimation.cpp | 6 +++--- src/quick/util/qquickbehavior.cpp | 6 +++--- src/quick/util/qquickpropertychanges.cpp | 12 ++++++------ src/quick/util/qquicksmoothedanimation.cpp | 12 ++++++------ src/quick/util/qquickspringanimation.cpp | 4 ++-- src/quick/util/qquicktransitionmanager.cpp | 6 +++--- 7 files changed, 25 insertions(+), 25 deletions(-) (limited to 'src/quick') diff --git a/src/quick/designer/qquickdesignercustomobjectdata.cpp b/src/quick/designer/qquickdesignercustomobjectdata.cpp index 42dcb08d45..3c8f4b281c 100644 --- a/src/quick/designer/qquickdesignercustomobjectdata.cpp +++ b/src/quick/designer/qquickdesignercustomobjectdata.cpp @@ -194,7 +194,7 @@ void QQuickDesignerCustomObjectData::doResetProperty(QQmlContext *context, const #endif if (qmlBinding) qmlBinding->setTarget(property); - QQmlPropertyPrivate::setBinding(binding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding); + QQmlPropertyPrivate::setBinding(binding, QQmlPropertyPrivate::None, QQmlPropertyData::DontRemoveBinding); if (qmlBinding) qmlBinding->update(); @@ -262,7 +262,7 @@ void QQuickDesignerCustomObjectData::setPropertyBinding(QQmlContext *context, binding->setTarget(property); binding->setNotifyOnValueChanged(true); - QQmlPropertyPrivate::setBinding(binding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding); + QQmlPropertyPrivate::setBinding(binding, QQmlPropertyPrivate::None, QQmlPropertyData::DontRemoveBinding); //Refcounting is taking take care of deletion binding->update(); if (binding->hasError()) { diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp index 741a583803..d782f9309f 100644 --- a/src/quick/util/qquickanimation.cpp +++ b/src/quick/util/qquickanimation.cpp @@ -1202,7 +1202,7 @@ QAbstractAnimationJob* QQuickPropertyAction::transition(QQuickStateActions &acti { for (int ii = 0; ii < actions.count(); ++ii) { const QQuickStateAction &action = actions.at(ii); - QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); + QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); } } virtual void debugAction(QDebug d, int indentLevel) const { @@ -2535,7 +2535,7 @@ void QQuickAnimationPropertyUpdater::setValue(qreal v) QQuickStateAction &action = actions[ii]; if (v == 1.) { - QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); + QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); } else { if (!fromSourced && !fromDefined) { action.fromValue = action.property.read(); @@ -2551,7 +2551,7 @@ void QQuickAnimationPropertyUpdater::setValue(qreal v) } } if (interpolator) - QQmlPropertyPrivate::write(action.property, interpolator(action.fromValue.constData(), action.toValue.constData(), v), QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); + QQmlPropertyPrivate::write(action.property, interpolator(action.fromValue.constData(), action.toValue.constData(), v), QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); } if (deleted) return; diff --git a/src/quick/util/qquickbehavior.cpp b/src/quick/util/qquickbehavior.cpp index 147380037d..1d3ee2c4be 100644 --- a/src/quick/util/qquickbehavior.cpp +++ b/src/quick/util/qquickbehavior.cpp @@ -180,7 +180,7 @@ void QQuickBehavior::write(const QVariant &value) if (!d->animation || bypass) { if (d->animationInstance) d->animationInstance->stop(); - QQmlPropertyPrivate::write(d->property, value, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); + QQmlPropertyPrivate::write(d->property, value, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); d->targetValue = value; return; } @@ -206,7 +206,7 @@ void QQuickBehavior::write(const QVariant &value) // is needed (value has not changed). If the Behavior was already // running, let it continue as normal to ensure correct behavior and state. if (!behaviorActive && d->targetValue == currentValue) { - QQmlPropertyPrivate::write(d->property, value, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); + QQmlPropertyPrivate::write(d->property, value, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); return; } @@ -234,7 +234,7 @@ void QQuickBehavior::write(const QVariant &value) d->blockRunningChanged = false; } if (!after.contains(d->property)) - QQmlPropertyPrivate::write(d->property, value, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); + QQmlPropertyPrivate::write(d->property, value, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); } void QQuickBehavior::setTarget(const QQmlProperty &property) diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp index a42ec31058..c4be68cd31 100644 --- a/src/quick/util/qquickpropertychanges.cpp +++ b/src/quick/util/qquickpropertychanges.cpp @@ -597,7 +597,7 @@ void QQuickPropertyChanges::changeValue(const QString &name, const QVariant &val state()->addEntryToRevertList(action); QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(action.property); if (oldBinding) - oldBinding->setEnabled(false, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); + oldBinding->setEnabled(false, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor); d->property(name).write(value); } } @@ -631,7 +631,7 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString &QQmlPropertyPrivate::get(prop)->core, expression, object(), qmlContext(this)); newBinding->setTarget(prop); - QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); + QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor); } return; } @@ -644,7 +644,7 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString if (hadValue) { QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(d->property(name)); if (oldBinding) { - oldBinding->setEnabled(false, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); + oldBinding->setEnabled(false, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor); state()->changeBindingInRevertList(object(), name, oldBinding); } @@ -653,7 +653,7 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString &QQmlPropertyPrivate::get(prop)->core, expression, object(), qmlContext(this)); newBinding->setTarget(prop); - QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); + QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor); } else { QQuickStateAction action; action.restore = restoreEntryValues(); @@ -679,9 +679,9 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString state()->addEntryToRevertList(action); QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(action.property); if (oldBinding) - oldBinding->setEnabled(false, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); + oldBinding->setEnabled(false, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor); - QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); + QQmlPropertyPrivate::setBinding(newBinding, QQmlPropertyPrivate::None, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor); } } } diff --git a/src/quick/util/qquicksmoothedanimation.cpp b/src/quick/util/qquicksmoothedanimation.cpp index 569cb37c95..a992589040 100644 --- a/src/quick/util/qquicksmoothedanimation.cpp +++ b/src/quick/util/qquicksmoothedanimation.cpp @@ -254,8 +254,8 @@ void QSmoothedAnimation::updateCurrentTime(int t) qreal value = easeFollow(time_seconds); value *= (invert? -1.0: 1.0); QQmlPropertyPrivate::write(target, initialValue + value, - QQmlPropertyPrivate::BypassInterceptor - | QQmlPropertyPrivate::DontRemoveBinding); + QQmlPropertyData::BypassInterceptor + | QQmlPropertyData::DontRemoveBinding); } void QSmoothedAnimation::init() @@ -287,8 +287,8 @@ void QSmoothedAnimation::init() break; case QQuickSmoothedAnimation::Sync: QQmlPropertyPrivate::write(target, to, - QQmlPropertyPrivate::BypassInterceptor - | QQmlPropertyPrivate::DontRemoveBinding); + QQmlPropertyData::BypassInterceptor + | QQmlPropertyData::DontRemoveBinding); trackVelocity = 0; stop(); return; @@ -304,8 +304,8 @@ void QSmoothedAnimation::init() if (!recalc()) { QQmlPropertyPrivate::write(target, to, - QQmlPropertyPrivate::BypassInterceptor - | QQmlPropertyPrivate::DontRemoveBinding); + QQmlPropertyData::BypassInterceptor + | QQmlPropertyData::DontRemoveBinding); stop(); return; } diff --git a/src/quick/util/qquickspringanimation.cpp b/src/quick/util/qquickspringanimation.cpp index d2bc3b4ece..294122150a 100644 --- a/src/quick/util/qquickspringanimation.cpp +++ b/src/quick/util/qquickspringanimation.cpp @@ -301,8 +301,8 @@ void QSpringAnimation::updateCurrentTime(int time) qreal old_to = to; QQmlPropertyPrivate::write(target, currentValue, - QQmlPropertyPrivate::BypassInterceptor | - QQmlPropertyPrivate::DontRemoveBinding); + QQmlPropertyData::BypassInterceptor | + QQmlPropertyData::DontRemoveBinding); if (stopped && old_to == to) { // do not stop if we got restarted if (animationTemplate) diff --git a/src/quick/util/qquicktransitionmanager.cpp b/src/quick/util/qquicktransitionmanager.cpp index 55abb0a207..60f710549b 100644 --- a/src/quick/util/qquicktransitionmanager.cpp +++ b/src/quick/util/qquicktransitionmanager.cpp @@ -159,9 +159,9 @@ void QQuickTransitionManager::transition(const QList &list, for (int ii = 0; ii < applyList.size(); ++ii) { const QQuickStateAction &action = applyList.at(ii); if (action.toBinding) { - QQmlPropertyPrivate::setBinding(action.toBinding.data(), QQmlPropertyPrivate::None, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); + QQmlPropertyPrivate::setBinding(action.toBinding.data(), QQmlPropertyPrivate::None, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); } else if (!action.event) { - QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); + QQmlPropertyPrivate::write(action.property, action.toValue, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); } else if (action.event->isReversable()) { if (action.reverseEvent) action.event->reverse(); @@ -197,7 +197,7 @@ void QQuickTransitionManager::transition(const QList &list, if (action.toBinding) QQmlPropertyPrivate::removeBinding(action.property); // Make sure this is disabled during the transition - QQmlPropertyPrivate::write(action.property, action.fromValue, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding); + QQmlPropertyPrivate::write(action.property, action.fromValue, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); } } -- cgit v1.2.3 From dbb56ab74a8978a8fb13572af020a63f378fc846 Mon Sep 17 00:00:00 2001 From: Nikita Krupenko Date: Mon, 12 Oct 2015 19:36:31 +0300 Subject: Expose HSV and HSL color values to QML [ChangeLog][QtQuick] Added properties to access color values for the HSV and HSL color models to the basic QML color type. Task-number: QTBUG-48723 Change-Id: I45fa52f9f3878553e1b3d0a34b47804ede7794f8 Reviewed-by: Mitch Curtis --- src/quick/doc/src/qmltypereference.qdoc | 13 +++--- src/quick/util/qquickvaluetypes.cpp | 72 +++++++++++++++++++++++++++++++++ src/quick/util/qquickvaluetypes_p.h | 18 +++++++++ 3 files changed, 98 insertions(+), 5 deletions(-) (limited to 'src/quick') diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc index 6e6e66e026..2406722dbc 100644 --- a/src/quick/doc/src/qmltypereference.qdoc +++ b/src/quick/doc/src/qmltypereference.qdoc @@ -100,9 +100,9 @@ available when you import \c QtQuick. \li By a hexadecimal triplet or quad in the form \c "#RRGGBB" and \c "#AARRGGBB" respectively. For example, the color red corresponds to a triplet of \c "#FF0000" and a slightly transparent blue to a quad of \c "#800000FF". - \li Using the \l{QtQml::Qt::rgba()}{Qt.rgba()}, \l{QtQml::Qt::hsla()}{Qt.hsla()}, - \l{QtQml::Qt::darker()}{Qt.darker()}, \l{QtQml::Qt::lighter()}{Qt.lighter()} or - \l{QtQml::Qt::tint()}{Qt.tint()} functions. + \li Using the \l{QtQml::Qt::rgba()}{Qt.rgba()}, \l{QtQml::Qt::hsva()}{Qt.hsva()}, + \l{QtQml::Qt::hsla()}{Qt.hsla()}, \l{QtQml::Qt::darker()}{Qt.darker()}, + \l{QtQml::Qt::lighter()}{Qt.lighter()} or \l{QtQml::Qt::tint()}{Qt.tint()} functions. \endlist Example: @@ -112,8 +112,11 @@ available when you import \c QtQuick. \enddiv \snippet qml/colors.qml colors - Additionally, a color type has \c r, \c g, \c b and \c a properties that refer to the - red, green, blue and alpha values of the color, respectively: + A color type has \c r, \c g, \c b and \c a properties that refer to the red, + green, blue and alpha values of the color, respectively. Additionally it has + \c hsvHue, \c hsvSaturation, \c hsvValue and \c hslHue, \c hslSaturation, + \c hslLightness properties, which allow access to color values in HSV and HSL + color models accordingly: \qml Text { diff --git a/src/quick/util/qquickvaluetypes.cpp b/src/quick/util/qquickvaluetypes.cpp index 7b9b6068bd..e673df0451 100644 --- a/src/quick/util/qquickvaluetypes.cpp +++ b/src/quick/util/qquickvaluetypes.cpp @@ -80,6 +80,36 @@ qreal QQuickColorValueType::a() const return v.alphaF(); } +qreal QQuickColorValueType::hsvHue() const +{ + return v.hsvHueF(); +} + +qreal QQuickColorValueType::hsvSaturation() const +{ + return v.hsvSaturationF(); +} + +qreal QQuickColorValueType::hsvValue() const +{ + return v.valueF(); +} + +qreal QQuickColorValueType::hslHue() const +{ + return v.hslHueF(); +} + +qreal QQuickColorValueType::hslSaturation() const +{ + return v.hslSaturationF(); +} + +qreal QQuickColorValueType::hslLightness() const +{ + return v.lightnessF(); +} + void QQuickColorValueType::setR(qreal r) { v.setRedF(r); @@ -100,6 +130,48 @@ void QQuickColorValueType::setA(qreal a) v.setAlphaF(a); } +void QQuickColorValueType::setHsvHue(qreal hsvHue) +{ + qreal hue, saturation, value, alpha; + v.getHsvF(&hue, &saturation, &value, &alpha); + v.setHsvF(hsvHue, saturation, value, alpha); +} + +void QQuickColorValueType::setHsvSaturation(qreal hsvSaturation) +{ + qreal hue, saturation, value, alpha; + v.getHsvF(&hue, &saturation, &value, &alpha); + v.setHsvF(hue, hsvSaturation, value, alpha); +} + +void QQuickColorValueType::setHsvValue(qreal hsvValue) +{ + qreal hue, saturation, value, alpha; + v.getHsvF(&hue, &saturation, &value, &alpha); + v.setHsvF(hue, saturation, hsvValue, alpha); +} + +void QQuickColorValueType::setHslHue(qreal hslHue) +{ + qreal hue, saturation, lightness, alpha; + v.getHslF(&hue, &saturation, &lightness, &alpha); + v.setHslF(hslHue, saturation, lightness, alpha); +} + +void QQuickColorValueType::setHslSaturation(qreal hslSaturation) +{ + qreal hue, saturation, lightness, alpha; + v.getHslF(&hue, &saturation, &lightness, &alpha); + v.setHslF(hue, hslSaturation, lightness, alpha); +} + +void QQuickColorValueType::setHslLightness(qreal hslLightness) +{ + qreal hue, saturation, lightness, alpha; + v.getHslF(&hue, &saturation, &lightness, &alpha); + v.setHslF(hue, saturation, hslLightness, alpha); +} + QString QQuickVector2DValueType::toString() const { return QString(QLatin1String("QVector2D(%1, %2)")).arg(v.x()).arg(v.y()); diff --git a/src/quick/util/qquickvaluetypes_p.h b/src/quick/util/qquickvaluetypes_p.h index 05e954f915..4a1598ec5c 100644 --- a/src/quick/util/qquickvaluetypes_p.h +++ b/src/quick/util/qquickvaluetypes_p.h @@ -78,6 +78,12 @@ class QQuickColorValueType Q_PROPERTY(qreal g READ g WRITE setG FINAL) Q_PROPERTY(qreal b READ b WRITE setB FINAL) Q_PROPERTY(qreal a READ a WRITE setA FINAL) + Q_PROPERTY(qreal hsvHue READ hsvHue WRITE setHsvHue FINAL) + Q_PROPERTY(qreal hsvSaturation READ hsvSaturation WRITE setHsvSaturation FINAL) + Q_PROPERTY(qreal hsvValue READ hsvValue WRITE setHsvValue FINAL) + Q_PROPERTY(qreal hslHue READ hslHue WRITE setHslHue FINAL) + Q_PROPERTY(qreal hslSaturation READ hslSaturation WRITE setHslSaturation FINAL) + Q_PROPERTY(qreal hslLightness READ hslLightness WRITE setHslLightness FINAL) Q_GADGET public: Q_INVOKABLE QString toString() const; @@ -86,10 +92,22 @@ public: qreal g() const; qreal b() const; qreal a() const; + qreal hsvHue() const; + qreal hsvSaturation() const; + qreal hsvValue() const; + qreal hslHue() const; + qreal hslSaturation() const; + qreal hslLightness() const; void setR(qreal); void setG(qreal); void setB(qreal); void setA(qreal); + void setHsvHue(qreal); + void setHsvSaturation(qreal); + void setHsvValue(qreal); + void setHslHue(qreal); + void setHslSaturation(qreal); + void setHslLightness(qreal); }; class QQuickVector2DValueType -- cgit v1.2.3 From e94aa8154b9f0f115dd0df0135ddb67534abc88d Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 20 Jul 2016 15:45:05 +0200 Subject: Remove some unnecessary includes Change-Id: I18f2b6f44decf5ecde45e20722541b9a18d60b16 Reviewed-by: Simon Hausmann --- src/quick/items/qquickview.cpp | 3 --- src/quick/qtquick2.cpp | 1 - 2 files changed, 4 deletions(-) (limited to 'src/quick') diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp index 1d89c8bfc2..8b74d26576 100644 --- a/src/quick/items/qquickview.cpp +++ b/src/quick/items/qquickview.cpp @@ -44,9 +44,6 @@ #include "qquickitem_p.h" #include "qquickitemchangelistener_p.h" -#include -#include -#include #include #include diff --git a/src/quick/qtquick2.cpp b/src/quick/qtquick2.cpp index bf5b0083e9..ca12155e63 100644 --- a/src/quick/qtquick2.cpp +++ b/src/quick/qtquick2.cpp @@ -49,7 +49,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 6129f48e4ad4dd7341eafaa1212855556b5ee787 Mon Sep 17 00:00:00 2001 From: Andy Nichols Date: Mon, 25 Jul 2016 17:05:24 +0200 Subject: Software Adaptation: Add threaded render loop This is a new attempt at providing a threaded render loop for the software adaptation in scenegraph. This approach is modeled after the D3D12 backend, and provides a separate thread for each window. To enable use the environment variable QSG_RENDER_LOOP=threaded as with the other backends. Change-Id: I6932975dd9c5579d36f0135aa4626dcc43b45ecd Reviewed-by: Laszlo Agocs --- .../adaptations/software/qsgsoftwareadaptation.cpp | 11 + .../software/qsgsoftwarethreadedrenderloop.cpp | 991 +++++++++++++++++++++ .../software/qsgsoftwarethreadedrenderloop_p.h | 118 +++ .../scenegraph/adaptations/software/software.pri | 6 +- 4 files changed, 1124 insertions(+), 2 deletions(-) create mode 100644 src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp create mode 100644 src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop_p.h (limited to 'src/quick') diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp index 0e2f4f5382..144e75d3e6 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp @@ -40,6 +40,7 @@ #include "qsgsoftwareadaptation_p.h" #include "qsgsoftwarecontext_p.h" #include "qsgsoftwarerenderloop_p.h" +#include "qsgsoftwarethreadedrenderloop_p.h" #include #include @@ -73,6 +74,16 @@ QSGContextFactoryInterface::Flags QSGSoftwareAdaptation::flags(const QString &) QSGRenderLoop *QSGSoftwareAdaptation::createWindowManager() { + static bool threaded = false; + static bool envChecked = false; + if (!envChecked) { + envChecked = true; + threaded = qgetenv("QSG_RENDER_LOOP") == QByteArrayLiteral("threaded"); + } + + if (threaded) + return new QSGSoftwareThreadedRenderLoop; + return new QSGSoftwareRenderLoop(); } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp new file mode 100644 index 0000000000..5d5485ed8f --- /dev/null +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp @@ -0,0 +1,991 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgsoftwarethreadedrenderloop_p.h" +#include "qsgsoftwarecontext_p.h" +#include "qsgsoftwarerenderer_p.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// Passed from the RL to the RT when a window is removed obscured and should be +// removed from the render loop. +const QEvent::Type WM_Obscure = QEvent::Type(QEvent::User + 1); + +// Passed from the RL to RT when GUI has been locked, waiting for sync. +const QEvent::Type WM_RequestSync = QEvent::Type(QEvent::User + 2); + +// Passed by the RT to itself to trigger another render pass. This is typically +// a result of QQuickWindow::update(). +const QEvent::Type WM_RequestRepaint = QEvent::Type(QEvent::User + 3); + +// Passed by the RL to the RT to maybe release resource if no windows are +// rendering. +const QEvent::Type WM_TryRelease = QEvent::Type(QEvent::User + 4); + +// Passed by the RL to the RT when a QQuickWindow::grabWindow() is called. +const QEvent::Type WM_Grab = QEvent::Type(QEvent::User + 5); + +// Passed by the window when there is a render job to run. +const QEvent::Type WM_PostJob = QEvent::Type(QEvent::User + 6); + +class QSGSoftwareWindowEvent : public QEvent +{ +public: + QSGSoftwareWindowEvent(QQuickWindow *c, QEvent::Type type) : QEvent(type), window(c) { } + QQuickWindow *window; +}; + +class QSGSoftwareTryReleaseEvent : public QSGSoftwareWindowEvent +{ +public: + QSGSoftwareTryReleaseEvent(QQuickWindow *win, bool destroy) + : QSGSoftwareWindowEvent(win, WM_TryRelease), destroying(destroy) { } + bool destroying; +}; + +class QSGSoftwareSyncEvent : public QSGSoftwareWindowEvent +{ +public: + QSGSoftwareSyncEvent(QQuickWindow *c, bool inExpose, bool force) + : QSGSoftwareWindowEvent(c, WM_RequestSync) + , size(c->size()) + , dpr(c->effectiveDevicePixelRatio()) + , syncInExpose(inExpose) + , forceRenderPass(force) { } + QSize size; + float dpr; + bool syncInExpose; + bool forceRenderPass; +}; + +class QSGSoftwareGrabEvent : public QSGSoftwareWindowEvent +{ +public: + QSGSoftwareGrabEvent(QQuickWindow *c, QImage *result) + : QSGSoftwareWindowEvent(c, WM_Grab), image(result) { } + QImage *image; +}; + +class QSGSoftwareJobEvent : public QSGSoftwareWindowEvent +{ +public: + QSGSoftwareJobEvent(QQuickWindow *c, QRunnable *postedJob) + : QSGSoftwareWindowEvent(c, WM_PostJob), job(postedJob) { } + ~QSGSoftwareJobEvent() { delete job; } + QRunnable *job; +}; + +class QSGSoftwareEventQueue : public QQueue +{ +public: + void addEvent(QEvent *e) { + mutex.lock(); + enqueue(e); + if (waiting) + condition.wakeOne(); + mutex.unlock(); + } + + QEvent *takeEvent(bool wait) { + mutex.lock(); + if (isEmpty() && wait) { + waiting = true; + condition.wait(&mutex); + waiting = false; + } + QEvent *e = dequeue(); + mutex.unlock(); + return e; + } + + bool hasMoreEvents() { + mutex.lock(); + bool has = !isEmpty(); + mutex.unlock(); + return has; + } + +private: + QMutex mutex; + QWaitCondition condition; + bool waiting = false; +}; + +static inline int qsgrl_animation_interval() +{ + const qreal refreshRate = QGuiApplication::primaryScreen() ? QGuiApplication::primaryScreen()->refreshRate() : 0; + return refreshRate < 1 ? 16 : int(1000 / refreshRate); +} + +class QSGSoftwareRenderThread : public QThread +{ + Q_OBJECT +public: + QSGSoftwareRenderThread(QSGSoftwareThreadedRenderLoop *rl, QSGRenderContext *renderContext) + : renderLoop(rl) + { + rc = static_cast(renderContext); + vsyncDelta = qsgrl_animation_interval(); + } + + ~QSGSoftwareRenderThread() + { + delete rc; + } + + bool event(QEvent *e); + void run(); + + void syncAndRender(); + void sync(bool inExpose); + + void requestRepaint() + { + if (sleeping) + stopEventProcessing = true; + if (exposedWindow) + pendingUpdate |= RepaintRequest; + } + + void processEventsAndWaitForMore(); + void processEvents(); + void postEvent(QEvent *e); + + enum UpdateRequest { + SyncRequest = 0x01, + RepaintRequest = 0x02, + ExposeRequest = 0x04 | RepaintRequest | SyncRequest + }; + + QSGSoftwareThreadedRenderLoop *renderLoop; + QSGSoftwareRenderContext *rc; + QAnimationDriver *rtAnim = nullptr; + volatile bool active = false; + uint pendingUpdate = 0; + bool sleeping = false; + bool syncResultedInChanges = false; + float vsyncDelta; + QMutex mutex; + QWaitCondition waitCondition; + QQuickWindow *exposedWindow = nullptr; + QBackingStore *backingStore = nullptr; + bool stopEventProcessing = false; + QSGSoftwareEventQueue eventQueue; + QElapsedTimer renderThrottleTimer; + qint64 syncTime; + qint64 renderTime; + qint64 sinceLastTime; + +public slots: + void onSceneGraphChanged() { + syncResultedInChanges = true; + } +}; + +bool QSGSoftwareRenderThread::event(QEvent *e) +{ + switch ((int)e->type()) { + + case WM_Obscure: + Q_ASSERT(!exposedWindow || exposedWindow == static_cast(e)->window); + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "RT - WM_Obscure" << exposedWindow; + mutex.lock(); + if (exposedWindow) { + QQuickWindowPrivate::get(exposedWindow)->fireAboutToStop(); + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_Obscure - window removed"); + exposedWindow = nullptr; + delete backingStore; + backingStore = nullptr; + } + waitCondition.wakeOne(); + mutex.unlock(); + return true; + + case WM_RequestSync: { + QSGSoftwareSyncEvent *wme = static_cast(e); + if (sleeping) + stopEventProcessing = true; + exposedWindow = wme->window; + if (backingStore == nullptr) + backingStore = new QBackingStore(exposedWindow); + if (backingStore->size() != exposedWindow->size()) + backingStore->resize(exposedWindow->size()); + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "RT - WM_RequestSync" << exposedWindow; + pendingUpdate |= SyncRequest; + if (wme->syncInExpose) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_RequestSync - triggered from expose"); + pendingUpdate |= ExposeRequest; + } + if (wme->forceRenderPass) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_RequestSync - repaint regardless"); + pendingUpdate |= RepaintRequest; + } + return true; + } + + case WM_TryRelease: { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_TryRelease"); + mutex.lock(); + renderLoop->lockedForSync = true; + QSGSoftwareTryReleaseEvent *wme = static_cast(e); + // Only when no windows are exposed anymore or we are shutting down. + if (!exposedWindow || wme->destroying) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_TryRelease - invalidating rc"); + if (wme->window) { + QQuickWindowPrivate *wd = QQuickWindowPrivate::get(wme->window); + if (wme->destroying) { + // Bye bye nodes... + wd->cleanupNodesOnShutdown(); + } + rc->invalidate(); + QCoreApplication::processEvents(); + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + if (wme->destroying) + delete wd->animationController; + } + if (wme->destroying) + active = false; + if (sleeping) + stopEventProcessing = true; + } else { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_TryRelease - not releasing because window is still active"); + } + waitCondition.wakeOne(); + renderLoop->lockedForSync = false; + mutex.unlock(); + return true; + } + + case WM_Grab: { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_Grab"); + QSGSoftwareGrabEvent *wme = static_cast(e); + Q_ASSERT(wme->window); + Q_ASSERT(wme->window == exposedWindow || !exposedWindow); + mutex.lock(); + if (wme->window) { + // Grabbing is generally done by rendering a frame and reading the + // color buffer contents back, without presenting, and then + // creating a QImage from the returned data. It is terribly + // inefficient since it involves a full blocking wait for the GPU. + // However, our hands are tied by the existing, synchronous APIs of + // QQuickWindow and such. + QQuickWindowPrivate *wd = QQuickWindowPrivate::get(wme->window); + auto softwareRenderer = static_cast(wd->renderer); + if (softwareRenderer) + softwareRenderer->setBackingStore(backingStore); + rc->initialize(nullptr); + wd->syncSceneGraph(); + wd->renderSceneGraph(wme->window->size()); + *wme->image = backingStore->handle()->toImage(); + } + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_Grab - waking gui to handle result"); + waitCondition.wakeOne(); + mutex.unlock(); + return true; + } + + case WM_PostJob: { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_PostJob"); + QSGSoftwareJobEvent *wme = static_cast(e); + Q_ASSERT(wme->window == exposedWindow); + if (exposedWindow) { + wme->job->run(); + delete wme->job; + wme->job = nullptr; + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_PostJob - job done"); + } + return true; + } + + case WM_RequestRepaint: + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - WM_RequestPaint"); + // When GUI posts this event, it is followed by a polishAndSync, so we + // must not exit the event loop yet. + pendingUpdate |= RepaintRequest; + break; + + default: + break; + } + + return QThread::event(e); +} + +void QSGSoftwareRenderThread::postEvent(QEvent *e) +{ + eventQueue.addEvent(e); +} + +void QSGSoftwareRenderThread::processEvents() +{ + while (eventQueue.hasMoreEvents()) { + QEvent *e = eventQueue.takeEvent(false); + event(e); + delete e; + } +} + +void QSGSoftwareRenderThread::processEventsAndWaitForMore() +{ + stopEventProcessing = false; + while (!stopEventProcessing) { + QEvent *e = eventQueue.takeEvent(true); + event(e); + delete e; + } +} + +void QSGSoftwareRenderThread::run() +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - run()"); + + rtAnim = rc->sceneGraphContext()->createAnimationDriver(nullptr); + rtAnim->install(); + + if (QQmlDebugConnector::service()) + QQuickProfiler::registerAnimationCallback(); + + renderThrottleTimer.start(); + + while (active) { + if (exposedWindow) + syncAndRender(); + + processEvents(); + QCoreApplication::processEvents(); + + if (pendingUpdate == 0 || !exposedWindow) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - done drawing, sleep"); + sleeping = true; + processEventsAndWaitForMore(); + sleeping = false; + } + } + + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - run() exiting"); + + delete rtAnim; + rtAnim = nullptr; + + rc->moveToThread(renderLoop->thread()); + moveToThread(renderLoop->thread()); +} + +void QSGSoftwareRenderThread::sync(bool inExpose) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - sync"); + + mutex.lock(); + Q_ASSERT_X(renderLoop->lockedForSync, "QSGD3D12RenderThread::sync()", "sync triggered with gui not locked"); + + if (exposedWindow) { + QQuickWindowPrivate *wd = QQuickWindowPrivate::get(exposedWindow); + bool hadRenderer = wd->renderer != nullptr; + // If the scene graph was touched since the last sync() make sure it sends the + // changed signal. + if (wd->renderer) + wd->renderer->clearChangedFlag(); + + rc->initialize(nullptr); + wd->syncSceneGraph(); + + if (!hadRenderer && wd->renderer) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - created renderer"); + syncResultedInChanges = true; + connect(wd->renderer, &QSGRenderer::sceneGraphChanged, this, + &QSGSoftwareRenderThread::onSceneGraphChanged, Qt::DirectConnection); + } + + // Process deferred deletes now, directly after the sync as deleteLater + // on the GUI must now also have resulted in SG changes and the delete + // is a safe operation. + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + } + + if (!inExpose) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - sync complete, waking gui"); + waitCondition.wakeOne(); + mutex.unlock(); + } +} + +void QSGSoftwareRenderThread::syncAndRender() +{ + Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphRenderLoopFrame); + + QElapsedTimer waitTimer; + waitTimer.start(); + + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - syncAndRender()"); + + syncResultedInChanges = false; + QQuickWindowPrivate *wd = QQuickWindowPrivate::get(exposedWindow); + + const bool repaintRequested = (pendingUpdate & RepaintRequest) || wd->customRenderStage; + const bool syncRequested = pendingUpdate & SyncRequest; + const bool exposeRequested = (pendingUpdate & ExposeRequest) == ExposeRequest; + pendingUpdate = 0; + + if (syncRequested) + sync(exposeRequested); + + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame); + + if (!syncResultedInChanges && !repaintRequested) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - no changes, render aborted"); + int waitTime = vsyncDelta - (int) waitTimer.elapsed(); + if (waitTime > 0) + msleep(waitTime); + return; + } + + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - rendering started"); + + if (rtAnim->isRunning()) { + wd->animationController->lock(); + rtAnim->advance(); + wd->animationController->unlock(); + } + + bool canRender = wd->renderer != nullptr; + + if (canRender) { + auto softwareRenderer = static_cast(wd->renderer); + if (softwareRenderer) + softwareRenderer->setBackingStore(backingStore); + wd->renderSceneGraph(exposedWindow->size()); + + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame); + + if (softwareRenderer && (!wd->customRenderStage || !wd->customRenderStage->swap())) + backingStore->flush(softwareRenderer->flushRegion()); + + // Since there is no V-Sync with QBackingStore, throttle rendering the refresh + // rate of the current screen the window is on. + int blockTime = vsyncDelta - (int) renderThrottleTimer.elapsed(); + if (blockTime > 0) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "RT - blocking for " << blockTime << "ms"; + msleep(blockTime); + } + renderThrottleTimer.restart(); + + wd->fireFrameSwapped(); + } else { + Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphRenderLoopFrame, 1); + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - window not ready, skipping render"); + } + + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - rendering done"); + + if (exposeRequested) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "RT - wake gui after initial expose"); + waitCondition.wakeOne(); + mutex.unlock(); + } + + Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame); +} + +template T *windowFor(const QVector &list, QQuickWindow *window) +{ + for (const T &t : list) { + if (t.window == window) + return const_cast(&t); + } + return nullptr; +} + + +QSGSoftwareThreadedRenderLoop::QSGSoftwareThreadedRenderLoop() +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "software threaded render loop constructor"); + m_sg = new QSGSoftwareContext; + m_anim = m_sg->createAnimationDriver(this); + connect(m_anim, &QAnimationDriver::started, this, &QSGSoftwareThreadedRenderLoop::onAnimationStarted); + connect(m_anim, &QAnimationDriver::stopped, this, &QSGSoftwareThreadedRenderLoop::onAnimationStopped); + m_anim->install(); +} + +QSGSoftwareThreadedRenderLoop::~QSGSoftwareThreadedRenderLoop() +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "software threaded render loop destructor"); + delete m_sg; +} + +void QSGSoftwareThreadedRenderLoop::show(QQuickWindow *window) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "show" << window; +} + +void QSGSoftwareThreadedRenderLoop::hide(QQuickWindow *window) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "hide" << window; + + if (window->isExposed()) + handleObscurity(windowFor(m_windows, window)); + + releaseResources(window); +} + +void QSGSoftwareThreadedRenderLoop::resize(QQuickWindow *window) +{ + if (!window->isExposed() || window->size().isEmpty()) + return; + + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "resize" << window << window->size(); +} + +void QSGSoftwareThreadedRenderLoop::windowDestroyed(QQuickWindow *window) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "window destroyed" << window; + + WindowData *w = windowFor(m_windows, window); + if (!w) + return; + + handleObscurity(w); + handleResourceRelease(w, true); + + QSGSoftwareRenderThread *thread = w->thread; + while (thread->isRunning()) + QThread::yieldCurrentThread(); + + Q_ASSERT(thread->thread() == QThread::currentThread()); + delete thread; + + for (int i = 0; i < m_windows.size(); ++i) { + if (m_windows.at(i).window == window) { + m_windows.removeAt(i); + break; + } + } +} + +void QSGSoftwareThreadedRenderLoop::exposureChanged(QQuickWindow *window) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "exposure changed" << window; + + if (window->isExposed()) { + handleExposure(window); + } else { + WindowData *w = windowFor(m_windows, window); + if (w) + handleObscurity(w); + } +} + +QImage QSGSoftwareThreadedRenderLoop::grab(QQuickWindow *window) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "grab" << window; + + WindowData *w = windowFor(m_windows, window); + // Have to support invisible (but created()'ed) windows as well. + // Unlike with GL, leaving that case for QQuickWindow to handle is not feasible. + const bool tempExpose = !w; + if (tempExpose) { + handleExposure(window); + w = windowFor(m_windows, window); + Q_ASSERT(w); + } + + if (!w->thread->isRunning()) + return QImage(); + + if (!window->handle()) + window->create(); + + QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window); + wd->polishItems(); + + QImage result; + w->thread->mutex.lock(); + lockedForSync = true; + w->thread->postEvent(new QSGSoftwareGrabEvent(window, &result)); + w->thread->waitCondition.wait(&w->thread->mutex); + lockedForSync = false; + w->thread->mutex.unlock(); + + result.setDevicePixelRatio(window->effectiveDevicePixelRatio()); + + if (tempExpose) + handleObscurity(w); + + return result; +} + +void QSGSoftwareThreadedRenderLoop::update(QQuickWindow *window) +{ + WindowData *w = windowFor(m_windows, window); + if (!w) + return; + + if (w->thread == QThread::currentThread()) { + w->thread->requestRepaint(); + return; + } + + // We set forceRenderPass because we want to make sure the QQuickWindow + // actually does a full render pass after the next sync. + w->forceRenderPass = true; + scheduleUpdate(w); +} + +void QSGSoftwareThreadedRenderLoop::maybeUpdate(QQuickWindow *window) +{ + WindowData *w = windowFor(m_windows, window); + if (w) + scheduleUpdate(w); +} + +void QSGSoftwareThreadedRenderLoop::handleUpdateRequest(QQuickWindow *window) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "handleUpdateRequest" << window; + + WindowData *w = windowFor(m_windows, window); + if (w) + polishAndSync(w, false); +} + +QAnimationDriver *QSGSoftwareThreadedRenderLoop::animationDriver() const +{ + return m_anim; +} + +QSGContext *QSGSoftwareThreadedRenderLoop::sceneGraphContext() const +{ + return m_sg; +} + +QSGRenderContext *QSGSoftwareThreadedRenderLoop::createRenderContext(QSGContext *) const +{ + return m_sg->createRenderContext(); +} + +void QSGSoftwareThreadedRenderLoop::releaseResources(QQuickWindow *window) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "releaseResources" << window; + + WindowData *w = windowFor(m_windows, window); + if (w) + handleResourceRelease(w, false); +} + +void QSGSoftwareThreadedRenderLoop::postJob(QQuickWindow *window, QRunnable *job) +{ + WindowData *w = windowFor(m_windows, window); + if (w && w->thread && w->thread->exposedWindow) + w->thread->postEvent(new QSGSoftwareJobEvent(window, job)); + else + delete job; +} + +QSurface::SurfaceType QSGSoftwareThreadedRenderLoop::windowSurfaceType() const +{ + return QSurface::RasterSurface; +} + +bool QSGSoftwareThreadedRenderLoop::interleaveIncubation() const +{ + bool somethingVisible = false; + for (const WindowData &w : m_windows) { + if (w.window->isVisible() && w.window->isExposed()) { + somethingVisible = true; + break; + } + } + return somethingVisible && m_anim->isRunning(); +} + +int QSGSoftwareThreadedRenderLoop::flags() const +{ + return SupportsGrabWithoutExpose; +} + +bool QSGSoftwareThreadedRenderLoop::event(QEvent *e) +{ + if (e->type() == QEvent::Timer) { + QTimerEvent *te = static_cast(e); + if (te->timerId() == animationTimer) { + m_anim->advance(); + emit timeToIncubate(); + return true; + } + } + + return QObject::event(e); +} + +void QSGSoftwareThreadedRenderLoop::onAnimationStarted() +{ + startOrStopAnimationTimer(); + + for (const WindowData &w : qAsConst(m_windows)) + w.window->requestUpdate(); +} + +void QSGSoftwareThreadedRenderLoop::onAnimationStopped() +{ + startOrStopAnimationTimer(); +} + +void QSGSoftwareThreadedRenderLoop::startOrStopAnimationTimer() +{ + int exposedWindowCount = 0; + const WindowData *exposed = nullptr; + + for (int i = 0; i < m_windows.size(); ++i) { + const WindowData &w(m_windows[i]); + if (w.window->isVisible() && w.window->isExposed()) { + ++exposedWindowCount; + exposed = &w; + } + } + + if (animationTimer && (exposedWindowCount == 1 || !m_anim->isRunning())) { + killTimer(animationTimer); + animationTimer = 0; + // If animations are running, make sure we keep on animating + if (m_anim->isRunning()) + exposed->window->requestUpdate(); + } else if (!animationTimer && exposedWindowCount != 1 && m_anim->isRunning()) { + animationTimer = startTimer(qsgrl_animation_interval()); + } +} + +void QSGSoftwareThreadedRenderLoop::handleExposure(QQuickWindow *window) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "handleExposure" << window; + + WindowData *w = windowFor(m_windows, window); + if (!w) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "adding window to list"); + WindowData win; + win.window = window; + QSGRenderContext *rc = QQuickWindowPrivate::get(window)->context; // will transfer ownership + win.thread = new QSGSoftwareRenderThread(this, rc); + win.updateDuringSync = false; + win.forceRenderPass = true; // also covered by polishAndSync(inExpose=true), but doesn't hurt + m_windows.append(win); + w = &m_windows.last(); + } + + // set this early as we'll be rendering shortly anyway and this avoids + // special casing exposure in polishAndSync. + w->thread->exposedWindow = window; + + if (w->window->size().isEmpty() + || (w->window->isTopLevel() && !w->window->geometry().intersects(w->window->screen()->availableGeometry()))) { +#ifndef QT_NO_DEBUG + qWarning().noquote().nospace() << "QSGSotwareThreadedRenderLoop: expose event received for window " + << w->window << " with invalid geometry: " << w->window->geometry() + << " on " << w->window->screen(); +#endif + } + + if (!w->window->handle()) + w->window->create(); + + // Start render thread if it is not running + if (!w->thread->isRunning()) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "starting render thread"); + // Push a few things to the render thread. + QQuickAnimatorController *controller = QQuickWindowPrivate::get(w->window)->animationController; + if (controller->thread() != w->thread) + controller->moveToThread(w->thread); + if (w->thread->thread() == QThread::currentThread()) { + w->thread->rc->moveToThread(w->thread); + w->thread->moveToThread(w->thread); + } + + w->thread->active = true; + w->thread->start(); + + if (!w->thread->isRunning()) + qFatal("Render thread failed to start, aborting application."); + } + + polishAndSync(w, true); + + startOrStopAnimationTimer(); +} + +void QSGSoftwareThreadedRenderLoop::handleObscurity(QSGSoftwareThreadedRenderLoop::WindowData *w) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "handleObscurity" << w->window; + + if (w->thread->isRunning()) { + w->thread->mutex.lock(); + w->thread->postEvent(new QSGSoftwareWindowEvent(w->window, WM_Obscure)); + w->thread->waitCondition.wait(&w->thread->mutex); + w->thread->mutex.unlock(); + } + + startOrStopAnimationTimer(); +} + +void QSGSoftwareThreadedRenderLoop::scheduleUpdate(QSGSoftwareThreadedRenderLoop::WindowData *w) +{ + if (!QCoreApplication::instance()) + return; + + if (!w || !w->thread->isRunning()) + return; + + QThread *current = QThread::currentThread(); + if (current != QCoreApplication::instance()->thread() && (current != w->thread || !lockedForSync)) { + qWarning() << "Updates can only be scheduled from GUI thread or from QQuickItem::updatePaintNode()"; + return; + } + + if (current == w->thread) { + w->updateDuringSync = true; + return; + } + + w->window->requestUpdate(); +} + +void QSGSoftwareThreadedRenderLoop::handleResourceRelease(QSGSoftwareThreadedRenderLoop::WindowData *w, bool destroying) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "handleResourceRelease" << (destroying ? "destroying" : "hide/releaseResources") << w->window; + + w->thread->mutex.lock(); + if (w->thread->isRunning() && w->thread->active) { + QQuickWindow *window = w->window; + + // Note that window->handle() is typically null by this time because + // the platform window is already destroyed. This should not be a + // problem for the D3D cleanup. + + w->thread->postEvent(new QSGSoftwareTryReleaseEvent(window, destroying)); + w->thread->waitCondition.wait(&w->thread->mutex); + + // Avoid a shutdown race condition. + // If SG is invalidated and 'active' becomes false, the thread's run() + // method will exit. handleExposure() relies on QThread::isRunning() (because it + // potentially needs to start the thread again) and our mutex cannot be used to + // track the thread stopping, so we wait a few nanoseconds extra so the thread + // can exit properly. + if (!w->thread->active) + w->thread->wait(); + } + w->thread->mutex.unlock(); +} + +void QSGSoftwareThreadedRenderLoop::polishAndSync(QSGSoftwareThreadedRenderLoop::WindowData *w, bool inExpose) +{ + qCDebug(QSG_RASTER_LOG_RENDERLOOP) << "polishAndSync" << (inExpose ? "(in expose)" : "(normal)") << w->window; + + QQuickWindow *window = w->window; + if (!w->thread || !w->thread->exposedWindow) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - not exposed, abort"); + return; + } + + // Flush pending touch events. + QQuickWindowPrivate::get(window)->flushFrameSynchronousEvents(); + // The delivery of the event might have caused the window to stop rendering + w = windowFor(m_windows, window); + if (!w || !w->thread || !w->thread->exposedWindow) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - removed after touch event flushing, abort"); + return; + } + + Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishAndSync); + + QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window); + wd->polishItems(); + + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync); + + w->updateDuringSync = false; + + emit window->afterAnimating(); + + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - lock for sync"); + w->thread->mutex.lock(); + lockedForSync = true; + w->thread->postEvent(new QSGSoftwareSyncEvent(window, inExpose, w->forceRenderPass)); + w->forceRenderPass = false; + + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - wait for sync"); + + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync); + w->thread->waitCondition.wait(&w->thread->mutex); + lockedForSync = false; + w->thread->mutex.unlock(); + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - unlock after sync"); + + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync); + + if (!animationTimer && m_anim->isRunning()) { + qCDebug(QSG_RASTER_LOG_RENDERLOOP, "polishAndSync - advancing animations"); + m_anim->advance(); + // We need to trigger another sync to keep animations running... + w->window->requestUpdate(); + emit timeToIncubate(); + } else if (w->updateDuringSync) { + w->window->requestUpdate(); + } + + Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphPolishAndSync); +} + +#include "qsgsoftwarethreadedrenderloop.moc" + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop_p.h new file mode 100644 index 0000000000..99993d651c --- /dev/null +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop_p.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGSOFTWARETHREADEDRENDERLOOP_H +#define QSGSOFTWARETHREADEDRENDERLOOP_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QSGSoftwareRenderThread; +class QSGSoftwareContext; + +class QSGSoftwareThreadedRenderLoop : public QSGRenderLoop +{ + Q_OBJECT +public: + QSGSoftwareThreadedRenderLoop(); + ~QSGSoftwareThreadedRenderLoop(); + + void show(QQuickWindow *window) override; + void hide(QQuickWindow *window) override; + void resize(QQuickWindow *window) override; + void windowDestroyed(QQuickWindow *window) override; + void exposureChanged(QQuickWindow *window) override; + QImage grab(QQuickWindow *window) override; + void update(QQuickWindow *window) override; + void maybeUpdate(QQuickWindow *window) override; + void handleUpdateRequest(QQuickWindow *window) override; + QAnimationDriver *animationDriver() const override; + QSGContext *sceneGraphContext() const override; + QSGRenderContext *createRenderContext(QSGContext *) const override; + void releaseResources(QQuickWindow *window) override; + void postJob(QQuickWindow *window, QRunnable *job) override; + QSurface::SurfaceType windowSurfaceType() const override; + bool interleaveIncubation() const override; + int flags() const override; + + bool event(QEvent *e) override; + +public Q_SLOTS: + void onAnimationStarted(); + void onAnimationStopped(); + +private: + struct WindowData { + QQuickWindow *window; + QSGSoftwareRenderThread *thread; + uint updateDuringSync : 1; + uint forceRenderPass : 1; + }; + + void startOrStopAnimationTimer(); + void handleExposure(QQuickWindow *window); + void handleObscurity(WindowData *w); + void scheduleUpdate(WindowData *w); + void handleResourceRelease(WindowData *w, bool destroying); + void polishAndSync(WindowData *w, bool inExpose); + + QSGSoftwareContext *m_sg; + QAnimationDriver *m_anim; + int animationTimer = 0; + bool lockedForSync = false; + QVector m_windows; + + friend class QSGSoftwareRenderThread; +}; + +QT_END_NAMESPACE + +#endif // QSGSOFTWARETHREADEDRENDERLOOP_H diff --git a/src/quick/scenegraph/adaptations/software/software.pri b/src/quick/scenegraph/adaptations/software/software.pri index 1933a37d48..97644fc36a 100644 --- a/src/quick/scenegraph/adaptations/software/software.pri +++ b/src/quick/scenegraph/adaptations/software/software.pri @@ -19,7 +19,8 @@ SOURCES += \ $$PWD/qsgsoftwarerenderloop.cpp \ $$PWD/qsgsoftwarelayer.cpp \ $$PWD/qsgsoftwareadaptation.cpp \ - $$PWD/qsgsoftwarespritenode.cpp + $$PWD/qsgsoftwarespritenode.cpp \ + $$PWD/qsgsoftwarethreadedrenderloop.cpp HEADERS += \ $$PWD/qsgsoftwarecontext_p.h \ @@ -38,4 +39,5 @@ HEADERS += \ $$PWD/qsgsoftwarerenderloop_p.h \ $$PWD/qsgsoftwarelayer_p.h \ $$PWD/qsgsoftwareadaptation_p.h \ - $$PWD/qsgsoftwarespritenode_p.h + $$PWD/qsgsoftwarespritenode_p.h \ + $$PWD/qsgsoftwarethreadedrenderloop_p.h -- cgit v1.2.3 From c809e56591862a874a347745e829a05e9036130a Mon Sep 17 00:00:00 2001 From: Andy Nichols Date: Wed, 27 Jul 2016 12:17:35 +0200 Subject: Software Adaptation: Fix issue with clip node handling Under certain circumstances the clip node state would not get propagated properly to child nodes. Change-Id: I6f34690c7cc6f2837854fbcaff9aa4d7522e47c3 Reviewed-by: Laszlo Agocs --- .../adaptations/software/qsgsoftwarerenderablenodeupdater.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/quick') diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp index 82f8623b74..12dbf63353 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp @@ -218,12 +218,13 @@ void QSGSoftwareRenderableNodeUpdater::updateNodes(QSGNode *node, bool isNodeRem m_opacityState.push(state.opacity); m_transformState.push(state.transform); m_clipState.push(state.clip); - + m_hasClip = state.hasClip; } else { // There is no parent, and no previous parent, so likely a root node m_opacityState.push(1.0f); m_transformState.push(QTransform()); m_clipState.push(QRegion()); + m_hasClip = false; } // If the node is being removed, then cleanup the state data -- cgit v1.2.3 From 3934ae38cd22f202508555014bca015ea8c7bf2e Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 25 Jul 2016 17:21:06 +0200 Subject: Remove some dead code Change-Id: I1fa95d3c91e7f3ad5f2bf8f9d732ef72b74a98c8 Reviewed-by: Simon Hausmann --- src/quick/util/qquickprofiler_p.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/quick') diff --git a/src/quick/util/qquickprofiler_p.h b/src/quick/util/qquickprofiler_p.h index f1af87f4e6..54d734a1c2 100644 --- a/src/quick/util/qquickprofiler_p.h +++ b/src/quick/util/qquickprofiler_p.h @@ -319,12 +319,7 @@ public: qint64 timestamp() { return m_timer.nsecsElapsed(); } - static quint64 featuresEnabled; - static bool profilingSceneGraph() - { - return featuresEnabled & (1 << QQuickProfiler::ProfileSceneGraph); - } static void initialize(QObject *parent); -- cgit v1.2.3 From bd48f0e5edb1d5ce10529360fb9d14e7b7135022 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 20 Jul 2016 15:35:50 +0200 Subject: Tooling: Convert connects to Qt5 style Change-Id: I6746b777f73d047f5cf610bfca9b320ac1e13676 Reviewed-by: Simon Hausmann --- src/quick/util/qquickprofiler.cpp | 9 +++++++-- src/quick/util/qquickprofiler_p.h | 7 +++---- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src/quick') diff --git a/src/quick/util/qquickprofiler.cpp b/src/quick/util/qquickprofiler.cpp index 659ffe1d84..841a1c9bcf 100644 --- a/src/quick/util/qquickprofiler.cpp +++ b/src/quick/util/qquickprofiler.cpp @@ -70,7 +70,7 @@ void QQuickProfiler::registerAnimationCallback() class CallbackRegistrationHelper : public QObject { Q_OBJECT -public slots: +public: void registerAnimationTimerCallback() { QQuickProfiler::registerAnimationCallback(); @@ -86,7 +86,12 @@ QQuickProfiler::QQuickProfiler(QObject *parent) : QObject(parent) m_timer.start(); CallbackRegistrationHelper *helper = new CallbackRegistrationHelper; // will delete itself helper->moveToThread(QCoreApplication::instance()->thread()); - QMetaObject::invokeMethod(helper, "registerAnimationTimerCallback", Qt::QueuedConnection); + + // Queue the signal to have the animation timer registration run in the right thread; + QObject signalSource; + connect(&signalSource, &QObject::destroyed, + helper, &CallbackRegistrationHelper::registerAnimationTimerCallback, + Qt::QueuedConnection); } QQuickProfiler::~QQuickProfiler() diff --git a/src/quick/util/qquickprofiler_p.h b/src/quick/util/qquickprofiler_p.h index 54d734a1c2..480a2ac3fb 100644 --- a/src/quick/util/qquickprofiler_p.h +++ b/src/quick/util/qquickprofiler_p.h @@ -325,6 +325,9 @@ public: virtual ~QQuickProfiler(); +signals: + void dataReady(const QVector &data); + protected: friend class QQuickProfilerAdapter; @@ -342,10 +345,6 @@ protected: m_data.append(message); } -signals: - void dataReady(const QVector &data); - -protected slots: void startProfilingImpl(quint64 features); void stopProfilingImpl(); void reportDataImpl(bool trackLocations); -- cgit v1.2.3 From d32319eca446d5583af9081a0056dea4667d6096 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 25 Jul 2016 17:20:04 +0200 Subject: Replace debugger and profiler with stubs on -no-qml-debug Change-Id: I0f029d92366b3b508bf024c67b877a14bae27cd6 Reviewed-by: Simon Hausmann --- src/quick/qtquick2.cpp | 7 +++ src/quick/util/qquickprofiler_p.h | 92 ++++++++++++++++++++++----------------- src/quick/util/util.pri | 7 ++- 3 files changed, 65 insertions(+), 41 deletions(-) (limited to 'src/quick') diff --git a/src/quick/qtquick2.cpp b/src/quick/qtquick2.cpp index ca12155e63..c36adf56ec 100644 --- a/src/quick/qtquick2.cpp +++ b/src/quick/qtquick2.cpp @@ -62,6 +62,12 @@ static void initResources() QT_BEGIN_NAMESPACE +#ifdef QT_NO_QML_DEBUGGER + +class QQmlQtQuick2DebugStatesDelegate : public QQmlDebugStatesDelegate {}; + +#else + class QQmlQtQuick2DebugStatesDelegate : public QQmlDebugStatesDelegate { public: @@ -174,6 +180,7 @@ void QQmlQtQuick2DebugStatesDelegate::resetBindingForInvalidProperty(QObject *ob } } +#endif // QT_NO_QML_DEBUGGER void QQmlQtQuick2Module::defineModule() { diff --git a/src/quick/util/qquickprofiler_p.h b/src/quick/util/qquickprofiler_p.h index 480a2ac3fb..66ed212722 100644 --- a/src/quick/util/qquickprofiler_p.h +++ b/src/quick/util/qquickprofiler_p.h @@ -62,52 +62,22 @@ QT_BEGIN_NAMESPACE +#ifdef QT_NO_QML_DEBUGGER + +#define Q_QUICK_PROFILE_IF_ENABLED(feature, Code) + +struct QQuickProfiler { + static void registerAnimationCallback() {} +}; + +#else + #define Q_QUICK_PROFILE_IF_ENABLED(feature, Code)\ if (QQuickProfiler::featuresEnabled & (1 << feature)) {\ Code;\ } else\ (void)0 -#define Q_QUICK_PROFILE(feature, Method)\ - Q_QUICK_PROFILE_IF_ENABLED(feature, QQuickProfiler::Method) - -#define Q_QUICK_SG_PROFILE_START(Type)\ - Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ - (QQuickProfiler::startSceneGraphFrame())) - -#define Q_QUICK_SG_PROFILE_RECORD(Type)\ - Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ - (QQuickProfiler::recordSceneGraphTimestamp())) - -#define Q_QUICK_SG_PROFILE_SKIP(Type, Skip)\ - Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ - (QQuickProfiler::skipSceneGraphTimestamps())) - -#define Q_QUICK_SG_PROFILE_START_SYNCHRONIZED(Type1, Type2)\ - Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ - (QQuickProfiler::startSceneGraphFrame())) - -#define Q_QUICK_SG_PROFILE_SWITCH(Type1, Type2) \ - Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ - (QQuickProfiler::reportSceneGraphFrame())) - -#define Q_QUICK_SG_PROFILE_REPORT(Type)\ - Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ - (QQuickProfiler::reportSceneGraphFrame())) - -#define Q_QUICK_SG_PROFILE_END(Type)\ - Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ - (QQuickProfiler::reportSceneGraphFrame())) - -#define Q_QUICK_SG_PROFILE_END_WITH_PAYLOAD(Type, Payload)\ - Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ - (QQuickProfiler::reportSceneGraphFrame(Payload))) - - -#define Q_QUICK_INPUT_PROFILE(Type, DetailType, A, B)\ - Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileInputEvents,\ - (QQuickProfiler::inputEvent(A, B))) - // This struct is somewhat dangerous to use: // You can save values either with 32 or 64 bit precision. toByteArrays will // guess the precision from messageType. If you state the wrong messageType @@ -351,6 +321,48 @@ protected: void setTimer(const QElapsedTimer &t); }; +#endif // QT_NO_QML_DEBUGGER + +#define Q_QUICK_PROFILE(feature, Method)\ + Q_QUICK_PROFILE_IF_ENABLED(feature, QQuickProfiler::Method) + +#define Q_QUICK_SG_PROFILE_START(Type)\ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ + (QQuickProfiler::startSceneGraphFrame())) + +#define Q_QUICK_SG_PROFILE_RECORD(Type)\ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ + (QQuickProfiler::recordSceneGraphTimestamp())) + +#define Q_QUICK_SG_PROFILE_SKIP(Type, Skip)\ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ + (QQuickProfiler::skipSceneGraphTimestamps())) + +#define Q_QUICK_SG_PROFILE_START_SYNCHRONIZED(Type1, Type2)\ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ + (QQuickProfiler::startSceneGraphFrame())) + +#define Q_QUICK_SG_PROFILE_SWITCH(Type1, Type2) \ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ + (QQuickProfiler::reportSceneGraphFrame())) + +#define Q_QUICK_SG_PROFILE_REPORT(Type)\ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ + (QQuickProfiler::reportSceneGraphFrame())) + +#define Q_QUICK_SG_PROFILE_END(Type)\ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ + (QQuickProfiler::reportSceneGraphFrame())) + +#define Q_QUICK_SG_PROFILE_END_WITH_PAYLOAD(Type, Payload)\ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ + (QQuickProfiler::reportSceneGraphFrame(Payload))) + + +#define Q_QUICK_INPUT_PROFILE(Type, DetailType, A, B)\ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileInputEvents,\ + (QQuickProfiler::inputEvent(A, B))) + QT_END_NAMESPACE #endif diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri index ffb31ae75e..2c31f6feed 100644 --- a/src/quick/util/util.pri +++ b/src/quick/util/util.pri @@ -26,12 +26,17 @@ SOURCES += \ $$PWD/qquickanimator.cpp \ $$PWD/qquickanimatorjob.cpp \ $$PWD/qquickanimatorcontroller.cpp \ - $$PWD/qquickprofiler.cpp \ $$PWD/qquickfontmetrics.cpp \ $$PWD/qquicktextmetrics.cpp \ $$PWD/qquickshortcut.cpp \ $$PWD/qquickvalidator.cpp +contains(QT_CONFIG, no-qml-debug) { + DEFINES += QT_NO_QML_DEBUGGER +} else { + SOURCES += $$PWD/qquickprofiler.cpp +} + HEADERS += \ $$PWD/qquickapplication_p.h\ $$PWD/qquickutilmodule_p.h\ -- cgit v1.2.3 From 75d6392d6c5efa6fdd1f63cac6a2438fedb2f2a9 Mon Sep 17 00:00:00 2001 From: Venugopal Shivashankar Date: Tue, 1 Mar 2016 15:31:52 +0100 Subject: Doc: Describe how to implement custom SQL models for QML Change-Id: I31781f32c2f9699f386a326f18cb5cc705582a89 Reviewed-by: Leena Miettinen Reviewed-by: Mitch Curtis --- .../doc/src/concepts/modelviewsdata/cppmodels.qdoc | 105 +++++++++++++++++++++ 1 file changed, 105 insertions(+) (limited to 'src/quick') diff --git a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc index cb281a2d4a..a764402c2f 100644 --- a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc +++ b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc @@ -156,6 +156,111 @@ with list models of QAbstractItemModel type: \li \l DelegateModel::parentModelIndex() returns a QModelIndex which can be assigned to DelegateModel::rootIndex \endlist +\section2 SQL Models + +Qt provides C++ classes that support SQL data models. These classes work +transparently on the underlying SQL data, reducing the need to run SQL +queries for basic SQL operations such as create, insert, or update. +For more details about these classes, see \l{Using the SQL Model Classes}. + +Although the C++ classes provide complete feature sets to operate on SQL +data, they do not provide data access to QML. So you must implement a +C++ custom data model as a subclass of one of these classes, and expose it +to QML either as a type or context property. + +\section3 Read-only Data Model + +The custom model must reimplement the following methods to enable read-only +access to the data from QML: + +\list +\li \l{QAbstractItemModel::}{roleNames}() to expose the role names to the + QML frontend. For example, the following version returns the selected + table's field names as role names: + \code + QHash SqlQueryModel::roleNames() const + { + QHash roles; + // record() returns an empty QSqlRecord + for (int i = 0; i < this->record().count(); i ++) { + roles.insert(Qt::UserRole + i + 1, record().fieldName(i).toUtf8()); + } + return roles; + } + \endcode +\li \l{QSqlQueryModel::}{data}() to expose SQL data to the QML frontend. + For example, the following implementation returns data for the given + model index: + \code + QVariant SqlQueryModel::data(const QModelIndex &index, int role) const + { + QVariant value; + + if (index.isValid()) { + if (role < Qt::UserRole) { + value = QSqlQueryModel::data(index, role); + } else { + int columnIdx = role - Qt::UserRole - 1; + QModelIndex modelIndex = this->index(index.row(), columnIdx); + value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole); + } + } + return value; + } + \endcode +\endlist + +The QSqlQueryModel class is good enough to implement a custom read-only +model that represents data in an SQL database. The +\l{Qt Quick Controls 2 - Chat Tutorial}{chat tutorial} example +demonstrates this very well by implementing a custom model to fetch the +contact details from an SQLite database. + +\section3 Editable Data Model + +Besides the \c roleNames() and \c data(), the editable models must reimplement +the \l{QSqlTableModel::}{setData} method to save changes to existing SQL data. +The following version of the method checks if the given model index is valid +and the \c role is equal to \l Qt::EditRole, before calling the parent class +version: + +\code +bool SqlEditableModel::setData(const QModelIndex &item, const QVariant &value, int role) +{ + if (item.isValid() && role == Qt::EditRole) { + QSqlTableModel::setData(item, value,role); + emit dataChanged(item, item); + return true; + } + return false; + +} +\endcode + +\note It is important to emit the \l{QAbstractItemModel::}{dataChanged}() +signal after saving the changes. + +Unlike the C++ item views such as QListView or QTableView, the \c setData() +method must be explicitly invoked from QML whenever appropriate. For example, +on the \l[QML]{TextField::}{editingFinished}() or \l[QML]{TextField::}{accepted}() +signal of \l[QtQuickControls]{TextField}. Depending on the +\l{QSqlTableModel::}{EditStrategy} used by the model, the changes are either +queued for submission later or submitted immediately. + +You can also insert new data into the model by calling +\l {QSqlTableModel::insertRecord}(). In the following example snippet, +a QSqlRecord is populated with book details and appended to the +model: + +\code + ... + QSqlRecord newRecord = record(); + newRecord.setValue("author", "John Grisham"); + newRecord.setValue("booktitle", "The Litigators"); + insertRecord(rowCount(), newRecord); + ... +\endcode + \section2 Exposing C++ Data Models to QML The above examples use QQmlContext::setContextProperty() to set -- cgit v1.2.3 From fe92db0a0eeed502ef851930b3404b38c4a03f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Fri, 29 Jul 2016 13:32:22 +0100 Subject: Revert "macOS: Use sRGB when doing native font rendering into FBO" This reverts commit 1e18a4f985f6ec4a0191a2e0cc087b13d29b1719. It breaks a QtCanvas3D unit-test and I can't look at it now. Will have another take at this soon. Change-Id: I22acd55443783934596d25cc4c8774bd34609f6b Reviewed-by: Liang Qi --- src/quick/scenegraph/qsgdefaultlayer.cpp | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) (limited to 'src/quick') diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp index 99735564ef..fa69f911dd 100644 --- a/src/quick/scenegraph/qsgdefaultlayer.cpp +++ b/src/quick/scenegraph/qsgdefaultlayer.cpp @@ -42,29 +42,6 @@ DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY) #endif DEFINE_BOOL_CONFIG_OPTION(qmlFboFlushBeforeDetach, QML_FBO_FLUSH_BEFORE_DETACH) - - -static QOpenGLFramebufferObject *createFramebuffer(const QSize &size, - QOpenGLFramebufferObjectFormat format) -{ -#ifdef Q_OS_MACOS - QOpenGLContext *context = QOpenGLContext::currentContext(); - if (context->hasExtension("GL_ARB_framebuffer_sRGB") - && context->hasExtension("GL_EXT_texture_sRGB") - && context->hasExtension("GL_EXT_texture_sRGB_decode")) - format.setInternalTextureFormat(GL_SRGB8_ALPHA8_EXT); -#endif - QOpenGLFramebufferObject *fbo = new QOpenGLFramebufferObject(size, format); -#ifdef Q_OS_MACOS - if (format.internalTextureFormat() == GL_SRGB8_ALPHA8_EXT) { - QOpenGLFunctions *funcs = context->functions(); - funcs->glBindTexture(GL_TEXTURE_2D, fbo->texture()); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); - } -#endif - return fbo; -} - namespace { class BindableFbo : public QSGBindable @@ -347,7 +324,7 @@ void QSGDefaultLayer::grab() format.setInternalTextureFormat(m_format); format.setSamples(m_context->openglContext()->format().samples()); - m_secondaryFbo = createFramebuffer(m_size, format); + m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { QOpenGLFramebufferObjectFormat format; @@ -356,14 +333,14 @@ void QSGDefaultLayer::grab() if (m_recursive) { deleteFboLater = true; delete m_secondaryFbo; - m_secondaryFbo = createFramebuffer(m_size, format); + m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { delete m_fbo; delete m_secondaryFbo; - m_fbo = createFramebuffer(m_size, format); + m_fbo = new QOpenGLFramebufferObject(m_size, format); m_secondaryFbo = 0; funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); @@ -377,7 +354,7 @@ void QSGDefaultLayer::grab() Q_ASSERT(m_fbo); Q_ASSERT(!m_multisampling); - m_secondaryFbo = createFramebuffer(m_size, m_fbo->format()); + m_secondaryFbo = new QOpenGLFramebufferObject(m_size, m_fbo->format()); funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); } -- cgit v1.2.3 From 44e86f701247a86da37e3a94b77853b57ab1b303 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 27 Jul 2016 11:59:17 +0200 Subject: Add optional flags and rect to QSGRenderNode Having rendernodes triggering fullscreen updates with the software backend is not ideal. Therefore, introduce the option of reporting that the rendernode is well-behaving, meaning it only writes inside the reported bounding rectangle. Similarly, the OpenGL batch renderer can keep using the depth buffer when the rendernode is known to behave like the renderer expects. Change-Id: I6acc434432c2504776f26e8917b5434b44be293d Reviewed-by: Gunnar Sletta --- .../software/qsgsoftwarerenderablenode.cpp | 18 +++++- src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 8 ++- src/quick/scenegraph/coreapi/qsgrendernode.cpp | 67 ++++++++++++++++++++++ src/quick/scenegraph/coreapi/qsgrendernode.h | 10 ++++ 4 files changed, 97 insertions(+), 6 deletions(-) (limited to 'src/quick') diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp index 032a06f946..d900688173 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp @@ -187,6 +187,12 @@ void QSGSoftwareRenderableNode::update() boundingRect = m_handle.spriteNode->rect().toRect(); break; case QSGSoftwareRenderableNode::RenderNode: + if (m_handle.renderNode->flags().testFlag(QSGRenderNode::OpaqueRendering) && !m_transform.isRotating()) + m_isOpaque = true; + else + m_isOpaque = false; + + boundingRect = m_handle.renderNode->rect().toRect(); break; default: break; @@ -244,14 +250,20 @@ QRegion QSGSoftwareRenderableNode::renderNode(QPainter *painter, bool forceOpaqu rd->m_opacity = m_opacity; RenderNodeState rs; rs.cr = m_clipRegion; + + const QRect br = m_handle.renderNode->flags().testFlag(QSGRenderNode::BoundedRectRendering) + ? m_boundingRect : + QRect(0, 0, painter->device()->width(), painter->device()->height()); + painter->save(); + painter->setClipRegion(br, Qt::ReplaceClip); m_handle.renderNode->render(&rs); painter->restore(); - const QRect fullRect = QRect(0, 0, painter->device()->width(), painter->device()->height()); - m_previousDirtyRegion = fullRect; + + m_previousDirtyRegion = QRegion(br); m_isDirty = false; m_dirtyRegion = QRegion(); - return fullRect; + return br; } } diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index bee2015007..49bbbf0ba8 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -1033,11 +1033,13 @@ void Renderer::nodeWasAdded(QSGNode *node, Node *shadowParent) m_rebuild |= FullRebuild; } else if (node->type() == QSGNode::RenderNodeType) { - RenderNodeElement *e = new RenderNodeElement(static_cast(node)); + QSGRenderNode *rn = static_cast(node); + RenderNodeElement *e = new RenderNodeElement(rn); snode->data = e; - Q_ASSERT(!m_renderNodeElements.contains(static_cast(node))); + Q_ASSERT(!m_renderNodeElements.contains(rn)); m_renderNodeElements.insert(e->renderNode, e); - m_useDepthBuffer = false; + if (!rn->flags().testFlag(QSGRenderNode::DepthAwareRendering)) + m_useDepthBuffer = false; m_rebuild |= FullRebuild; } diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp index 365abd09e2..5915d51f2b 100644 --- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp +++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp @@ -179,6 +179,11 @@ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const default value according to the OpenGL specification. For other APIs, see the documentation for changedStates() for more information. + \note Depth writes are disabled when this function is called (for example, + glDepthMask(false) in case of OpenGL). Enabling depth writes can lead to + unexpected results, depending on the scenegraph backend in use, so nodes + should avoid this. + For APIs other than OpenGL, it will likely be necessary to query certain API-specific resources (for example, the graphics device or the command list/buffer to add the commands to). This is done via QSGRendererInterface. @@ -210,6 +215,68 @@ void QSGRenderNode::releaseResources() { } +/*! + \enum QSGRenderNode::RenderingFlag + + Possible values for the bitmask returned from flags(). + + \value BoundedRectRendering Indicates that the implementation of render() + does not render outside the area reported from rect() in item + coordinates. Such node implementations can lead to more efficient rendering, + depending on the scenegraph backend. For example, the software backend can + continue to use the more optimal partial update path when all render nodes + in the scene have this flag set. + + \value DepthAwareRendering Indicates that the implementations of render() + conforms to scenegraph expectations by only generating a Z value of 0 in + scene coordinates which is then transformed by the matrices retrieved from + RenderState::projectionMatrix() and matrix(), as described in the notes for + render(). Such node implementations can lead to more efficient rendering, + depending on the scenegraph backend. For example, the batching OpenGL + renderer can continue to use a more optimal path when all render nodes in + the scene have this flag set. + + \value OpaqueRendering Indicates that the implementation of render() writes + out opaque pixels for the entire area reported from rect(). By default the + renderers must assume that render() can also output semi or fully + transparent pixels. Setting this flag can improve performance in some + cases. + + \sa render(), rect() + */ + +/*! + \return flags describing the behavior of this render node. + + The default implementation returns 0. + + \sa RenderingFlag, rect() + */ +QSGRenderNode::RenderingFlags QSGRenderNode::flags() const +{ + return 0; +} + +/*! + \return the bounding rectangle in item coordinates for the area render() + touches. The value is only in use when flags() includes + BoundedRectRendering, ignored otherwise. + + Reporting the rectangle in combination with BoundedRectRendering is + particularly important with the \c software backend because otherwise + having a rendernode in the scene would trigger fullscreen updates, skipping + all partial update optimizations. + + For rendernodes covering the entire area of a corresponding QQuickItem the + return value will be (0, 0, item->width(), item->height()). + + \sa flags() +*/ +QRectF QSGRenderNode::rect() const +{ + return QRectF(); +} + /*! \return pointer to the current model-view matrix. */ diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.h b/src/quick/scenegraph/coreapi/qsgrendernode.h index 6eb425c03b..f6bc40d3ee 100644 --- a/src/quick/scenegraph/coreapi/qsgrendernode.h +++ b/src/quick/scenegraph/coreapi/qsgrendernode.h @@ -61,6 +61,13 @@ public: }; Q_DECLARE_FLAGS(StateFlags, StateFlag) + enum RenderingFlag { + BoundedRectRendering = 0x01, + DepthAwareRendering = 0x02, + OpaqueRendering = 0x04 + }; + Q_DECLARE_FLAGS(RenderingFlags, RenderingFlag) + struct Q_QUICK_EXPORT RenderState { virtual ~RenderState(); virtual const QMatrix4x4 *projectionMatrix() const = 0; @@ -78,6 +85,8 @@ public: virtual StateFlags changedStates() const; virtual void render(const RenderState *state) = 0; virtual void releaseResources(); + virtual RenderingFlags flags() const; + virtual QRectF rect() const; const QMatrix4x4 *matrix() const; const QSGClipNode *clipList() const; @@ -89,6 +98,7 @@ private: }; Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderNode::StateFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderNode::RenderingFlags) QT_END_NAMESPACE -- cgit v1.2.3 From 5b620ed68909c63f3a5a892577a07f66d35c2923 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 1 Aug 2016 16:38:56 +0200 Subject: Add QT_NO_QML_DEBUGGER to MODULE_DEFINES on -no-qml-debug If -no-qml-debug is set when building QtQml, we have to add QT_NO_QML_DEBUGGER when building application code, because this build option modifies the headers and linking an application built with QML debugging against a Qt built without is crashy. Change-Id: Ib150810f40deb98dcf398e3998401358a25155d9 Reviewed-by: Simon Hausmann Reviewed-by: Oswald Buddenhagen --- src/quick/util/util.pri | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src/quick') diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri index 2c31f6feed..66792536d7 100644 --- a/src/quick/util/util.pri +++ b/src/quick/util/util.pri @@ -31,11 +31,7 @@ SOURCES += \ $$PWD/qquickshortcut.cpp \ $$PWD/qquickvalidator.cpp -contains(QT_CONFIG, no-qml-debug) { - DEFINES += QT_NO_QML_DEBUGGER -} else { - SOURCES += $$PWD/qquickprofiler.cpp -} +!contains(QT_CONFIG, no-qml-debug): SOURCES += $$PWD/qquickprofiler.cpp HEADERS += \ $$PWD/qquickapplication_p.h\ -- cgit v1.2.3 From c8978bd582eabf8deb139e2606317b0df0aa7ec2 Mon Sep 17 00:00:00 2001 From: Andy Nichols Date: Tue, 2 Aug 2016 17:20:42 +0200 Subject: QQuickDefaultClipNode: Set clipRect before marking geometry dirty The ordering here is important because the software adaptation uses the QSGClipNode's clipRect property instead of the geometry to update the clipRect, and with the previous code the clip node would not be correct for the next frame. Change-Id: I43147aaabd65f22820f01afb326975bb62ea95cc Reviewed-by: Laszlo Agocs --- src/quick/items/qquickclipnode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/quick') diff --git a/src/quick/items/qquickclipnode.cpp b/src/quick/items/qquickclipnode.cpp index 1114686a9a..7c7fee4a42 100644 --- a/src/quick/items/qquickclipnode.cpp +++ b/src/quick/items/qquickclipnode.cpp @@ -113,7 +113,7 @@ void QQuickDefaultClipNode::updateGeometry() } } - markDirty(DirtyGeometry); setClipRect(m_rect); + markDirty(DirtyGeometry); } -- cgit v1.2.3