aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@theqtcompany.com>2016-02-29 15:44:30 +0100
committerAndy Nichols <andy.nichols@theqtcompany.com>2016-03-04 10:46:50 +0000
commit7d0cdf06a6771e57fb3d70d62076bb9685747879 (patch)
tree9c17c3408a10f9847673e06c3dad2f61659a1f5c
parent2d1f8937acf874a37b7ef1d0814ee6dc7912f81b (diff)
D3D12: add opacity support, fix buffer handling and dirty tracking
Avoid using .h for generated headers with shader blobs in order not to confuse syncqt. All buffer Map and memcpy is now done only at the end of the frame. This is relevant for the constant buffer which can this way Map once and memcpy only the data for elements that changed something. This also marks a change from how simplerenderer works: instead of having per-program matrix, opacity, etc. values (uniforms), there is a separate copy of these in a dedicated area of the constant buffer for each element. This allows reusing the data in the buffer as-is for non-changing elements at the cost of higher memory usage (256 bytes per element both on CPU & GPU side at minimum) and is also necessary in order to be able to build command lists with multiple draw calls without intra-dependencies for the cbuffer contents. The somewhat broken dirty tracking of simplerenderer (matrices always treated as dirty, forgetting the root node for ever in the list of dirty transform nodes, etc.) is now corrected so that the DirtyMatrix and DirtyOpacity states reflect reality, meaning the cbuffer update can be skipped completely for items whose transform or inherited opacity has not changed at all. Format mapping is now moved to the engine. Change-Id: Ia0a0d73e2a954970cb2745deb1a62c09f3d3cb7c Reviewed-by: Andy Nichols <andy.nichols@theqtcompany.com>
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp174
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h2
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h7
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12material.cpp4
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp144
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h6
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri4
-rw-r--r--tests/manual/nodetypes/main.qml22
8 files changed, 243 insertions, 120 deletions
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp
index a623956e72..c26bcfdd9e 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp
@@ -286,6 +286,11 @@ void QSGD3D12Engine::setConstantBuffer(const quint8 *data, int size)
d->setConstantBuffer(data, size);
}
+void QSGD3D12Engine::markConstantBufferDirty(int offset, int size)
+{
+ d->markConstantBufferDirty(offset, size);
+}
+
void QSGD3D12Engine::queueViewport(const QRect &rect)
{
d->queueViewport(rect);
@@ -333,6 +338,59 @@ quint32 QSGD3D12Engine::alignedConstantBufferSize(quint32 size)
return (size + D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1) & ~(D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1);
}
+QSGD3D12Format QSGD3D12Engine::toDXGIFormat(QSGGeometry::Type sgtype, int tupleSize, int *size)
+{
+ QSGD3D12Format format = FmtUnknown;
+
+ static const QSGD3D12Format formatMap_ub[] = { FmtUnknown,
+ FmtUNormByte,
+ FmtUNormByte2,
+ FmtUnknown,
+ FmtUNormByte4 };
+
+ static const QSGD3D12Format formatMap_f[] = { FmtUnknown,
+ FmtFloat,
+ FmtFloat2,
+ FmtFloat3,
+ FmtFloat4 };
+
+ switch (sgtype) {
+ case QSGGeometry::TypeUnsignedByte:
+ format = formatMap_ub[tupleSize];
+ if (size)
+ *size = tupleSize;
+ break;
+ case QSGGeometry::TypeFloat:
+ format = formatMap_f[tupleSize];
+ if (size)
+ *size = sizeof(float) * tupleSize;
+ break;
+
+ case QSGGeometry::TypeUnsignedShort:
+ format = FmtUnsignedShort;
+ if (size)
+ *size = sizeof(ushort) * tupleSize;
+ break;
+ case QSGGeometry::TypeUnsignedInt:
+ format = FmtUnsignedInt;
+ if (size)
+ *size = sizeof(uint) * tupleSize;
+ break;
+
+ case QSGGeometry::TypeByte:
+ case QSGGeometry::TypeInt:
+ case QSGGeometry::TypeShort:
+ qWarning("no mapping for GL type 0x%x", sgtype);
+ break;
+
+ default:
+ qWarning("unknown GL type 0x%x", sgtype);
+ break;
+ }
+
+ return format;
+}
+
void QSGD3D12EnginePrivate::releaseResources()
{
if (!initialized)
@@ -661,10 +719,33 @@ void QSGD3D12EnginePrivate::beginFrame()
transitionResource(backBufferRT(), commandList.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
}
+void QSGD3D12EnginePrivate::updateBuffer(StagingBufferRef *br, ID3D12Resource *r, const char *dbgstr)
+{
+ quint8 *p = nullptr;
+ const D3D12_RANGE readRange = { 0, 0 };
+ if (!br->dirty.isEmpty()) {
+ if (FAILED(r->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed for %s buffer of size %d", dbgstr, br->size);
+ return;
+ }
+ for (const auto &r : qAsConst(br->dirty)) {
+ qDebug("%s o %d s %d", dbgstr, r.first, r.second);
+ memcpy(p + r.first, br->p + r.first, r.second);
+ }
+ r->Unmap(0, nullptr);
+ br->dirty.clear();
+ }
+}
+
void QSGD3D12EnginePrivate::endFrame()
{
qDebug() << "***** end frame";
+ // Now is the time to sync all the changed areas in the buffers.
+ updateBuffer(&vertexData, vertexBuffer.Get(), "vertex");
+ updateBuffer(&indexData, indexBuffer.Get(), "index");
+ updateBuffer(&constantData, constantBuffer.Get(), "constant");
+
transitionResource(backBufferRT(), commandList.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
HRESULT hr = commandList->Close();
@@ -754,17 +835,21 @@ void QSGD3D12EnginePrivate::setPipelineState(const QSGD3D12PipelineState &pipeli
psoDesc.RasterizerState = rastDesc;
- // ### this is wrong
- const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {
- TRUE, FALSE,
- D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD,
- D3D12_BLEND_ZERO, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
- D3D12_LOGIC_OP_NOOP,
- D3D12_COLOR_WRITE_ENABLE_ALL
- };
D3D12_BLEND_DESC blendDesc = {};
- blendDesc.RenderTarget[0] = defaultRenderTargetBlendDesc;
-
+ if (pipelineState.premulBlend) {
+ const D3D12_RENDER_TARGET_BLEND_DESC premulBlendDesc = {
+ TRUE, FALSE,
+ 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
+ };
+ blendDesc.RenderTarget[0] = premulBlendDesc;
+ } else {
+ D3D12_RENDER_TARGET_BLEND_DESC noBlendDesc = {};
+ noBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
+ blendDesc.RenderTarget[0] = noBlendDesc;
+ }
psoDesc.BlendState = blendDesc;
psoDesc.DepthStencilState.DepthEnable = pipelineState.depthEnable;
@@ -796,21 +881,26 @@ void QSGD3D12EnginePrivate::setVertexBuffer(const quint8 *data, int size)
{
vertexData.p = data;
vertexData.size = size;
- vertexData.changed = true;
+ vertexData.fullChange = true;
}
void QSGD3D12EnginePrivate::setIndexBuffer(const quint8 *data, int size)
{
indexData.p = data;
indexData.size = size;
- indexData.changed = true;
+ indexData.fullChange = true;
}
void QSGD3D12EnginePrivate::setConstantBuffer(const quint8 *data, int size)
{
constantData.p = data;
constantData.size = size;
- constantData.changed = true;
+ constantData.fullChange = true;
+}
+
+void QSGD3D12EnginePrivate::markConstantBufferDirty(int offset, int size)
+{
+ constantData.dirty.append(qMakePair(offset, size));
}
void QSGD3D12EnginePrivate::queueViewport(const QRect &rect)
@@ -847,72 +937,52 @@ void QSGD3D12EnginePrivate::queueDraw(QSGGeometry::DrawingMode mode, int count,
int cboOffset,
int startIndexIndex, QSGD3D12Format indexFormat)
{
- // Due to the simplistic way our current renderer works, we can just upload the
- // entire vertex/index data in case it was rebuilt.
-
- if (vertexData.changed) {
- vertexData.changed = false;
- qDebug("upload vertex");
+ // Ensure buffers are created but do not copy the data here, leave that to endFrame().
+ if (vertexData.fullChange) {
+ vertexData.fullChange = false;
// Only enlarge, never shrink
const bool newBufferNeeded = vertexBuffer ? (vertexData.size > vertexBuffer->GetDesc().Width) : true;
if (newBufferNeeded) {
qDebug("new vertex buffer of size %d", vertexData.size);
vertexBuffer.Attach(createBuffer(vertexData.size));
}
- if (!vertexBuffer)
- return;
- quint8 *p = nullptr;
- D3D12_RANGE readRange = { 0, 0 };
- if (FAILED(vertexBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
- qWarning("Map failed for buffer of size %d", vertexData.size);
+ vertexData.dirty.clear();
+ if (vertexBuffer)
+ vertexData.dirty.append(qMakePair(0, vertexData.size));
+ else
return;
- }
- memcpy(p, vertexData.p, vertexData.size);
- vertexBuffer->Unmap(0, nullptr);
}
- if (indexData.changed) {
- indexData.changed = false;
+ if (indexData.fullChange) {
+ indexData.fullChange = false;
if (indexData.size > 0) {
- qDebug("upload index");
const bool newBufferNeeded = indexBuffer ? (indexData.size > indexBuffer->GetDesc().Width) : true;
if (newBufferNeeded) {
qDebug("new index buffer of size %d", indexData.size);
indexBuffer.Attach(createBuffer(indexData.size));
}
- if (!indexBuffer)
+ indexData.dirty.clear();
+ if (indexBuffer)
+ indexData.dirty.append(qMakePair(0, indexData.size));
+ else
return;
- quint8 *p = nullptr;
- D3D12_RANGE readRange = { 0, 0 };
- if (FAILED(indexBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
- qWarning("Map failed for buffer of size %d", indexData.size);
- return;
- }
- memcpy(p, indexData.p, indexData.size);
- indexBuffer->Unmap(0, nullptr);
} else {
indexBuffer = nullptr;
}
}
- if (constantData.changed) {
- constantData.changed = false;
- qDebug("upload constant");
+ if (constantData.fullChange) {
+ constantData.fullChange = false;
const bool newBufferNeeded = constantBuffer ? (constantData.size > constantBuffer->GetDesc().Width) : true;
if (newBufferNeeded) {
qDebug("new constant buffer of size %d", constantData.size);
constantBuffer.Attach(createBuffer(constantData.size));
}
- if (!constantBuffer)
- return;
- quint8 *p = nullptr;
- D3D12_RANGE readRange = { 0, 0 };
- if (FAILED(constantBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
- qWarning("Map failed for buffer of size %d", constantData.size);
+ constantData.dirty.clear();
+ if (constantBuffer)
+ constantData.dirty.append(qMakePair(0, constantData.size));
+ else
return;
- }
- memcpy(p, constantData.p, constantData.size);
- constantBuffer->Unmap(0, nullptr);
}
if (cboOffset >= 0 && constantBuffer)
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h
index d5f038fd0c..52ca80a002 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h
@@ -200,6 +200,7 @@ public:
void setVertexBuffer(const quint8 *data, int size);
void setIndexBuffer(const quint8 *data, int size);
void setConstantBuffer(const quint8 *data, int size);
+ void markConstantBufferDirty(int offset, int size);
void queueViewport(const QRect &rect);
void queueScissor(const QRect &rect);
@@ -215,6 +216,7 @@ public:
void waitGPU();
static quint32 alignedConstantBufferSize(quint32 size);
+ static QSGD3D12Format toDXGIFormat(QSGGeometry::Type sgtype, int tupleSize = 1, int *size = nullptr);
private:
QSGD3D12EnginePrivate *d;
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h
index 733444339c..fd72c4f064 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h
@@ -150,6 +150,7 @@ public:
void setVertexBuffer(const quint8 *data, int size);
void setIndexBuffer(const quint8 *data, int size);
void setConstantBuffer(const quint8 *data, int size);
+ void markConstantBufferDirty(int offset, int size);
void queueViewport(const QRect &rect);
void queueScissor(const QRect &rect);
@@ -188,9 +189,13 @@ private:
struct StagingBufferRef {
const quint8 *p = nullptr;
int size = 0;
- bool changed = true;
+ bool fullChange = true;
+ QVector<QPair<int, int> > dirty;
+ StagingBufferRef() { dirty.reserve(256); }
};
+ void updateBuffer(StagingBufferRef *br, ID3D12Resource *r, const char *dbgstr);
+
bool initialized = false;
QWindow *window = nullptr;
int swapChainBufferCount = 2;
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12material.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12material.cpp
index e7cee712d3..d5b5861280 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12material.cpp
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12material.cpp
@@ -40,8 +40,8 @@
#include "qsgd3d12material_p.h"
#include <private/qsgrenderer_p.h>
-#include "hlsl_vs_vertexcolor.h"
-#include "hlsl_ps_vertexcolor.h"
+#include "vs_vertexcolor.hlslh"
+#include "ps_vertexcolor.hlslh"
QT_BEGIN_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp
index b063138d74..2e55f7ec0e 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp
@@ -39,7 +39,6 @@
#include "qsgd3d12renderer_p.h"
#include "qsgd3d12rendercontext_p.h"
-#include "qsgd3d12material_p.h"
#include <private/qsgnodeupdater_p.h>
QT_BEGIN_NAMESPACE
@@ -81,15 +80,15 @@ void QSGD3D12Renderer::renderScene(GLuint fboId)
QSGRenderer::renderScene(bindable);
}
-// Search through the node set and remove nodes that are leaves of other
+// Search through the node set and remove nodes that are descendants of other
// nodes in the same set.
-static QSet<QSGNode *> qsg_filterSubTree(const QSet<QSGNode *> &nodes, QSGRootNode *root)
+static QSet<QSGNode *> qsg_removeDescendants(const QSet<QSGNode *> &nodes, QSGRootNode *root)
{
QSet<QSGNode *> result = nodes;
for (QSGNode *node : nodes) {
QSGNode *n = node;
while (n != root) {
- if (result.contains(n)) {
+ if (n != node && result.contains(n)) {
result.remove(node);
break;
}
@@ -112,16 +111,42 @@ void QSGD3D12Renderer::updateMatrices(QSGNode *node, QSGTransformNode *xform)
tn->setCombinedMatrix(tn->matrix());
QSGNODE_TRAVERSE(node)
updateMatrices(child, tn);
-
} else {
if (node->type() == QSGNode::GeometryNodeType || node->type() == QSGNode::ClipNodeType) {
- static_cast<QSGBasicGeometryNode *>(node)->setMatrix(xform ? &xform->combinedMatrix() : 0);
+ m_nodeDirtyMap[node] |= QSGD3D12Material::RenderState::DirtyMatrix;
+ QSGBasicGeometryNode *gnode = static_cast<QSGBasicGeometryNode *>(node);
+ const QMatrix4x4 *newMatrix = xform ? &xform->combinedMatrix() : nullptr;
+ // NB the newMatrix ptr is usually the same as before as it just
+ // references the transform node's own matrix.
+ gnode->setMatrix(newMatrix);
}
QSGNODE_TRAVERSE(node)
updateMatrices(child, xform);
}
}
+void QSGD3D12Renderer::updateOpacities(QSGNode *node, float inheritedOpacity)
+{
+ if (node->isSubtreeBlocked())
+ return;
+
+ if (node->type() == QSGNode::OpacityNodeType) {
+ QSGOpacityNode *on = static_cast<QSGOpacityNode *>(node);
+ float combined = inheritedOpacity * on->opacity();
+ on->setCombinedOpacity(combined);
+ QSGNODE_TRAVERSE(node)
+ updateOpacities(child, combined);
+ } else {
+ if (node->type() == QSGNode::GeometryNodeType) {
+ m_nodeDirtyMap[node] |= QSGD3D12Material::RenderState::DirtyOpacity;
+ QSGGeometryNode *gn = static_cast<QSGGeometryNode *>(node);
+ gn->setInheritedOpacity(inheritedOpacity);
+ }
+ QSGNODE_TRAVERSE(node)
+ updateOpacities(child, inheritedOpacity);
+ }
+}
+
void QSGD3D12Renderer::buildRenderList(QSGNode *node, QSGClipNode *clip)
{
if (node->isSubtreeBlocked())
@@ -174,10 +199,12 @@ void QSGD3D12Renderer::render()
m_engine->beginFrame();
if (m_rebuild) {
- // This changes everything, so discard all cached states
m_rebuild = false;
+
m_dirtyTransformNodes.clear();
m_dirtyTransformNodes.insert(rootNode());
+ m_dirtyOpacityNodes.clear();
+ m_dirtyOpacityNodes.insert(rootNode());
m_renderList.reset();
m_vboData.reset();
@@ -188,6 +215,7 @@ void QSGD3D12Renderer::render()
m_engine->setVertexBuffer(m_vboData.data(), m_vboData.size());
m_engine->setIndexBuffer(m_iboData.data(), m_iboData.size());
+ m_engine->setConstantBuffer(m_cboData.data(), m_cboData.size());
if (Q_UNLIKELY(debug_build())) {
qDebug("renderList: %d elements in total", m_renderList.size());
@@ -199,7 +227,7 @@ void QSGD3D12Renderer::render()
}
if (m_dirtyTransformNodes.size()) {
- const QSet<QSGNode *> subTreeRoots = qsg_filterSubTree(m_dirtyTransformNodes, rootNode());
+ const QSet<QSGNode *> subTreeRoots = qsg_removeDescendants(m_dirtyTransformNodes, rootNode());
for (QSGNode *node : subTreeRoots) {
// First find the parent transform so we have the accumulated
// matrix up until this point.
@@ -217,6 +245,23 @@ void QSGD3D12Renderer::render()
}
}
+ if (m_dirtyOpacityNodes.size()) {
+ const QSet<QSGNode *> subTreeRoots = qsg_removeDescendants(m_dirtyOpacityNodes, rootNode());
+ for (QSGNode *node : subTreeRoots) {
+ float opacity = 1.0f;
+ QSGNode *n = node;
+ if (n->type() == QSGNode::OpacityNodeType)
+ n = node->parent();
+ while (n != rootNode() && n->type() != QSGNode::OpacityNodeType)
+ n = n->parent();
+ if (n != rootNode())
+ opacity = static_cast<QSGOpacityNode *>(n)->combinedOpacity();
+
+ updateOpacities(node, opacity);
+ }
+ m_dirtyOpaqueElements = true;
+ }
+
if (m_dirtyOpaqueElements) {
m_dirtyOpaqueElements = false;
m_opaqueElements.clear();
@@ -231,9 +276,17 @@ void QSGD3D12Renderer::render()
}
}
+ // Build pipeline state and draw calls.
renderElements();
+ m_dirtyTransformNodes.clear();
+ m_dirtyOpacityNodes.clear();
+ m_dirtyOpaqueElements = false;
+ m_nodeDirtyMap.clear();
+
+ // Finalize buffers and execute commands.
m_engine->endFrame();
+
m_engine = nullptr;
}
@@ -279,6 +332,9 @@ void QSGD3D12Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
if (state & QSGNode::DirtyMatrix)
m_dirtyTransformNodes << node;
+ if (state & QSGNode::DirtyOpacity)
+ m_dirtyOpacityNodes << node;
+
if (state & QSGNode::DirtyMaterial)
m_dirtyOpaqueElements = true;
@@ -302,11 +358,10 @@ void QSGD3D12Renderer::renderElements()
m_current_projection_matrix = projectionMatrix();
// First do opaque...
- // The algorithm is quite simple. We traverse the list back-to-from
- // and for every item, we start a second traversal from this point
- // and draw all elements which have identical material. Then we clear
- // the bit for this in the rendered list so we don't draw it again
- // when we come to that index.
+ // The algorithm is quite simple. We traverse the list back-to-front, and
+ // for every item we start a second traversal and draw all elements which
+ // have identical material. Then we clear the bit for this in the rendered
+ // list so we don't draw it again when we come to that index.
QBitArray rendered = m_opaqueElements;
for (int i = m_renderList.size() - 1; i >= 0; --i) {
if (rendered.testBit(i)) {
@@ -360,17 +415,16 @@ void QSGD3D12Renderer::renderElement(int elementIndex)
if (gn->inheritedOpacity() < 0.001f) // pretty much invisible, don't draw it
return;
- QSGD3D12Material::RenderState::DirtyStates dirtyState = QSGD3D12Material::RenderState::DirtyMatrix;
+ // Update the QSGRenderer members which the materials will access.
m_current_projection_matrix = projectionMatrix();
- qreal scale = 1.0 / m_renderList.size();
+ const float scale = 1.0 / m_renderList.size();
m_current_projection_matrix(2, 2) = scale;
m_current_projection_matrix(2, 3) = 1.0f - (elementIndex + 1) * scale;
m_current_model_view_matrix = gn->matrix() ? *gn->matrix() : QMatrix4x4();
m_current_determinant = m_current_model_view_matrix.determinant();
- if (gn->inheritedOpacity() != m_current_opacity) {
- m_current_opacity = gn->inheritedOpacity();
- dirtyState |= QSGD3D12Material::RenderState::DirtyOpacity;
- }
+ m_current_opacity = gn->inheritedOpacity();
+
+ QSGD3D12Material::RenderState::DirtyStates dirtyState = m_nodeDirtyMap.value(e.node);
const QSGGeometry *g = gn->geometry();
QSGD3D12Material *m = static_cast<QSGD3D12Material *>(gn->activeMaterial());
@@ -387,7 +441,7 @@ void QSGD3D12Renderer::renderElement(int elementIndex)
if (e.cboSize > 0)
cboPtr = m_cboData.data() + e.cboOffset;
- qDebug() << "ds" << dirtyState;
+ qDebug() << "dirtystate for" << e.node << "is" << dirtyState;
QSGD3D12Material::UpdateResults updRes = m->updatePipeline(QSGD3D12Material::makeRenderState(this, dirtyState),
&m_pipelineState.shaders,
cboPtr);
@@ -396,7 +450,7 @@ void QSGD3D12Renderer::renderElement(int elementIndex)
// root signature and communicate the need for SRVs or UAVs to the engine.
if (updRes.testFlag(QSGD3D12Material::UpdatedConstantBuffer))
- m_engine->setConstantBuffer(m_cboData.data(), m_cboData.size());
+ m_engine->markConstantBufferDirty(e.cboOffset, e.cboSize);
// Input element layout
m_pipelineState.inputElements.resize(g->attributeCount());
@@ -409,37 +463,11 @@ void QSGD3D12Renderer::renderElement(int elementIndex)
const int tupleSize = attrs[i].tupleSize;
ie.name = semanticNames[attrs[i].semantic];
ie.offset = offset;
- // ### move format mapping to engine
- static const QSGD3D12Format formatMap_ub[] = { FmtUnknown,
- FmtUNormByte,
- FmtUNormByte2,
- FmtUnknown,
- FmtUNormByte4 };
- static const QSGD3D12Format formatMap_f[] = { FmtUnknown,
- FmtFloat,
- FmtFloat2,
- FmtFloat3,
- FmtFloat4 };
- switch (attrs[i].type) {
- case QSGGeometry::TypeUnsignedByte:
- ie.format = formatMap_ub[tupleSize];
- offset += tupleSize;
- break;
- case QSGGeometry::TypeFloat:
- ie.format = formatMap_f[tupleSize];
- offset += sizeof(float) * tupleSize;
- break;
- case QSGGeometry::TypeByte:
- case QSGGeometry::TypeInt:
- case QSGGeometry::TypeUnsignedInt:
- case QSGGeometry::TypeShort:
- case QSGGeometry::TypeUnsignedShort:
- qFatal("QSGD3D12Renderer: attribute type 0x%x is not currently supported", attrs[i].type);
- break;
- }
+ int bytesPerTuple = 0;
+ ie.format = QSGD3D12Engine::toDXGIFormat(QSGGeometry::Type(attrs[i].type), tupleSize, &bytesPerTuple);
if (ie.format == FmtUnknown)
qFatal("QSGD3D12Renderer: unsupported tuple size for attribute type 0x%x", attrs[i].type);
-
+ offset += bytesPerTuple;
// There is one buffer with interleaved data so the slot is always 0.
ie.slot = 0;
}
@@ -451,20 +479,10 @@ void QSGD3D12Renderer::renderElement(int elementIndex)
m_engine->setPipelineState(m_pipelineState);
if (e.iboOffset >= 0) {
- // ### move format mapping to engine
- QSGD3D12Format indexFormat;
const QSGGeometry::Type indexType = QSGGeometry::Type(g->indexType());
- switch (indexType) {
- case QSGGeometry::TypeUnsignedShort:
- indexFormat = FmtUnsignedShort;
- break;
- case QSGGeometry::TypeUnsignedInt:
- indexFormat = FmtUnsignedInt;
- break;
- default:
- qFatal("QSGD3D12Renderer: unsupported index data type 0x%x", indexType);
- break;
- };
+ const QSGD3D12Format indexFormat = QSGD3D12Engine::toDXGIFormat(indexType);
+ if (indexFormat == FmtUnknown)
+ qFatal("QSGD3D12Renderer: unsupported index type 0x%x", indexType);
m_engine->queueDraw(QSGGeometry::DrawingMode(g->drawingMode()), g->indexCount(), e.vboOffset, g->sizeOfVertex(),
e.cboOffset,
e.iboOffset / e.iboStride, indexFormat);
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h
index a0ae99a2e0..e637dbbb9c 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h
@@ -54,6 +54,7 @@
#include <private/qsgrenderer_p.h>
#include <QtGui/private/qdatabuffer_p.h>
#include "qsgd3d12engine_p.h"
+#include "qsgd3d12material_p.h"
QT_BEGIN_NAMESPACE
@@ -68,6 +69,7 @@ public:
private:
void updateMatrices(QSGNode *node, QSGTransformNode *xform);
+ void updateOpacities(QSGNode *node, float inheritedOpacity);
void buildRenderList(QSGNode *node, QSGClipNode *clip);
void renderElements();
void renderElement(int elementIndex);
@@ -83,6 +85,7 @@ private:
};
QSet<QSGNode *> m_dirtyTransformNodes;
+ QSet<QSGNode *> m_dirtyOpacityNodes;
QBitArray m_opaqueElements;
bool m_rebuild = true;
bool m_dirtyOpaqueElements = true;
@@ -94,6 +97,9 @@ private:
QSGMaterialType *m_lastMaterialType = nullptr;
QSGD3D12PipelineState m_pipelineState;
+
+ typedef QHash<QSGNode *, QSGD3D12Material::RenderState::DirtyStates> NodeDirtyMap;
+ NodeDirtyMap m_nodeDirtyMap;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri b/src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri
index c3745cc682..6fc591cb33 100644
--- a/src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri
+++ b/src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri
@@ -1,10 +1,10 @@
vertexcolor_VSPS = $$PWD/vertexcolor.hlsl
vertexcolor_vshader.input = vertexcolor_VSPS
-vertexcolor_vshader.header = hlsl_vs_vertexcolor.h
+vertexcolor_vshader.header = vs_vertexcolor.hlslh
vertexcolor_vshader.entry = VS_VertexColor
vertexcolor_vshader.type = vs_5_0
vertexcolor_pshader.input = vertexcolor_VSPS
-vertexcolor_pshader.header = hlsl_ps_vertexcolor.h
+vertexcolor_pshader.header = ps_vertexcolor.hlslh
vertexcolor_pshader.entry = PS_VertexColor
vertexcolor_pshader.type = ps_5_0
diff --git a/tests/manual/nodetypes/main.qml b/tests/manual/nodetypes/main.qml
index c4d0a5266d..81d1e63ead 100644
--- a/tests/manual/nodetypes/main.qml
+++ b/tests/manual/nodetypes/main.qml
@@ -47,6 +47,28 @@ Item {
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 {