diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2017-12-13 10:46:43 +0100 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2017-12-13 10:47:04 +0100 |
commit | bfb58a7fff934fde6f4c2b4c989f411b43aee8d9 (patch) | |
tree | 432201a0c7fb6c49d7835f728fc0da97d8742b39 /src/render | |
parent | f660c657092811e77aa0ffb8145d6b060464292c (diff) | |
parent | d69e2c2b42719e6839f32e8ab796cf22d9f29bfa (diff) |
Merge remote-tracking branch 'origin/5.10' into dev
Change-Id: Ib51c8311ce78b2fec62dd0c09cb943a85a7d0b2b
Diffstat (limited to 'src/render')
20 files changed, 604 insertions, 73 deletions
diff --git a/src/render/backend/attachmentpack.cpp b/src/render/backend/attachmentpack.cpp index 9a08fdde4..a2ac8c30c 100644 --- a/src/render/backend/attachmentpack.cpp +++ b/src/render/backend/attachmentpack.cpp @@ -50,11 +50,10 @@ AttachmentPack::AttachmentPack() { } -AttachmentPack::AttachmentPack(const RenderTargetSelector *selector, const RenderTarget *target, AttachmentManager *attachmentManager) +AttachmentPack::AttachmentPack(const RenderTarget *target, + AttachmentManager *attachmentManager, + const QVector<QRenderTargetOutput::AttachmentPoint> &drawBuffers) { - // Cache draw buffers list - const QVector<QRenderTargetOutput::AttachmentPoint> selectedAttachmentPoints = selector->outputs(); - // Copy attachments const auto outputIds = target->renderOutputs(); for (Qt3DCore::QNodeId outputId : outputIds) { @@ -66,15 +65,15 @@ AttachmentPack::AttachmentPack(const RenderTargetSelector *selector, const Rende // Create actual DrawBuffers list that is used for glDrawBuffers // If nothing is specified, use all the attachments as draw buffers - if (selectedAttachmentPoints.isEmpty()) { + if (drawBuffers.isEmpty()) { m_drawBuffers.reserve(m_attachments.size()); for (const Attachment &attachment : qAsConst(m_attachments)) // only consider Color Attachments if (attachment.m_point <= QRenderTargetOutput::Color15) m_drawBuffers.push_back((int) attachment.m_point); } else { - m_drawBuffers.reserve(selectedAttachmentPoints.size()); - for (QRenderTargetOutput::AttachmentPoint drawBuffer : selectedAttachmentPoints) + m_drawBuffers.reserve(drawBuffers.size()); + for (QRenderTargetOutput::AttachmentPoint drawBuffer : drawBuffers) if (drawBuffer <= QRenderTargetOutput::Color15) m_drawBuffers.push_back((int) drawBuffer); } diff --git a/src/render/backend/attachmentpack_p.h b/src/render/backend/attachmentpack_p.h index 98362149a..a3a2586dd 100644 --- a/src/render/backend/attachmentpack_p.h +++ b/src/render/backend/attachmentpack_p.h @@ -84,7 +84,9 @@ class AttachmentPack { public: AttachmentPack(); - AttachmentPack(const RenderTargetSelector *selector, const RenderTarget *target, AttachmentManager *attachmentManager); + AttachmentPack(const RenderTarget *target, + AttachmentManager *attachmentManager, + const QVector<QRenderTargetOutput::AttachmentPoint> &drawBuffers = QVector<QRenderTargetOutput::AttachmentPoint>()); QVector<Attachment> attachments() const { return m_attachments; } QVector<int> getGlDrawBuffers() const { return m_drawBuffers; } diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index dbb33fbcf..4bf22cf0e 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -1985,7 +1985,7 @@ const QVector<Qt3DCore::QNodeId> Renderer::takePendingRenderCaptureSendRequests( // 1 dirty buffer == 1 job, all job can be performed in parallel QVector<Qt3DCore::QAspectJobPtr> Renderer::createRenderBufferJobs() const { - const QVector<QNodeId> dirtyBuffers = m_nodesManager->bufferManager()->dirtyBuffers(); + const QVector<QNodeId> dirtyBuffers = m_nodesManager->bufferManager()->takeDirtyBuffers(); QVector<QAspectJobPtr> dirtyBuffersJobs; dirtyBuffersJobs.reserve(dirtyBuffers.size()); diff --git a/src/render/backend/renderviewbuilder.cpp b/src/render/backend/renderviewbuilder.cpp index dca75f517..0682018fc 100644 --- a/src/render/backend/renderviewbuilder.cpp +++ b/src/render/backend/renderviewbuilder.cpp @@ -218,7 +218,7 @@ public: const QVector<Entity *> filteredEntities = m_renderer->cache()->leafNodeCache.value(m_leafNode).filterEntitiesByLayer; lock.unlock(); // Remove all entities from the compute and renderable vectors that aren't in the filtered layer vector - RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, filteredEntities); + renderableEntities = RenderViewBuilder::entitiesInSubset(renderableEntities, filteredEntities); // Set the light sources, with layer filters applied. QVector<LightSource> lightSources = m_lightGathererJob->lights(); @@ -231,9 +231,9 @@ public: if (isDraw) { // Filter out frustum culled entity for drawable entities if (rv->frustumCulling()) - RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, m_frustumCullingJob->visibleEntities()); + renderableEntities = RenderViewBuilder::entitiesInSubset(renderableEntities, m_frustumCullingJob->visibleEntities()); // Filter out entities which didn't satisfy proximity filtering - RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, m_filterProximityJob->filteredEntities()); + renderableEntities = RenderViewBuilder::entitiesInSubset(renderableEntities, m_filterProximityJob->filteredEntities()); } // Split among the number of command builders @@ -647,17 +647,15 @@ int RenderViewBuilder::optimalJobCount() return RenderViewBuilder::m_optimalParallelJobCount; } -void RenderViewBuilder::removeEntitiesNotInSubset(QVector<Entity *> &entities, QVector<Entity *> subset) +QVector<Entity *> RenderViewBuilder::entitiesInSubset(const QVector<Entity *> &entities, const QVector<Entity *> &subset) { - // Note: assumes entities was sorted already - std::sort(subset.begin(), subset.end()); + QVector<Entity *> intersection; + intersection.reserve(qMin(entities.size(), subset.size())); + std::set_intersection(entities.begin(), entities.end(), + subset.begin(), subset.end(), + std::back_inserter(intersection)); - for (auto i = entities.size() - 1, j = subset.size() - 1; i >= 0; --i) { - while (j >= 0 && subset.at(j) > entities.at(i)) - --j; - if (j < 0 || entities.at(i) != subset.at(j)) - entities.removeAt(i); - } + return intersection; } } // Render diff --git a/src/render/backend/renderviewbuilder_p.h b/src/render/backend/renderviewbuilder_p.h index 8094fb46a..818313500 100644 --- a/src/render/backend/renderviewbuilder_p.h +++ b/src/render/backend/renderviewbuilder_p.h @@ -110,7 +110,7 @@ public: bool materialGathererCacheNeedsToBeRebuilt() const; static int optimalJobCount(); - static void removeEntitiesNotInSubset(QVector<Entity *> &entities, QVector<Entity *> subset); + static QVector<Entity *> entitiesInSubset(const QVector<Entity *> &entities, const QVector<Entity *> &subset); private: Render::FrameGraphNode *m_leafNode; diff --git a/src/render/framegraph/qblitframebuffer.cpp b/src/render/framegraph/qblitframebuffer.cpp index 505bab96c..d5484b719 100644 --- a/src/render/framegraph/qblitframebuffer.cpp +++ b/src/render/framegraph/qblitframebuffer.cpp @@ -47,6 +47,99 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { +/*! + \class Qt3DRender::QBlitFramebuffer + \inmodule Qt3DRender + \since 5.10 + \ingroup framegraph + \brief FrameGraph node to transfer a rectangle of pixel values from one + region of a render target to another. + + This node inserts a \c glBlitFrameBuffer or an equivalent into the command + stream. This provides a more efficient method for copying rectangles + between textures or surface backbuffers wrapped by QRenderTarget than + drawing textured quads. It also supports scaling with the specified + interpolation method. + + \note In practice the QBlitFramebuffer node will often be used in + combination with QNoDraw since a blit should not involve issuing draw calls + for any entities. + */ + +/*! + \qmltype BlitFramebuffer + \inqmlmodule Qt3D.Render + \instantiates Qt3DRender::QBlitFramebuffer + \inherits FrameGraphNode + \since 5.10 + \brief FrameGraph node to transfer a rectangle of pixel values from one + region of a render target to another. + + This node inserts a \c glBlitFrameBuffer or an equivalent into the command + stream. This provides a more efficient method for copying rectangles + between textures or surface backbuffers wrapped by QRenderTarget than + drawing textured quads. It also supports scaling with the specified + interpolation method. + + \note In practice the BlitFramebuffer node will often be used in + combination with NoDraw since a blit should not involve issuing draw calls + for any entities. +*/ + +/*! + \qmlproperty RenderTarget BlitFramebuffer::source + + Specifies the source render target. When not set, the source is assumed to + be the default framebuffer (i.e. the backbuffer of the current surface), if + there is one. + + \note the source and destination must not refer to the same render target. + */ + +/*! + \qmlproperty RenderTarget BlitFramebuffer::destination + + Specifies the destination render target. When not set, the destination is + assumed to be the default framebuffer (i.e. the backbuffer of the current + surface), if there is one. + + \note the source and destination must not refer to the same render target. + */ + +/*! + \qmlproperty Rect BlitFramebuffer::sourceRect + + Specifies the source rectangle. The coordinates are assumed to follow the + normal Qt coordinate system, meaning Y runs from top to bottom. + */ + +/*! + \qmlproperty Rect BlitFramebuffer::destinationRect + + Specifies the destination rectangle. The coordinates are assumed to follow + the normal Qt coordinate system, meaning Y runs from top to bottom. + */ + +/*! + \qmlproperty RenderTargetOutput.AttachmentPoint BlitFramebuffer::sourceAttachmentPoint + + Specifies the source attachment point. Defaults to + RenderTargetOutput.AttachmentPoint.Color0. + */ + +/*! + \qmlproperty RenderTargetOutput.AttachmentPoint BlitFramebuffer::destinationAttachmentPoint + + Specifies the source attachment point. Defaults to + RenderTargetOutput.AttachmentPoint.Color0. + */ + +/*! + \qmlproperty InterpolationMethod BlitFramebuffer::interpolationMethod + + Specifies the interpolation applied if the image is stretched. Defaults to Linear. + */ + QBlitFramebufferPrivate::QBlitFramebufferPrivate() : QFrameGraphNodePrivate() , m_source(nullptr) @@ -59,82 +152,168 @@ QBlitFramebufferPrivate::QBlitFramebufferPrivate() { } +/*! + Constructs a new QBlitFramebuffer with the given \a parent. + */ QBlitFramebuffer::QBlitFramebuffer(QNode *parent) : QFrameGraphNode(*new QBlitFramebufferPrivate, parent) { } +/*! + \internal + */ QBlitFramebuffer::QBlitFramebuffer(QBlitFramebufferPrivate &dd, QNode *parent) : QFrameGraphNode(dd, parent) { } +/*! + Destructor. + */ QBlitFramebuffer::~QBlitFramebuffer() { } +/*! + \return the source render target. + */ QRenderTarget *QBlitFramebuffer::source() const { Q_D(const QBlitFramebuffer); return d->m_source; } +/*! + \return the destination render target. + */ QRenderTarget *QBlitFramebuffer::destination() const { Q_D(const QBlitFramebuffer); return d->m_destination; } +/*! + \return the source rectangle. + */ QRectF QBlitFramebuffer::sourceRect() const { Q_D(const QBlitFramebuffer); return d->m_sourceRect; } +/*! + \return the destination rectangle. + */ QRectF QBlitFramebuffer::destinationRect() const { Q_D(const QBlitFramebuffer); return d->m_destinationRect; } +/*! + \return the source attachment point. + */ Qt3DRender::QRenderTargetOutput::AttachmentPoint QBlitFramebuffer::sourceAttachmentPoint() const { Q_D(const QBlitFramebuffer); return d->m_sourceAttachmentPoint; } +/*! + \return the destination attachment point. + */ QRenderTargetOutput::AttachmentPoint QBlitFramebuffer::destinationAttachmentPoint() const { Q_D(const QBlitFramebuffer); return d->m_destinationAttachmentPoint; } +/*! + \return the interpolation method. + */ QBlitFramebuffer::InterpolationMethod QBlitFramebuffer::interpolationMethod() const { Q_D(const QBlitFramebuffer); return d->m_interpolationMethod; } +/*! + Sets the source render target. The default value is nullptr, in which + case the source is assumed to be be the default framebuffer (i.e. the + backbuffer of the current surface), if there is one. + + \note the source and destination must not refer to the same render target. + + \note As with other nodes, \a source gets automatically parented to the + QBlitFramebuffer instance when no parent has been set. The lifetime is also + tracked, meaning the source reverts to nullptr in case the currently set + \a source is destroyed. + */ void QBlitFramebuffer::setSource(QRenderTarget *source) { Q_D(QBlitFramebuffer); if (d->m_source != source) { + if (d->m_source) { + // Remove bookkeeping connection + d->unregisterDestructionHelper(d->m_source); + } + d->m_source = source; + + if (d->m_source) { + // Ensures proper bookkeeping. Calls us back with nullptr in case the rt gets destroyed. + d->registerDestructionHelper(d->m_source, &QBlitFramebuffer::setSource, d->m_source); + + if (!d->m_source->parent()) + d->m_source->setParent(this); + } + emit sourceChanged(); } } +/*! + Sets the destination render target. The default value is nullptr, in which + case the destination is assumed to be be the default framebuffer (i.e. the + backbuffer of the current surface), if there is one. + + \note the source and destination must not refer to the same render target. + + \note As with other nodes, \a destination gets automatically parented to the + QBlitFramebuffer instance when no parent has been set. The lifetime is also + tracked, meaning the destination reverts to nullptr in case the currently set + \a destination is destroyed. + */ void QBlitFramebuffer::setDestination(QRenderTarget *destination) { Q_D(QBlitFramebuffer); if (d->m_destination != destination) { + if (d->m_destination) { + // Remove bookkeeping connection + d->unregisterDestructionHelper(d->m_destination); + } + d->m_destination = destination; + + if (d->m_destination) { + // Ensures proper bookkeeping. Calls us back with nullptr in case the rt gets destroyed. + d->registerDestructionHelper(d->m_destination, &QBlitFramebuffer::setDestination, d->m_destination); + + if (!d->m_destination->parent()) + d->m_destination->setParent(this); + } + emit destinationChanged(); } } +/*! + Sets the source rectangle to \a inputRect. The coordinates are assumed to + follow the normal Qt coordinate system, meaning Y runs from top to bottom. + */ void QBlitFramebuffer::setSourceRect(const QRectF &inputRect) { Q_D(QBlitFramebuffer); @@ -144,6 +323,11 @@ void QBlitFramebuffer::setSourceRect(const QRectF &inputRect) } } +/*! + Sets the destination rectangle to \a inputRect. The coordinates are assumed + to follow the normal Qt coordinate system, meaning Y runs from top to + bottom. + */ void QBlitFramebuffer::setDestinationRect(const QRectF &outputRect) { Q_D(QBlitFramebuffer); @@ -153,6 +337,10 @@ void QBlitFramebuffer::setDestinationRect(const QRectF &outputRect) } } +/*! + Sets the \a sourceAttachmentPoint. Defaults to + Qt3DRender::QRenderTargetOutput::AttachmentPoint::Color0. + */ void QBlitFramebuffer::setSourceAttachmentPoint(Qt3DRender::QRenderTargetOutput::AttachmentPoint sourceAttachmentPoint) { Q_D(QBlitFramebuffer); @@ -162,6 +350,10 @@ void QBlitFramebuffer::setSourceAttachmentPoint(Qt3DRender::QRenderTargetOutput: } } +/*! + Sets the \a destinationAttachmentPoint. Defaults to + Qt3DRender::QRenderTargetOutput::AttachmentPoint::Color0. + */ void QBlitFramebuffer::setDestinationAttachmentPoint(QRenderTargetOutput::AttachmentPoint destinationAttachmentPoint) { Q_D(QBlitFramebuffer); @@ -171,6 +363,10 @@ void QBlitFramebuffer::setDestinationAttachmentPoint(QRenderTargetOutput::Attach } } +/*! + Sets the \a interpolationMethod that is applied if the image is stretched. + Defaults to Linear. + */ void QBlitFramebuffer::setInterpolationMethod(QBlitFramebuffer::InterpolationMethod interpolationMethod) { Q_D(QBlitFramebuffer); @@ -180,6 +376,9 @@ void QBlitFramebuffer::setInterpolationMethod(QBlitFramebuffer::InterpolationMet } } +/*! + \internal + */ Qt3DCore::QNodeCreatedChangeBasePtr QBlitFramebuffer::createNodeCreationChange() const { auto creationChange = QFrameGraphNodeCreatedChangePtr<QBlitFramebufferData>::create(this); diff --git a/src/render/framegraph/qrendercapture.cpp b/src/render/framegraph/qrendercapture.cpp index 66c518506..28bc41b91 100644 --- a/src/render/framegraph/qrendercapture.cpp +++ b/src/render/framegraph/qrendercapture.cpp @@ -149,6 +149,15 @@ namespace Qt3DRender { */ /*! + * \qmlmethod RenderCaptureReply Qt3D.Render::RenderCapture::requestCapture(Rect rect) + * + * Used to request render capture from a specified \a rect. Only one render capture + * result is produced per requestCapture call even if the frame graph has multiple leaf nodes. + * The function returns a QRenderCaptureReply object, which receives the captured image + * when it is done. The user is responsible for deallocating the returned object. + */ + +/*! * \internal */ QRenderCaptureReplyPrivate::QRenderCaptureReplyPrivate() @@ -311,7 +320,7 @@ QRenderCapture::QRenderCapture(Qt3DCore::QNode *parent) * The function returns a QRenderCaptureReply object, which receives the captured image * when it is done. The user is responsible for deallocating the returned object. */ -QRenderCaptureReply *QRenderCapture::requestCapture(int captureId, const QRect &rect) +QRenderCaptureReply *QRenderCapture::requestCapture(int captureId) { Q_D(QRenderCapture); QRenderCaptureReply *reply = d->createReply(captureId); @@ -322,7 +331,7 @@ QRenderCaptureReply *QRenderCapture::requestCapture(int captureId, const QRect & Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(id())); change->setPropertyName(QByteArrayLiteral("renderCaptureRequest")); - const QRenderCaptureRequest request = { captureId, rect }; + const QRenderCaptureRequest request = { captureId, QRect() }; change->setValue(QVariant::fromValue(request)); d->notifyObservers(change); @@ -330,8 +339,8 @@ QRenderCaptureReply *QRenderCapture::requestCapture(int captureId, const QRect & } /*! - * Used to request render capture. Only one render capture result is produced per - * requestCapture call even if the frame graph has multiple leaf nodes. + * Used to request render capture from a specified \a rect. Only one render capture result + * is produced per requestCapture call even if the frame graph has multiple leaf nodes. * The function returns a QRenderCaptureReply object, which receives the captured image * when it is done. The user is responsible for deallocating the returned object. */ @@ -357,6 +366,17 @@ QRenderCaptureReply *QRenderCapture::requestCapture(const QRect &rect) } /*! + * Used to request render capture. Only one render capture result is produced per + * requestCapture call even if the frame graph has multiple leaf nodes. + * The function returns a QRenderCaptureReply object, which receives the captured image + * when it is done. The user is responsible for deallocating the returned object. + */ +Qt3DRender::QRenderCaptureReply *QRenderCapture::requestCapture() +{ + return requestCapture(QRect()); +} + +/*! * \internal */ void QRenderCapture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) diff --git a/src/render/framegraph/qrendercapture.h b/src/render/framegraph/qrendercapture.h index c0a4d4ab4..80eeabe64 100644 --- a/src/render/framegraph/qrendercapture.h +++ b/src/render/framegraph/qrendercapture.h @@ -84,9 +84,10 @@ class QT3DRENDERSHARED_EXPORT QRenderCapture : public QFrameGraphNode public: explicit QRenderCapture(Qt3DCore::QNode *parent = nullptr); - Q_INVOKABLE Q_DECL_DEPRECATED_X("Use the overload with no parameter") - Qt3DRender::QRenderCaptureReply *requestCapture(int captureId, const QRect &rect = QRect()); - Q_REVISION(9) Q_INVOKABLE Qt3DRender::QRenderCaptureReply *requestCapture(const QRect &rect = QRect()); + Q_INVOKABLE Q_DECL_DEPRECATED_X("Use the overload with no id parameter") + Qt3DRender::QRenderCaptureReply *requestCapture(int captureId); + Q_REVISION(9) Q_INVOKABLE Qt3DRender::QRenderCaptureReply *requestCapture(); + Q_REVISION(10) Q_INVOKABLE Qt3DRender::QRenderCaptureReply *requestCapture(const QRect &rect); protected: void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override; diff --git a/src/render/frontend/qlevelofdetail.h b/src/render/frontend/qlevelofdetail.h index 14ed92628..24d5942ab 100644 --- a/src/render/frontend/qlevelofdetail.h +++ b/src/render/frontend/qlevelofdetail.h @@ -78,7 +78,7 @@ public: QVector<qreal> thresholds() const; QLevelOfDetailBoundingSphere volumeOverride() const; - Q_INVOKABLE QLevelOfDetailBoundingSphere createBoundingSphere(const QVector3D ¢er, float radius); + Q_INVOKABLE Qt3DRender::QLevelOfDetailBoundingSphere createBoundingSphere(const QVector3D ¢er, float radius); public Q_SLOTS: void setCamera(QCamera *camera); diff --git a/src/render/geometry/buffermanager.cpp b/src/render/geometry/buffermanager.cpp index 25f95189e..14b552879 100644 --- a/src/render/geometry/buffermanager.cpp +++ b/src/render/geometry/buffermanager.cpp @@ -58,7 +58,7 @@ void BufferManager::addDirtyBuffer(Qt3DCore::QNodeId bufferId) m_dirtyBuffers.push_back(bufferId); } -QVector<Qt3DCore::QNodeId> BufferManager::dirtyBuffers() +QVector<Qt3DCore::QNodeId> BufferManager::takeDirtyBuffers() { return qMove(m_dirtyBuffers); } diff --git a/src/render/geometry/buffermanager_p.h b/src/render/geometry/buffermanager_p.h index ed3563876..4805955bd 100644 --- a/src/render/geometry/buffermanager_p.h +++ b/src/render/geometry/buffermanager_p.h @@ -72,7 +72,7 @@ public: // Aspect Thread void addDirtyBuffer(Qt3DCore::QNodeId bufferId); - QVector<Qt3DCore::QNodeId> dirtyBuffers(); + QVector<Qt3DCore::QNodeId> takeDirtyBuffers(); // Aspect Thread void addBufferReference(Qt3DCore::QNodeId bufferId); diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp index 9a20c77e7..d33aca825 100644 --- a/src/render/graphicshelpers/graphicscontext.cpp +++ b/src/render/graphicshelpers/graphicscontext.cpp @@ -366,6 +366,10 @@ QSize GraphicsContext::renderTargetSize(const QSize &surfaceSize) const void GraphicsContext::setViewport(const QRectF &viewport, const QSize &surfaceSize) { + // save for later use; this has nothing to do with the viewport but it is + // here that we get to know the surfaceSize from the RenderView. + m_surfaceSize = surfaceSize; + m_viewport = viewport; QSize size = renderTargetSize(surfaceSize); @@ -579,38 +583,11 @@ void GraphicsContext::activateRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, // this is the default fbo that some platforms create (iOS), we just register it // Insert FBO into hash m_renderTargets.insert(renderTargetNodeId, fboId); - } else if ((fboId = m_glHelper->createFrameBufferObject()) != 0) { - // The FBO is created and its attachments are set once - // Insert FBO into hash - m_renderTargets.insert(renderTargetNodeId, fboId); - // Bind FBO - m_glHelper->bindFrameBufferObject(fboId, GraphicsHelperInterface::FBODraw); - bindFrameBufferAttachmentHelper(fboId, attachments); } else { - qCritical() << "Failed to create FBO"; + fboId = createRenderTarget(renderTargetNodeId, attachments); } } else { - fboId = m_renderTargets.value(renderTargetNodeId); - - // We need to check if one of the attachment was resized - bool needsResize = !m_renderTargetsSize.contains(fboId); // not even initialized yet? - if (!needsResize) { - // render target exists, has attachment been resized? - GLTextureManager *glTextureManager = m_renderer->nodeManagers()->glTextureManager(); - const QSize s = m_renderTargetsSize[fboId]; - const auto attachments_ = attachments.attachments(); - for (const Attachment &attachment : attachments_) { - GLTexture *rTex = glTextureManager->lookupResource(attachment.m_textureUuid); - needsResize |= (rTex != nullptr && rTex->size() != s); - if (attachment.m_point == QRenderTargetOutput::Color0) - m_renderTargetFormat = rTex->properties().format; - } - } - - if (needsResize) { - m_glHelper->bindFrameBufferObject(fboId, GraphicsHelperInterface::FBODraw); - bindFrameBufferAttachmentHelper(fboId, attachments); - } + fboId = updateRenderTarget(renderTargetNodeId, attachments, true); } } m_activeFBO = fboId; @@ -619,6 +596,54 @@ void GraphicsContext::activateRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, activateDrawBuffers(attachments); } +GLuint GraphicsContext::createRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, const AttachmentPack &attachments) +{ + const GLuint fboId = m_glHelper->createFrameBufferObject(); + if (fboId) { + // The FBO is created and its attachments are set once + // Insert FBO into hash + m_renderTargets.insert(renderTargetNodeId, fboId); + // Bind FBO + m_glHelper->bindFrameBufferObject(fboId, GraphicsHelperInterface::FBODraw); + bindFrameBufferAttachmentHelper(fboId, attachments); + } else { + qCritical("Failed to create FBO"); + } + return fboId; +} + +GLuint GraphicsContext::updateRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, const AttachmentPack &attachments, bool isActiveRenderTarget) +{ + const GLuint fboId = m_renderTargets.value(renderTargetNodeId); + + // We need to check if one of the attachment was resized + bool needsResize = !m_renderTargetsSize.contains(fboId); // not even initialized yet? + if (!needsResize) { + // render target exists, has attachment been resized? + GLTextureManager *glTextureManager = m_renderer->nodeManagers()->glTextureManager(); + const QSize s = m_renderTargetsSize[fboId]; + const auto attachments_ = attachments.attachments(); + for (const Attachment &attachment : attachments_) { + GLTexture *rTex = glTextureManager->lookupResource(attachment.m_textureUuid); + // ### TODO QTBUG-64757 this check is insufficient since the + // texture may have changed to another one with the same size. That + // case is not handled atm. + needsResize |= (rTex != nullptr && rTex->size() != s); + if (isActiveRenderTarget) { + if (attachment.m_point == QRenderTargetOutput::Color0) + m_renderTargetFormat = rTex->properties().format; + } + } + } + + if (needsResize) { + m_glHelper->bindFrameBufferObject(fboId, GraphicsHelperInterface::FBODraw); + bindFrameBufferAttachmentHelper(fboId, attachments); + } + + return fboId; +} + void GraphicsContext::bindFrameBufferAttachmentHelper(GLuint fboId, const AttachmentPack &attachments) { // Set FBO attachments. These are normally textures, except that on Open GL @@ -1515,30 +1540,53 @@ bool GraphicsContext::hasGLBufferForBuffer(Buffer *buffer) return (it != m_renderBufferHash.end()); } -void GraphicsContext::blitFramebuffer(Qt3DCore::QNodeId inputRenderTarget, - Qt3DCore::QNodeId outputRenderTarget, +void GraphicsContext::blitFramebuffer(Qt3DCore::QNodeId inputRenderTargetId, + Qt3DCore::QNodeId outputRenderTargetId, QRect inputRect, QRect outputRect, uint defaultFboId, QRenderTargetOutput::AttachmentPoint inputAttachmentPoint, QRenderTargetOutput::AttachmentPoint outputAttachmentPoint, QBlitFramebuffer::InterpolationMethod interpolationMethod) { - //Find the context side name for the render targets - const GLuint inputFboId = m_renderTargets[inputRenderTarget]; + GLuint inputFboId = defaultFboId; + bool inputBufferIsDefault = true; + if (!inputRenderTargetId.isNull()) { + RenderTarget *renderTarget = m_renderer->nodeManagers()->renderTargetManager()->lookupResource(inputRenderTargetId); + if (renderTarget) { + AttachmentPack attachments(renderTarget, m_renderer->nodeManagers()->attachmentManager()); + if (m_renderTargets.contains(inputRenderTargetId)) + inputFboId = updateRenderTarget(inputRenderTargetId, attachments, false); + else + inputFboId = createRenderTarget(inputRenderTargetId, attachments); + } + inputBufferIsDefault = false; + } + GLuint outputFboId = defaultFboId; bool outputBufferIsDefault = true; - if (!outputRenderTarget.isNull() && m_renderTargets.contains(outputRenderTarget)) { - outputFboId = m_renderTargets[outputRenderTarget]; + if (!outputRenderTargetId.isNull()) { + RenderTarget *renderTarget = m_renderer->nodeManagers()->renderTargetManager()->lookupResource(outputRenderTargetId); + if (renderTarget) { + AttachmentPack attachments(renderTarget, m_renderer->nodeManagers()->attachmentManager()); + if (m_renderTargets.contains(outputRenderTargetId)) + outputFboId = updateRenderTarget(outputRenderTargetId, attachments, false); + else + outputFboId = createRenderTarget(outputRenderTargetId, attachments); + } outputBufferIsDefault = false; } + // Up until this point the input and output rects are normal Qt rectangles. + // Convert them to GL rectangles (Y at bottom). + const int inputFboHeight = inputFboId == defaultFboId ? m_surfaceSize.height() : m_renderTargetsSize[inputFboId].height(); const GLint srcX0 = inputRect.left(); - const GLint srcY0 = inputRect.top(); + const GLint srcY0 = inputFboHeight - (inputRect.top() + inputRect.height()); const GLint srcX1 = srcX0 + inputRect.width(); const GLint srcY1 = srcY0 + inputRect.height(); + const int outputFboHeight = outputFboId == defaultFboId ? m_surfaceSize.height() : m_renderTargetsSize[outputFboId].height(); const GLint dstX0 = outputRect.left(); - const GLint dstY0 = outputRect.top(); + const GLint dstY0 = outputFboHeight - (outputRect.top() + outputRect.height()); const GLint dstX1 = dstX0 + outputRect.width(); const GLint dstY1 = dstY0 + outputRect.height(); @@ -1552,7 +1600,8 @@ void GraphicsContext::blitFramebuffer(Qt3DCore::QNodeId inputRenderTarget, bindFramebuffer(outputFboId, GraphicsHelperInterface::FBODraw); //Bind texture - readBuffer(GL_COLOR_ATTACHMENT0 + inputAttachmentPoint); + if (!inputBufferIsDefault) + readBuffer(GL_COLOR_ATTACHMENT0 + inputAttachmentPoint); if (!outputBufferIsDefault) drawBuffer(GL_COLOR_ATTACHMENT0 + outputAttachmentPoint); diff --git a/src/render/graphicshelpers/graphicscontext_p.h b/src/render/graphicshelpers/graphicscontext_p.h index b07a11c7e..24b08e45e 100644 --- a/src/render/graphicshelpers/graphicscontext_p.h +++ b/src/render/graphicshelpers/graphicscontext_p.h @@ -168,7 +168,7 @@ public: void releaseBuffer(Qt3DCore::QNodeId bufferId); bool hasGLBufferForBuffer(Buffer *buffer); - void blitFramebuffer(Qt3DCore::QNodeId outputRenderTarget, Qt3DCore::QNodeId inputRenderTarget, + void blitFramebuffer(Qt3DCore::QNodeId outputRenderTargetId, Qt3DCore::QNodeId inputRenderTargetId, QRect inputRect, QRect outputRect, uint defaultFboId, QRenderTargetOutput::AttachmentPoint inputAttachmentPoint, @@ -268,6 +268,8 @@ private: GraphicsHelperInterface *resolveHighestOpenGLFunctions(); + GLuint createRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, const AttachmentPack &attachments); + GLuint updateRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, const AttachmentPack &attachments, bool isActiveRenderTarget); void bindFrameBufferAttachmentHelper(GLuint fboId, const AttachmentPack &attachments); void activateDrawBuffers(const AttachmentPack &attachments); HGLBuffer createGLBufferFor(Buffer *buffer, GLBuffer::Type type); @@ -291,6 +293,7 @@ private: QHash<Qt3DCore::QNodeId, GLuint> m_renderTargets; QHash<GLuint, QSize> m_renderTargetsSize; QAbstractTexture::TextureFormat m_renderTargetFormat; + QSize m_surfaceSize; QHash<QSurface *, GraphicsHelperInterface*> m_glHelpers; diff --git a/src/render/jobs/filterlayerentityjob.cpp b/src/render/jobs/filterlayerentityjob.cpp index 902338be7..f727e0820 100644 --- a/src/render/jobs/filterlayerentityjob.cpp +++ b/src/render/jobs/filterlayerentityjob.cpp @@ -113,6 +113,9 @@ void FilterLayerEntityJob::run() } else { // No LayerFilter set -> retrieve all selectAllEntities(); } + + // sort needed for set_intersection in RenderViewBuilder + std::sort(m_filteredEntities.begin(), m_filteredEntities.end()); } // We accept the entity if it contains any of the layers that are in the layer filter diff --git a/src/render/jobs/filterproximitydistancejob.cpp b/src/render/jobs/filterproximitydistancejob.cpp index b07997336..5067eeba2 100644 --- a/src/render/jobs/filterproximitydistancejob.cpp +++ b/src/render/jobs/filterproximitydistancejob.cpp @@ -82,6 +82,9 @@ void FilterProximityDistanceJob::run() } m_filteredEntities = std::move(entitiesToFilter); } + + // sort needed for set_intersection in RenderViewBuilder + std::sort(m_filteredEntities.begin(), m_filteredEntities.end()); } void FilterProximityDistanceJob::selectAllEntities() diff --git a/src/render/jobs/frustumcullingjob.cpp b/src/render/jobs/frustumcullingjob.cpp index 13ba2b438..85c6b5cad 100644 --- a/src/render/jobs/frustumcullingjob.cpp +++ b/src/render/jobs/frustumcullingjob.cpp @@ -76,6 +76,9 @@ void FrustumCullingJob::run() }; cullScene(m_root, planes); + + // sort needed for set_intersection in RenderViewBuilder + std::sort(m_visibleEntities.begin(), m_visibleEntities.end()); } void FrustumCullingJob::cullScene(Entity *e, const Plane *planes) diff --git a/src/render/jobs/renderviewjobutils.cpp b/src/render/jobs/renderviewjobutils.cpp index 6a6f62916..ffad387c6 100644 --- a/src/render/jobs/renderviewjobutils.cpp +++ b/src/render/jobs/renderviewjobutils.cpp @@ -145,7 +145,7 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN RenderTarget *renderTarget = manager->renderTargetManager()->data(renderTargetHandle); if (renderTarget) - rv->setAttachmentPack(AttachmentPack(targetSelector, renderTarget, manager->attachmentManager())); + rv->setAttachmentPack(AttachmentPack(renderTarget, manager->attachmentManager(), targetSelector->outputs())); } break; } diff --git a/src/render/materialsystem/qshaderprogram.cpp b/src/render/materialsystem/qshaderprogram.cpp index e6f9631d0..0ca8a9947 100644 --- a/src/render/materialsystem/qshaderprogram.cpp +++ b/src/render/materialsystem/qshaderprogram.cpp @@ -54,6 +54,127 @@ \since 5.5 A shader program consists of several different shaders, such as vertex and fragment shaders. + + Qt3D will automatically populate a set of default uniforms if they are + encountered during the shader instrospection phase. + + \table + \header + \li {1, 1} Default Uniform + \li {2, 1} Associated Qt3D Parameter name + \li {3, 1} GLSL declaration + + \row + \li {1, 1} ModelMatrix + \li {2, 1} modelMatrix + \li {3, 1} uniform mat4 modelMatrix; + + \row + \li {1, 1} ViewMatrix + \li {2, 1} viewMatrix + \li {3, 1} uniform mat4 viewMatrix; + + \row + \li {1, 1} ProjectionMatrix + \li {2, 1} projectionMatrix + \li {3, 1} uniform mat4 projectionMatrix; + + \row + \li {1, 1} ModelViewMatrix + \li {2, 1} modelView + \li {3, 1} uniform mat4 modelView; + + \row + \li {1, 1} ViewProjectionMatrix + \li {2, 1} viewProjectionMatrix + \li {3, 1} uniform mat4 viewProjectionMatrix; + + \row + \li {1, 1} ModelViewProjectionMatrix + \li {2, 1} modelViewProjection \br mvp + \li {3, 1} uniform mat4 modelViewProjection; \br uniform mat4 mvp; + + \row + \li {1, 1} InverseModelMatrix + \li {2, 1} inverseModelMatrix + \li {3, 1} uniform mat4 inverseModelMatrix; + + \row + \li {1, 1} InverseViewMatrix + \li {2, 1} inverseViewMatrix + \li {3, 1} uniform mat4 inverseViewMatrix; + + \row + \li {1, 1} InverseProjectionMatrix + \li {2, 1} inverseProjectionMatrix + \li {3, 1} uniform mat4 inverseProjectionMatrix; + + \row + \li {1, 1} InverseModelViewMatrix + \li {2, 1} inverseModelView + \li {3, 1} uniform mat4 inverseModelView; + + \row + \li {1, 1} InverseViewProjectionMatrix + \li {2, 1} inverseViewProjectionMatrix + \li {3, 1} uniform mat4 inverseViewProjectionMatrix; + + \row + \li {1, 1} InverseModelViewProjectionMatrix + \li {2, 1} inverseModelViewProjection + \li {3, 1} uniform mat4 inverseModelViewProjection; + + \row + \li {1, 1} ModelNormalMatrix + \li {2, 1} modelNormalMatrix + \li {3, 1} uniform mat3 modelNormalMatrix; + + \row + \li {1, 1} ModelViewNormalMatrix + \li {2, 1} modelViewNormal + \li {3, 1} uniform mat3 modelViewNormal; + + \row + \li {1, 1} ViewportMatrix + \li {2, 1} viewportMatrix + \li {3, 1} uniform mat4 viewportMatrix; + + \row + \li {1, 1} InverseViewportMatrix + \li {2, 1} inverseViewportMatrix + \li {3, 1} uniform mat4 inverseViewportMatrix; + + \row + \li {1, 1} AspectRatio \br (surface width / surface height) + \li {2, 1} aspectRatio + \li {3, 1} uniform float aspectRatio; + + \row + \li {1, 1} Exposure + \li {2, 1} exposure + \li {3, 1} uniform float exposure; + + \row + \li {1, 1} Gamma + \li {2, 1} gamma + \li {3, 1} uniform float gamma; + + \row + \li {1, 1} Time \br (in nano seconds) + \li {2, 1} time + \li {3, 1} uniform float time; + + \row + \li {1, 1} EyePosition + \li {2, 1} eyePosition + \li {3, 1} uniform vec3 eyePosition; + + \row + \li {1, 1} SkinningPalette + \li {2, 1} skinningPalette[0] + \li {3, 1} const int maxJoints = 100; \br uniform mat4 skinningPalette[maxJoints]; + + \endtable */ /*! @@ -65,6 +186,127 @@ ShaderProgram class encapsulates a shader program. A shader program consists of several different shaders, such as vertex and fragment shaders. + + Qt3D will automatically populate a set of default uniforms if they are + encountered during the shader instrospection phase. + + \table + \header + \li {1, 1} Default Uniform + \li {2, 1} Associated Qt3D Parameter name + \li {3, 1} GLSL declaration + + \row + \li {1, 1} ModelMatrix + \li {2, 1} modelMatrix + \li {3, 1} uniform mat4 modelMatrix; + + \row + \li {1, 1} ViewMatrix + \li {2, 1} viewMatrix + \li {3, 1} uniform mat4 viewMatrix; + + \row + \li {1, 1} ProjectionMatrix + \li {2, 1} projectionMatrix + \li {3, 1} uniform mat4 projectionMatrix; + + \row + \li {1, 1} ModelViewMatrix + \li {2, 1} modelView + \li {3, 1} uniform mat4 modelView; + + \row + \li {1, 1} ViewProjectionMatrix + \li {2, 1} viewProjectionMatrix + \li {3, 1} uniform mat4 viewProjectionMatrix; + + \row + \li {1, 1} ModelViewProjectionMatrix + \li {2, 1} modelViewProjection \br mvp + \li {3, 1} uniform mat4 modelViewProjection; \br uniform mat4 mvp; + + \row + \li {1, 1} InverseModelMatrix + \li {2, 1} inverseModelMatrix + \li {3, 1} uniform mat4 inverseModelMatrix; + + \row + \li {1, 1} InverseViewMatrix + \li {2, 1} inverseViewMatrix + \li {3, 1} uniform mat4 inverseViewMatrix; + + \row + \li {1, 1} InverseProjectionMatrix + \li {2, 1} inverseProjectionMatrix + \li {3, 1} uniform mat4 inverseProjectionMatrix; + + \row + \li {1, 1} InverseModelViewMatrix + \li {2, 1} inverseModelView + \li {3, 1} uniform mat4 inverseModelView; + + \row + \li {1, 1} InverseViewProjectionMatrix + \li {2, 1} inverseViewProjectionMatrix + \li {3, 1} uniform mat4 inverseViewProjectionMatrix; + + \row + \li {1, 1} InverseModelViewProjectionMatrix + \li {2, 1} inverseModelViewProjection + \li {3, 1} uniform mat4 inverseModelViewProjection; + + \row + \li {1, 1} ModelNormalMatrix + \li {2, 1} modelNormalMatrix + \li {3, 1} uniform mat3 modelNormalMatrix; + + \row + \li {1, 1} ModelViewNormalMatrix + \li {2, 1} modelViewNormal + \li {3, 1} uniform mat3 modelViewNormal; + + \row + \li {1, 1} ViewportMatrix + \li {2, 1} viewportMatrix + \li {3, 1} uniform mat4 viewportMatrix; + + \row + \li {1, 1} InverseViewportMatrix + \li {2, 1} inverseViewportMatrix + \li {3, 1} uniform mat4 inverseViewportMatrix; + + \row + \li {1, 1} AspectRatio \br (surface width / surface height) + \li {2, 1} aspectRatio + \li {3, 1} uniform float aspectRatio; + + \row + \li {1, 1} Exposure + \li {2, 1} exposure + \li {3, 1} uniform float exposure; + + \row + \li {1, 1} Gamma + \li {2, 1} gamma + \li {3, 1} uniform float gamma; + + \row + \li {1, 1} Time \br (in nano seconds) + \li {2, 1} time + \li {3, 1} uniform float time; + + \row + \li {1, 1} EyePosition + \li {2, 1} eyePosition + \li {3, 1} uniform vec3 eyePosition; + + \row + \li {1, 1} SkinningPalette + \li {2, 1} skinningPalette[0] + \li {3, 1} const int maxJoints = 100; \br uniform mat4 skinningPalette[maxJoints]; + + \endtable */ /*! diff --git a/src/render/materialsystem/shaderbuilder.cpp b/src/render/materialsystem/shaderbuilder.cpp index c2b32ce86..da1e6a713 100644 --- a/src/render/materialsystem/shaderbuilder.cpp +++ b/src/render/materialsystem/shaderbuilder.cpp @@ -51,6 +51,13 @@ #include <QFileInfo> #include <QUrl> +static void initResources() +{ +#ifdef QT_STATIC + Q_INIT_RESOURCE(materialsystem); +#endif +} + QT_BEGIN_NAMESPACE class GlobalShaderPrototypes @@ -58,6 +65,7 @@ class GlobalShaderPrototypes public: GlobalShaderPrototypes() { + initResources(); setPrototypesFile(QStringLiteral(":/prototypes/default.json")); } diff --git a/src/render/texture/gltexture.cpp b/src/render/texture/gltexture.cpp index 11cc1544f..4665be561 100644 --- a/src/render/texture/gltexture.cpp +++ b/src/render/texture/gltexture.cpp @@ -175,7 +175,8 @@ QOpenGLTexture* GLTexture::getOrCreateGLTexture() setDirtyFlag(Properties, true); } } else { - qWarning() << "[Qt3DRender::GLTexture] No QTextureImageData generated from functor yet, texture will be invalid for this frame"; + // No QTextureImageData generated from functor yet, texture will be invalid for this frame + // but will be correctly loaded at frame n+1 texturedDataInvalid = true; } } |