From 7447e2b337f12b4d04935d0f30fc673e4327d5a0 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 24 Feb 2020 16:23:27 +0100 Subject: QTextMarkdownImporter: fix use after free; add fuzz-generated tests It was possible to end up with a dangling pointer in m_listStack. This is now avoided by using QPointer and doing nullptr checks before accessing any QTextList pointer stored there. We have 2 specimens of garbage that caused crashes before; now they don't. But only fuzz20450 triggered the dangling pointer in the list stack. The crash caused by fuzz20580 was fixed by updating md4c from upstream: 4b0fc030777cd541604f5ebaaad47a2b76d61ff9 Change-Id: I8e1eca23b281256a03aea0f55e9ae20f1bdd2a38 Reviewed-by: Robert Loehning --- src/gui/text/qtextmarkdownimporter.cpp | 7 +++++-- src/gui/text/qtextmarkdownimporter_p.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src/gui') diff --git a/src/gui/text/qtextmarkdownimporter.cpp b/src/gui/text/qtextmarkdownimporter.cpp index 7e18a10895..5e75e7816b 100644 --- a/src/gui/text/qtextmarkdownimporter.cpp +++ b/src/gui/text/qtextmarkdownimporter.cpp @@ -577,7 +577,10 @@ void QTextMarkdownImporter::insertBlock() QTextBlockFormat blockFormat; if (!m_listStack.isEmpty() && !m_needsInsertList && m_listItem) { QTextList *list = m_listStack.top(); - blockFormat = list->item(list->count() - 1).blockFormat(); + if (list) + blockFormat = list->item(list->count() - 1).blockFormat(); + else + qWarning() << "attempted to insert into a list that no longer exists"; } if (m_blockQuoteDepth) { blockFormat.setProperty(QTextFormat::BlockQuoteLevel, m_blockQuoteDepth); @@ -607,7 +610,7 @@ void QTextMarkdownImporter::insertBlock() } if (m_needsInsertList) { m_listStack.push(m_cursor->createList(m_listFormat)); - } else if (!m_listStack.isEmpty() && m_listItem) { + } else if (!m_listStack.isEmpty() && m_listItem && m_listStack.top()) { m_listStack.top()->add(m_cursor->block()); } m_needsInsertList = false; diff --git a/src/gui/text/qtextmarkdownimporter_p.h b/src/gui/text/qtextmarkdownimporter_p.h index f450da5eb3..e3b4bcd0f2 100644 --- a/src/gui/text/qtextmarkdownimporter_p.h +++ b/src/gui/text/qtextmarkdownimporter_p.h @@ -113,7 +113,7 @@ private: #endif QString m_blockCodeLanguage; QVector m_nonEmptyTableCells; // in the current row - QStack m_listStack; + QStack> m_listStack; QStack m_spanFormatStack; QFont m_monoFont; QPalette m_palette; -- cgit v1.2.3 From 08d5059320334223ff1f9009342324f25c231f0b Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 14 Oct 2019 14:54:44 +0200 Subject: Fix geometry handling for native child windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't move the native child window position for native child windows. Initial-patch-by: Błażej Szczygieł Task-number: QTBUG-82312 Fixes: QTBUG-79166 Change-Id: I117ef08da13c8e90ff60cf034126c9efdc17b836 Reviewed-by: Błażej Szczygieł Reviewed-by: Morten Johan Sørvig Reviewed-by: Oliver Wolff --- src/gui/kernel/qwindow.cpp | 10 +++++++--- src/gui/kernel/qwindowsysteminterface.cpp | 13 ++++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) (limited to 'src/gui') diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 0a4277c118..9cb851a7a2 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -1666,7 +1666,7 @@ void QWindow::setGeometry(const QRect &rect) if (newScreen && isTopLevel()) nativeRect = QHighDpi::toNativePixels(rect, newScreen); else - nativeRect = QHighDpi::toNativePixels(rect, this); + nativeRect = QHighDpi::toNativeLocalPosition(rect, newScreen); d->platformWindow->setGeometry(nativeRect); } else { d->geometry = rect; @@ -1717,8 +1717,12 @@ QScreen *QWindowPrivate::screenForGeometry(const QRect &newGeometry) const QRect QWindow::geometry() const { Q_D(const QWindow); - if (d->platformWindow) - return QHighDpi::fromNativePixels(d->platformWindow->geometry(), this); + if (d->platformWindow) { + const auto nativeGeometry = d->platformWindow->geometry(); + return isTopLevel() + ? QHighDpi::fromNativePixels(nativeGeometry, this) + : QHighDpi::fromNativeLocalPosition(nativeGeometry, this); + } return d->geometry; } diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 8457282bed..8f2927901a 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -296,14 +296,21 @@ QWindowSystemInterfacePrivate::GeometryChangeEvent::GeometryChangeEvent(QWindow , window(window) , newGeometry(newGeometry) { - if (const QPlatformWindow *pw = window->handle()) - requestedGeometry = QHighDpi::fromNativePixels(pw->QPlatformWindow::geometry(), window); + if (const QPlatformWindow *pw = window->handle()) { + const auto nativeGeometry = pw->QPlatformWindow::geometry(); + requestedGeometry = window->isTopLevel() + ? QHighDpi::fromNativePixels(nativeGeometry, window) + : QHighDpi::fromNativeLocalPosition(nativeGeometry, window); + } } QT_DEFINE_QPA_EVENT_HANDLER(void, handleGeometryChange, QWindow *window, const QRect &newRect) { Q_ASSERT(window); - QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(window, QHighDpi::fromNativePixels(newRect, window)); + const auto newRectDi = window->isTopLevel() + ? QHighDpi::fromNativePixels(newRect, window) + : QHighDpi::fromNativeLocalPosition(newRect, window); + auto e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(window, newRectDi); if (window->handle()) { // Persist the new geometry so that QWindow::geometry() can be queried in the resize event window->handle()->QPlatformWindow::setGeometry(newRect); -- cgit v1.2.3 From 761f46f8b526147b29a324b65d253077f35867a9 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 2 Mar 2020 14:45:39 +0100 Subject: Remove overrides of QImageIOHandler::name() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We will remove the virtual base class function in Qt 6. For now, name() returns format(). Change-Id: I1597e823b859e4db148b3e5ac0f1c15350a582eb Reviewed-by: Eirik Aavitsland Reviewed-by: Jan Arve Sæther --- src/gui/image/qbmphandler.cpp | 7 ------- src/gui/image/qbmphandler_p.h | 3 --- src/gui/image/qpnghandler.cpp | 7 ------- src/gui/image/qpnghandler_p.h | 4 ---- src/gui/image/qppmhandler.cpp | 7 ------- src/gui/image/qppmhandler_p.h | 4 ---- src/gui/image/qxbmhandler.cpp | 7 ------- src/gui/image/qxbmhandler_p.h | 4 ---- src/gui/image/qxpmhandler.cpp | 7 ------- src/gui/image/qxpmhandler_p.h | 4 ---- 10 files changed, 54 deletions(-) (limited to 'src/gui') diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index 32b6131309..387c7b7746 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -866,13 +866,6 @@ void QBmpHandler::setOption(ImageOption option, const QVariant &value) Q_UNUSED(value); } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QBmpHandler::name() const -{ - return formatName(); -} -#endif - QT_END_NAMESPACE #endif // QT_NO_IMAGEFORMAT_BMP diff --git a/src/gui/image/qbmphandler_p.h b/src/gui/image/qbmphandler_p.h index 33b5b9c501..fd044fc442 100644 --- a/src/gui/image/qbmphandler_p.h +++ b/src/gui/image/qbmphandler_p.h @@ -113,9 +113,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif static bool canRead(QIODevice *device); QVariant option(ImageOption option) const override; diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index 8435e5a0fe..f956f254ee 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -1296,13 +1296,6 @@ void QPngHandler::setOption(ImageOption option, const QVariant &value) d->scaledSize = value.toSize(); } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QPngHandler::name() const -{ - return "png"; -} -#endif - QT_END_NAMESPACE #endif // QT_NO_IMAGEFORMAT_PNG diff --git a/src/gui/image/qpnghandler_p.h b/src/gui/image/qpnghandler_p.h index 5d4da97395..9e12d2d081 100644 --- a/src/gui/image/qpnghandler_p.h +++ b/src/gui/image/qpnghandler_p.h @@ -69,10 +69,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - QVariant option(ImageOption option) const override; void setOption(ImageOption option, const QVariant &value) override; bool supportsOption(ImageOption option) const override; diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp index 13ee2eadd2..728259ba9e 100644 --- a/src/gui/image/qppmhandler.cpp +++ b/src/gui/image/qppmhandler.cpp @@ -576,13 +576,6 @@ void QPpmHandler::setOption(ImageOption option, const QVariant &value) subType = value.toByteArray().toLower(); } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QPpmHandler::name() const -{ - return subType.isEmpty() ? QByteArray("ppm") : subType; -} -#endif - QT_END_NAMESPACE #endif // QT_NO_IMAGEFORMAT_PPM diff --git a/src/gui/image/qppmhandler_p.h b/src/gui/image/qppmhandler_p.h index 2f3811b759..f2faf93984 100644 --- a/src/gui/image/qppmhandler_p.h +++ b/src/gui/image/qppmhandler_p.h @@ -67,10 +67,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - static bool canRead(QIODevice *device, QByteArray *subType = nullptr); QVariant option(ImageOption option) const override; diff --git a/src/gui/image/qxbmhandler.cpp b/src/gui/image/qxbmhandler.cpp index 3cd15b3e4d..f06561690c 100644 --- a/src/gui/image/qxbmhandler.cpp +++ b/src/gui/image/qxbmhandler.cpp @@ -357,13 +357,6 @@ void QXbmHandler::setOption(ImageOption option, const QVariant &value) fileName = value.toString(); } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QXbmHandler::name() const -{ - return "xbm"; -} -#endif - QT_END_NAMESPACE #endif // QT_NO_IMAGEFORMAT_XBM diff --git a/src/gui/image/qxbmhandler_p.h b/src/gui/image/qxbmhandler_p.h index ae590a1944..db5f352d46 100644 --- a/src/gui/image/qxbmhandler_p.h +++ b/src/gui/image/qxbmhandler_p.h @@ -66,10 +66,6 @@ public: bool read(QImage *image) override; bool write(const QImage &image) override; -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - static bool canRead(QIODevice *device); QVariant option(ImageOption option) const override; diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp index f9424b62bb..07fec929bf 100644 --- a/src/gui/image/qxpmhandler.cpp +++ b/src/gui/image/qxpmhandler.cpp @@ -1280,13 +1280,6 @@ void QXpmHandler::setOption(ImageOption option, const QVariant &value) fileName = value.toString(); } -#if QT_DEPRECATED_SINCE(5, 13) -QByteArray QXpmHandler::name() const -{ - return "xpm"; -} -#endif - QT_END_NAMESPACE #endif // QT_NO_IMAGEFORMAT_XPM diff --git a/src/gui/image/qxpmhandler_p.h b/src/gui/image/qxpmhandler_p.h index a4dd88cd17..646e8df69e 100644 --- a/src/gui/image/qxpmhandler_p.h +++ b/src/gui/image/qxpmhandler_p.h @@ -68,10 +68,6 @@ public: static bool canRead(QIODevice *device); -#if QT_DEPRECATED_SINCE(5, 13) - QByteArray name() const override; -#endif - QVariant option(ImageOption option) const override; void setOption(ImageOption option, const QVariant &value) override; bool supportsOption(ImageOption option) const override; -- cgit v1.2.3 From 753e4d82be966b82ff6ba41a0e7c4452f494790a Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Sun, 23 Feb 2020 15:05:44 +0100 Subject: rhi: Execute pending host writes on nativeBuffer() query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise it is impossible to write an application that pulls out the VkBuffer for a Dynamic QRhiBuffer, and then uses it with custom Vulkan operations that read from the buffer. More precisely, the problem arises only if the buffer in question is not used in combination with any QRhi operations, because in that case there is nothing that would trigger doing the host writes queued up by a resource batch's updateDynamicBuffer(). Task-number: QTBUG-82435 Change-Id: Ieb54422f1493921bc6d4d029be56130cd3a1362a Reviewed-by: Christian Strømme --- src/gui/rhi/qrhi.cpp | 8 +++----- src/gui/rhi/qrhid3d11.cpp | 12 ++++++++---- src/gui/rhi/qrhid3d11_p_p.h | 2 +- src/gui/rhi/qrhimetal.mm | 23 +++++++++++++++-------- src/gui/rhi/qrhimetal_p_p.h | 1 + src/gui/rhi/qrhivulkan.cpp | 25 ++++++++++++++----------- src/gui/rhi/qrhivulkan_p_p.h | 2 +- 7 files changed, 43 insertions(+), 30 deletions(-) (limited to 'src/gui') diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 7a0d53e1e4..6243bcda58 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -2048,11 +2048,9 @@ QRhiResource::Type QRhiBuffer::resourceType() const UniformBuffer may not even be backed by a native buffer object at all if uniform buffers are not used or supported by a given backend and graphics API. There are also differences to how data is written to the buffer and - the type of backing memory used, and, if host visible memory is involved, - when memory writes become available and visible. Therefore, in general it - is recommended to limit native buffer object access to vertex and index - buffers with types Static or Immutable, because these operate in a - relatively uniform manner with all backends. + the type of backing memory used. For buffers backed by host visible memory, + calling this function guarantees that pending host writes are executed for + all the returned native buffers. \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight */ diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index f7c7f4a9f2..ce39b42cf5 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -608,7 +608,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind { QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.ubuf.buf); if (bufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWrites(bufD); if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) { srbUpdate = true; @@ -725,7 +725,7 @@ void QRhiD3D11::setVertexInput(QRhiCommandBuffer *cb, QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, bindings[i].first); Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer)); if (bufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWrites(bufD); if (cbD->currentVertexBuffers[inputSlot] != bufD->buffer || cbD->currentVertexOffsets[inputSlot] != bindings[i].second) @@ -757,7 +757,7 @@ void QRhiD3D11::setVertexInput(QRhiCommandBuffer *cb, QD3D11Buffer *ibufD = QRHI_RES(QD3D11Buffer, indexBuf); Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer)); if (ibufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(ibufD); + executeBufferHostWrites(ibufD); const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; @@ -1920,7 +1920,7 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) srbD->csUAVs.finish(); } -void QRhiD3D11::executeBufferHostWritesForCurrentFrame(QD3D11Buffer *bufD) +void QRhiD3D11::executeBufferHostWrites(QD3D11Buffer *bufD) { if (!bufD->hasPendingDynamicUpdates) return; @@ -2388,6 +2388,10 @@ bool QD3D11Buffer::build() QRhiBuffer::NativeBuffer QD3D11Buffer::nativeBuffer() { + if (m_type == Dynamic) { + QRHI_RES_RHI(QRhiD3D11); + rhiD->executeBufferHostWrites(this); + } return { { &buffer }, 1 }; } diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index 04751397f7..b70f541c68 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -643,7 +643,7 @@ public: int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc); void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates); void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD); - void executeBufferHostWritesForCurrentFrame(QD3D11Buffer *bufD); + void executeBufferHostWrites(QD3D11Buffer *bufD); void bindShaderResources(QD3D11ShaderResourceBindings *srbD, const uint *dynOfsPairs, int dynOfsPairCount, bool offsetOnlyChange); diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 48a562ef1d..314c58b0b7 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -1827,16 +1827,15 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate } // this handles all types of buffers, not just Dynamic -void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD) +void QRhiMetal::executeBufferHostWritesForSlot(QMetalBuffer *bufD, int slot) { - const int idx = bufD->d->slotted ? currentFrameSlot : 0; - if (bufD->d->pendingUpdates[idx].isEmpty()) + if (bufD->d->pendingUpdates[slot].isEmpty()) return; - void *p = [bufD->d->buf[idx] contents]; + void *p = [bufD->d->buf[slot] contents]; int changeBegin = -1; int changeEnd = -1; - for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->d->pendingUpdates[idx])) { + for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->d->pendingUpdates[slot])) { Q_ASSERT(bufD == QRHI_RES(QMetalBuffer, u.buf)); memcpy(static_cast(p) + u.offset, u.data.constData(), size_t(u.data.size())); if (changeBegin == -1 || u.offset < changeBegin) @@ -1846,10 +1845,15 @@ void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD) } #ifdef Q_OS_MACOS if (changeBegin >= 0 && bufD->d->managed) - [bufD->d->buf[idx] didModifyRange: NSMakeRange(NSUInteger(changeBegin), NSUInteger(changeEnd - changeBegin))]; + [bufD->d->buf[slot] didModifyRange: NSMakeRange(NSUInteger(changeBegin), NSUInteger(changeEnd - changeBegin))]; #endif - bufD->d->pendingUpdates[idx].clear(); + bufD->d->pendingUpdates[slot].clear(); +} + +void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD) +{ + executeBufferHostWritesForSlot(bufD, bufD->d->slotted ? currentFrameSlot : 0); } void QRhiMetal::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) @@ -2205,8 +2209,11 @@ QRhiBuffer::NativeBuffer QMetalBuffer::nativeBuffer() if (d->slotted) { NativeBuffer b; Q_ASSERT(sizeof(b.objects) / sizeof(b.objects[0]) >= size_t(QMTL_FRAMES_IN_FLIGHT)); - for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) + for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) { + QRHI_RES_RHI(QRhiMetal); + rhiD->executeBufferHostWritesForSlot(this, i); b.objects[i] = &d->buf[i]; + } b.slotCount = QMTL_FRAMES_IN_FLIGHT; return b; } diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h index 212b731b71..a5af5611a6 100644 --- a/src/gui/rhi/qrhimetal_p_p.h +++ b/src/gui/rhi/qrhimetal_p_p.h @@ -437,6 +437,7 @@ public: int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc, qsizetype *curOfs); void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates); + void executeBufferHostWritesForSlot(QMetalBuffer *bufD, int slot); void executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD); static const int SUPPORTED_STAGES = 3; void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index d378e2a4ad..8f6f118c9b 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -2903,7 +2903,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat } else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) { QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf); if (bufD->m_type == QRhiBuffer::Dynamic) { - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWritesForSlot(bufD, currentFrameSlot); void *p = nullptr; VmaAllocation a = toVmaAllocation(bufD->allocations[currentFrameSlot]); VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p); @@ -3300,14 +3300,14 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat ud->free(); } -void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD) +void QRhiVulkan::executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot) { - if (bufD->pendingDynamicUpdates[currentFrameSlot].isEmpty()) + if (bufD->pendingDynamicUpdates[slot].isEmpty()) return; Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic); void *p = nullptr; - VmaAllocation a = toVmaAllocation(bufD->allocations[currentFrameSlot]); + VmaAllocation a = toVmaAllocation(bufD->allocations[slot]); // The vmaMap/Unmap are basically a no-op when persistently mapped since it // refcounts; this is great because we don't need to care if the allocation // was created as persistently mapped or not. @@ -3318,7 +3318,7 @@ void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD) } int changeBegin = -1; int changeEnd = -1; - for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->pendingDynamicUpdates[currentFrameSlot])) { + for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->pendingDynamicUpdates[slot])) { Q_ASSERT(bufD == QRHI_RES(QVkBuffer, u.buf)); memcpy(static_cast(p) + u.offset, u.data.constData(), size_t(u.data.size())); if (changeBegin == -1 || u.offset < changeBegin) @@ -3330,7 +3330,7 @@ void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD) if (changeBegin >= 0) vmaFlushAllocation(toVmaAllocator(allocator), a, VkDeviceSize(changeBegin), VkDeviceSize(changeEnd - changeBegin)); - bufD->pendingDynamicUpdates[currentFrameSlot].clear(); + bufD->pendingDynamicUpdates[slot].clear(); } static void qrhivk_releaseBuffer(const QRhiVulkan::DeferredReleaseEntry &e, void *allocator) @@ -4166,7 +4166,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)); if (bufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWritesForSlot(bufD, currentFrameSlot); bufD->lastActiveFrameSlot = currentFrameSlot; trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0, @@ -4240,7 +4240,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer)); if (bufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWritesForSlot(bufD, currentFrameSlot); bufD->lastActiveFrameSlot = currentFrameSlot; QRhiPassResourceTracker::BufferAccess access; @@ -4349,7 +4349,7 @@ void QRhiVulkan::setVertexInput(QRhiCommandBuffer *cb, Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer)); bufD->lastActiveFrameSlot = currentFrameSlot; if (bufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(bufD); + executeBufferHostWritesForSlot(bufD, currentFrameSlot); const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0]; if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf @@ -4395,7 +4395,7 @@ void QRhiVulkan::setVertexInput(QRhiCommandBuffer *cb, Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer)); ibufD->lastActiveFrameSlot = currentFrameSlot; if (ibufD->m_type == QRhiBuffer::Dynamic) - executeBufferHostWritesForCurrentFrame(ibufD); + executeBufferHostWritesForSlot(ibufD, currentFrameSlot); const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0; const VkBuffer vkindexbuf = ibufD->buffers[slot]; @@ -5188,10 +5188,13 @@ bool QVkBuffer::build() QRhiBuffer::NativeBuffer QVkBuffer::nativeBuffer() { if (m_type == Dynamic) { + QRHI_RES_RHI(QRhiVulkan); NativeBuffer b; Q_ASSERT(sizeof(b.objects) / sizeof(b.objects[0]) >= size_t(QVK_FRAMES_IN_FLIGHT)); - for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i) + for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i) { + rhiD->executeBufferHostWritesForSlot(this, i); b.objects[i] = &buffers[i]; + } b.slotCount = QVK_FRAMES_IN_FLIGHT; return b; } diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index 6322882569..0f0a89cbff 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -778,7 +778,7 @@ public: size_t *curOfs, void *mp, BufferImageCopyList *copyInfos); void enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates); - void executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD); + void executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot); void enqueueTransitionPassResources(QVkCommandBuffer *cbD); void recordPrimaryCommandBuffer(QVkCommandBuffer *cbD); void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker, -- cgit v1.2.3 From 5bbc9986f99a5d61c2e43b79fe815ea8ca450fcd Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 26 Feb 2020 15:07:49 +0100 Subject: rhi: d3d: Use native resource binding mapping table when present MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Newer versions of QShaderBaker will now use distinct, zero-based b, t+s, and u register spaces in the generated HLSL source. If this is the case, the native resource binding map (which so far we only used with Metal) contains the SPIR-V binding -> HLSL register binding mappings. This way we won't end up with invalid resource binding attempts (consider that e.g. D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT is only 16), just because, for example, a combined image sampler had a binding of 18 which then got blindly mapped to s18 and t18 in HLSL. Task-number: QTBUG-82472 Change-Id: I8bdcb5378634cf159f6367424582f9e9e5821c8e Reviewed-by: Christian Strømme --- src/gui/rhi/qrhid3d11.cpp | 257 ++++++++++++++++++++++++++++++++++---------- src/gui/rhi/qrhid3d11_p_p.h | 22 +++- 2 files changed, 215 insertions(+), 64 deletions(-) (limited to 'src/gui') diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index ce39b42cf5..7b583e6fd2 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -580,6 +580,11 @@ void QRhiD3D11::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline } } +static const int RBM_SUPPORTED_STAGES = 3; +static const int RBM_VERTEX = 0; +static const int RBM_FRAGMENT = 1; +static const int RBM_COMPUTE = 2; + void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb, int dynamicOffsetCount, const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) @@ -667,8 +672,17 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind } } - if (srbUpdate) - updateShaderResourceBindings(srbD); + if (srbUpdate) { + const QShader::NativeResourceBindingMap *resBindMaps[RBM_SUPPORTED_STAGES]; + memset(resBindMaps, 0, sizeof(resBindMaps)); + if (gfxPsD) { + resBindMaps[RBM_VERTEX] = &gfxPsD->vs.nativeResourceBindingMap; + resBindMaps[RBM_FRAGMENT] = &gfxPsD->fs.nativeResourceBindingMap; + } else { + resBindMaps[RBM_COMPUTE] = &compPsD->cs.nativeResourceBindingMap; + } + updateShaderResourceBindings(srbD, resBindMaps); + } const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb); const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation; @@ -1774,7 +1788,26 @@ void QRhiD3D11::dispatch(QRhiCommandBuffer *cb, int x, int y, int z) cbD->commands.append(cmd); } -void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) +static inline QPair mapBinding(int binding, + int stageIndex, + const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]) +{ + const QShader::NativeResourceBindingMap *map = nativeResourceBindingMaps[stageIndex]; + if (!map || map->isEmpty()) + return { binding, binding }; // old QShader versions do not have this map, assume 1:1 mapping then + + auto it = map->constFind(binding); + if (it != map->cend()) + return *it; + + // Hitting this path is normal too. It is not given that the resource is + // present in the shaders for all the stages specified by the visibility + // mask in the QRhiShaderResourceBinding. + return { -1, -1 }; +} + +void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, + const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]) { srbD->vsubufs.clear(); srbD->vsubufoffsets.clear(); @@ -1799,6 +1832,31 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) srbD->csUAVs.clear(); + struct Stage { + struct Buffer { + int breg; // b0, b1, ... + ID3D11Buffer *buffer; + uint offsetInConstants; + uint sizeInConstants; + }; + struct Texture { + int treg; // t0, t1, ... + ID3D11ShaderResourceView *srv; + }; + struct Sampler { + int sreg; // s0, s1, ... + ID3D11SamplerState *sampler; + }; + struct Uav { + int ureg; + ID3D11UnorderedAccessView *uav; + }; + QVarLengthArray buffers; + QVarLengthArray textures; + QVarLengthArray samplers; + QVarLengthArray uavs; + } res[RBM_SUPPORTED_STAGES]; + for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) { const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data(); QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]); @@ -1818,26 +1876,24 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) // (ByteWidth) is always a multiple of 256. const uint sizeInConstants = uint(aligned(b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size, 256) / 16); if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - srbD->vsubufs.feed(b->binding, bufD->buffer); - srbD->vsubufoffsets.feed(b->binding, offsetInConstants); - srbD->vsubufsizes.feed(b->binding, sizeInConstants); + QPair nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) + res[RBM_VERTEX].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - srbD->fsubufs.feed(b->binding, bufD->buffer); - srbD->fsubufoffsets.feed(b->binding, offsetInConstants); - srbD->fsubufsizes.feed(b->binding, sizeInConstants); + QPair nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) + res[RBM_FRAGMENT].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - srbD->csubufs.feed(b->binding, bufD->buffer); - srbD->csubufoffsets.feed(b->binding, offsetInConstants); - srbD->csubufsizes.feed(b->binding, sizeInConstants); + QPair nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) + res[RBM_COMPUTE].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants }); } } break; case QRhiShaderResourceBinding::SampledTexture: { - // A sampler with binding N is mapped to a HLSL sampler and texture - // with registers sN and tN by SPIRV-Cross. QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.stex.tex); QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, b->u.stex.sampler); bd.stex.texId = texD->m_id; @@ -1845,16 +1901,25 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) bd.stex.samplerId = samplerD->m_id; bd.stex.samplerGeneration = samplerD->generation; if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - srbD->vssamplers.feed(b->binding, samplerD->samplerState); - srbD->vsshaderresources.feed(b->binding, texD->srv); + QPair nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps); + if (nativeBinding.first >= 0 && nativeBinding.second >= 0) { + res[RBM_VERTEX].textures.append({ nativeBinding.first, texD->srv }); + res[RBM_VERTEX].samplers.append({ nativeBinding.second, samplerD->samplerState }); + } } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - srbD->fssamplers.feed(b->binding, samplerD->samplerState); - srbD->fsshaderresources.feed(b->binding, texD->srv); + QPair nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps); + if (nativeBinding.first >= 0 && nativeBinding.second >= 0) { + res[RBM_FRAGMENT].textures.append({ nativeBinding.first, texD->srv }); + res[RBM_FRAGMENT].samplers.append({ nativeBinding.second, samplerD->samplerState }); + } } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - srbD->cssamplers.feed(b->binding, samplerD->samplerState); - srbD->csshaderresources.feed(b->binding, texD->srv); + QPair nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); + if (nativeBinding.first >= 0 && nativeBinding.second >= 0) { + res[RBM_COMPUTE].textures.append({ nativeBinding.first, texD->srv }); + res[RBM_COMPUTE].samplers.append({ nativeBinding.second, samplerD->samplerState }); + } } } break; @@ -1866,9 +1931,12 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) bd.simage.id = texD->m_id; bd.simage.generation = texD->generation; if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - ID3D11UnorderedAccessView *uav = texD->unorderedAccessViewForLevel(b->u.simage.level); - if (uav) - srbD->csUAVs.feed(b->binding, uav); + QPair nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) { + ID3D11UnorderedAccessView *uav = texD->unorderedAccessViewForLevel(b->u.simage.level); + if (uav) + res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav }); + } } else { qWarning("Unordered access only supported at compute stage"); } @@ -1882,9 +1950,12 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) bd.sbuf.id = bufD->m_id; bd.sbuf.generation = bufD->generation; if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - ID3D11UnorderedAccessView *uav = bufD->unorderedAccessView(); - if (uav) - srbD->csUAVs.feed(b->binding, uav); + QPair nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps); + if (nativeBinding.first >= 0) { + ID3D11UnorderedAccessView *uav = bufD->unorderedAccessView(); + if (uav) + res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav }); + } } else { qWarning("Unordered access only supported at compute stage"); } @@ -1896,27 +1967,75 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) } } + // QRhiBatchedBindings works with the native bindings and expects + // sorted input. The pre-sorted QRhiShaderResourceBinding list (based + // on the QRhi (SPIR-V) binding) is not helpful in this regard, so we + // have to sort here every time. + for (int stage = 0; stage < RBM_SUPPORTED_STAGES; ++stage) { + std::sort(res[stage].buffers.begin(), res[stage].buffers.end(), [](const Stage::Buffer &a, const Stage::Buffer &b) { + return a.breg < b.breg; + }); + std::sort(res[stage].textures.begin(), res[stage].textures.end(), [](const Stage::Texture &a, const Stage::Texture &b) { + return a.treg < b.treg; + }); + std::sort(res[stage].samplers.begin(), res[stage].samplers.end(), [](const Stage::Sampler &a, const Stage::Sampler &b) { + return a.sreg < b.sreg; + }); + std::sort(res[stage].uavs.begin(), res[stage].uavs.end(), [](const Stage::Uav &a, const Stage::Uav &b) { + return a.ureg < b.ureg; + }); + } + + for (const Stage::Buffer &buf : qAsConst(res[RBM_VERTEX].buffers)) { + srbD->vsubufs.feed(buf.breg, buf.buffer); + srbD->vsubufoffsets.feed(buf.breg, buf.offsetInConstants); + srbD->vsubufsizes.feed(buf.breg, buf.sizeInConstants); + } srbD->vsubufs.finish(); srbD->vsubufoffsets.finish(); srbD->vsubufsizes.finish(); + for (const Stage::Buffer &buf : qAsConst(res[RBM_FRAGMENT].buffers)) { + srbD->fsubufs.feed(buf.breg, buf.buffer); + srbD->fsubufoffsets.feed(buf.breg, buf.offsetInConstants); + srbD->fsubufsizes.feed(buf.breg, buf.sizeInConstants); + } srbD->fsubufs.finish(); srbD->fsubufoffsets.finish(); srbD->fsubufsizes.finish(); + for (const Stage::Buffer &buf : qAsConst(res[RBM_COMPUTE].buffers)) { + srbD->csubufs.feed(buf.breg, buf.buffer); + srbD->csubufoffsets.feed(buf.breg, buf.offsetInConstants); + srbD->csubufsizes.feed(buf.breg, buf.sizeInConstants); + } srbD->csubufs.finish(); srbD->csubufoffsets.finish(); srbD->csubufsizes.finish(); + for (const Stage::Texture &t : qAsConst(res[RBM_VERTEX].textures)) + srbD->vsshaderresources.feed(t.treg, t.srv); + for (const Stage::Sampler &s : qAsConst(res[RBM_VERTEX].samplers)) + srbD->vssamplers.feed(s.sreg, s.sampler); srbD->vssamplers.finish(); srbD->vsshaderresources.finish(); + for (const Stage::Texture &t : qAsConst(res[RBM_FRAGMENT].textures)) + srbD->fsshaderresources.feed(t.treg, t.srv); + for (const Stage::Sampler &s : qAsConst(res[RBM_FRAGMENT].samplers)) + srbD->fssamplers.feed(s.sreg, s.sampler); srbD->fssamplers.finish(); srbD->fsshaderresources.finish(); + for (const Stage::Texture &t : qAsConst(res[RBM_COMPUTE].textures)) + srbD->csshaderresources.feed(t.treg, t.srv); + for (const Stage::Sampler &s : qAsConst(res[RBM_COMPUTE].samplers)) + srbD->cssamplers.feed(s.sreg, s.sampler); srbD->cssamplers.finish(); srbD->csshaderresources.finish(); + for (const Stage::Uav &u : qAsConst(res[RBM_COMPUTE].uavs)) + srbD->csUAVs.feed(u.ureg, u.uav); srbD->csUAVs.finish(); } @@ -2205,8 +2324,8 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain * case QD3D11CommandBuffer::Command::BindGraphicsPipeline: { QD3D11GraphicsPipeline *psD = cmd.args.bindGraphicsPipeline.ps; - context->VSSetShader(psD->vs, nullptr, 0); - context->PSSetShader(psD->fs, nullptr, 0); + context->VSSetShader(psD->vs.shader, nullptr, 0); + context->PSSetShader(psD->fs.shader, nullptr, 0); context->IASetPrimitiveTopology(psD->d3dTopology); context->IASetInputLayout(psD->inputLayout); context->OMSetDepthStencilState(psD->dsState, stencilRef); @@ -2281,7 +2400,7 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain * annotations->SetMarker(reinterpret_cast(QString::fromLatin1(cmd.args.debugMark.s).utf16())); break; case QD3D11CommandBuffer::Command::BindComputePipeline: - context->CSSetShader(cmd.args.bindComputePipeline.ps->cs, nullptr, 0); + context->CSSetShader(cmd.args.bindComputePipeline.ps->cs.shader, nullptr, 0); break; case QD3D11CommandBuffer::Command::Dispatch: context->Dispatch(cmd.args.dispatch.x, cmd.args.dispatch.y, cmd.args.dispatch.z); @@ -3137,6 +3256,7 @@ QD3D11ShaderResourceBindings::~QD3D11ShaderResourceBindings() void QD3D11ShaderResourceBindings::release() { sortedBindings.clear(); + boundResourceData.clear(); } bool QD3D11ShaderResourceBindings::build() @@ -3153,8 +3273,8 @@ bool QD3D11ShaderResourceBindings::build() boundResourceData.resize(sortedBindings.count()); - QRHI_RES_RHI(QRhiD3D11); - rhiD->updateShaderResourceBindings(this); + for (BoundResourceData &bd : boundResourceData) + memset(&bd, 0, sizeof(BoundResourceData)); generation += 1; return true; @@ -3195,15 +3315,17 @@ void QD3D11GraphicsPipeline::release() rastState = nullptr; } - if (vs) { - vs->Release(); - vs = nullptr; + if (vs.shader) { + vs.shader->Release(); + vs.shader = nullptr; } + vs.nativeResourceBindingMap.clear(); - if (fs) { - fs->Release(); - fs = nullptr; + if (fs.shader) { + fs.shader->Release(); + fs.shader = nullptr; } + fs.nativeResourceBindingMap.clear(); rhiD->unregisterResource(this); } @@ -3405,13 +3527,14 @@ static pD3DCompile resolveD3DCompile() return nullptr; } -static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, QString *error) +static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, QString *error, QShaderKey *usedShaderKey) { QShaderCode dxbc = shader.shader({ QShader::DxbcShader, 50, shaderVariant }); if (!dxbc.shader().isEmpty()) return dxbc.shader(); - QShaderCode hlslSource = shader.shader({ QShader::HlslShader, 50, shaderVariant }); + const QShaderKey key = { QShader::HlslShader, 50, shaderVariant }; + QShaderCode hlslSource = shader.shader(key); if (hlslSource.shader().isEmpty()) { qWarning() << "No HLSL (shader model 5.0) code found in baked shader" << shader; return QByteArray(); @@ -3463,6 +3586,9 @@ static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Varian return QByteArray(); } + if (usedShaderKey) + *usedShaderKey = key; + QByteArray result; result.resize(int(bytecode->GetBufferSize())); memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size())); @@ -3554,20 +3680,23 @@ bool QD3D11GraphicsPipeline::build() if (cacheIt != rhiD->m_shaderCache.constEnd()) { switch (shaderStage.type()) { case QRhiShaderStage::Vertex: - vs = static_cast(cacheIt->s); - vs->AddRef(); + vs.shader = static_cast(cacheIt->s); + vs.shader->AddRef(); vsByteCode = cacheIt->bytecode; + vs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap; break; case QRhiShaderStage::Fragment: - fs = static_cast(cacheIt->s); - fs->AddRef(); + fs.shader = static_cast(cacheIt->s); + fs.shader->AddRef(); + fs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap; break; default: break; } } else { QString error; - const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error); + QShaderKey shaderKey; + const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error, &shaderKey); if (bytecode.isEmpty()) { qWarning("HLSL shader compilation failed: %s", qPrintable(error)); return false; @@ -3580,23 +3709,27 @@ bool QD3D11GraphicsPipeline::build() switch (shaderStage.type()) { case QRhiShaderStage::Vertex: - hr = rhiD->dev->CreateVertexShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &vs); + hr = rhiD->dev->CreateVertexShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &vs.shader); if (FAILED(hr)) { qWarning("Failed to create vertex shader: %s", qPrintable(comErrorMessage(hr))); return false; } vsByteCode = bytecode; - rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs, bytecode)); - vs->AddRef(); + if (const QShader::NativeResourceBindingMap *map = shaderStage.shader().nativeResourceBindingMap(shaderKey)) + vs.nativeResourceBindingMap = *map; + rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs.shader, bytecode, vs.nativeResourceBindingMap)); + vs.shader->AddRef(); break; case QRhiShaderStage::Fragment: - hr = rhiD->dev->CreatePixelShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &fs); + hr = rhiD->dev->CreatePixelShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &fs.shader); if (FAILED(hr)) { qWarning("Failed to create pixel shader: %s", qPrintable(comErrorMessage(hr))); return false; } - rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs, bytecode)); - fs->AddRef(); + if (const QShader::NativeResourceBindingMap *map = shaderStage.shader().nativeResourceBindingMap(shaderKey)) + fs.nativeResourceBindingMap = *map; + rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs.shader, bytecode, fs.nativeResourceBindingMap)); + fs.shader->AddRef(); break; default: break; @@ -3655,46 +3788,52 @@ void QD3D11ComputePipeline::release() { QRHI_RES_RHI(QRhiD3D11); - if (!cs) + if (!cs.shader) return; - cs->Release(); - cs = nullptr; + cs.shader->Release(); + cs.shader = nullptr; + cs.nativeResourceBindingMap.clear(); rhiD->unregisterResource(this); } bool QD3D11ComputePipeline::build() { - if (cs) + if (cs.shader) release(); QRHI_RES_RHI(QRhiD3D11); auto cacheIt = rhiD->m_shaderCache.constFind(m_shaderStage); if (cacheIt != rhiD->m_shaderCache.constEnd()) { - cs = static_cast(cacheIt->s); + cs.shader = static_cast(cacheIt->s); + cs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap; } else { QString error; - const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error); + QShaderKey shaderKey; + const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error, &shaderKey); if (bytecode.isEmpty()) { qWarning("HLSL compute shader compilation failed: %s", qPrintable(error)); return false; } - HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &cs); + HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &cs.shader); if (FAILED(hr)) { qWarning("Failed to create compute shader: %s", qPrintable(comErrorMessage(hr))); return false; } + if (const QShader::NativeResourceBindingMap *map = m_shaderStage.shader().nativeResourceBindingMap(shaderKey)) + cs.nativeResourceBindingMap = *map; + if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES) rhiD->clearShaderCache(); - rhiD->m_shaderCache.insert(m_shaderStage, QRhiD3D11::Shader(cs, bytecode)); + rhiD->m_shaderCache.insert(m_shaderStage, QRhiD3D11::Shader(cs.shader, bytecode, cs.nativeResourceBindingMap)); } - cs->AddRef(); + cs.shader->AddRef(); generation += 1; rhiD->registerResource(this); diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index b70f541c68..f749b612b5 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -270,8 +270,14 @@ struct QD3D11GraphicsPipeline : public QRhiGraphicsPipeline ID3D11DepthStencilState *dsState = nullptr; ID3D11BlendState *blendState = nullptr; - ID3D11VertexShader *vs = nullptr; - ID3D11PixelShader *fs = nullptr; + struct { + ID3D11VertexShader *shader = nullptr; + QShader::NativeResourceBindingMap nativeResourceBindingMap; + } vs; + struct { + ID3D11PixelShader *shader = nullptr; + QShader::NativeResourceBindingMap nativeResourceBindingMap; + } fs; ID3D11InputLayout *inputLayout = nullptr; D3D11_PRIMITIVE_TOPOLOGY d3dTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; ID3D11RasterizerState *rastState = nullptr; @@ -286,7 +292,10 @@ struct QD3D11ComputePipeline : public QRhiComputePipeline void release() override; bool build() override; - ID3D11ComputeShader *cs = nullptr; + struct { + ID3D11ComputeShader *shader = nullptr; + QShader::NativeResourceBindingMap nativeResourceBindingMap; + } cs; uint generation = 0; friend class QRhiD3D11; }; @@ -642,7 +651,8 @@ public: void enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cbD, int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc); void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates); - void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD); + void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, + const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]); void executeBufferHostWrites(QD3D11Buffer *bufD); void bindShaderResources(QD3D11ShaderResourceBindings *srbD, const uint *dynOfsPairs, int dynOfsPairCount, @@ -701,9 +711,11 @@ public: struct Shader { Shader() = default; - Shader(IUnknown *s, const QByteArray &bytecode) : s(s), bytecode(bytecode) { } + Shader(IUnknown *s, const QByteArray &bytecode, const QShader::NativeResourceBindingMap &rbm) + : s(s), bytecode(bytecode), nativeResourceBindingMap(rbm) { } IUnknown *s; QByteArray bytecode; + QShader::NativeResourceBindingMap nativeResourceBindingMap; }; QHash m_shaderCache; -- cgit v1.2.3 From bd2b77120e1db8cb991aff23dd1f99cec792fa8e Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Sat, 29 Feb 2020 15:38:07 +0100 Subject: rhi: vulkan: Sanitize device extension handling Instead of qputenv("QT_VULKAN_DEVICE_EXTENSIONS", "VK_KHR_get_memory_requirements2;VK_NV_ray_tracing"); one can now do params.deviceExtensions = { "VK_KHR_get_memory_requirements2", "VK_NV_ray_tracing" }; on the QRhiVulkanInitParams passed to QRhi::create(). The environment variable stays important for Qt Quick applications, which provide no configurability for the QRhi construction (yet). On the other hand, applications using QRhi directly can now also use the new approach to specify the list of device extensions to enable. In addition, take QVulkanInfoVector into use. There is no reason not to rely on the infrastructure provided by QVulkanInstance. This also implies showing an informative warning for unsupported extensions, instead of merely failing the device creation. (applications will likely not be able to recover of course, but at least the reason for failing is made obvious this way) Task-number: QTBUG-82435 Change-Id: Ib47fd1a10c02be5ceef2c973e61e896c34f92fa3 Reviewed-by: Eirik Aavitsland --- src/gui/rhi/qrhivulkan.cpp | 60 +++++++++++++++++++++++++++++++------------- src/gui/rhi/qrhivulkan_p.h | 1 + src/gui/rhi/qrhivulkan_p_p.h | 1 + 3 files changed, 44 insertions(+), 18 deletions(-) (limited to 'src/gui') diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 8f6f118c9b..60ab15e89d 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -149,6 +149,10 @@ QT_BEGIN_NAMESPACE for other windows as well, as long as they all have their QWindow::surfaceType() set to QSurface::VulkanSurface. + To request additional extensions to be enabled on the Vulkan device, list them + in deviceExtensions. This can be relevant when integrating with native Vulkan + rendering code. + \section2 Working with existing Vulkan devices When interoperating with another graphics engine, it may be necessary to @@ -299,6 +303,7 @@ QRhiVulkan::QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *im { inst = params->inst; maybeWindow = params->window; // may be null + requestedDeviceExtensions = params->deviceExtensions; importedDevice = importDevice != nullptr; if (importedDevice) { @@ -463,40 +468,59 @@ bool QRhiVulkan::create(QRhi::Flags flags) if (inst->layers().contains("VK_LAYER_LUNARG_standard_validation")) devLayers.append("VK_LAYER_LUNARG_standard_validation"); + QVulkanInfoVector devExts; uint32_t devExtCount = 0; f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, nullptr); - QVector devExts(devExtCount); - f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, devExts.data()); + if (devExtCount) { + QVector extProps(devExtCount); + f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, extProps.data()); + for (const VkExtensionProperties &p : qAsConst(extProps)) + devExts.append({ p.extensionName, p.specVersion }); + } qCDebug(QRHI_LOG_INFO, "%d device extensions available", devExts.count()); QVector requestedDevExts; requestedDevExts.append("VK_KHR_swapchain"); debugMarkersAvailable = false; + if (devExts.contains(VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) { + requestedDevExts.append(VK_EXT_DEBUG_MARKER_EXTENSION_NAME); + debugMarkersAvailable = true; + } + vertexAttribDivisorAvailable = false; - for (const VkExtensionProperties &ext : devExts) { - if (!strcmp(ext.extensionName, VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) { - requestedDevExts.append(VK_EXT_DEBUG_MARKER_EXTENSION_NAME); - debugMarkersAvailable = true; - } else if (!strcmp(ext.extensionName, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) { - if (inst->extensions().contains(QByteArrayLiteral("VK_KHR_get_physical_device_properties2"))) { - requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); - vertexAttribDivisorAvailable = true; - } + if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) { + if (inst->extensions().contains(QByteArrayLiteral("VK_KHR_get_physical_device_properties2"))) { + requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); + vertexAttribDivisorAvailable = true; } } - QByteArrayList envExtList; - if (qEnvironmentVariableIsSet("QT_VULKAN_DEVICE_EXTENSIONS")) { - envExtList = qgetenv("QT_VULKAN_DEVICE_EXTENSIONS").split(';'); - for (auto ext : requestedDevExts) - envExtList.removeAll(ext); - for (const QByteArray &ext : envExtList) { - if (!ext.isEmpty()) + for (const QByteArray &ext : requestedDeviceExtensions) { + if (!ext.isEmpty()) { + if (devExts.contains(ext)) requestedDevExts.append(ext.constData()); + else + qWarning("Device extension %s is not supported", ext.constData()); } } + QByteArrayList envExtList = qgetenv("QT_VULKAN_DEVICE_EXTENSIONS").split(';'); + for (const QByteArray &ext : envExtList) { + if (!ext.isEmpty() && !requestedDevExts.contains(ext)) { + if (devExts.contains(ext)) + requestedDevExts.append(ext.constData()); + else + qWarning("Device extension %s is not supported", ext.constData()); + } + } + + if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) { + qCDebug(QRHI_LOG_INFO, "Enabling device extensions:"); + for (const char *ext : requestedDevExts) + qCDebug(QRHI_LOG_INFO, " %s", ext); + } + VkDeviceCreateInfo devInfo; memset(&devInfo, 0, sizeof(devInfo)); devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; diff --git a/src/gui/rhi/qrhivulkan_p.h b/src/gui/rhi/qrhivulkan_p.h index d495919671..f8870dcd77 100644 --- a/src/gui/rhi/qrhivulkan_p.h +++ b/src/gui/rhi/qrhivulkan_p.h @@ -57,6 +57,7 @@ struct Q_GUI_EXPORT QRhiVulkanInitParams : public QRhiInitParams { QVulkanInstance *inst = nullptr; QWindow *window = nullptr; + QByteArrayList deviceExtensions; }; struct Q_GUI_EXPORT QRhiVulkanNativeHandles : public QRhiNativeHandles diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index 0f0a89cbff..a6bcb7e7b6 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -810,6 +810,7 @@ public: QVulkanInstance *inst = nullptr; QWindow *maybeWindow = nullptr; + QByteArrayList requestedDeviceExtensions; bool importedDevice = false; VkPhysicalDevice physDev = VK_NULL_HANDLE; VkDevice dev = VK_NULL_HANDLE; -- cgit v1.2.3 From 4cff6e102dc65693d4f535079c72b0f8a63e8ebf Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 2 Mar 2020 17:23:28 +0100 Subject: rhi: Include an arrayDims vector in InOutVariable too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use the this struct to describe combined image samplers and storage images as well. Especially with the former, it is not unlikely that we will need arrays, so e.g. layout(binding = 1) uniform samplerCube shadowCubes[8]. In this case the '8' is something that must be reported in to the reflection information. The new arrayDims member is expected to work exactly like the similarly named member in BlockVariable. Task-number: QTBUG-82624 Change-Id: I1fb8b0318906ff4c116c1a7ec23a399c6545c730 Reviewed-by: Christian Strømme --- src/gui/rhi/qshaderdescription.cpp | 23 ++++++++++++++++++++++- src/gui/rhi/qshaderdescription_p.h | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'src/gui') diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp index 96c8d082fc..80cda259ec 100644 --- a/src/gui/rhi/qshaderdescription.cpp +++ b/src/gui/rhi/qshaderdescription.cpp @@ -783,6 +783,8 @@ QDebug operator<<(QDebug dbg, const QShaderDescription::InOutVariable &var) dbg.nospace() << " imageFormat=" << imageFormatStr(var.imageFormat); if (var.imageFlags) dbg.nospace() << " imageFlags=" << var.imageFlags; + if (!var.arrayDims.isEmpty()) + dbg.nospace() << " array=" << var.arrayDims; dbg.nospace() << ')'; return dbg; } @@ -878,6 +880,12 @@ static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v (*obj)[imageFormatKey] = imageFormatStr(v.imageFormat); if (v.imageFlags) (*obj)[imageFlagsKey] = int(v.imageFlags); + if (!v.arrayDims.isEmpty()) { + QJsonArray dimArr; + for (int dim : v.arrayDims) + dimArr.append(dim); + (*obj)[arrayDimsKey] = dimArr; + } } static void serializeDecorations(QDataStream *stream, const QShaderDescription::InOutVariable &v) @@ -887,6 +895,9 @@ static void serializeDecorations(QDataStream *stream, const QShaderDescription:: (*stream) << v.descriptorSet; (*stream) << int(v.imageFormat); (*stream) << int(v.imageFlags); + (*stream) << v.arrayDims.count(); + for (int dim : v.arrayDims) + (*stream) << dim; } static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v) @@ -1124,6 +1135,11 @@ static QShaderDescription::InOutVariable inOutVar(const QJsonObject &obj) var.imageFormat = mapImageFormat(obj[imageFormatKey].toString()); if (obj.contains(imageFlagsKey)) var.imageFlags = QShaderDescription::ImageFlags(obj[imageFlagsKey].toInt()); + if (obj.contains(arrayDimsKey)) { + QJsonArray dimArr = obj[arrayDimsKey].toArray(); + for (int i = 0; i < dimArr.count(); ++i) + var.arrayDims.append(dimArr.at(i).toInt()); + } return var; } @@ -1137,6 +1153,10 @@ static void deserializeDecorations(QDataStream *stream, QShaderDescription::InOu v->imageFormat = QShaderDescription::ImageFormat(f); (*stream) >> f; v->imageFlags = QShaderDescription::ImageFlags(f); + (*stream) >> f; + v->arrayDims.resize(f); + for (int i = 0; i < f; ++i) + (*stream) >> v->arrayDims[i]; } static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream) @@ -1420,7 +1440,8 @@ bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescr && lhs.binding == rhs.binding && lhs.descriptorSet == rhs.descriptorSet && lhs.imageFormat == rhs.imageFormat - && lhs.imageFlags == rhs.imageFlags; + && lhs.imageFlags == rhs.imageFlags + && lhs.arrayDims == rhs.arrayDims; } /*! diff --git a/src/gui/rhi/qshaderdescription_p.h b/src/gui/rhi/qshaderdescription_p.h index 108fc32a56..783aa384e1 100644 --- a/src/gui/rhi/qshaderdescription_p.h +++ b/src/gui/rhi/qshaderdescription_p.h @@ -216,6 +216,7 @@ public: int descriptorSet = -1; ImageFormat imageFormat = ImageFormatUnknown; ImageFlags imageFlags; + QVector arrayDims; }; struct BlockVariable { -- cgit v1.2.3 From 0378332bc1a6cf3592a4bf5f7e73fe10963168ca Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 3 Mar 2020 11:19:14 +0100 Subject: rhi: Use versioning in QShaderDescription serialization as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the first time that we add something to QShaderDescription after migrating to the non-JSON based serialization system. This now involves checking the "qsb version" when deserializing. Task-number: QTBUG-82624 Change-Id: I2bd875ef21e461559b878dccc5537cdfa43feaa2 Reviewed-by: Christian Strømme --- src/gui/rhi/qshader.cpp | 3 ++- src/gui/rhi/qshader_p_p.h | 3 ++- src/gui/rhi/qshaderdescription.cpp | 42 ++++++++++++++++++++---------------- src/gui/rhi/qshaderdescription_p.h | 2 +- src/gui/rhi/qshaderdescription_p_p.h | 2 +- 5 files changed, 29 insertions(+), 23 deletions(-) (limited to 'src/gui') diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp index 69f4a68215..945f4820c2 100644 --- a/src/gui/rhi/qshader.cpp +++ b/src/gui/rhi/qshader.cpp @@ -428,6 +428,7 @@ QShader QShader::fromSerialized(const QByteArray &data) ds >> intVal; d->qsbVersion = intVal; if (d->qsbVersion != QShaderPrivate::QSB_VERSION + && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_VAR_ARRAYDIMS && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITH_CBOR && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_BINDINGS) @@ -439,7 +440,7 @@ QShader QShader::fromSerialized(const QByteArray &data) ds >> intVal; d->stage = Stage(intVal); if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITH_CBOR) { - d->desc = QShaderDescription::deserialize(&ds); + d->desc = QShaderDescription::deserialize(&ds, d->qsbVersion); } else if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON) { QByteArray descBin; ds >> descBin; diff --git a/src/gui/rhi/qshader_p_p.h b/src/gui/rhi/qshader_p_p.h index 66ef18f391..ec9d25971f 100644 --- a/src/gui/rhi/qshader_p_p.h +++ b/src/gui/rhi/qshader_p_p.h @@ -57,7 +57,8 @@ QT_BEGIN_NAMESPACE struct Q_GUI_EXPORT QShaderPrivate { - static const int QSB_VERSION = 4; + static const int QSB_VERSION = 5; + static const int QSB_VERSION_WITHOUT_VAR_ARRAYDIMS = 4; static const int QSB_VERSION_WITH_CBOR = 3; static const int QSB_VERSION_WITH_BINARY_JSON = 2; static const int QSB_VERSION_WITHOUT_BINDINGS = 1; diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp index 80cda259ec..f3ef5edd12 100644 --- a/src/gui/rhi/qshaderdescription.cpp +++ b/src/gui/rhi/qshaderdescription.cpp @@ -35,6 +35,7 @@ ****************************************************************************/ #include "qshaderdescription_p_p.h" +#include "qshader_p_p.h" #include #include #include @@ -402,10 +403,10 @@ QShaderDescription QShaderDescription::fromCbor(const QByteArray &data) return desc; } -QShaderDescription QShaderDescription::deserialize(QDataStream *stream) +QShaderDescription QShaderDescription::deserialize(QDataStream *stream, int version) { QShaderDescription desc; - QShaderDescriptionPrivate::get(&desc)->loadFromStream(stream); + QShaderDescriptionPrivate::get(&desc)->loadFromStream(stream, version); return desc; } @@ -1143,7 +1144,7 @@ static QShaderDescription::InOutVariable inOutVar(const QJsonObject &obj) return var; } -static void deserializeDecorations(QDataStream *stream, QShaderDescription::InOutVariable *v) +static void deserializeDecorations(QDataStream *stream, int version, QShaderDescription::InOutVariable *v) { (*stream) >> v->location; (*stream) >> v->binding; @@ -1153,20 +1154,23 @@ static void deserializeDecorations(QDataStream *stream, QShaderDescription::InOu v->imageFormat = QShaderDescription::ImageFormat(f); (*stream) >> f; v->imageFlags = QShaderDescription::ImageFlags(f); - (*stream) >> f; - v->arrayDims.resize(f); - for (int i = 0; i < f; ++i) - (*stream) >> v->arrayDims[i]; + + if (version > QShaderPrivate::QSB_VERSION_WITHOUT_VAR_ARRAYDIMS) { + (*stream) >> f; + v->arrayDims.resize(f); + for (int i = 0; i < f; ++i) + (*stream) >> v->arrayDims[i]; + } } -static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream) +static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream, int version) { QShaderDescription::InOutVariable var; (*stream) >> var.name; int t; (*stream) >> t; var.type = QShaderDescription::VariableType(t); - deserializeDecorations(stream, &var); + deserializeDecorations(stream, version, &var); return var; } @@ -1196,7 +1200,7 @@ static QShaderDescription::BlockVariable blockVar(const QJsonObject &obj) return var; } -static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream *stream) +static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream *stream, int version) { QShaderDescription::BlockVariable var; (*stream) >> var.name; @@ -1216,7 +1220,7 @@ static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream * (*stream) >> count; var.structMembers.resize(count); for (int i = 0; i < count; ++i) - var.structMembers[i] = deserializeBlockMemberVar(stream); + var.structMembers[i] = deserializeBlockMemberVar(stream, version); return var; } @@ -1324,7 +1328,7 @@ void QShaderDescriptionPrivate::loadDoc(const QJsonDocument &doc) } } -void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) +void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream, int version) { Q_ASSERT(ref.loadRelaxed() == 1); // must be detached @@ -1332,12 +1336,12 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) (*stream) >> count; inVars.resize(count); for (int i = 0; i < count; ++i) - inVars[i] = deserializeInOutVar(stream); + inVars[i] = deserializeInOutVar(stream, version); (*stream) >> count; outVars.resize(count); for (int i = 0; i < count; ++i) - outVars[i] = deserializeInOutVar(stream); + outVars[i] = deserializeInOutVar(stream, version); (*stream) >> count; uniformBlocks.resize(count); @@ -1351,7 +1355,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) (*stream) >> memberCount; uniformBlocks[i].members.resize(memberCount); for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx) - uniformBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream); + uniformBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version); } (*stream) >> count; @@ -1363,7 +1367,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) (*stream) >> memberCount; pushConstantBlocks[i].members.resize(memberCount); for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx) - pushConstantBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream); + pushConstantBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version); } (*stream) >> count; @@ -1378,7 +1382,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) (*stream) >> memberCount; storageBlocks[i].members.resize(memberCount); for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx) - storageBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream); + storageBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version); } (*stream) >> count; @@ -1388,7 +1392,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) int t; (*stream) >> t; combinedImageSamplers[i].type = QShaderDescription::VariableType(t); - deserializeDecorations(stream, &combinedImageSamplers[i]); + deserializeDecorations(stream, version, &combinedImageSamplers[i]); } (*stream) >> count; @@ -1398,7 +1402,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream) int t; (*stream) >> t; storageImages[i].type = QShaderDescription::VariableType(t); - deserializeDecorations(stream, &storageImages[i]); + deserializeDecorations(stream, version, &storageImages[i]); } for (size_t i = 0; i < 3; ++i) diff --git a/src/gui/rhi/qshaderdescription_p.h b/src/gui/rhi/qshaderdescription_p.h index 783aa384e1..e5650ed921 100644 --- a/src/gui/rhi/qshaderdescription_p.h +++ b/src/gui/rhi/qshaderdescription_p.h @@ -78,7 +78,7 @@ public: static QShaderDescription fromBinaryJson(const QByteArray &data); #endif static QShaderDescription fromCbor(const QByteArray &data); - static QShaderDescription deserialize(QDataStream *stream); + static QShaderDescription deserialize(QDataStream *stream, int version); enum VariableType { Unknown = 0, diff --git a/src/gui/rhi/qshaderdescription_p_p.h b/src/gui/rhi/qshaderdescription_p_p.h index 69b6e811a1..ec2b0b6b4c 100644 --- a/src/gui/rhi/qshaderdescription_p_p.h +++ b/src/gui/rhi/qshaderdescription_p_p.h @@ -82,7 +82,7 @@ struct Q_GUI_EXPORT QShaderDescriptionPrivate QJsonDocument makeDoc(); void writeToStream(QDataStream *stream); void loadDoc(const QJsonDocument &doc); - void loadFromStream(QDataStream *stream); + void loadFromStream(QDataStream *stream, int version); QAtomicInt ref; QVector inVars; -- cgit v1.2.3 From eff6f77c1a38a5a89268b2dfbe9ab03cf9b2d652 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 27 Feb 2020 14:50:38 +0100 Subject: Add since 5.15 to new QVulkanInstance function Change-Id: Ib1fb6186a8c76d6848d5eda1756e7749383dae40 Reviewed-by: Eirik Aavitsland --- src/gui/vulkan/qvulkaninstance.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/gui') diff --git a/src/gui/vulkan/qvulkaninstance.cpp b/src/gui/vulkan/qvulkaninstance.cpp index 4b961a6f20..555dee3a9c 100644 --- a/src/gui/vulkan/qvulkaninstance.cpp +++ b/src/gui/vulkan/qvulkaninstance.cpp @@ -781,6 +781,8 @@ bool QVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, uint32_t system dependent synchronization. For example, on Wayland this will add send a wl_surface.frame request in order to prevent the driver from blocking for minimized windows. + + \since 5.15 */ void QVulkanInstance::presentAboutToBeQueued(QWindow *window) { -- cgit v1.2.3 From bbc52a043da3b38a2d44a5502c8587a1fdc8ad59 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Sat, 29 Feb 2020 16:47:55 +0100 Subject: rhi: Add a way to communicate back the native image layout for a QRhiTexture Relevant when doing custom rendering combined with QRhi, and only for APIs like Vulkan, where image layouts are a thing. As shown by demo apps, it is not currently possible to implement a correct application that renders or raytraces into a QRhiTexture's backing VkImage, and then uses that QRhiTexture in a QRhi-based render pass. This is because QRhi has no knowledge of the image layout if it changes due to commands recorded by direct Vulkan calls, and not via QRhi itself. So, except for certain simple cases, one will end up with incorrect image layout transitions in the barriers. (at minimum this will be caught by the validation layer) To remedy this, add a simple function taking the layout as int (we already do the opposite in nativeTexture()). Task-number: QTBUG-82435 Change-Id: Ic9e9c1b820b018f3b236742f99fe99fa6de63d36 Reviewed-by: Eirik Aavitsland --- src/gui/rhi/qrhi.cpp | 25 +++++++++++++++++++++++++ src/gui/rhi/qrhi_p.h | 1 + src/gui/rhi/qrhivulkan.cpp | 5 +++++ src/gui/rhi/qrhivulkan_p_p.h | 1 + 4 files changed, 32 insertions(+) (limited to 'src/gui') diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 6243bcda58..c805e23ad0 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -2339,6 +2339,31 @@ bool QRhiTexture::buildFrom(QRhiTexture::NativeTexture src) return false; } +/*! + With some graphics APIs, such as Vulkan, integrating custom rendering code + that uses the graphics API directly needs special care when it comes to + image layouts. This function allows communicating the expected layout the + image backing the QRhiTexture is in after the native rendering commands. + + For example, consider rendering into a QRhiTexture's VkImage directly with + Vulkan in a code block enclosed by QRhiCommandBuffer::beginExternal() and + QRhiCommandBuffer::endExternal(), followed by using the image for texture + sampling in a QRhi-based render pass. To avoid potentially incorrect image + layout transitions, this function can be used to indicate what the image + layout will be once the commands recorded in said code block complete. + + Calling this function makes sense only after + QRhiCommandBuffer::endExternal() and before a subsequent + QRhiCommandBuffer::beginPass(). + + This function has no effect with QRhi backends where the underlying + graphics API does not expose a concept of image layouts. + */ +void QRhiTexture::setNativeLayout(int layout) +{ + Q_UNUSED(layout); +} + /*! \class QRhiSampler \internal diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 8f53808d34..17c911a5ff 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -791,6 +791,7 @@ public: virtual bool build() = 0; virtual NativeTexture nativeTexture(); virtual bool buildFrom(NativeTexture src); + virtual void setNativeLayout(int layout); protected: QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &pixelSize_, diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 60ab15e89d..a92c3e14e9 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -5563,6 +5563,11 @@ QRhiTexture::NativeTexture QVkTexture::nativeTexture() return {&image, usageState.layout}; } +void QVkTexture::setNativeLayout(int layout) +{ + usageState.layout = VkImageLayout(layout); +} + VkImageView QVkTexture::imageViewForLevel(int level) { Q_ASSERT(level >= 0 && level < int(mipLevelCount)); diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index a6bcb7e7b6..fd65417e75 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -123,6 +123,7 @@ struct QVkTexture : public QRhiTexture bool build() override; bool buildFrom(NativeTexture src) override; NativeTexture nativeTexture() override; + void setNativeLayout(int layout) override; bool prepareBuild(QSize *adjustedSize = nullptr); bool finishBuild(); -- cgit v1.2.3 From dd0a197be40bdec1af02e58f50926afb11af9509 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 27 Feb 2020 14:58:10 +0100 Subject: QVulkanWindow: Remove queueCreateInfoModifier getter This is inconsistent with the other similar functions in QVulkanWindow, we do not provide getters for those either. Change-Id: If764b49f4b26ff14a2fa908b8d5b37429047250c Reviewed-by: Paul Olav Tvete --- src/gui/vulkan/qvulkanwindow.cpp | 13 ------------- src/gui/vulkan/qvulkanwindow.h | 1 - 2 files changed, 14 deletions(-) (limited to 'src/gui') diff --git a/src/gui/vulkan/qvulkanwindow.cpp b/src/gui/vulkan/qvulkanwindow.cpp index e211863f21..ee49cf0999 100644 --- a/src/gui/vulkan/qvulkanwindow.cpp +++ b/src/gui/vulkan/qvulkanwindow.cpp @@ -1595,19 +1595,6 @@ bool QVulkanWindow::event(QEvent *e) \sa setQueueCreateInfoModifier() */ -/*! - Return a previously set queue create info modification function. - - \sa setQueueCreateInfoModifier() - - \since 5.15 - */ -QVulkanWindow::QueueCreateInfoModifier QVulkanWindow::queueCreateInfoModifier() const -{ - Q_D(const QVulkanWindow); - return d->queueCreateInfoModifier; -} - /*! Set a queue create info modification function. diff --git a/src/gui/vulkan/qvulkanwindow.h b/src/gui/vulkan/qvulkanwindow.h index 530b6c0744..511b9501bd 100644 --- a/src/gui/vulkan/qvulkanwindow.h +++ b/src/gui/vulkan/qvulkanwindow.h @@ -106,7 +106,6 @@ public: typedef std::function &)> QueueCreateInfoModifier; - QueueCreateInfoModifier queueCreateInfoModifier() const; void setQueueCreateInfoModifier(QueueCreateInfoModifier modifier); bool isValid() const; -- cgit v1.2.3