aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12builtinmaterials.cpp121
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12builtinmaterials_p.h23
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp103
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h2
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h11
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12glyphcache.cpp18
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12glyphnode.cpp22
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12material_p.h2
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp13
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h1
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri19
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/shaders/textmask.hlsl61
-rw-r--r--tests/manual/nodetypes/Text.qml10
13 files changed, 313 insertions, 93 deletions
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12builtinmaterials.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12builtinmaterials.cpp
index 009b63b4c7..2790bf48a9 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12builtinmaterials.cpp
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12builtinmaterials.cpp
@@ -53,9 +53,17 @@
#include "ps_textmask24.hlslh"
#include "ps_textmask32.hlslh"
#include "ps_textmask8.hlslh"
+#include "vs_styledtext.hlslh"
+#include "ps_styledtext.hlslh"
+#include "vs_outlinedtext.hlslh"
+#include "ps_outlinedtext.hlslh"
QT_BEGIN_NAMESPACE
+// NB! In HLSL constant buffer data is packed into 4-byte boundaries and, more
+// importantly, it is packed so that it does not cross a 16-byte (float4)
+// boundary. Hence the need for padding in some cases.
+
QSGMaterialType QSGD3D12VertexColorMaterial::mtype;
QSGMaterialType *QSGD3D12VertexColorMaterial::type() const
@@ -378,8 +386,10 @@ static inline int qsg_colorDiff(const QVector4D &a, const QVector4D &b)
return 0;
}
-QSGD3D12TextMaterial::QSGD3D12TextMaterial(QSGD3D12RenderContext *rc, const QRawFont &font, QFontEngine::GlyphFormat glyphFormat)
- : m_font(font),
+QSGD3D12TextMaterial::QSGD3D12TextMaterial(StyleType styleType, QSGD3D12RenderContext *rc,
+ const QRawFont &font, QFontEngine::GlyphFormat glyphFormat)
+ : m_styleType(styleType),
+ m_font(font),
m_rc(rc)
{
setFlag(Blending, true);
@@ -405,28 +415,39 @@ QSGD3D12TextMaterial::QSGD3D12TextMaterial(QSGD3D12RenderContext *rc, const QRaw
}
}
-QSGMaterialType QSGD3D12TextMaterial::mtype;
+QSGMaterialType QSGD3D12TextMaterial::mtype[QSGD3D12TextMaterial::NStyleTypes];
QSGMaterialType *QSGD3D12TextMaterial::type() const
{
- return &QSGD3D12TextMaterial::mtype;
+ return &QSGD3D12TextMaterial::mtype[m_styleType];
}
int QSGD3D12TextMaterial::compare(const QSGMaterial *other) const
{
Q_ASSERT(other && type() == other->type());
const QSGD3D12TextMaterial *o = static_cast<const QSGD3D12TextMaterial *>(other);
+ if (m_styleType != o->m_styleType)
+ return m_styleType - o->m_styleType;
if (m_glyphCache != o->m_glyphCache)
return m_glyphCache.data() < o->m_glyphCache.data() ? -1 : 1;
- return qsg_colorDiff(color(), o->color());
-}
-
-static const int TEXT_CB_SIZE_0 = 16 * sizeof(float); // float4x4
-static const int TEXT_CB_SIZE_1 = 2 * sizeof(float); // float2
-static const int TEXT_CB_SIZE_2 = sizeof(float); // float
-static const int TEXT_CB_SIZE_3 = sizeof(float); // float
-static const int TEXT_CB_SIZE_4 = 4 * sizeof(float); // float4
-static const int TEXT_CB_SIZE = TEXT_CB_SIZE_0 + TEXT_CB_SIZE_1 + TEXT_CB_SIZE_2 + TEXT_CB_SIZE_3 + TEXT_CB_SIZE_4;
+ if (m_styleShift != o->m_styleShift)
+ return m_styleShift.y() - o->m_styleShift.y();
+ int styleColorDiff = qsg_colorDiff(m_styleColor, o->m_styleColor);
+ if (styleColorDiff)
+ return styleColorDiff;
+ return qsg_colorDiff(m_color, o->m_color);
+}
+
+static const int TEXT_CB_SIZE_0 = 16 * sizeof(float); // float4x4 mvp
+static const int TEXT_CB_SIZE_1 = 2 * sizeof(float); // float2 textureScale
+static const int TEXT_CB_SIZE_2 = sizeof(float); // float dpr
+static const int TEXT_CB_SIZE_3 = sizeof(float); // float color
+static const int TEXT_CB_SIZE_4 = 4 * sizeof(float); // float4 colorVec
+static const int TEXT_CB_SIZE_5 = 2 * sizeof(float); // float2 shift
+static const int TEXT_CB_SIZE_5_PADDING = 2 * sizeof(float); // float2 padding (the next float4 would cross the 16-byte boundary)
+static const int TEXT_CB_SIZE_6 = 4 * sizeof(float); // float4 styleColor
+static const int TEXT_CB_SIZE = TEXT_CB_SIZE_0 + TEXT_CB_SIZE_1 + TEXT_CB_SIZE_2 + TEXT_CB_SIZE_3
+ + TEXT_CB_SIZE_4 + TEXT_CB_SIZE_5 + TEXT_CB_SIZE_5_PADDING + TEXT_CB_SIZE_6;
int QSGD3D12TextMaterial::constantBufferSize() const
{
@@ -435,22 +456,33 @@ int QSGD3D12TextMaterial::constantBufferSize() const
void QSGD3D12TextMaterial::preparePipeline(QSGD3D12PipelineState *pipelineState)
{
- pipelineState->shaders.vs = g_VS_TextMask;
- pipelineState->shaders.vsSize = sizeof(g_VS_TextMask);
-
- switch (glyphCache()->glyphFormat()) {
- case QFontEngine::Format_A32:
- pipelineState->shaders.ps = g_PS_TextMask24;
- pipelineState->shaders.psSize = sizeof(g_PS_TextMask24);
- break;
- case QFontEngine::Format_ARGB:
- pipelineState->shaders.ps = g_PS_TextMask32;
- pipelineState->shaders.psSize = sizeof(g_PS_TextMask32);
- break;
- default:
- pipelineState->shaders.ps = g_PS_TextMask8;
- pipelineState->shaders.psSize = sizeof(g_PS_TextMask8);
- break;
+ if (m_styleType == Normal) {
+ pipelineState->shaders.vs = g_VS_TextMask;
+ pipelineState->shaders.vsSize = sizeof(g_VS_TextMask);
+ switch (glyphCache()->glyphFormat()) {
+ case QFontEngine::Format_A32:
+ pipelineState->shaders.ps = g_PS_TextMask24;
+ pipelineState->shaders.psSize = sizeof(g_PS_TextMask24);
+ break;
+ case QFontEngine::Format_ARGB:
+ pipelineState->shaders.ps = g_PS_TextMask32;
+ pipelineState->shaders.psSize = sizeof(g_PS_TextMask32);
+ break;
+ default:
+ pipelineState->shaders.ps = g_PS_TextMask8;
+ pipelineState->shaders.psSize = sizeof(g_PS_TextMask8);
+ break;
+ }
+ } else if (m_styleType == Outlined) {
+ pipelineState->shaders.vs = g_VS_OutlinedText;
+ pipelineState->shaders.vsSize = sizeof(g_VS_OutlinedText);
+ pipelineState->shaders.ps = g_PS_OutlinedText;
+ pipelineState->shaders.psSize = sizeof(g_PS_OutlinedText);
+ } else {
+ pipelineState->shaders.vs = g_VS_StyledText;
+ pipelineState->shaders.vsSize = sizeof(g_VS_StyledText);
+ pipelineState->shaders.ps = g_PS_StyledText;
+ pipelineState->shaders.psSize = sizeof(g_PS_StyledText);
}
pipelineState->shaders.rootSig.textureViews.resize(1);
@@ -464,9 +496,16 @@ QSGD3D12Material::UpdateResults QSGD3D12TextMaterial::updatePipeline(const Rende
QSGD3D12Material::UpdateResults r = 0;
quint8 *p = constantBuffer;
- pipelineState->blend = QSGD3D12PipelineState::BlendColor;
- extraState->blendFactor = m_color;
- r |= UpdatedBlendFactor; // must be set always as this affects the command list
+ if (glyphCache()->glyphFormat() == QFontEngine::Format_A32) {
+ pipelineState->blend = QSGD3D12PipelineState::BlendColor;
+ extraState->blendFactor = m_color;
+ r |= UpdatedBlendFactor; // must be set always as this affects the command list
+ }
+
+ if (state.isConstantBufferDirty()) { // only used to avoid flags like bool m_isLastStyleShiftValid
+ memset(p, 0, TEXT_CB_SIZE);
+ r |= UpdatedConstantBuffer;
+ }
if (state.isMatrixDirty()) {
memcpy(p, state.combinedMatrix().constData(), TEXT_CB_SIZE_0);
@@ -507,6 +546,24 @@ QSGD3D12Material::UpdateResults QSGD3D12TextMaterial::updatePipeline(const Rende
}
r |= UpdatedConstantBuffer;
}
+ p += TEXT_CB_SIZE_3 + TEXT_CB_SIZE_4;
+
+ if (m_styleType == Styled && m_lastStyleShift != m_styleShift) {
+ m_lastStyleShift = m_styleShift;
+ const float f[2] = { m_styleShift.x(), m_styleShift.y() };
+ memcpy(p, f, TEXT_CB_SIZE_5);
+ r |= UpdatedConstantBuffer;
+ }
+ p += TEXT_CB_SIZE_5 + TEXT_CB_SIZE_5_PADDING;
+
+ if ((m_styleType == Styled || m_styleType == Outlined)
+ && (state.isOpacityDirty() || m_lastStyleColor != m_styleColor)) {
+ m_lastStyleColor = m_styleColor;
+ const QVector4D color = qsg_premultiply(m_styleColor, state.opacity());
+ const float f[4] = { color.x(), color.y(), color.z(), color.w() };
+ memcpy(p, f, TEXT_CB_SIZE_6);
+ r |= UpdatedConstantBuffer;
+ }
QSGD3D12TextureView &tv(pipelineState->shaders.rootSig.textureViews[0]);
tv.filter = QSGD3D12TextureView::FilterNearest;
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12builtinmaterials_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12builtinmaterials_p.h
index c1de9edeaf..49c710b504 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12builtinmaterials_p.h
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12builtinmaterials_p.h
@@ -176,7 +176,14 @@ private:
class QSGD3D12TextMaterial : public QSGD3D12Material
{
public:
- QSGD3D12TextMaterial(QSGD3D12RenderContext *rc, const QRawFont &font,
+ enum StyleType {
+ Normal,
+ Styled,
+ Outlined,
+
+ NStyleTypes
+ };
+ QSGD3D12TextMaterial(StyleType styleType, QSGD3D12RenderContext *rc, const QRawFont &font,
QFontEngine::GlyphFormat glyphFormat = QFontEngine::Format_None);
QSGMaterialType *type() const override;
@@ -193,6 +200,13 @@ public:
void setColor(const QVector4D &color) { m_color = color; }
const QVector4D &color() const { return m_color; }
+ void setStyleShift(const QVector2D &shift) { m_styleShift = shift; }
+ const QVector2D &styleShift() const { return m_styleShift; }
+
+ void setStyleColor(const QColor &c) { m_styleColor = QVector4D(c.redF(), c.greenF(), c.blueF(), c.alphaF()); }
+ void setStyleColor(const QVector4D &color) { m_styleColor = color; }
+ const QVector4D &styleColor() const { return m_styleColor; }
+
void populate(const QPointF &position,
const QVector<quint32> &glyphIndexes, const QVector<QPointF> &glyphPositions,
QSGGeometry *geometry, QRectF *boundingRect, QPointF *baseLine,
@@ -201,14 +215,19 @@ public:
QSGD3D12GlyphCache *glyphCache() const { return static_cast<QSGD3D12GlyphCache *>(m_glyphCache.data()); }
private:
- static QSGMaterialType mtype;
+ static QSGMaterialType mtype[NStyleTypes];
+ StyleType m_styleType;
QSGD3D12RenderContext *m_rc;
QVector4D m_color;
+ QVector2D m_styleShift;
+ QVector4D m_styleColor;
QRawFont m_font;
QExplicitlySharedDataPointer<QFontEngineGlyphCache> m_glyphCache;
QSize m_lastGlyphCacheSize;
float m_lastDpr = 0;
QVector4D m_lastColor;
+ QVector2D m_lastStyleShift;
+ QVector4D m_lastStyleColor;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp
index e6f0fda28e..f0ac2eee15 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp
@@ -428,9 +428,9 @@ void QSGD3D12Engine::createTexture(uint id, const QSize &size, QImage::Format fo
d->createTexture(id, size, format, flags);
}
-void QSGD3D12Engine::queueResizeTexture(uint id, const QSize &size)
+void QSGD3D12Engine::queueTextureResize(uint id, const QSize &size)
{
- d->queueResizeTexture(id, size);
+ d->queueTextureResize(id, size);
}
void QSGD3D12Engine::queueTextureUpload(uint id, const QImage &image, const QPoint &dstPos)
@@ -1099,14 +1099,6 @@ void QSGD3D12EnginePrivate::beginFrame()
copyCommandAllocator->Reset();
}
}
- if (!pfd.pendingTextureReleases.isEmpty()) {
- for (uint id : qAsConst(pfd.pendingTextureReleases)) {
- Texture &t(textures[id - 1]);
- t.entryInUse = false; // createTexture() can now reuse this entry
- t.texture = nullptr;
- }
- pfd.pendingTextureReleases.clear();
- }
// Do the deferred deletes.
if (!pfd.deleteQueue.isEmpty()) {
@@ -1120,6 +1112,28 @@ void QSGD3D12EnginePrivate::beginFrame()
}
pfd.deleteQueue.clear();
}
+ // Deferred deletes issued outside a begin-endFrame go to the next
+ // frame's out-of-frame delete queue as these cannot be executed in the
+ // next beginFrame, only in next + MAX_FRAMES_IN_FLIGHT. Move to the
+ // normal queue if this is the next beginFrame.
+ if (!pfd.outOfFrameDeleteQueue.isEmpty()) {
+ pfd.deleteQueue = pfd.outOfFrameDeleteQueue;
+ pfd.outOfFrameDeleteQueue.clear();
+ }
+
+ // Mark released texture slots free.
+ if (!pfd.pendingTextureReleases.isEmpty()) {
+ for (uint id : qAsConst(pfd.pendingTextureReleases)) {
+ Texture &t(textures[id - 1]);
+ t.entryInUse = false; // createTexture() can now reuse this entry
+ t.texture = nullptr;
+ }
+ pfd.pendingTextureReleases.clear();
+ }
+ if (!pfd.outOfFramePendingTextureReleases.isEmpty()) {
+ pfd.pendingTextureReleases = pfd.outOfFramePendingTextureReleases;
+ pfd.outOfFramePendingTextureReleases.clear();
+ }
}
beginDrawCalls(true);
@@ -1673,7 +1687,7 @@ void QSGD3D12EnginePrivate::ensureGPUDescriptorHeap(int cbvSrvUavDescriptorCount
if (newSize != pfd.gpuCbvSrvUavHeapSize) {
if (Q_UNLIKELY(debug_render()))
qDebug("Out of space for SRVs, creating new CBV-SRV-UAV descriptor heap with descriptor count %d", newSize);
- pfd.deferredDelete(pfd.gpuCbvSrvUavHeap);
+ deferredDelete(pfd.gpuCbvSrvUavHeap);
createCbvSrvUavHeap(currentPFrameIndex, newSize);
setDescriptorHeaps(true);
pfd.cbvSrvUavNextFreeDescriptorIndex = 0;
@@ -1742,8 +1756,10 @@ static inline DXGI_FORMAT textureFormat(QImage::Format format, bool wantsAlpha,
if (!mipmap) {
switch (format) {
+ case QImage::Format_Grayscale8:
case QImage::Format_Indexed8:
- f = DXGI_FORMAT_A8_UNORM;
+ case QImage::Format_Alpha8:
+ f = DXGI_FORMAT_R8_UNORM;
bpp = 1;
break;
case QImage::Format_RGB32:
@@ -1838,11 +1854,8 @@ void QSGD3D12EnginePrivate::createTexture(uint id, const QSize &size, QImage::Fo
qDebug("created texture %u, size %dx%d, miplevels %d", id, adjustedSize.width(), adjustedSize.height(), textureDesc.MipLevels);
}
-void QSGD3D12EnginePrivate::queueResizeTexture(uint id, const QSize &size)
+void QSGD3D12EnginePrivate::queueTextureResize(uint id, const QSize &size)
{
- // This function can safely be called outside begin-endFrame, even though
- // it uses currentPFrameIndex.
-
Q_ASSERT(id);
const int idx = id - 1;
Q_ASSERT(idx < textures.count() && textures[idx].entryInUse);
@@ -1861,8 +1874,6 @@ void QSGD3D12EnginePrivate::queueResizeTexture(uint id, const QSize &size)
if (Q_UNLIKELY(debug_render()))
qDebug("resizing texture %u, size %dx%d", id, size.width(), size.height());
- PersistentFrameData &pfd(pframeData[currentPFrameIndex]);
-
D3D12_RESOURCE_DESC textureDesc = t.texture->GetDesc();
textureDesc.Width = size.width();
textureDesc.Height = size.height();
@@ -1871,8 +1882,7 @@ void QSGD3D12EnginePrivate::queueResizeTexture(uint id, const QSize &size)
defaultHeapProp.Type = D3D12_HEAP_TYPE_DEFAULT;
ComPtr<ID3D12Resource> oldTexture = t.texture;
- // release the old one only in current_frame + 2
- pfd.deferredDelete(t.texture);
+ deferredDelete(t.texture);
HRESULT hr = device->CreateCommittedResource(&defaultHeapProp, D3D12_HEAP_FLAG_NONE, &textureDesc,
D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&t.texture));
@@ -1881,7 +1891,7 @@ void QSGD3D12EnginePrivate::queueResizeTexture(uint id, const QSize &size)
return;
}
- pfd.deferredDelete(t.srv);
+ deferredDelete(t.srv);
t.srv = cpuDescHeapManager.allocate(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
@@ -1987,6 +1997,8 @@ void QSGD3D12EnginePrivate::queueTextureUpload(uint id, const QVector<QImage> &i
QImage::Format convFormat;
int bytesPerPixel;
textureFormat(images[i].format(), t.alpha, t.mipmap, &convFormat, &bytesPerPixel);
+ if (Q_UNLIKELY(debug_render() && i == 0))
+ qDebug("source image format %d, target format %d, bpp %d", images[i].format(), convFormat, bytesPerPixel);
QImage convImage = images[i].format() == convFormat ? images[i] : images[i].convertToFormat(convFormat);
@@ -2020,7 +2032,7 @@ void QSGD3D12EnginePrivate::queueTextureUpload(uint id, const QVector<QImage> &i
return;
}
for (int y = 0, ye = convImage.height(); y < ye; ++y) {
- memcpy(p, convImage.scanLine(y), convImage.width() * bytesPerPixel);
+ memcpy(p, convImage.constScanLine(y), convImage.width() * bytesPerPixel);
p += stride;
}
sbuf.buffer->Unmap(0, nullptr);
@@ -2054,9 +2066,6 @@ void QSGD3D12EnginePrivate::queueTextureUpload(uint id, const QVector<QImage> &i
void QSGD3D12EnginePrivate::releaseTexture(uint id)
{
- // This function can safely be called outside begin-endFrame, even though
- // it uses currentPFrameIndex.
-
if (!id)
return;
@@ -2070,16 +2079,18 @@ void QSGD3D12EnginePrivate::releaseTexture(uint id)
if (!t.entryInUse)
return;
- PersistentFrameData &pfd(pframeData[currentPFrameIndex]);
-
if (t.texture) {
- pfd.deferredDelete(t.texture);
- pfd.deferredDelete(t.srv);
+ deferredDelete(t.texture);
+ deferredDelete(t.srv);
for (D3D12_CPU_DESCRIPTOR_HANDLE h : t.mipUAVs)
- pfd.deferredDelete(h);
+ deferredDelete(h);
}
- pfd.pendingTextureReleases.insert(id);
+ QSet<uint> *pendingTextureReleasesSet = inFrame
+ ? &pframeData[currentPFrameIndex].pendingTextureReleases
+ : &pframeData[(currentPFrameIndex + 1) % MAX_FRAMES_IN_FLIGHT].outOfFramePendingTextureReleases;
+
+ pendingTextureReleasesSet->insert(id);
}
SIZE_T QSGD3D12EnginePrivate::textureSRV(uint id) const
@@ -2254,4 +2265,34 @@ void QSGD3D12EnginePrivate::MipMapGen::queueGenerate(const Texture &t)
pfd.cbvSrvUavNextFreeDescriptorIndex += descriptorCount;
}
+void QSGD3D12EnginePrivate::deferredDelete(ComPtr<ID3D12Resource> res)
+{
+ PersistentFrameData::DeleteQueueEntry e;
+ e.res = res;
+ QVector<PersistentFrameData::DeleteQueueEntry> *dq = inFrame
+ ? &pframeData[currentPFrameIndex].deleteQueue
+ : &pframeData[(currentPFrameIndex + 1) % MAX_FRAMES_IN_FLIGHT].outOfFrameDeleteQueue;
+ (*dq) << e;
+}
+
+void QSGD3D12EnginePrivate::deferredDelete(ComPtr<ID3D12DescriptorHeap> dh)
+{
+ PersistentFrameData::DeleteQueueEntry e;
+ e.descHeap = dh;
+ QVector<PersistentFrameData::DeleteQueueEntry> *dq = inFrame
+ ? &pframeData[currentPFrameIndex].deleteQueue
+ : &pframeData[(currentPFrameIndex + 1) % MAX_FRAMES_IN_FLIGHT].outOfFrameDeleteQueue;
+ (*dq) << e;
+}
+
+void QSGD3D12EnginePrivate::deferredDelete(D3D12_CPU_DESCRIPTOR_HANDLE h)
+{
+ PersistentFrameData::DeleteQueueEntry e;
+ e.cpuDescriptorPtr = h.ptr;
+ QVector<PersistentFrameData::DeleteQueueEntry> *dq = inFrame
+ ? &pframeData[currentPFrameIndex].deleteQueue
+ : &pframeData[(currentPFrameIndex + 1) % MAX_FRAMES_IN_FLIGHT].outOfFrameDeleteQueue;
+ (*dq) << e;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h
index a89a0beeb8..7236053cf4 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h
@@ -317,7 +317,7 @@ public:
uint genTexture();
void createTexture(uint id, const QSize &size, QImage::Format format, TextureCreateFlags flags);
- void queueResizeTexture(uint id, const QSize &size);
+ void queueTextureResize(uint id, const QSize &size);
void queueTextureUpload(uint id, const QImage &image, const QPoint &dstPos = QPoint());
void queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos);
void releaseTexture(uint id);
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h
index bdd616b967..573dbded8e 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h
@@ -166,7 +166,7 @@ public:
uint genTexture();
void createTexture(uint id, const QSize &size, QImage::Format format, QSGD3D12Engine::TextureCreateFlags flags);
- void queueResizeTexture(uint id, const QSize &size);
+ void queueTextureResize(uint id, const QSize &size);
void queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos);
void releaseTexture(uint id);
SIZE_T textureSRV(uint id) const;
@@ -222,17 +222,20 @@ private:
QSet<uint> pendingTextureUploads;
QSet<uint> pendingTextureMipMap;
QSet<uint> pendingTextureReleases;
+ QSet<uint> outOfFramePendingTextureReleases;
struct DeleteQueueEntry {
ComPtr<ID3D12Resource> res;
ComPtr<ID3D12DescriptorHeap> descHeap;
SIZE_T cpuDescriptorPtr = 0;
};
QVector<DeleteQueueEntry> deleteQueue;
- void deferredDelete(ComPtr<ID3D12Resource> res) { DeleteQueueEntry e; e.res = res; deleteQueue << e; }
- void deferredDelete(ComPtr<ID3D12DescriptorHeap> dh) { DeleteQueueEntry e; e.descHeap = dh; deleteQueue << e; }
- void deferredDelete(D3D12_CPU_DESCRIPTOR_HANDLE h) { DeleteQueueEntry e; e.cpuDescriptorPtr = h.ptr; deleteQueue << e; }
+ QVector<DeleteQueueEntry> outOfFrameDeleteQueue;
};
+ void deferredDelete(ComPtr<ID3D12Resource> res);
+ void deferredDelete(ComPtr<ID3D12DescriptorHeap> dh);
+ void deferredDelete(D3D12_CPU_DESCRIPTOR_HANDLE h);
+
void markCPUBufferDirty(CPUBufferRef *dst, PersistentFrameData::ChangeTrackedBuffer *buf, int offset, int size);
void ensureBuffer(CPUBufferRef *src, PersistentFrameData::ChangeTrackedBuffer *buf, const char *dbgstr);
void updateBuffer(CPUBufferRef *src, PersistentFrameData::ChangeTrackedBuffer *buf, const char *dbgstr);
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12glyphcache.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12glyphcache.cpp
index 5401f056d0..373e16d7c4 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12glyphcache.cpp
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12glyphcache.cpp
@@ -64,24 +64,36 @@ QSGD3D12GlyphCache::~QSGD3D12GlyphCache()
void QSGD3D12GlyphCache::createTextureData(int width, int height)
{
+ width = qMax(128, width);
+ height = qMax(32, height);
+
m_id = m_engine->genTexture();
Q_ASSERT(m_id);
if (Q_UNLIKELY(debug_render()))
- qDebug("new glyph cache texture %u of size %dx%d", m_id, width, height);
+ qDebug("new glyph cache texture %u of size %dx%d, fontengine format %d", m_id, width, height, m_format);
m_size = QSize(width, height);
- m_engine->createTexture(m_id, m_size, QImage::Format_ARGB32_Premultiplied, QSGD3D12Engine::CreateWithAlpha);
+
+ const QImage::Format imageFormat =
+ m_format == QFontEngine::Format_A8 ? QImage::Format_Alpha8 : QImage::Format_ARGB32_Premultiplied;
+ m_engine->createTexture(m_id, m_size, imageFormat, QSGD3D12Engine::CreateWithAlpha);
}
void QSGD3D12GlyphCache::resizeTextureData(int width, int height)
{
+ width = qMax(128, width);
+ height = qMax(32, height);
+
+ if (m_size.width() >= width && m_size.height() >= height)
+ return;
+
if (Q_UNLIKELY(debug_render()))
qDebug("glyph cache texture %u resize to %dx%d", m_id, width, height);
m_size = QSize(width, height);
- m_engine->queueResizeTexture(m_id, m_size);
+ m_engine->queueTextureResize(m_id, m_size);
}
void QSGD3D12GlyphCache::beginFillTexture()
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12glyphnode.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12glyphnode.cpp
index c5e53219fa..e559739018 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12glyphnode.cpp
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12glyphnode.cpp
@@ -54,25 +54,25 @@ void QSGD3D12GlyphNode::update()
if (m_style == QQuickText::Normal) {
// QSGBasicGlyphNode dtor will delete
- m_material = new QSGD3D12TextMaterial(m_rc, font);
+ m_material = new QSGD3D12TextMaterial(QSGD3D12TextMaterial::Normal, m_rc, font);
} else if (m_style == QQuickText::Outline) {
- // ### not yet supported
-// QSGOutlinedTextMaterial *material = new QSGOutlinedTextMaterial(font);
-// material->setStyleColor(m_styleColor);
-// m_material = material;
+ QSGD3D12TextMaterial *material = new QSGD3D12TextMaterial(QSGD3D12TextMaterial::Outlined,
+ m_rc, font, QFontEngine::Format_A8);
+ material->setStyleColor(m_styleColor);
+ m_material = material;
margins = QMargins(1, 1, 1, 1);
} else {
- // ### not yet supported
-// QSGStyledTextMaterial *material = new QSGStyledTextMaterial(font);
+ QSGD3D12TextMaterial *material = new QSGD3D12TextMaterial(QSGD3D12TextMaterial::Styled,
+ m_rc, font, QFontEngine::Format_A8);
if (m_style == QQuickText::Sunken) {
-// material->setStyleShift(QVector2D(0, -1));
+ material->setStyleShift(QVector2D(0, -1));
margins.setTop(1);
} else if (m_style == QQuickText::Raised) {
-// material->setStyleShift(QVector2D(0, 1));
+ material->setStyleShift(QVector2D(0, 1));
margins.setBottom(1);
}
-// material->setStyleColor(m_styleColor);
-// m_material = material;
+ material->setStyleColor(m_styleColor);
+ m_material = material;
}
QSGD3D12TextMaterial *textMaterial = static_cast<QSGD3D12TextMaterial *>(m_material);
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12material_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12material_p.h
index 307f73bbde..ce64799bc6 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12material_p.h
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12material_p.h
@@ -69,6 +69,7 @@ public:
enum DirtyState {
DirtyMatrix = 0x0001,
DirtyOpacity = 0x0002,
+ DirtyConstantBuffer = 0x0004,
DirtyAll = 0xFFFF
};
Q_DECLARE_FLAGS(DirtyStates, DirtyState)
@@ -77,6 +78,7 @@ public:
bool isMatrixDirty() const { return m_dirty & DirtyMatrix; }
bool isOpacityDirty() const { return m_dirty & DirtyOpacity; }
+ bool isConstantBufferDirty() const { return m_dirty & DirtyConstantBuffer; }
float opacity() const;
QMatrix4x4 combinedMatrix() const;
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp
index d766aab2d8..79db0eba42 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp
@@ -74,6 +74,7 @@ QSGD3D12Renderer::QSGD3D12Renderer(QSGRenderContext *context)
m_cboData(4096)
{
setNodeUpdater(new DummyUpdater);
+ m_freshPipelineState.shaders.rootSig.textureViews.reserve(4);
}
void QSGD3D12Renderer::renderScene(GLuint fboId)
@@ -365,9 +366,9 @@ void QSGD3D12Renderer::renderElements()
m_engine->queueClearRenderTarget(clearColor());
m_engine->queueClearDepthStencil(1, 0, QSGD3D12Engine::ClearDepth | QSGD3D12Engine::ClearStencil);
- m_pipelineState.blend = QSGD3D12PipelineState::BlendNone;
- m_pipelineState.depthEnable = true;
- m_pipelineState.depthWrite = true;
+ m_pipelineState.blend = m_freshPipelineState.blend = QSGD3D12PipelineState::BlendNone;
+ m_pipelineState.depthEnable = m_freshPipelineState.depthEnable = true;
+ m_pipelineState.depthWrite = m_freshPipelineState.depthWrite = true;
// First do opaque...
// The algorithm is quite simple. We traverse the list back-to-front, and
@@ -400,8 +401,8 @@ void QSGD3D12Renderer::renderElements()
}
}
- m_pipelineState.blend = QSGD3D12PipelineState::BlendPremul;
- m_pipelineState.depthWrite = false;
+ m_pipelineState.blend = m_freshPipelineState.blend = QSGD3D12PipelineState::BlendPremul;
+ m_pipelineState.depthWrite = m_freshPipelineState.depthWrite = false;
// ...then the alpha ones
for (int i = 0; i < m_renderList.size(); ++i) {
@@ -440,7 +441,7 @@ void QSGD3D12Renderer::renderElement(int elementIndex)
QSGD3D12Material *m = static_cast<QSGD3D12Material *>(gn->activeMaterial());
if (m->type() != m_lastMaterialType) {
- m_pipelineState.shaders.rootSig.textureViews.clear();
+ m_pipelineState = m_freshPipelineState;
m->preparePipeline(&m_pipelineState);
}
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h
index 81273ff84f..e1dc6bf78e 100644
--- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h
@@ -103,6 +103,7 @@ private:
QSGMaterialType *m_lastMaterialType = nullptr;
QSGD3D12PipelineState m_pipelineState;
+ QSGD3D12PipelineState m_freshPipelineState;
typedef QHash<QSGNode *, QSGD3D12Material::RenderState::DirtyStates> NodeDirtyMap;
NodeDirtyMap m_nodeDirtyMap;
diff --git a/src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri b/src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri
index 7de8708907..02786e2606 100644
--- a/src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri
+++ b/src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri
@@ -71,6 +71,22 @@ textmask_pshader8.input = textmask_VSPS
textmask_pshader8.header = ps_textmask8.hlslh
textmask_pshader8.entry = PS_TextMask8
textmask_pshader8.type = ps_5_0
+styledtext_vshader.input = textmask_VSPS
+styledtext_vshader.header = vs_styledtext.hlslh
+styledtext_vshader.entry = VS_StyledText
+styledtext_vshader.type = vs_5_0
+styledtext_pshader.input = textmask_VSPS
+styledtext_pshader.header = ps_styledtext.hlslh
+styledtext_pshader.entry = PS_StyledText
+styledtext_pshader.type = ps_5_0
+outlinedtext_vshader.input = textmask_VSPS
+outlinedtext_vshader.header = vs_outlinedtext.hlslh
+outlinedtext_vshader.entry = VS_OutlinedText
+outlinedtext_vshader.type = vs_5_0
+outlinedtext_pshader.input = textmask_VSPS
+outlinedtext_pshader.header = ps_outlinedtext.hlslh
+outlinedtext_pshader.entry = PS_OutlinedText
+outlinedtext_pshader.type = ps_5_0
HLSL_SHADERS = \
vertexcolor_vshader vertexcolor_pshader \
@@ -79,6 +95,7 @@ HLSL_SHADERS = \
texture_vshader texture_pshader \
smoothtexture_vshader smoothtexture_pshader \
mipmapgen_cshader \
- textmask_vshader textmask_pshader24 textmask_pshader32 textmask_pshader8
+ textmask_vshader textmask_pshader24 textmask_pshader32 textmask_pshader8 \
+ styledtext_vshader styledtext_pshader outlinedtext_vshader outlinedtext_pshader
load(hlsl_bytecode_header)
diff --git a/src/quick/scenegraph/adaptations/d3d12/shaders/textmask.hlsl b/src/quick/scenegraph/adaptations/d3d12/shaders/textmask.hlsl
index e6df7569ca..f9d92e8ee9 100644
--- a/src/quick/scenegraph/adaptations/d3d12/shaders/textmask.hlsl
+++ b/src/quick/scenegraph/adaptations/d3d12/shaders/textmask.hlsl
@@ -10,7 +10,9 @@ cbuffer ConstantBuffer : register(b0)
float2 textureScale;
float dpr;
float color; // for TextMask24 and 32
- float4 colorVec; // for TextMask8
+ float4 colorVec; // for TextMask8 and Styled and Outlined
+ float2 shift; // for Styled
+ float4 styleColor; // for Styled and Outlined
};
struct PSInput
@@ -43,5 +45,60 @@ float4 PS_TextMask32(PSInput input) : SV_TARGET
float4 PS_TextMask8(PSInput input) : SV_TARGET
{
- return colorVec * tex.Sample(samp, input.coord).a;
+ return colorVec * tex.Sample(samp, input.coord).r;
+}
+
+struct StyledPSInput
+{
+ float4 position : SV_POSITION;
+ float2 coord : TEXCOORD0;
+ float2 shiftedCoord : TEXCOORD1;
+};
+
+StyledPSInput VS_StyledText(VSInput input)
+{
+ StyledPSInput result;
+ result.position = mul(mvp, floor(input.position * dpr + 0.5) / dpr);
+ result.coord = input.coord * textureScale;
+ result.shiftedCoord = (input.coord - shift) * textureScale;
+ return result;
+}
+
+float4 PS_StyledText(StyledPSInput input) : SV_TARGET
+{
+ float glyph = tex.Sample(samp, input.coord).r;
+ float style = clamp(tex.Sample(samp, input.shiftedCoord).r - glyph, 0.0, 1.0);
+ return style * styleColor + glyph * colorVec;
+}
+
+struct OutlinedPSInput
+{
+ float4 position : SV_POSITION;
+ float2 coord : TEXCOORD0;
+ float2 coordUp : TEXCOORD1;
+ float2 coordDown : TEXCOORD2;
+ float2 coordLeft : TEXCOORD3;
+ float2 coordRight : TEXCOORD4;
+};
+
+OutlinedPSInput VS_OutlinedText(VSInput input)
+{
+ OutlinedPSInput result;
+ result.position = mul(mvp, floor(input.position * dpr + 0.5) / dpr);
+ result.coord = input.coord * textureScale;
+ result.coordUp = (input.coord - float2(0.0, -1.0)) * textureScale;
+ result.coordDown = (input.coord - float2(0.0, 1.0)) * textureScale;
+ result.coordLeft = (input.coord - float2(-1.0, 0.0)) * textureScale;
+ result.coordRight = (input.coord - float2(1.0, 0.0)) * textureScale;
+ return result;
+}
+
+float4 PS_OutlinedText(OutlinedPSInput input) : SV_TARGET
+{
+ float glyph = tex.Sample(samp, input.coord).r;
+ float outline = clamp(clamp(tex.Sample(samp, input.coordUp).r
+ + tex.Sample(samp, input.coordDown).r
+ + tex.Sample(samp, input.coordLeft).r
+ + tex.Sample(samp, input.coordRight).r, 0.0, 1.0) - glyph, 0.0, 1.0);
+ return outline * styleColor + glyph * colorVec;
}
diff --git a/tests/manual/nodetypes/Text.qml b/tests/manual/nodetypes/Text.qml
index 573bf4c959..fb0c92cb10 100644
--- a/tests/manual/nodetypes/Text.qml
+++ b/tests/manual/nodetypes/Text.qml
@@ -42,6 +42,7 @@ import QtQuick 2.0
Item {
Text {
+ id: text1
anchors.top: parent.top
text: "árvíztűrő tükörfúrógép\nÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP"
}
@@ -58,4 +59,13 @@ Item {
color: "green"
NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; }
}
+
+ Row {
+ anchors.top: text1.bottom
+ anchors.margins: 10
+ Text { font.pointSize: 24; text: "Normal" }
+ Text { font.pointSize: 24; text: "Raised"; style: Text.Raised; styleColor: "#AAAAAA" }
+ Text { font.pointSize: 24; text: "Outline"; style: Text.Outline; styleColor: "red" }
+ Text { font.pointSize: 24; text: "Sunken"; style: Text.Sunken; styleColor: "#AAAAAA" }
+ }
}