aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@theqtcompany.com>2016-03-01 16:51:38 +0100
committerAndy Nichols <andy.nichols@theqtcompany.com>2016-03-04 10:48:28 +0000
commita86a0e9a79ca9d984f07a202c62a46b75956f73e (patch)
treee68b923e42a7e9c91d81892aed320fcfdb0f3c5c
parent7d0cdf06a6771e57fb3d70d62076bb9685747879 (diff)
D3D12: Add support for clipping via scissor and stencil
Change-Id: Ie55b9a2fd39d9e11321454a34a21c2a52ff1d23a Reviewed-by: Andy Nichols <andy.nichols@theqtcompany.com>
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp98
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h59
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h6
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode.cpp5
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode_p.h1
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp186
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h8
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri15
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/shaders/stencilclip.hlsl26
-rw-r--r--src/quick/scenegraph/qsgdefaultrectanglenode.cpp3
-rw-r--r--src/quick/scenegraph/qsgdefaultrectanglenode_p.h1
-rw-r--r--tests/manual/nodetypes/Rects.qml126
-rw-r--r--tests/manual/nodetypes/main.qml69
-rw-r--r--tests/manual/nodetypes/nodetypes.cpp4
-rw-r--r--tests/manual/nodetypes/nodetypes.pro2
-rw-r--r--tests/manual/nodetypes/nodetypes.qrc1
16 files changed, 479 insertions, 131 deletions
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp
index c26bcfdd9e..6f78d740c3 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp
@@ -311,9 +311,14 @@ void QSGD3D12Engine::queueClearRenderTarget(const QColor &color)
d->queueClearRenderTarget(color);
}
-void QSGD3D12Engine::queueClearDepthStencil(float depthValue, quint8 stencilValue)
+void QSGD3D12Engine::queueClearDepthStencil(float depthValue, quint8 stencilValue, ClearFlags which)
{
- d->queueClearDepthStencil(depthValue, stencilValue);
+ d->queueClearDepthStencil(depthValue, stencilValue, which);
+}
+
+void QSGD3D12Engine::queueSetStencilRef(quint32 ref)
+{
+ d->queueSetStencilRef(ref);
}
void QSGD3D12Engine::queueDraw(QSGGeometry::DrawingMode mode, int count, int vboOffset, int vboStride,
@@ -537,7 +542,7 @@ DXGI_SAMPLE_DESC QSGD3D12EnginePrivate::makeSampleDesc(DXGI_FORMAT format, int s
ID3D12Resource *QSGD3D12EnginePrivate::createDepthStencil(D3D12_CPU_DESCRIPTOR_HANDLE viewHandle, const QSize &size, int samples)
{
D3D12_CLEAR_VALUE depthClearValue = {};
- depthClearValue.Format = DXGI_FORMAT_D32_FLOAT;
+ depthClearValue.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthClearValue.DepthStencil.Depth = 1.0f;
depthClearValue.DepthStencil.Stencil = 0;
@@ -550,7 +555,7 @@ ID3D12Resource *QSGD3D12EnginePrivate::createDepthStencil(D3D12_CPU_DESCRIPTOR_H
bufDesc.Height = size.height();
bufDesc.DepthOrArraySize = 1;
bufDesc.MipLevels = 1;
- bufDesc.Format = DXGI_FORMAT_D32_FLOAT;
+ bufDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
bufDesc.SampleDesc = makeSampleDesc(bufDesc.Format, samples);
bufDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
bufDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
@@ -563,7 +568,7 @@ ID3D12Resource *QSGD3D12EnginePrivate::createDepthStencil(D3D12_CPU_DESCRIPTOR_H
}
D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilDesc = {};
- depthStencilDesc.Format = DXGI_FORMAT_D32_FLOAT;
+ depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilDesc.ViewDimension = bufDesc.SampleDesc.Count <= 1 ? D3D12_DSV_DIMENSION_TEXTURE2D : D3D12_DSV_DIMENSION_TEXTURE2DMS;
device->CreateDepthStencilView(resource, &depthStencilDesc, viewHandle);
@@ -717,6 +722,9 @@ void QSGD3D12EnginePrivate::beginFrame()
commandList->Reset(commandAllocator.Get(), nullptr);
transitionResource(backBufferRT(), commandList.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ m_drawingMode = QSGGeometry::DrawingMode(-1);
+ m_indexBufferSet = false;
}
void QSGD3D12EnginePrivate::updateBuffer(StagingBufferRef *br, ID3D12Resource *r, const char *dbgstr)
@@ -842,12 +850,12 @@ void QSGD3D12EnginePrivate::setPipelineState(const QSGD3D12PipelineState &pipeli
D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD,
D3D12_BLEND_INV_DEST_ALPHA, D3D12_BLEND_ONE, D3D12_BLEND_OP_ADD,
D3D12_LOGIC_OP_NOOP,
- D3D12_COLOR_WRITE_ENABLE_ALL
+ UINT8(pipelineState.colorWrite ? D3D12_COLOR_WRITE_ENABLE_ALL : 0)
};
blendDesc.RenderTarget[0] = premulBlendDesc;
} else {
D3D12_RENDER_TARGET_BLEND_DESC noBlendDesc = {};
- noBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
+ noBlendDesc.RenderTargetWriteMask = pipelineState.colorWrite ? D3D12_COLOR_WRITE_ENABLE_ALL : 0;
blendDesc.RenderTarget[0] = noBlendDesc;
}
psoDesc.BlendState = blendDesc;
@@ -855,13 +863,22 @@ void QSGD3D12EnginePrivate::setPipelineState(const QSGD3D12PipelineState &pipeli
psoDesc.DepthStencilState.DepthEnable = pipelineState.depthEnable;
psoDesc.DepthStencilState.DepthWriteMask = pipelineState.depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC(pipelineState.depthFunc);
+
psoDesc.DepthStencilState.StencilEnable = pipelineState.stencilEnable;
- // ### stencil stuff
+ psoDesc.DepthStencilState.StencilReadMask = psoDesc.DepthStencilState.StencilWriteMask = 0xFF;
+ D3D12_DEPTH_STENCILOP_DESC stencilOpDesc = {
+ D3D12_STENCIL_OP(pipelineState.stencilFailOp),
+ D3D12_STENCIL_OP(pipelineState.stencilDepthFailOp),
+ D3D12_STENCIL_OP(pipelineState.stencilPassOp),
+ D3D12_COMPARISON_FUNC(pipelineState.stencilFunc)
+ };
+ psoDesc.DepthStencilState.FrontFace = psoDesc.DepthStencilState.BackFace = stencilOpDesc;
+
psoDesc.SampleMask = UINT_MAX;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE(pipelineState.topologyType);
psoDesc.NumRenderTargets = 1;
psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
- psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
+ psoDesc.DSVFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
psoDesc.SampleDesc.Count = 1;
HRESULT hr = device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pso));
@@ -905,13 +922,13 @@ void QSGD3D12EnginePrivate::markConstantBufferDirty(int offset, int size)
void QSGD3D12EnginePrivate::queueViewport(const QRect &rect)
{
- const D3D12_VIEWPORT viewport = { 0, 0, float(rect.width()), float(rect.height()), 0, 1 };
+ const D3D12_VIEWPORT viewport = { float(rect.x()), float(rect.y()), float(rect.width()), float(rect.height()), 0, 1 };
commandList->RSSetViewports(1, &viewport);
}
void QSGD3D12EnginePrivate::queueScissor(const QRect &rect)
{
- const D3D12_RECT scissorRect = { 0, 0, rect.width() - 1, rect.height() - 1 };
+ const D3D12_RECT scissorRect = { rect.left(), rect.top(), rect.right(), rect.bottom() };
commandList->RSSetScissorRects(1, &scissorRect);
}
@@ -928,9 +945,14 @@ void QSGD3D12EnginePrivate::queueClearRenderTarget(const QColor &color)
commandList->ClearRenderTargetView(backBufferRTV(), clearColor, 0, nullptr);
}
-void QSGD3D12EnginePrivate::queueClearDepthStencil(float depthValue, quint8 stencilValue)
+void QSGD3D12EnginePrivate::queueClearDepthStencil(float depthValue, quint8 stencilValue, QSGD3D12Engine::ClearFlags which)
{
- commandList->ClearDepthStencilView(dsv, D3D12_CLEAR_FLAG_DEPTH, depthValue, stencilValue, 0, nullptr);
+ commandList->ClearDepthStencilView(dsv, D3D12_CLEAR_FLAGS(int(which)), depthValue, stencilValue, 0, nullptr);
+}
+
+void QSGD3D12EnginePrivate::queueSetStencilRef(quint32 ref)
+{
+ commandList->OMSetStencilRef(ref);
}
void QSGD3D12EnginePrivate::queueDraw(QSGGeometry::DrawingMode mode, int count, int vboOffset, int vboStride,
@@ -997,33 +1019,37 @@ void QSGD3D12EnginePrivate::queueDraw(QSGGeometry::DrawingMode mode, int count,
Q_ASSERT(indexBuffer || startIndexIndex < 0);
- D3D_PRIMITIVE_TOPOLOGY topology;
- switch (mode) {
- case QSGGeometry::DrawPoints:
- topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
- break;
- case QSGGeometry::DrawLines:
- topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
- break;
- case QSGGeometry::DrawLineStrip:
- topology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
- break;
- case QSGGeometry::DrawTriangles:
- topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
- break;
- case QSGGeometry::DrawTriangleStrip:
- topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
- break;
- default:
- qFatal("Unsupported drawing mode 0x%x", mode);
- break;
+ if (mode != m_drawingMode) {
+ D3D_PRIMITIVE_TOPOLOGY topology;
+ switch (mode) {
+ case QSGGeometry::DrawPoints:
+ topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
+ break;
+ case QSGGeometry::DrawLines:
+ topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
+ break;
+ case QSGGeometry::DrawLineStrip:
+ topology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
+ break;
+ case QSGGeometry::DrawTriangles:
+ topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
+ break;
+ case QSGGeometry::DrawTriangleStrip:
+ topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
+ break;
+ default:
+ qFatal("Unsupported drawing mode 0x%x", mode);
+ break;
+ }
+ commandList->IASetPrimitiveTopology(topology);
+ m_drawingMode = mode;
}
- commandList->IASetPrimitiveTopology(topology);
-
+ // must be set after the topology
commandList->IASetVertexBuffers(0, 1, &vbv);
- if (startIndexIndex >= 0) {
+ if (startIndexIndex >= 0 && !m_indexBufferSet) {
+ m_indexBufferSet = true;
D3D12_INDEX_BUFFER_VIEW ibv;
ibv.BufferLocation = indexBuffer->GetGPUVirtualAddress();
ibv.SizeInBytes = indexData.size;
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h
index 52ca80a002..a03be4b884 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h
@@ -130,15 +130,26 @@ struct QSGD3D12PipelineState
CullBack
};
- enum DepthFunc {
- DepthNever = 1,
- DepthLess,
- DepthEqual,
- DepthLessEqual,
- DepthGreater,
- DepthNotEqual,
- DepthGreaterEqual,
- DepthAlways
+ enum CompareFunc {
+ CompareNever = 1,
+ CompareLess,
+ CompareEqual,
+ CompareLessEqual,
+ CompareGreater,
+ CompareNotEqual,
+ CompareGreaterEqual,
+ CompareAlways
+ };
+
+ enum StencilOp {
+ StencilKeep = 1,
+ StencilZero,
+ StencilReplace,
+ StencilIncrSat,
+ StencilDecrSat,
+ StencilInvert,
+ StencilIncr,
+ StencilDescr
};
enum TopologyType {
@@ -153,12 +164,16 @@ struct QSGD3D12PipelineState
CullMode cullMode = CullNone;
bool frontCCW = true;
+ bool colorWrite = true;
bool premulBlend = false; // == GL_ONE, GL_ONE_MINUS_SRC_ALPHA
bool depthEnable = true;
- DepthFunc depthFunc = DepthLess;
+ CompareFunc depthFunc = CompareLess;
bool depthWrite = true;
bool stencilEnable = false;
- // ### stencil stuff
+ CompareFunc stencilFunc = CompareEqual;
+ StencilOp stencilFailOp = StencilKeep;
+ StencilOp stencilDepthFailOp = StencilKeep;
+ StencilOp stencilPassOp = StencilKeep;
TopologyType topologyType = TopologyTypeTriangle;
bool operator==(const QSGD3D12PipelineState &other) const {
@@ -166,11 +181,16 @@ struct QSGD3D12PipelineState
&& inputElements == other.inputElements
&& cullMode == other.cullMode
&& frontCCW == other.frontCCW
+ && colorWrite == other.colorWrite
&& premulBlend == other.premulBlend
&& depthEnable == other.depthEnable
&& depthFunc == other.depthFunc
&& depthWrite == other.depthWrite
&& stencilEnable == other.stencilEnable
+ && stencilFunc == other.stencilFunc
+ && stencilFailOp == other.stencilFailOp
+ && stencilDepthFailOp == other.stencilDepthFailOp
+ && stencilPassOp == other.stencilPassOp
&& topologyType == other.topologyType;
}
};
@@ -178,8 +198,10 @@ struct QSGD3D12PipelineState
inline uint qHash(const QSGD3D12PipelineState &key, uint seed = 0)
{
return qHash(key.shaders, seed) + qHash(key.inputElements, seed)
- + key.cullMode + key.frontCCW + key.premulBlend + key.depthEnable
- + key.depthFunc + key.depthWrite + key.stencilEnable + key.topologyType;
+ + key.cullMode + key.frontCCW + key.colorWrite + key.premulBlend + key.depthEnable
+ + key.depthFunc + key.depthWrite + key.stencilEnable + key.stencilFunc
+ + key.stencilFailOp + key.stencilDepthFailOp + key.stencilPassOp
+ + key.topologyType;
}
class QSGD3D12Engine
@@ -202,11 +224,18 @@ public:
void setConstantBuffer(const quint8 *data, int size);
void markConstantBufferDirty(int offset, int size);
+ enum ClearFlag {
+ ClearDepth = 0x1,
+ ClearStencil = 0x2
+ };
+ Q_DECLARE_FLAGS(ClearFlags, ClearFlag)
+
void queueViewport(const QRect &rect);
void queueScissor(const QRect &rect);
void queueSetRenderTarget();
void queueClearRenderTarget(const QColor &color);
- void queueClearDepthStencil(float depthValue, quint8 stencilValue);
+ void queueClearDepthStencil(float depthValue, quint8 stencilValue, ClearFlags which);
+ void queueSetStencilRef(quint32 ref);
void queueDraw(QSGGeometry::DrawingMode mode, int count, int vboOffset, int vboStride,
int cboOffset,
@@ -223,6 +252,8 @@ private:
Q_DISABLE_COPY(QSGD3D12Engine)
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGD3D12Engine::ClearFlags)
+
QT_END_NAMESPACE
#endif // QSGD3D12ENGINE_P_H
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h
index fd72c4f064..6dd95e725e 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h
@@ -156,7 +156,8 @@ public:
void queueScissor(const QRect &rect);
void queueSetRenderTarget();
void queueClearRenderTarget(const QColor &color);
- void queueClearDepthStencil(float depthValue, quint8 stencilValue);
+ void queueClearDepthStencil(float depthValue, quint8 stencilValue, QSGD3D12Engine::ClearFlags which);
+ void queueSetStencilRef(quint32 ref);
void queueDraw(QSGGeometry::DrawingMode mode, int count, int vboOffset, int vboStride,
int cboOffset,
@@ -223,6 +224,9 @@ private:
QHash<QSGD3D12PipelineState, ComPtr<ID3D12PipelineState> > m_psoCache;
ComPtr<ID3D12RootSignature> m_rootSig;
+
+ QSGGeometry::DrawingMode m_drawingMode;
+ bool m_indexBufferSet;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode.cpp
index 5956a06e2f..4a537731ce 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode.cpp
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode.cpp
@@ -46,6 +46,11 @@ QSGD3D12RectangleNode::QSGD3D12RectangleNode()
setMaterial(&m_material);
}
+bool QSGD3D12RectangleNode::supportsAntialiasing() const
+{
+ return false; // ###
+}
+
void QSGD3D12RectangleNode::updateMaterialAntialiasing()
{
//if (m_antialiasing)
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode_p.h
index 464dc763a6..dfabb4f832 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode_p.h
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode_p.h
@@ -62,6 +62,7 @@ public:
QSGD3D12RectangleNode();
private:
+ bool supportsAntialiasing() const;
void updateMaterialAntialiasing() override;
void updateMaterialBlending(QSGNode::DirtyState *state) override;
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp
index 2e55f7ec0e..521cefc7c1 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp
@@ -41,6 +41,11 @@
#include "qsgd3d12rendercontext_p.h"
#include <private/qsgnodeupdater_p.h>
+#include "vs_stencilclip.hlslh"
+#include "ps_stencilclip.hlslh"
+
+//#define I_LIKE_STENCIL
+
QT_BEGIN_NAMESPACE
#define QSGNODE_TRAVERSE(NODE) for (QSGNode *child = NODE->firstChild(); child; child = child->nextSibling())
@@ -64,7 +69,7 @@ QSGD3D12Renderer::QSGD3D12Renderer(QSGRenderContext *context)
m_renderList(16),
m_vboData(1024),
m_iboData(256),
- m_cboData(256)
+ m_cboData(4096)
{
setNodeUpdater(new DummyUpdater);
}
@@ -174,12 +179,15 @@ void QSGD3D12Renderer::buildRenderList(QSGNode *node, QSGClipNode *clip)
memcpy(m_iboData.data() + e.iboOffset, g->indexData(), indexSize);
}
+ e.cboOffset = m_cboData.size();
if (node->type() == QSGNode::GeometryNodeType) {
QSGD3D12Material *m = static_cast<QSGD3D12Material *>(static_cast<QSGGeometryNode *>(node)->activeMaterial());
- e.cboOffset = m_cboData.size();
e.cboSize = m->constantBufferSize();
- m_cboData.resize(m_cboData.size() + e.cboSize);
+ } else {
+ // Stencil-based clipping needs a 4x4 matrix.
+ e.cboSize = QSGD3D12Engine::alignedConstantBufferSize(16 * sizeof(float));
}
+ m_cboData.resize(m_cboData.size() + e.cboSize);
m_renderList.add(e);
@@ -198,6 +206,8 @@ void QSGD3D12Renderer::render()
m_engine = rc->engine();
m_engine->beginFrame();
+ m_activeScissorRect = QRect();
+
if (m_rebuild) {
m_rebuild = false;
@@ -211,7 +221,7 @@ void QSGD3D12Renderer::render()
m_iboData.reset();
m_cboData.reset();
- buildRenderList(rootNode(), 0);
+ buildRenderList(rootNode(), nullptr);
m_engine->setVertexBuffer(m_vboData.data(), m_vboData.size());
m_engine->setIndexBuffer(m_iboData.data(), m_iboData.size());
@@ -343,13 +353,10 @@ void QSGD3D12Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
void QSGD3D12Renderer::renderElements()
{
- QRect r = viewportRect();
- r.setY(deviceRect().bottom() - r.bottom());
- m_engine->queueViewport(r);
- m_engine->queueScissor(r);
+ m_engine->queueViewport(viewportRect());
m_engine->queueSetRenderTarget();
m_engine->queueClearRenderTarget(clearColor());
- m_engine->queueClearDepthStencil(1, 0);
+ m_engine->queueClearDepthStencil(1, 0, QSGD3D12Engine::ClearDepth | QSGD3D12Engine::ClearStencil);
m_pipelineState.premulBlend = false;
m_pipelineState.depthEnable = true;
@@ -452,12 +459,26 @@ void QSGD3D12Renderer::renderElement(int elementIndex)
if (updRes.testFlag(QSGD3D12Material::UpdatedConstantBuffer))
m_engine->markConstantBufferDirty(e.cboOffset, e.cboSize);
- // Input element layout
- m_pipelineState.inputElements.resize(g->attributeCount());
+ setInputLayout(g, &m_pipelineState);
+
+ m_lastMaterialType = m->type();
+
+ setupClipping(gn, elementIndex);
+
+ // ### line width / point size ??
+
+ m_engine->setPipelineState(m_pipelineState);
+
+ queueDrawCall(g, e);
+}
+
+void QSGD3D12Renderer::setInputLayout(const QSGGeometry *g, QSGD3D12PipelineState *pipelineState)
+{
+ pipelineState->inputElements.resize(g->attributeCount());
const QSGGeometry::Attribute *attrs = g->attributes();
quint32 offset = 0;
for (int i = 0; i < g->attributeCount(); ++i) {
- QSGD3D12InputElement &ie(m_pipelineState.inputElements[i]);
+ QSGD3D12InputElement &ie(pipelineState->inputElements[i]);
static const char *semanticNames[] = { "UNKNOWN", "POSITION", "COLOR", "TEXCOORD" };
Q_ASSERT(attrs[i].semantic >= 1 && attrs[i].semantic < _countof(semanticNames));
const int tupleSize = attrs[i].tupleSize;
@@ -471,13 +492,10 @@ void QSGD3D12Renderer::renderElement(int elementIndex)
// There is one buffer with interleaved data so the slot is always 0.
ie.slot = 0;
}
+}
- m_lastMaterialType = m->type();
-
- // ### line width / point size ??
-
- m_engine->setPipelineState(m_pipelineState);
-
+void QSGD3D12Renderer::queueDrawCall(const QSGGeometry *g, const QSGD3D12Renderer::Element &e)
+{
if (e.iboOffset >= 0) {
const QSGGeometry::Type indexType = QSGGeometry::Type(g->indexType());
const QSGD3D12Format indexFormat = QSGD3D12Engine::toDXGIFormat(indexType);
@@ -492,4 +510,136 @@ void QSGD3D12Renderer::renderElement(int elementIndex)
}
}
+void QSGD3D12Renderer::setupClipping(const QSGGeometryNode *gn, 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;
+
+ while (clip) {
+ QMatrix4x4 m = projectionMatrix();
+ if (clip->matrix())
+ m *= *clip->matrix();
+
+#ifndef I_LIKE_STENCIL
+ const bool isRectangleWithNoPerspective = clip->isRectangular()
+ && qFuzzyIsNull(m(3, 0)) && qFuzzyIsNull(m(3, 1));
+ const bool noRotate = qFuzzyIsNull(m(0, 1)) && qFuzzyIsNull(m(1, 0));
+ const bool isRotate90 = qFuzzyIsNull(m(0, 0)) && qFuzzyIsNull(m(1, 1));
+
+ if (isRectangleWithNoPerspective && (noRotate || isRotate90)) {
+ QRectF bbox = clip->clipRect();
+ float invW = 1.0f / m(3, 3);
+ float fx1, fy1, fx2, fy2;
+ if (noRotate) {
+ fx1 = (bbox.left() * m(0, 0) + m(0, 3)) * invW;
+ fy1 = (bbox.bottom() * m(1, 1) + m(1, 3)) * invW;
+ fx2 = (bbox.right() * m(0, 0) + m(0, 3)) * invW;
+ fy2 = (bbox.top() * m(1, 1) + m(1, 3)) * invW;
+ } else {
+ Q_ASSERT(isRotate90);
+ fx1 = (bbox.bottom() * m(0, 1) + m(0, 3)) * invW;
+ fy1 = (bbox.left() * m(1, 0) + m(1, 3)) * invW;
+ fx2 = (bbox.top() * m(0, 1) + m(0, 3)) * invW;
+ fy2 = (bbox.right() * m(1, 0) + m(1, 3)) * invW;
+ }
+
+ if (fx1 > fx2)
+ qSwap(fx1, fx2);
+ if (fy1 > fy2)
+ qSwap(fy1, fy2);
+
+ int ix1 = qRound((fx1 + 1) * devRect.width() * 0.5f);
+ int iy1 = qRound((fy1 + 1) * devRect.height() * 0.5f);
+ int ix2 = qRound((fx2 + 1) * devRect.width() * 0.5f);
+ int iy2 = qRound((fy2 + 1) * devRect.height() * 0.5f);
+
+ if (!(clipTypes & ClipScissor)) {
+ scissorRect = QRect(ix1, devRect.height() - iy2, ix2 - ix1 + 1, iy2 - iy1 + 1);
+ clipTypes |= ClipScissor;
+ } else {
+ scissorRect &= QRect(ix1, devRect.height() - iy2, ix2 - ix1 + 1, iy2 - iy1 + 1);
+ }
+ } else
+#endif
+ {
+ clipTypes |= ClipStencil;
+ renderStencilClip(clip, elementIndex, m, stencilValue);
+ }
+
+ clip = clip->clipList();
+ }
+
+ setScissor((clipTypes & ClipScissor) ? scissorRect : viewportRect());
+
+ if (clipTypes & ClipStencil) {
+ m_pipelineState.stencilEnable = true;
+ m_engine->queueSetStencilRef(stencilValue);
+ } else {
+ m_pipelineState.stencilEnable = false;
+ }
+}
+
+void QSGD3D12Renderer::setScissor(const QRect &r)
+{
+ if (m_activeScissorRect == r)
+ return;
+
+ m_activeScissorRect = r;
+ m_engine->queueScissor(r);
+}
+
+void QSGD3D12Renderer::renderStencilClip(const QSGClipNode *clip, int elementIndex,
+ const QMatrix4x4 &m, quint32 &stencilValue)
+{
+ QSGD3D12PipelineState sps;
+ sps.shaders.vs = g_VS_StencilClip;
+ sps.shaders.vsSize = sizeof(g_VS_StencilClip);
+ sps.shaders.ps = g_PS_StencilClip;
+ sps.shaders.psSize = sizeof(g_PS_StencilClip);
+
+ m_engine->queueClearDepthStencil(1, 0, QSGD3D12Engine::ClearStencil);
+ sps.stencilEnable = true;
+ sps.colorWrite = false;
+ sps.depthWrite = false;
+
+ sps.stencilFunc = QSGD3D12PipelineState::CompareEqual;
+ sps.stencilFailOp = QSGD3D12PipelineState::StencilKeep;
+ sps.stencilDepthFailOp = QSGD3D12PipelineState::StencilKeep;
+ sps.stencilPassOp = QSGD3D12PipelineState::StencilIncr;
+
+ m_engine->queueSetStencilRef(stencilValue);
+
+ int clipIndex = elementIndex;
+ while (m_renderList.at(--clipIndex).node != clip) {
+ Q_ASSERT(clipIndex >= 0);
+ }
+ const Element &ce = m_renderList.at(clipIndex);
+ Q_ASSERT(ce.node == clip);
+
+ const QSGGeometry *g = clip->geometry();
+ Q_ASSERT(g->attributeCount() == 1);
+ Q_ASSERT(g->attributes()[0].tupleSize == 2);
+ Q_ASSERT(g->attributes()[0].type == GL_FLOAT);
+
+ setInputLayout(g, &sps);
+ m_engine->setPipelineState(sps);
+
+ Q_ASSERT(ce.cboSize > 0);
+ quint8 *p = m_cboData.data() + ce.cboOffset;
+ memcpy(p, m.constData(), 16 * sizeof(float));
+ m_engine->markConstantBufferDirty(ce.cboOffset, ce.cboSize);
+
+ queueDrawCall(g, ce);
+
+ ++stencilValue;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h
index e637dbbb9c..8b430e1f1b 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h
@@ -73,6 +73,10 @@ private:
void buildRenderList(QSGNode *node, QSGClipNode *clip);
void renderElements();
void renderElement(int elementIndex);
+ void setInputLayout(const QSGGeometry *g, QSGD3D12PipelineState *pipelineState);
+ void setupClipping(const QSGGeometryNode *gn, int elementIndex);
+ void setScissor(const QRect &r);
+ void renderStencilClip(const QSGClipNode *clip, int elementIndex, const QMatrix4x4 &m, quint32 &stencilValue);
struct Element {
QSGBasicGeometryNode *node = nullptr;
@@ -84,6 +88,8 @@ private:
bool cboPrepared = false;
};
+ void queueDrawCall(const QSGGeometry *g, const Element &e);
+
QSet<QSGNode *> m_dirtyTransformNodes;
QSet<QSGNode *> m_dirtyOpacityNodes;
QBitArray m_opaqueElements;
@@ -100,6 +106,8 @@ private:
typedef QHash<QSGNode *, QSGD3D12Material::RenderState::DirtyStates> NodeDirtyMap;
NodeDirtyMap m_nodeDirtyMap;
+
+ QRect m_activeScissorRect;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri b/src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri
index 6fc591cb33..e7ea6cdde5 100644
--- a/src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri
+++ b/src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri
@@ -8,5 +8,18 @@ vertexcolor_pshader.header = ps_vertexcolor.hlslh
vertexcolor_pshader.entry = PS_VertexColor
vertexcolor_pshader.type = ps_5_0
-HLSL_SHADERS = vertexcolor_vshader vertexcolor_pshader
+stencilclip_VSPS = $$PWD/stencilclip.hlsl
+stencilclip_vshader.input = stencilclip_VSPS
+stencilclip_vshader.header = vs_stencilclip.hlslh
+stencilclip_vshader.entry = VS_StencilClip
+stencilclip_vshader.type = vs_5_0
+stencilclip_pshader.input = stencilclip_VSPS
+stencilclip_pshader.header = ps_stencilclip.hlslh
+stencilclip_pshader.entry = PS_StencilClip
+stencilclip_pshader.type = ps_5_0
+
+HLSL_SHADERS = \
+ vertexcolor_vshader vertexcolor_pshader \
+ stencilclip_vshader stencilclip_pshader
+
load(hlsl_bytecode_header)
diff --git a/src/quick/scenegraph/adaptations/d3d12/shaders/stencilclip.hlsl b/src/quick/scenegraph/adaptations/d3d12/shaders/stencilclip.hlsl
new file mode 100644
index 0000000000..9aff84d261
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/shaders/stencilclip.hlsl
@@ -0,0 +1,26 @@
+struct VSInput
+{
+ float4 position : POSITION;
+};
+
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 mvp;
+};
+
+struct PSInput
+{
+ float4 position : SV_POSITION;
+};
+
+PSInput VS_StencilClip(VSInput input)
+{
+ PSInput result;
+ result.position = mul(mvp, input.position);
+ return result;
+}
+
+float4 PS_StencilClip(PSInput input) : SV_TARGET
+{
+ return float4(0.81, 0.83, 0.12, 1.0); // Trolltech green ftw!
+}
diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
index 9a219ece63..9e78847667 100644
--- a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
@@ -258,6 +258,9 @@ void QSGDefaultNoMaterialRectangleNode::setRadius(qreal radius)
void QSGDefaultNoMaterialRectangleNode::setAntialiasing(bool antialiasing)
{
+ if (!supportsAntialiasing())
+ return;
+
if (antialiasing == m_antialiasing)
return;
m_antialiasing = antialiasing;
diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode_p.h b/src/quick/scenegraph/qsgdefaultrectanglenode_p.h
index 61bf4fb4ae..f5f3c465b7 100644
--- a/src/quick/scenegraph/qsgdefaultrectanglenode_p.h
+++ b/src/quick/scenegraph/qsgdefaultrectanglenode_p.h
@@ -88,6 +88,7 @@ public:
void update() override;
protected:
+ virtual bool supportsAntialiasing() const { return true; }
virtual void updateMaterialAntialiasing() = 0;
virtual void updateMaterialBlending(QSGNode::DirtyState *state) = 0;
diff --git a/tests/manual/nodetypes/Rects.qml b/tests/manual/nodetypes/Rects.qml
new file mode 100644
index 0000000000..a6eeb375d4
--- /dev/null
+++ b/tests/manual/nodetypes/Rects.qml
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ Rectangle {
+ width: 100
+ height: 100
+ anchors.centerIn: parent
+ color: "red"
+ NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; }
+
+ Rectangle {
+ color: "gray"
+ width: 50
+ height: 50
+ anchors.centerIn: parent
+
+ SequentialAnimation on opacity {
+ loops: Animation.Infinite
+ NumberAnimation {
+ from: 1.0
+ to: 0.0
+ duration: 4000
+ }
+ NumberAnimation {
+ from: 0.0
+ to: 1.0
+ duration: 4000
+ easing.type: Easing.InOutQuad
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ color: "green"
+ width: 100
+ height: 200
+ x: 0
+ y: 0
+
+ NumberAnimation on x {
+ from: 0
+ to: 300
+ duration: 5000
+ }
+ NumberAnimation on y {
+ from: 0
+ to: 50
+ duration: 2000
+ }
+
+ clip: true
+ Rectangle {
+ color: "lightGreen"
+ width: 50
+ height: 50
+ x: 75
+ y: 175
+ }
+ }
+
+ Rectangle {
+ color: "blue"
+ width: 200
+ height: 100
+ x: 100
+ y: 300
+ radius: 16
+ border.color: "red"
+ border.width: 4
+
+ SequentialAnimation on y {
+ loops: Animation.Infinite
+ NumberAnimation {
+ from: 300
+ to: 500
+ duration: 7000
+ }
+ NumberAnimation {
+ from: 500
+ to: 300
+ duration: 3000
+ }
+ }
+ }
+}
diff --git a/tests/manual/nodetypes/main.qml b/tests/manual/nodetypes/main.qml
index 81d1e63ead..8e816fac28 100644
--- a/tests/manual/nodetypes/main.qml
+++ b/tests/manual/nodetypes/main.qml
@@ -41,69 +41,18 @@
import QtQuick 2.0
Item {
- Rectangle {
- width: 100
- height: 100
- anchors.centerIn: parent
- color: "red"
- NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; }
+ focus: true
- Rectangle {
- color: "gray"
- width: 50
- height: 50
- anchors.centerIn: parent
-
- SequentialAnimation on opacity {
- loops: Animation.Infinite
- NumberAnimation {
- from: 1.0
- to: 0.0
- duration: 4000
- }
- NumberAnimation {
- from: 0.0
- to: 1.0
- duration: 4000
- easing.type: Easing.InOutQuad
- }
- }
- }
- }
-
- Rectangle {
- color: "green"
- width: 100
- height: 200
- x: 0
- y: 0
-
- NumberAnimation on x {
- from: 0
- to: 300
- duration: 10000
- }
+ Loader {
+ anchors.fill: parent
+ id: loader
}
- Rectangle {
- color: "blue"
- width: 200
- height: 100
- x: 100
- y: 300
+ Keys.onPressed: {
+ if (event.key === Qt.Key_S)
+ loader.source = "";
- SequentialAnimation on y {
- loops: Animation.Infinite
- NumberAnimation {
- from: 300
- to: 500
- duration: 7000
- }
- NumberAnimation {
- from: 500
- to: 300
- duration: 3000
- }
- }
+ if (event.key === Qt.Key_R)
+ loader.source = "qrc:/Rects.qml";
}
}
diff --git a/tests/manual/nodetypes/nodetypes.cpp b/tests/manual/nodetypes/nodetypes.cpp
index 506a202ec7..f1ad15a92d 100644
--- a/tests/manual/nodetypes/nodetypes.cpp
+++ b/tests/manual/nodetypes/nodetypes.cpp
@@ -47,6 +47,10 @@ int main(int argc, char **argv)
QGuiApplication app(argc, argv);
+ qDebug("Available tests:");
+ qDebug(" [R] - Rectangles");
+ qDebug("\nPress S to stop the currently running test\n");
+
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
view.resize(1024, 768);
diff --git a/tests/manual/nodetypes/nodetypes.pro b/tests/manual/nodetypes/nodetypes.pro
index c0b258d9ae..4ac026fc41 100644
--- a/tests/manual/nodetypes/nodetypes.pro
+++ b/tests/manual/nodetypes/nodetypes.pro
@@ -4,4 +4,4 @@ SOURCES += nodetypes.cpp
RESOURCES += nodetypes.qrc
-OTHER_FILES += main.qml
+OTHER_FILES += main.qml Rects.qml
diff --git a/tests/manual/nodetypes/nodetypes.qrc b/tests/manual/nodetypes/nodetypes.qrc
index 5f6483ac33..ce582ab75a 100644
--- a/tests/manual/nodetypes/nodetypes.qrc
+++ b/tests/manual/nodetypes/nodetypes.qrc
@@ -1,5 +1,6 @@
<RCC>
<qresource prefix="/">
<file>main.qml</file>
+ <file>Rects.qml</file>
</qresource>
</RCC>