aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@theqtcompany.com>2016-04-13 12:33:00 +0200
committerLaszlo Agocs <laszlo.agocs@theqtcompany.com>2016-04-20 13:22:19 +0000
commit28f8795d716035516f03542cd55275375462fdc5 (patch)
treedd8afa6ae6b86e8867ca0af7543e3fd6ba24f942 /src
parent40f1aa2d06e8217abb36f29d2a5a9189beab0826 (diff)
Make rendernode suitable for public consumption
For non-OpenGL APIs the primary (and likely the only) way to add custom rendering into the Qt Quick scene is via the render node. Other approaches,like the before/afterRendering signals, QQuickFramebufferObject, remain OpenGL-only. (although QQuickFramebufferObject may get a multi-API replacement based on QSGRenderNode at a later time) Note that this is not a generic 3D content integration enabler. It targets creating 2D and 2.5D Quick items with custom rendering via the graphics API in use. Make QSGRenderNode public, enhance the docs a bit and add a releaseResources(). Add a QSGRendererInterface with a query function in QQuickWindow and QSGEngine. The scenegraph adaptation can then return a custom implementation of the interface. This will be necessary to query API-specific values, f.ex. the ID3D12Device and ID3D12CommandList when running with the d3d12 backend. The interface allows querying the API and void* resources. Resources that we know about in advance are enum-based to prevent the QPlatformNativeInterface-like ugliness of string keys. Support is there in the batch renderer already, fix this up according to the new public API, and implement the corresponding bits for the D3D12 renderer. For D3D12, fix also an issue with QSGNode destruction where graphics resources in use were attempted to be final-released without a proper wait. The semantics of changedStates() in QSGRenderNode is changed so that it can be called at any time, including before render(). This is very useful since we can implement some state restoring in a more efficient manner. Added a new example as well. Documentation for QSGRenderNode is heavily expanded. Change-Id: I4c4a261c55791d0e38743a784bc4c05a53b3462d Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12context.cpp10
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12context_p.h1
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp58
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h9
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12engine_p_p.h4
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp19
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h3
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12renderer.cpp94
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12renderer_p.h13
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp6
-rw-r--r--src/quick/items/qquickwindow.cpp16
-rw-r--r--src/quick/items/qquickwindow.h3
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp11
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h6
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp55
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h3
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.h2
-rw-r--r--src/quick/scenegraph/coreapi/qsgnodeupdater.cpp7
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendererinterface.cpp119
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendererinterface.h75
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendernode.cpp235
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendernode.h94
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendernode_p.h51
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp7
-rw-r--r--src/quick/scenegraph/qsgcontext_p.h3
-rw-r--r--src/quick/scenegraph/qsgdefaultcontext.cpp11
-rw-r--r--src/quick/scenegraph/qsgdefaultcontext_p.h6
-rw-r--r--src/quick/scenegraph/scenegraph.pri5
-rw-r--r--src/quick/scenegraph/util/qsgengine.cpp16
-rw-r--r--src/quick/scenegraph/util/qsgengine.h2
30 files changed, 824 insertions, 120 deletions
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp
index 0bb342226b..d43dcd5997 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp
@@ -97,4 +97,14 @@ QSurfaceFormat QSGD3D12Context::defaultSurfaceFormat() const
return QSurfaceFormat::defaultFormat();
}
+QSGRendererInterface *QSGD3D12Context::rendererInterface(QSGRenderContext *renderContext)
+{
+ QSGD3D12RenderContext *rc = static_cast<QSGD3D12RenderContext *>(renderContext);
+ if (!rc->engine()) {
+ qWarning("No D3D12 engine available yet (no render thread due to window not exposed?)");
+ return nullptr;
+ }
+ return rc->engine();
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h
index 2afe22e3af..c597ed90dd 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h
@@ -69,6 +69,7 @@ public:
QSGLayer *createLayer(QSGRenderContext *rc) override;
QSize minimumFBOSize() const override;
QSurfaceFormat defaultSurfaceFormat() const override;
+ QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp
index afeeea760c..cbdf54a9ea 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp
@@ -360,6 +360,16 @@ void QSGD3D12Engine::endLayer()
d->endLayer();
}
+void QSGD3D12Engine::invalidateCachedFrameState()
+{
+ d->invalidateCachedFrameState();
+}
+
+void QSGD3D12Engine::restoreFrameState(bool minimal)
+{
+ d->restoreFrameState(minimal);
+}
+
void QSGD3D12Engine::finalizePipeline(const QSGD3D12PipelineState &pipelineState)
{
d->finalizePipeline(pipelineState);
@@ -495,6 +505,16 @@ void QSGD3D12Engine::activateRenderTargetAsTexture(uint id)
d->activateRenderTargetAsTexture(id);
}
+QSGRendererInterface::GraphicsAPI QSGD3D12Engine::graphicsAPI() const
+{
+ return Direct3D12;
+}
+
+void *QSGD3D12Engine::getResource(Resource resource) const
+{
+ return d->getResource(resource);
+}
+
static inline quint32 alignedSize(quint32 size, quint32 byteAlign)
{
return (size + byteAlign - 1) & ~(byteAlign - 1);
@@ -1296,7 +1316,11 @@ void QSGD3D12EnginePrivate::beginDrawCalls()
{
frameCommandList->Reset(frameCommandAllocator[frameIndex % frameInFlightCount].Get(), nullptr);
commandList = frameCommandList.Get();
+ invalidateCachedFrameState();
+}
+void QSGD3D12EnginePrivate::invalidateCachedFrameState()
+{
tframeData.drawingMode = QSGGeometry::DrawingMode(-1);
tframeData.currentIndexBuffer = 0;
tframeData.drawCount = 0;
@@ -1305,6 +1329,18 @@ void QSGD3D12EnginePrivate::beginDrawCalls()
tframeData.descHeapSet = false;
}
+void QSGD3D12EnginePrivate::restoreFrameState(bool minimal)
+{
+ queueSetRenderTarget(currentRenderTarget);
+ if (!minimal) {
+ queueViewport(tframeData.viewport);
+ queueScissor(tframeData.scissor);
+ queueSetBlendFactor(tframeData.blendFactor);
+ queueSetStencilRef(tframeData.stencilRef);
+ }
+ finalizePipeline(tframeData.pipelineState);
+}
+
void QSGD3D12EnginePrivate::beginFrameDraw()
{
if (windowSamples == 1)
@@ -1886,12 +1922,7 @@ void QSGD3D12EnginePrivate::queueDraw(const QSGD3D12Engine::DrawParams &params)
// start a new one
beginDrawCalls();
// prepare for the upcoming drawcalls
- queueSetRenderTarget(currentRenderTarget);
- queueViewport(tframeData.viewport);
- queueScissor(tframeData.scissor);
- queueSetBlendFactor(tframeData.blendFactor);
- queueSetStencilRef(tframeData.stencilRef);
- finalizePipeline(tframeData.pipelineState);
+ restoreFrameState();
}
}
@@ -2737,4 +2768,19 @@ void QSGD3D12EnginePrivate::activateRenderTargetAsTexture(uint id)
tframeData.activeTextures.append(TransientFrameData::ActiveTexture::ActiveTexture(TransientFrameData::ActiveTexture::TypeRenderTarget, id));
}
+void *QSGD3D12EnginePrivate::getResource(QSGRendererInterface::Resource resource) const
+{
+ switch (resource) {
+ case QSGRendererInterface::Device:
+ return device;
+ case QSGRendererInterface::CommandQueue:
+ return commandQueue.Get();
+ case QSGRendererInterface::CommandList:
+ return commandList;
+ default:
+ break;
+ }
+ return nullptr;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h
index 84bb5a554e..3b7dd7cdc6 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h
@@ -55,6 +55,7 @@
#include <QImage>
#include <QVector4D>
#include <qsggeometry.h>
+#include <qsgrendererinterface.h>
#include <qt_windows.h>
QT_BEGIN_NAMESPACE
@@ -260,7 +261,7 @@ inline uint qHash(const QSGD3D12PipelineState &key, uint seed = 0)
+ key.topologyType;
}
-class QSGD3D12Engine
+class QSGD3D12Engine : public QSGRendererInterface
{
public:
QSGD3D12Engine();
@@ -278,6 +279,8 @@ public:
void endFrame();
void beginLayer();
void endLayer();
+ void invalidateCachedFrameState();
+ void restoreFrameState(bool minimal = false);
uint genBuffer();
void releaseBuffer(uint id);
@@ -344,6 +347,10 @@ public:
void releaseRenderTarget(uint id);
void activateRenderTargetAsTexture(uint id);
+ // QSGRendererInterface
+ GraphicsAPI graphicsAPI() const override;
+ void *getResource(Resource resource) const override;
+
private:
QSGD3D12EnginePrivate *d;
Q_DISABLE_COPY(QSGD3D12Engine)
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p_p.h
index 40d1fdb510..047036b52a 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p_p.h
@@ -142,6 +142,8 @@ public:
void endFrame();
void beginLayer();
void endLayer();
+ void invalidateCachedFrameState();
+ void restoreFrameState(bool minimal = false);
uint genBuffer();
void releaseBuffer(uint id);
@@ -176,6 +178,8 @@ public:
void releaseRenderTarget(uint id);
void activateRenderTargetAsTexture(uint id);
+ void *getResource(QSGRendererInterface::Resource resource) const;
+
// the device is intentionally hidden here. all resources have to go
// through the engine and, unlike with GL, cannot just be created in random
// places due to the need for proper tracking, managing and releasing.
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp
index af3e8e36ee..ab590b95c5 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp
@@ -56,6 +56,14 @@ QSGD3D12RenderContext::QSGD3D12RenderContext(QSGContext *ctx)
{
}
+bool QSGD3D12RenderContext::isValid() const
+{
+ // The render thread sets an engine when it starts up and resets when it
+ // quits. The rc is initialized and functional between those two points,
+ // regardless of any calls to invalidate(). See setEngine().
+ return m_engine != nullptr;
+}
+
void QSGD3D12RenderContext::invalidate()
{
if (Q_UNLIKELY(debug_render()))
@@ -98,4 +106,15 @@ void QSGD3D12RenderContext::renderNextFrame(QSGRenderer *renderer, uint fbo)
static_cast<QSGD3D12Renderer *>(renderer)->renderScene(fbo);
}
+void QSGD3D12RenderContext::setEngine(QSGD3D12Engine *engine)
+{
+ if (m_engine == engine)
+ return;
+
+ m_engine = engine;
+
+ if (m_engine)
+ emit initialized();
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h
index 1acb7e4205..e2cd6e3182 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h
@@ -61,12 +61,13 @@ class QSGD3D12RenderContext : public QSGRenderContext
{
public:
QSGD3D12RenderContext(QSGContext *ctx);
+ bool isValid() const override;
void invalidate() override;
void renderNextFrame(QSGRenderer *renderer, uint fbo) override;
QSGTexture *createTexture(const QImage &image, uint flags) const override;
QSGRenderer *createRenderer() override;
- void setEngine(QSGD3D12Engine *engine) { m_engine = engine; }
+ void setEngine(QSGD3D12Engine *engine);
QSGD3D12Engine *engine() { return m_engine; }
private:
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12renderer.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12renderer.cpp
index 7f8b10f003..f76927c0bd 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12renderer.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12renderer.cpp
@@ -40,6 +40,7 @@
#include "qsgd3d12renderer_p.h"
#include "qsgd3d12rendercontext_p.h"
#include <private/qsgnodeupdater_p.h>
+#include <private/qsgrendernode_p.h>
#include "vs_stencilclip.hlslh"
#include "ps_stencilclip.hlslh"
@@ -206,6 +207,11 @@ void QSGD3D12Renderer::buildRenderList(QSGNode *node, QSGClipNode *clip)
gn->setClipList(clip);
if (node->type() == QSGNode::ClipNodeType)
clip = static_cast<QSGClipNode *>(node);
+ } else if (node->type() == QSGNode::RenderNodeType) {
+ QSGRenderNode *rn = static_cast<QSGRenderNode *>(node);
+ Element e;
+ e.node = rn;
+ m_renderList.add(e);
}
QSGNODE_TRAVERSE(node)
@@ -316,6 +322,7 @@ void QSGD3D12Renderer::render()
if (gn->inheritedOpacity() > 0.999f && ((gn->activeMaterial()->flags() & QSGMaterial::Blending) == 0))
m_opaqueElements.setBit(i);
}
+ // QSGRenderNodes are always treated as non-opaque
}
}
@@ -432,15 +439,36 @@ void QSGD3D12Renderer::renderElements()
// ...then the alpha ones
for (int i = 0; i < m_renderList.size(); ++i) {
- if (m_renderList.at(i).node->type() == QSGNode::GeometryNodeType && !m_opaqueElements.testBit(i))
+ if ((m_renderList.at(i).node->type() == QSGNode::GeometryNodeType && !m_opaqueElements.testBit(i))
+ || m_renderList.at(i).node->type() == QSGNode::RenderNodeType)
renderElement(i);
}
}
+struct RenderNodeState : public QSGRenderNode::RenderState
+{
+ const QMatrix4x4 *projectionMatrix() const override { return m_projectionMatrix; }
+ QRect scissorRect() const { return m_scissorRect; }
+ bool scissorEnabled() const { return m_scissorEnabled; }
+ int stencilValue() const { return m_stencilValue; }
+ bool stencilEnabled() const { return m_stencilEnabled; }
+
+ const QMatrix4x4 *m_projectionMatrix;
+ QRect m_scissorRect;
+ bool m_scissorEnabled;
+ int m_stencilValue;
+ bool m_stencilEnabled;
+};
+
void QSGD3D12Renderer::renderElement(int elementIndex)
{
Element &e = m_renderList.at(elementIndex);
- Q_ASSERT(e.node->type() == QSGNode::GeometryNodeType);
+ Q_ASSERT(e.node->type() == QSGNode::GeometryNodeType || e.node->type() == QSGNode::RenderNodeType);
+
+ if (e.node->type() == QSGNode::RenderNodeType) {
+ renderRenderNode(static_cast<QSGRenderNode *>(e.node), elementIndex);
+ return;
+ }
if (e.vboOffset < 0)
return;
@@ -508,7 +536,7 @@ void QSGD3D12Renderer::renderElement(int elementIndex)
m_lastMaterialType = m->type();
- setupClipping(gn, elementIndex);
+ setupClipping(gn->clipList(), elementIndex);
// ### Lines and points with sizes other than 1 have to be implemented in some other way. Just ignore for now.
if (g->drawingMode() == QSGGeometry::DrawLineStrip || g->drawingMode() == QSGGeometry::DrawLines) {
@@ -575,16 +603,10 @@ void QSGD3D12Renderer::queueDrawCall(const QSGGeometry *g, const QSGD3D12Rendere
m_engine->queueDraw(dp);
}
-void QSGD3D12Renderer::setupClipping(const QSGGeometryNode *gn, int elementIndex)
+void QSGD3D12Renderer::setupClipping(const QSGClipNode *clip, int elementIndex)
{
- const QSGClipNode *clip = gn->clipList();
-
const QRect devRect = deviceRect();
QRect scissorRect;
- enum ClipType {
- ClipScissor = 0x1,
- ClipStencil = 0x2
- };
int clipTypes = 0;
quint32 stencilValue = 0;
@@ -647,9 +669,13 @@ void QSGD3D12Renderer::setupClipping(const QSGGeometryNode *gn, int elementIndex
if (clipTypes & ClipStencil) {
m_pipelineState.stencilEnable = true;
m_engine->queueSetStencilRef(stencilValue);
+ m_currentStencilValue = stencilValue;
} else {
m_pipelineState.stencilEnable = false;
+ m_currentStencilValue = 0;
}
+
+ m_currentClipTypes = clipTypes;
}
void QSGD3D12Renderer::setScissor(const QRect &r)
@@ -707,4 +733,52 @@ void QSGD3D12Renderer::renderStencilClip(const QSGClipNode *clip, int elementInd
++stencilValue;
}
+void QSGD3D12Renderer::renderRenderNode(QSGRenderNode *node, int elementIndex)
+{
+ QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(node);
+ RenderNodeState state;
+
+ setupClipping(rd->m_clip_list, elementIndex);
+
+ QMatrix4x4 pm = projectionMatrix();
+ state.m_projectionMatrix = &pm;
+ state.m_scissorEnabled = m_currentClipTypes & ClipScissor;
+ state.m_stencilEnabled = m_currentClipTypes & ClipStencil;
+ state.m_scissorRect = m_activeScissorRect;
+ state.m_stencilValue = m_currentStencilValue;
+
+ // ### rendernodes do not have the QSGBasicGeometryNode infrastructure
+ // for storing combined matrices, opacity and such, but perhaps they should.
+ QSGNode *xform = node->parent();
+ QSGNode *root = rootNode();
+ QMatrix4x4 modelview;
+ while (xform != root) {
+ if (xform->type() == QSGNode::TransformNodeType) {
+ modelview *= static_cast<QSGTransformNode *>(xform)->combinedMatrix();
+ break;
+ }
+ xform = xform->parent();
+ }
+ rd->m_matrix = &modelview;
+
+ QSGNode *opacity = node->parent();
+ rd->m_opacity = 1.0;
+ while (opacity != rootNode()) {
+ if (opacity->type() == QSGNode::OpacityNodeType) {
+ rd->m_opacity = static_cast<QSGOpacityNode *>(opacity)->combinedOpacity();
+ break;
+ }
+ opacity = opacity->parent();
+ }
+
+ node->render(&state);
+
+ m_engine->invalidateCachedFrameState();
+ // For simplicity, reset viewport, scissor, blend factor, stencil ref when
+ // any of them got changed. This will likely be rare so skip these otherwise.
+ // Render target, pipeline state, draw call related stuff will be reset always.
+ const bool restoreMinimal = node->changedStates() == 0;
+ m_engine->restoreFrameState(restoreMinimal);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12renderer_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12renderer_p.h
index 0877c3699a..bed34df3a1 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12renderer_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12renderer_p.h
@@ -59,6 +59,8 @@
QT_BEGIN_NAMESPACE
+class QSGRenderNode;
+
class QSGD3D12Renderer : public QSGRenderer
{
public:
@@ -78,12 +80,13 @@ private:
void renderElements();
void renderElement(int elementIndex);
void setInputLayout(const QSGGeometry *g, QSGD3D12PipelineState *pipelineState);
- void setupClipping(const QSGGeometryNode *gn, int elementIndex);
+ void setupClipping(const QSGClipNode *clip, int elementIndex);
void setScissor(const QRect &r);
void renderStencilClip(const QSGClipNode *clip, int elementIndex, const QMatrix4x4 &m, quint32 &stencilValue);
+ void renderRenderNode(QSGRenderNode *node, int elementIndex);
struct Element {
- QSGBasicGeometryNode *node = nullptr;
+ QSGNode *node = nullptr;
qint32 vboOffset = -1;
qint32 iboOffset = -1;
quint32 iboStride = 0;
@@ -121,6 +124,12 @@ private:
bool m_projectionChangedDueToDeviceSize;
uint m_renderTarget = 0;
+ quint32 m_currentStencilValue;
+ enum ClipType {
+ ClipScissor = 0x1,
+ ClipStencil = 0x2
+ };
+ int m_currentClipTypes;
};
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp
index 94bdf38819..2c05ce01c6 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp
@@ -331,8 +331,12 @@ bool QSGD3D12RenderThread::event(QEvent *e)
qDebug("RT - WM_TryRelease - invalidating rc");
if (wme->window) {
QQuickWindowPrivate *wd = QQuickWindowPrivate::get(wme->window);
- if (wme->destroying)
+ if (wme->destroying) {
+ // QSGNode destruction may release graphics resources in use so wait first.
+ engine->waitGPU();
+ // Bye bye nodes...
wd->cleanupNodesOnShutdown();
+ }
rc->invalidate();
QCoreApplication::processEvents();
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index a932e7a508..2642daf19f 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -4345,6 +4345,22 @@ qreal QQuickWindow::effectiveDevicePixelRatio() const
return w ? w->devicePixelRatio() : devicePixelRatio();
}
+/*!
+ Returns the current renderer interface if there is one. Otherwise null is returned.
+
+ \sa QSGRenderNode, QSGRendererInterface
+ \since 5.8
+ */
+QSGRendererInterface *QQuickWindow::rendererInterface() const
+{
+ Q_D(const QQuickWindow);
+ if (!isSceneGraphInitialized()) {
+ qWarning("The QSGRendererInterface cannot be queried before the scenegraph is initialized");
+ return nullptr;
+ }
+ return d->context->sceneGraphContext()->rendererInterface(d->context);
+}
+
#include "moc_qquickwindow.cpp"
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index a4060541c0..977b4956b2 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -60,6 +60,7 @@ class QQmlIncubationController;
class QInputMethodEvent;
class QQuickCloseEvent;
class QQuickRenderControl;
+class QSGRendererInterface;
class Q_QUICK_EXPORT QQuickWindow : public QWindow
{
@@ -153,6 +154,8 @@ public:
qreal effectiveDevicePixelRatio() const;
+ QSGRendererInterface *rendererInterface() const;
+
Q_SIGNALS:
void frameSwapped();
Q_REVISION(2) void openglContextCreated(QOpenGLContext *context);
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp
index 04fc6da84e..2ed1da46f4 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp
@@ -169,4 +169,15 @@ void QSGSoftwareRenderContext::renderNextFrame(QSGRenderer *renderer, uint fbo)
renderer->renderScene(fbo);
}
+QSGRendererInterface *QSGSoftwareContext::rendererInterface(QSGRenderContext *renderContext)
+{
+ Q_UNUSED(renderContext);
+ return this;
+}
+
+QSGRendererInterface::GraphicsAPI QSGSoftwareContext::graphicsAPI() const
+{
+ return Software;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h
index 086278b2f1..8f9daceb7e 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h
@@ -53,6 +53,7 @@
#include <private/qsgcontext_p.h>
#include <private/qsgadaptationlayer_p.h>
+#include "qsgrendererinterface.h"
Q_DECLARE_LOGGING_CATEGORY(QSG_RASTER_LOG_TIME_RENDERLOOP)
Q_DECLARE_LOGGING_CATEGORY(QSG_RASTER_LOG_TIME_COMPILATION)
@@ -79,7 +80,7 @@ public:
bool m_initialized;
};
-class QSGSoftwareContext : public QSGContext
+class QSGSoftwareContext : public QSGContext, public QSGRendererInterface
{
Q_OBJECT
public:
@@ -93,6 +94,9 @@ public:
QSGNinePatchNode *createNinePatchNode() override;
QSGLayer *createLayer(QSGRenderContext *renderContext) override;
QSurfaceFormat defaultSurfaceFormat() const override;
+ QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override;
+
+ GraphicsAPI graphicsAPI() const override;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index a89dbc0ea2..f277475dbf 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -2763,6 +2763,21 @@ void Renderer::render()
m_vao->release();
}
+struct RenderNodeState : public QSGRenderNode::RenderState
+{
+ const QMatrix4x4 *projectionMatrix() const override { return m_projectionMatrix; }
+ QRect scissorRect() const { return m_scissorRect; }
+ bool scissorEnabled() const { return m_scissorEnabled; }
+ int stencilValue() const { return m_stencilValue; }
+ bool stencilEnabled() const { return m_stencilEnabled; }
+
+ const QMatrix4x4 *m_projectionMatrix;
+ QRect m_scissorRect;
+ bool m_scissorEnabled;
+ int m_stencilValue;
+ bool m_stencilEnabled;
+};
+
void Renderer::renderRenderNode(Batch *batch)
{
if (Q_UNLIKELY(debug_render()))
@@ -2774,24 +2789,25 @@ void Renderer::renderRenderNode(Batch *batch)
setActiveShader(0, 0);
QSGNode *clip = e->renderNode->parent();
- e->renderNode->m_clip_list = 0;
+ QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(e->renderNode);
+ rd->m_clip_list = 0;
while (clip != rootNode()) {
if (clip->type() == QSGNode::ClipNodeType) {
- e->renderNode->m_clip_list = static_cast<QSGClipNode *>(clip);
+ rd->m_clip_list = static_cast<QSGClipNode *>(clip);
break;
}
clip = clip->parent();
}
- updateClip(e->renderNode->m_clip_list, batch);
+ updateClip(rd->m_clip_list, batch);
- QSGRenderNode::RenderState state;
+ RenderNodeState state;
QMatrix4x4 pm = projectionMatrix();
- state.projectionMatrix = &pm;
- state.scissorEnabled = m_currentClipType & ScissorClip;
- state.stencilEnabled = m_currentClipType & StencilClip;
- state.scissorRect = m_currentScissorRect;
- state.stencilValue = m_currentStencilValue;
+ state.m_projectionMatrix = &pm;
+ state.m_scissorEnabled = m_currentClipType & ScissorClip;
+ state.m_stencilEnabled = m_currentClipType & StencilClip;
+ state.m_scissorRect = m_currentScissorRect;
+ state.m_stencilValue = m_currentStencilValue;
QSGNode *xform = e->renderNode->parent();
QMatrix4x4 matrix;
@@ -2807,13 +2823,13 @@ void Renderer::renderRenderNode(Batch *batch)
}
xform = xform->parent();
}
- e->renderNode->m_matrix = &matrix;
+ rd->m_matrix = &matrix;
QSGNode *opacity = e->renderNode->parent();
- e->renderNode->m_opacity = 1.0;
+ rd->m_opacity = 1.0;
while (opacity != rootNode()) {
if (opacity->type() == QSGNode::OpacityNodeType) {
- e->renderNode->m_opacity = static_cast<QSGOpacityNode *>(opacity)->combinedOpacity();
+ rd->m_opacity = static_cast<QSGOpacityNode *>(opacity)->combinedOpacity();
break;
}
opacity = opacity->parent();
@@ -2825,12 +2841,17 @@ void Renderer::renderRenderNode(Batch *batch)
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- e->renderNode->render(state);
+ QSGRenderNode::StateFlags changes = e->renderNode->changedStates();
+
+ GLuint prevFbo = 0;
+ if (changes & QSGRenderNode::RenderTargetState)
+ glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);
- e->renderNode->m_matrix = 0;
- e->renderNode->m_clip_list = 0;
+ e->renderNode->render(&state);
+
+ rd->m_matrix = 0;
+ rd->m_clip_list = 0;
- QSGRenderNode::StateFlags changes = e->renderNode->changedStates();
if (changes & QSGRenderNode::ViewportState) {
QRect r = viewportRect();
glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height());
@@ -2864,6 +2885,8 @@ void Renderer::renderRenderNode(Batch *batch)
glDisable(GL_CULL_FACE);
}
+ if (changes & QSGRenderNode::RenderTargetState)
+ glBindFramebuffer(GL_FRAMEBUFFER, prevFbo);
}
class VisualizeShader : public QOpenGLShaderProgram
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index a84ac6d177..c56f15d655 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -56,9 +56,8 @@
#include <private/qsgrenderer_p.h>
#include <private/qsgdefaultrendercontext_p.h>
#include <private/qsgnodeupdater_p.h>
-#include <private/qdatabuffer_p.h>
-
#include <private/qsgrendernode_p.h>
+#include <private/qdatabuffer_p.h>
#include <QtCore/QBitArray>
diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h
index 349753a361..627fe6e27f 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.h
+++ b/src/quick/scenegraph/coreapi/qsgnode.h
@@ -79,8 +79,8 @@ public:
OpacityNodeType,
#ifndef qdoc
RootNodeType,
- RenderNodeType
#endif
+ RenderNodeType
};
enum Flag {
diff --git a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
index 372ffce9d6..d6d533307e 100644
--- a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
@@ -175,9 +175,10 @@ void QSGNodeUpdater::enterRenderNode(QSGRenderNode *r)
qDebug() << "enter render:" << r;
#endif
- r->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.last();
- r->m_clip_list = m_current_clip;
- r->setInheritedOpacity(m_opacity_stack.last());
+ QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(r);
+ rd->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.last();
+ rd->m_clip_list = m_current_clip;
+ rd->m_opacity = m_opacity_stack.last();
}
void QSGNodeUpdater::leaveRenderNode(QSGRenderNode *r)
diff --git a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp
new file mode 100644
index 0000000000..6a01fac212
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgrendererinterface.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSGRendererInterface
+ \brief An interface providing access to some of the graphics API specific internals
+ of the scenegraph.
+ \inmodule QtQuick
+ \since 5.8
+
+ Renderer interfaces allow accessing graphics API specific functionality in
+ the scenegraph. Such internals are not typically exposed. However, when
+ integrating custom rendering via QSGRenderNode for example, it may become
+ necessary to query certain values, for instance the graphics device (e.g.
+ the Direct3D or Vulkan device) that is used by the scenegraph.
+
+ \note QSGRendererInterface is only available after the scenegraph is
+ initialized. Additionally, there may be backend-specific limitations on
+ when the functions can be called. The only way that is guaranteed to
+ succeed is calling them when the rendering of a node (i.e. the preparation
+ of the command list for the next frame) is active. In practice this
+ typically means QSGRenderNode::render().
+ */
+
+/*!
+ \enum QSGRenderNode::GraphicsAPI
+ \value Unknown An unknown graphics API is in use
+ \value Software The Qt Quick 2D Renderer is in use
+ \value OpenGL OpenGL ES 2.0 or higher
+ \value Direct3D12 Direct3D 12
+ \value Vulkan Vulkan
+ \value Metal Metal
+ */
+
+/*!
+ \enum QSGRenderNode::Resource
+ \value Device The graphics device
+ \value CommandQueue The graphics command queue used by the scenergaph
+ \value CommandList The command list or buffer used by the scenegraph
+ */
+
+QSGRendererInterface::~QSGRendererInterface()
+{
+}
+
+/*!
+ \fn QSGRenderNode::GraphicsAPI QSGRenderNode::graphicsAPI() const
+
+ Returns the graphics API that is in use by the Qt Quick scenegraph.
+ */
+
+/*!
+ Queries a graphics \a resource. Returns null when the resource in question is
+ not supported or not available.
+
+ When successful, the returned pointer is either a direct pointer to an
+ interface (and can be cast, for example, to \c{ID3D12Device *}) or a
+ pointer to an opaque handle that needs to be dereferenced first (for
+ example, \c{VkDevice dev = *static_cast<VkDevice *>(result)}). The latter
+ is necessary since such handles may have sizes different from a pointer.
+ */
+void *QSGRendererInterface::getResource(Resource resource) const
+{
+ Q_UNUSED(resource);
+ return nullptr;
+}
+
+/*!
+ Queries a graphics resource. \a resource is a backend-specific key. This
+ allows supporting any future resources that are not listed in the
+ Resource enum.
+ */
+void *QSGRendererInterface::getResource(const char *resource) const
+{
+ Q_UNUSED(resource);
+ return nullptr;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsgrendererinterface.h b/src/quick/scenegraph/coreapi/qsgrendererinterface.h
new file mode 100644
index 0000000000..c4a145dd0f
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgrendererinterface.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGRENDERERINTERFACE_H
+#define QSGRENDERERINTERFACE_H
+
+#include <QtQuick/qsgnode.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_EXPORT QSGRendererInterface
+{
+public:
+ enum GraphicsAPI {
+ Unknown,
+ Software,
+ OpenGL,
+ Direct3D12,
+ Vulkan,
+ Metal
+ };
+
+ enum Resource {
+ Device,
+ CommandQueue,
+ CommandList
+ };
+
+ virtual ~QSGRendererInterface();
+
+ virtual GraphicsAPI graphicsAPI() const = 0;
+
+ virtual void *getResource(Resource resource) const;
+ virtual void *getResource(const char *resource) const;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp
index 1a38f6495e..8dc82a0d66 100644
--- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp
@@ -37,28 +37,51 @@
**
****************************************************************************/
+#include "qsgrendernode.h"
#include "qsgrendernode_p.h"
QT_BEGIN_NAMESPACE
+/*!
+ \class QSGRenderNode
+ \brief The QSGMaterialShader class represents a set of custom rendering commands
+ targeting the graphics API that is in use by the scenegraph.
+ \inmodule QtQuick
+ \since 5.8
+ */
+
QSGRenderNode::QSGRenderNode()
- : QSGNode(RenderNodeType)
- , m_matrix(0)
- , m_clip_list(0)
- , m_opacity(1)
+ : QSGNode(RenderNodeType),
+ d(new QSGRenderNodePrivate)
{
}
-void QSGRenderNode::setInheritedOpacity(qreal opacity)
+/*!
+ Destructs the render node. Derived classes are expected to perform cleanup
+ similar to releaseResources() in here.
+
+ When a low-level graphics API is in use, the scenegraph will make sure
+ there is a CPU-side wait for the GPU to complete all work submitted to the
+ scenegraph's graphics command queue before the scenegraph's nodes are
+ deleted. Therefore there is no need to issue additional waits here, unless
+ the render() implementation is using additional command queues.
+
+ \sa releaseResources()
+ */
+QSGRenderNode::~QSGRenderNode()
{
- Q_ASSERT(opacity >= 0 && opacity <= 1);
- m_opacity = opacity;
+ delete d;
}
-/*!
- \fn QSGRenderNode::StateFlags QSGRenderNode::changedStates()
+QSGRenderNodePrivate::QSGRenderNodePrivate()
+ : m_matrix(0)
+ , m_clip_list(0)
+ , m_opacity(1)
+{
+}
- This function should return a mask where each bit represents OpenGL states changed by
+/*!
+ This function should return a mask where each bit represents graphics states changed by
the \l render() function:
\list
\li DepthState - depth write mask, depth test enabled, depth comparison function
@@ -69,30 +92,72 @@ void QSGRenderNode::setInheritedOpacity(qreal opacity)
\li BlendState - blend enabled, blend function
\li CullState - front face, cull face enabled
\li ViewportState - viewport
+ \li RenderTargetState - render target
\endlist
- The function is called by the renderer so it can reset the OpenGL states after rendering this
- node.
+ The function is called by the renderer so it can reset the states after
+ rendering this node. This makes the implementation of render() simpler
+ since it does not have to query and restore these states.
- \internal
+ The default implementation returns 0, meaning no relevant state was changed
+ in render().
+
+ With APIs other than OpenGL the relevant states are only those that are set
+ via the command list (for example, OMSetRenderTargets, RSSetViewports,
+ RSSetScissorRects, OMSetBlendFactor, OMSetStencilRef in case of D3D12), and
+ only when such commands were added to the scenegraph's command list queried
+ via the QSGRendererInterface::CommandList resource enum. States set in
+ pipeline state objects do not need to be reported here. Similarly, draw
+ call related settings (root signature, descriptor heaps, etc.) are always
+ set again by the scenegraph so render() can freely change them.
+
+ \note This function may be called before render().
*/
+QSGRenderNode::StateFlags QSGRenderNode::changedStates() const
+{
+ return 0;
+}
/*!
- \fn void QSGRenderNode::render(const RenderState &state)
+ \fn void QSGRenderNode::render(const RenderState *state)
- This function is called by the renderer and should paint this node with OpenGL commands.
+ This function is called by the renderer and should paint this node with
+ directly invoking commands in the graphics API (OpenGL, Direct3D, etc.)
+ currently in use.
- The states necessary for clipping has already been set before the function is called.
- The clip is a combination of a stencil clip and scissor clip. Information about the clip is
- found in \a state.
+ The states necessary for clipping has already been set before the function
+ is called. The clip is a combination of a stencil clip and scissor clip.
+ Information about the clip is found in \a state.
+
+ \note This means that setting viewport, scissor rectangle, stencil
+ reference value, and similar is not necessary in render() since the
+ corresponding commands are on the command list (or, in case of OpenGL, the
+ context) already. However, for APIs other than OpenGL stencil-based
+ clipping will need enabling stencil testing in the pipeline state that is
+ used by render().
The effective opacity can be retrieved with \l inheritedOpacity().
- The projection matrix is available through \a state, while the model-view matrix can be
- fetched with \l matrix(). The combined matrix is then the projection matrix times the
- model-view matrix.
+ The projection matrix is available through \a state, while the model-view
+ matrix can be fetched with \l matrix(). The combined matrix is then the
+ projection matrix times the model-view matrix. The correct stacking of the
+ items in the scene is ensured by the projection matrix.
+
+ When using the provided matrices, the coordinate system for vertex data
+ follows the usual QQuickItem conventions: top-left is (0, 0), bottom-right
+ is the corresponding QQuickItem's width() and height() minus one. For
+ example, assuming a two float (x-y) per vertex coordinate layout, a
+ triangle covering half of the item can be specified as (width - 1, height - 1),
+ (0, 0), (0, height - 1) using counter-clockwise direction.
+
+ \note QSGRenderNode is provided as a means to implement custom 2D or 2.5D
+ Qt Quick items. It is not intended for integrating true 3D content into the
+ Qt Quick scene. That use case is better supported by
+ QQuickFramebufferObject, QQuickWindow::beforeRendering(), or the
+ equivalents of those for APIs other than OpenGL.
- The following states are set before this function is called:
+ For OpenGL the following states are set on the render thread's context
+ before this function is called:
\list
\li glDepthMask(false)
\li glDisable(GL_DEPTH_TEST)
@@ -107,14 +172,128 @@ void QSGRenderNode::setInheritedOpacity(qreal opacity)
\li glDisable(GL_CULL_FACE)
\endlist
- States that are not listed above, but are included in \l StateFlags, can have arbitrary
- values.
+ States that are not listed above, but are included in \l StateFlags, can
+ have arbitrary values.
- \l changedStates() should return which states this function has changed. If a state is not
- covered by \l StateFlags, the state should be set to the default value according to the
- OpenGL specification.
+ \l changedStates() should return which states this function changes. If a
+ state is not covered by \l StateFlags, the state should be set to the
+ default value according to the OpenGL specification. For other APIs, see
+ the documentation for changedStates() for more information.
- \internal
+ For APIs other than OpenGL, it will likely be necessary to query certain
+ API-specific resources (for example, the graphics device or the command
+ list/buffer to add the commands to). This is done via QSGRendererInterface.
+
+ \sa QSGRendererInterface, QQuickWindow::rendererInterface()
*/
+/*!
+ \fn void QSGRenderNode::releaseResources()
+
+ This function is called when all custom graphics resources allocated by
+ this node have to be freed immediately. In case the node does not directly
+ allocate graphics resources (buffers, textures, render targets, fences,
+ etc.) through the graphics API that is in use, there is nothing to do here.
+
+ Failing to release all custom resources can lead to incorrect behavior in
+ graphics device loss scenarios on some systems since subsequent
+ reinitialization of the graphics system may fail.
+
+ \note Some scenegraph backends may choose not to call this function.
+ Therefore it is expected that QSGRenderNode implementations perform cleanup
+ both in their destructor and in releaseResources().
+
+ Unlike with the destructor, it is expected that render() can reinitialize
+ all resources it needs when called after a call to releaseResources().
+
+ With OpenGL, the scenegraph's OpenGL context will be current both when
+ calling the destructor and this function.
+ */
+
+/*!
+ \return pointer to the current model-view matrix.
+ */
+const QMatrix4x4 *QSGRenderNode::matrix() const
+{
+ return d->m_matrix;
+}
+
+/*!
+ \return the current clip list.
+ */
+const QSGClipNode *QSGRenderNode::clipList() const
+{
+ return d->m_clip_list;
+}
+
+/*!
+ \return the current effective opacity.
+ */
+qreal QSGRenderNode::inheritedOpacity() const
+{
+ return d->m_opacity;
+}
+
+QSGRenderNode::RenderState::~RenderState()
+{
+}
+
+/*!
+ \fn const QMatrix4x4 *QSGRenderNode::RenderState::projectionMatrix() const
+
+ \return pointer to the current projection matrix.
+
+ The model-view matrix can be retrieved with QSGRenderNode::matrix().
+ Typically \c{projection * modelview} is the matrix that is then used in the
+ vertex shader to transform the vertices.
+ */
+
+/*!
+ \fn const QMatrix4x4 *QSGRenderNode::RenderState::scissorRect() const
+
+ \return the current scissor rectangle when clipping is active.
+
+ \note Be aware of the differences between graphics APIs: for some the
+ scissor rect is only active when scissoring is enabled (for example,
+ OpenGL), while for others the scissor rect is equal to the viewport rect
+ when there is no need to scissor away anything (for example, Direct3D 12).
+ */
+
+/*!
+ \fn const QMatrix4x4 *QSGRenderNode::RenderState::scissorEnabled() const
+
+ \return the current state of scissoring.
+
+ \note Only relevant for graphics APIs that have a dedicated on/off state of
+ scissoring.
+ */
+
+/*!
+ \fn const QMatrix4x4 *QSGRenderNode::RenderState::stencilValue() const
+
+ \return the current stencil reference value when clipping is active.
+ */
+
+/*!
+ \fn const QMatrix4x4 *QSGRenderNode::RenderState::stencilEnabled() const
+
+ \return the current state of stencil testing.
+
+ \note With graphics APIs where stencil testing is enabled in pipeline state
+ objects, instead of individual state-setting commands, it is up to the
+ implementation of render() to enable stencil testing with operations
+ \c KEEP, comparison function \c EQUAL, and a read and write mask of \c 0xFF.
+ */
+
+/*!
+ \return pointer to a \a state value.
+
+ Reserved for future use.
+ */
+void *QSGRenderNode::RenderState::get(const char *state) const
+{
+ Q_UNUSED(state);
+ return nullptr;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.h b/src/quick/scenegraph/coreapi/qsgrendernode.h
new file mode 100644
index 0000000000..5441b64fe4
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgrendernode.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGRENDERNODE_H
+#define QSGRENDERNODE_H
+
+#include <QtQuick/qsgnode.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGRenderNodePrivate;
+
+class Q_QUICK_EXPORT QSGRenderNode : public QSGNode
+{
+public:
+ enum StateFlag {
+ DepthState = 0x01,
+ StencilState = 0x02,
+ ScissorState = 0x04,
+ ColorState = 0x08,
+ BlendState = 0x10,
+ CullState = 0x20,
+ ViewportState = 0x40,
+ RenderTargetState = 0x80
+ };
+ Q_DECLARE_FLAGS(StateFlags, StateFlag)
+
+ struct Q_QUICK_EXPORT RenderState {
+ virtual ~RenderState();
+ virtual const QMatrix4x4 *projectionMatrix() const = 0;
+ virtual QRect scissorRect() const = 0;
+ virtual bool scissorEnabled() const = 0;
+ virtual int stencilValue() const = 0;
+ virtual bool stencilEnabled() const = 0;
+ virtual void *get(const char *state) const;
+ };
+
+ QSGRenderNode();
+ ~QSGRenderNode();
+
+ virtual StateFlags changedStates() const;
+ virtual void render(const RenderState *state) = 0;
+ virtual void releaseResources() = 0;
+
+ const QMatrix4x4 *matrix() const;
+ const QSGClipNode *clipList() const;
+ qreal inheritedOpacity() const;
+
+private:
+ QSGRenderNodePrivate *d;
+ friend class QSGRenderNodePrivate;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderNode::StateFlags)
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/scenegraph/coreapi/qsgrendernode_p.h b/src/quick/scenegraph/coreapi/qsgrendernode_p.h
index 8659b0e62c..5c42e55689 100644
--- a/src/quick/scenegraph/coreapi/qsgrendernode_p.h
+++ b/src/quick/scenegraph/coreapi/qsgrendernode_p.h
@@ -51,64 +51,23 @@
// We mean it.
//
-#include "qsgnode.h"
-#include <private/qtquickglobal_p.h>
+#include <QtQuick/qsgnode.h>
+#include <QtQuick/qsgrendernode.h>
QT_BEGIN_NAMESPACE
-namespace QSGBatchRenderer {
- class Renderer;
-}
-
-class Q_QUICK_PRIVATE_EXPORT QSGRenderNode : public QSGNode
+class QSGRenderNodePrivate
{
public:
- enum StateFlag
- {
- DepthState = 0x01, // depth mask, depth test enable, depth func, clear depth
- StencilState = 0x02, // stencil mask, stencil test enable, stencil op, stencil func, clear stencil
- ScissorState = 0x04, // scissor enable, scissor test enable
- ColorState = 0x08, // clear color, color mask
- BlendState = 0x10, // blend enable, blend func
- CullState = 0x20, // front face, cull face enable
- ViewportState = 0x40 // viewport
- };
- Q_DECLARE_FLAGS(StateFlags, StateFlag)
-
- struct RenderState
- {
- // The model-view matrix can be retrieved with matrix().
- // The opacity can be retrieved with inheritedOpacity().
- const QMatrix4x4 *projectionMatrix;
- QRect scissorRect;
- int stencilValue;
-
- bool stencilEnabled;
- bool scissorEnabled;
- };
-
- QSGRenderNode();
+ QSGRenderNodePrivate();
- virtual StateFlags changedStates() = 0;
- virtual void render(const RenderState &state) = 0;
-
- const QMatrix4x4 *matrix() const { return m_matrix; }
- const QSGClipNode *clipList() const { return m_clip_list; }
-
- void setInheritedOpacity(qreal opacity);
- qreal inheritedOpacity() const { return m_opacity; }
-
-private:
- friend class QSGNodeUpdater;
- friend class QSGBatchRenderer::Renderer;
+ static QSGRenderNodePrivate *get(QSGRenderNode *node) { return node->d; }
const QMatrix4x4 *m_matrix;
const QSGClipNode *m_clip_list;
qreal m_opacity;
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderNode::StateFlags)
-
QT_END_NAMESPACE
#endif
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index b0dd24af23..0f0a7be3b2 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -296,6 +296,13 @@ QSize QSGContext::minimumFBOSize() const
return QSize(1, 1);
}
+QSGRendererInterface *QSGContext::rendererInterface(QSGRenderContext *renderContext)
+{
+ Q_UNUSED(renderContext);
+ qWarning("QSGRendererInterface not implemented");
+ return nullptr;
+}
+
QSGRenderContext::QSGRenderContext(QSGContext *context)
: m_sg(context)
, m_distanceFieldCacheManager(0)
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index 3893560142..19a8636f19 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -82,6 +82,7 @@ class QQuickTextureFactory;
class QSGDistanceFieldGlyphCacheManager;
class QSGContext;
class QQuickPaintedItem;
+class QSGRendererInterface;
Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERLOOP)
Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_COMPILATION)
@@ -170,6 +171,8 @@ public:
virtual QSize minimumFBOSize() const;
virtual QSurfaceFormat defaultSurfaceFormat() const = 0;
+ virtual QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext);
+
static QSGContext *createDefaultContext();
static QQuickTextureFactory *createTextureFactoryFromImage(const QImage &image);
static QSGRenderLoop *createWindowManager();
diff --git a/src/quick/scenegraph/qsgdefaultcontext.cpp b/src/quick/scenegraph/qsgdefaultcontext.cpp
index f969359e7c..4b05f64887 100644
--- a/src/quick/scenegraph/qsgdefaultcontext.cpp
+++ b/src/quick/scenegraph/qsgdefaultcontext.cpp
@@ -240,4 +240,15 @@ bool QSGDefaultContext::isDistanceFieldEnabled() const
return !m_distanceFieldDisabled;
}
+QSGRendererInterface *QSGDefaultContext::rendererInterface(QSGRenderContext *renderContext)
+{
+ Q_UNUSED(renderContext);
+ return this;
+}
+
+QSGRendererInterface::GraphicsAPI QSGDefaultContext::graphicsAPI() const
+{
+ return OpenGL;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultcontext_p.h b/src/quick/scenegraph/qsgdefaultcontext_p.h
index 0569b7c321..923d1ee7ec 100644
--- a/src/quick/scenegraph/qsgdefaultcontext_p.h
+++ b/src/quick/scenegraph/qsgdefaultcontext_p.h
@@ -53,10 +53,11 @@
#include <QtQuick/private/qsgcontext_p.h>
#include <QtQuick/private/qsgdistancefieldglyphnode_p.h>
+#include "qsgrendererinterface.h"
QT_BEGIN_NAMESPACE
-class QSGDefaultContext : public QSGContext
+class QSGDefaultContext : public QSGContext, public QSGRendererInterface
{
public:
QSGDefaultContext(QObject *parent = 0);
@@ -72,10 +73,13 @@ public:
QSGNinePatchNode *createNinePatchNode() override;
QSGLayer *createLayer(QSGRenderContext *renderContext) override;
QSurfaceFormat defaultSurfaceFormat() const override;
+ QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override;
void setDistanceFieldEnabled(bool enabled);
bool isDistanceFieldEnabled() const;
+ GraphicsAPI graphicsAPI() const override;
+
private:
QMutex m_mutex;
QSGContext::AntialiasingMethod m_antialiasingMethod;
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index 79971a2b0d..d8dfd01e7a 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -14,7 +14,9 @@ HEADERS += \
$$PWD/coreapi/qsgabstractrenderer.h \
$$PWD/coreapi/qsgabstractrenderer_p.h \
$$PWD/coreapi/qsgrenderer_p.h \
+ $$PWD/coreapi/qsgrendernode.h \
$$PWD/coreapi/qsgrendernode_p.h \
+ $$PWD/coreapi/qsgrendererinterface.h \
$$PWD/coreapi/qsggeometry_p.h
SOURCES += \
@@ -24,7 +26,8 @@ SOURCES += \
$$PWD/coreapi/qsgnode.cpp \
$$PWD/coreapi/qsgnodeupdater.cpp \
$$PWD/coreapi/qsgrenderer.cpp \
- $$PWD/coreapi/qsgrendernode.cpp
+ $$PWD/coreapi/qsgrendernode.cpp \
+ $$PWD/coreapi/qsgrendererinterface.cpp
contains(QT_CONFIG, opengl(es1|es2)?) {
HEADERS += \
diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp
index da7a65cfec..3f2c69d461 100644
--- a/src/quick/scenegraph/util/qsgengine.cpp
+++ b/src/quick/scenegraph/util/qsgengine.cpp
@@ -209,4 +209,20 @@ QSGTexture *QSGEngine::createTextureFromId(uint id, const QSize &size, CreateTex
return 0;
}
+/*!
+ Returns the current renderer interface if there is one. Otherwise null is returned.
+
+ \sa QSGRenderNode, QSGRendererInterface
+ \since 5.8
+ */
+QSGRendererInterface *QSGEngine::rendererInterface() const
+{
+ Q_D(const QSGEngine);
+ if (!d->sgRenderContext->isValid()) {
+ qWarning("The QSGRendererInterface cannot be queried before the scenegraph is initialized");
+ return nullptr;
+ }
+ return d->sgRenderContext->sceneGraphContext()->rendererInterface(d->sgRenderContext.data());
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h
index 89af71fb47..9d27fb5525 100644
--- a/src/quick/scenegraph/util/qsgengine.h
+++ b/src/quick/scenegraph/util/qsgengine.h
@@ -49,6 +49,7 @@ class QOpenGLContext;
class QSGAbstractRenderer;
class QSGEnginePrivate;
class QSGTexture;
+class QSGRendererInterface;
class Q_QUICK_EXPORT QSGEngine : public QObject
{
@@ -72,6 +73,7 @@ public:
QSGAbstractRenderer *createRenderer() const;
QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options = CreateTextureOption()) const;
QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption()) const;
+ QSGRendererInterface *rendererInterface() const;
};
QT_END_NAMESPACE