aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@theqtcompany.com>2016-03-18 09:24:33 +0100
committerLaszlo Agocs <laszlo.agocs@theqtcompany.com>2016-03-22 09:51:46 +0000
commit83eee56e9c047ff83329fe4a175a4b40fdbcb5d2 (patch)
treee4f07a8996694b1aa5584dd222f5127345e9676e
parent9b6f8bfb5167448ee4c18549c20457ee3b4f510d (diff)
D3D12: Support styled and outlined text
The texture resizing highlighted a potential issue with deferred deletes and texture releases: All the texture management functions are special in the sense that they can be called outside a begin-endFrame. (this is what glyph caches do in fact when resizing is involved) In this case using currentPFrameIndex (referring to the last frame's pframeData slot) seems safe, but using it is in fact incorrect under some scenarios: a resource queued for releasing between frame 1 and 2 cannot be released in beginFrame of frame 3, which was the case until now. The CPU wait in frame 3's beginFrame only guarantees the commands submitted before frame 1's endFrame have completed, and those will not include a wait for the copy queue's commands that are added between frames 1 and 2. Using the next frame's pframeData is not an option either since that would lead to an immediate release once beginFrame is called the next time. Therefore, introduce an out-of-frame queue for deleting and texture slot reuse. With the previous example the release will be done in frame 4, which is safe since everything submitted in frame 2 - which will normally include a wait for the copy queue if there were commands issued there before frame 2 using the to-be-released texture - are guaranteed to be done due to the CPU wait. Change-Id: Iaa3b5f0af991946dc97ba44448823b22cbf419dc Reviewed-by: Andy Nichols <andy.nichols@theqtcompany.com>
-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" }
+ }
}