diff options
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" } + } } |