diff options
Diffstat (limited to 'src/quick/scenegraph')
7 files changed, 121 insertions, 42 deletions
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp index ba9952e19d..09eae137bb 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp @@ -375,21 +375,7 @@ void QSGSoftwareInternalImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrap void QSGSoftwareInternalImageNode::update() { - if (m_cachedMirroredPixmapIsDirty) { - if (m_mirrorHorizontally || m_mirrorVertically || m_textureIsLayer) { - QTransform transform( - (m_mirrorHorizontally ? -1 : 1), 0, - 0 , (m_textureIsLayer ? -1 : 1) * (m_mirrorVertically ? -1 : 1), - 0 , 0 - ); - m_cachedMirroredPixmap = pixmap().transformed(transform); - } else { - //Cleanup cached pixmap if necessary - if (!m_cachedMirroredPixmap.isNull()) - m_cachedMirroredPixmap = QPixmap(); - } - m_cachedMirroredPixmapIsDirty = false; - } + updateCachedMirroredPixmap(); } void QSGSoftwareInternalImageNode::preprocess() @@ -423,6 +409,7 @@ void QSGSoftwareInternalImageNode::paint(QPainter *painter) // Disable antialiased clipping. It causes transformed tiles to have gaps. painter->setRenderHint(QPainter::Antialiasing, false); + updateCachedMirroredPixmap(); const QPixmap &pm = m_mirrorHorizontally || m_mirrorVertically || m_textureIsLayer ? m_cachedMirroredPixmap : pixmap(); if (m_innerTargetRect != m_targetRect) { @@ -468,4 +455,23 @@ const QPixmap &QSGSoftwareInternalImageNode::pixmap() const return nullPixmap; } +void QSGSoftwareInternalImageNode::updateCachedMirroredPixmap() +{ + if (m_cachedMirroredPixmapIsDirty) { + if (m_mirrorHorizontally || m_mirrorVertically || m_textureIsLayer) { + QTransform transform( + (m_mirrorHorizontally ? -1 : 1), 0, + 0 , (m_textureIsLayer ? -1 : 1) * (m_mirrorVertically ? -1 : 1), + 0 , 0 + ); + m_cachedMirroredPixmap = pixmap().transformed(transform); + } else { + //Cleanup cached pixmap if necessary + if (!m_cachedMirroredPixmap.isNull()) + m_cachedMirroredPixmap = QPixmap(); + } + m_cachedMirroredPixmapIsDirty = false; + } +} + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h index bfbe8420d2..5b5de86708 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h @@ -92,7 +92,7 @@ public: const QPixmap &pixmap() const; private: - + void updateCachedMirroredPixmap(); QRectF m_targetRect; QRectF m_innerTargetRect; QRectF m_innerSourceRect; diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index d1394ee3b1..3d5a6c7705 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -922,7 +922,14 @@ Renderer::~Renderer() Element *e = n->element(); if (!e->removed) m_elementsToDelete.add(e); + } else if (n->type() == QSGNode::ClipNodeType) { + delete n->clipInfo(); + } else if (n->type() == QSGNode::RenderNodeType) { + RenderNodeElement *e = n->renderNodeElement(); + if (!e->removed) + m_elementsToDelete.add(e); } + m_nodeAllocator.release(n); } @@ -1681,13 +1688,19 @@ void Renderer::prepareOpaqueBatches() QSGGeometryNode *gnj = ej->node; + const QSGGeometry *gniGeometry = gni->geometry(); + const QSGMaterial *gniMaterial = gni->activeMaterial(); + const QSGGeometry *gnjGeometry = gnj->geometry(); + const QSGMaterial *gnjMaterial = gnj->activeMaterial(); if (gni->clipList() == gnj->clipList() - && gni->geometry()->drawingMode() == gnj->geometry()->drawingMode() - && (gni->geometry()->drawingMode() != QSGGeometry::DrawLines || gni->geometry()->lineWidth() == gnj->geometry()->lineWidth()) - && gni->geometry()->attributes() == gnj->geometry()->attributes() + && gniGeometry->drawingMode() == gnjGeometry->drawingMode() + && (gniGeometry->drawingMode() != QSGGeometry::DrawLines || gniGeometry->lineWidth() == gnjGeometry->lineWidth()) + && gniGeometry->attributes() == gnjGeometry->attributes() + && gniGeometry->indexType() == gnjGeometry->indexType() && gni->inheritedOpacity() == gnj->inheritedOpacity() - && gni->activeMaterial()->type() == gnj->activeMaterial()->type() - && gni->activeMaterial()->compare(gnj->activeMaterial()) == 0) { + && gniMaterial->type() == gnjMaterial->type() + && gniMaterial->compare(gnjMaterial) == 0) + { ej->batch = batch; next->nextInBatch = ej; next = ej; @@ -1788,17 +1801,23 @@ void Renderer::prepareAlphaBatches() if (gnj->geometry()->vertexCount() == 0) continue; + const QSGGeometry *gniGeometry = gni->geometry(); + const QSGMaterial *gniMaterial = gni->activeMaterial(); + const QSGGeometry *gnjGeometry = gnj->geometry(); + const QSGMaterial *gnjMaterial = gnj->activeMaterial(); if (gni->clipList() == gnj->clipList() - && gni->geometry()->drawingMode() == gnj->geometry()->drawingMode() - && (gni->geometry()->drawingMode() != QSGGeometry::DrawLines - || (gni->geometry()->lineWidth() == gnj->geometry()->lineWidth() + && gniGeometry->drawingMode() == gnjGeometry->drawingMode() + && (gniGeometry->drawingMode() != QSGGeometry::DrawLines + || (gniGeometry->lineWidth() == gnjGeometry->lineWidth() // Must not do overlap checks when the line width is not 1, // we have no knowledge how such lines are rasterized. - && gni->geometry()->lineWidth() == 1.0f)) - && gni->geometry()->attributes() == gnj->geometry()->attributes() + && gniGeometry->lineWidth() == 1.0f)) + && gniGeometry->attributes() == gnjGeometry->attributes() + && gniGeometry->indexType() == gnjGeometry->indexType() && gni->inheritedOpacity() == gnj->inheritedOpacity() - && gni->activeMaterial()->type() == gnj->activeMaterial()->type() - && gni->activeMaterial()->compare(gnj->activeMaterial()) == 0) { + && gniMaterial->type() == gnjMaterial->type() + && gniMaterial->compare(gnjMaterial) == 0) + { if (!overlapBounds.intersects(ej->bounds) || !checkOverlap(i+1, j - 1, ej->bounds)) { ej->batch = batch; next->nextInBatch = ej; @@ -2001,7 +2020,7 @@ void Renderer::uploadBatch(Batch *b) bool canMerge = (g->drawingMode() == QSGGeometry::DrawTriangles || g->drawingMode() == QSGGeometry::DrawTriangleStrip || g->drawingMode() == QSGGeometry::DrawLines || g->drawingMode() == QSGGeometry::DrawPoints) && b->positionAttribute >= 0 - && (g->indexType() == QSGGeometry::UnsignedShortType && g->indexCount() > 0) + && g->indexType() == QSGGeometry::UnsignedShortType && (flags & (QSGMaterial::NoBatching | QSGMaterial_FullMatrix)) == 0 && ((flags & QSGMaterial::RequiresFullMatrixExceptTranslate) == 0 || b->isTranslateOnlyToRoot()) && b->isSafeToBatch(); @@ -2014,6 +2033,8 @@ void Renderer::uploadBatch(Batch *b) int unmergedIndexSize = 0; Element *e = b->first; + // Merged batches always do indexed draw calls. Non-indexed geometry gets + // indices generated automatically, when merged. while (e) { QSGGeometry *eg = e->node->geometry(); b->vertexCount += eg->vertexCount(); @@ -2829,7 +2850,8 @@ void Renderer::updateMaterialDynamicData(ShaderManager::Shader *sms, const Batch *batch, Element *e, int ubufOffset, - int ubufRegionSize) + int ubufRegionSize, + char *directUpdatePtr) { m_current_resource_update_batch = m_resourceUpdates; @@ -2842,8 +2864,12 @@ void Renderer::updateMaterialDynamicData(ShaderManager::Shader *sms, const bool changed = shader->updateUniformData(renderState, material, m_currentMaterial); m_current_uniform_data = nullptr; - if (changed || !batch->ubufDataValid) - m_resourceUpdates->updateDynamicBuffer(batch->ubuf, ubufOffset, ubufRegionSize, pd->masterUniformData.constData()); + if (changed || !batch->ubufDataValid) { + if (directUpdatePtr) + memcpy(directUpdatePtr + ubufOffset, pd->masterUniformData.constData(), ubufRegionSize); + else + m_resourceUpdates->updateDynamicBuffer(batch->ubuf, ubufOffset, ubufRegionSize, pd->masterUniformData.constData()); + } bindings.append(QRhiShaderResourceBinding::uniformBuffer(pd->ubufBinding, pd->ubufStages, @@ -2857,7 +2883,7 @@ void Renderer::updateMaterialDynamicData(ShaderManager::Shader *sms, if (!stages) continue; - QVarLengthArray<QSGTexture *, 4> prevTex = pd->textureBindingTable[binding]; + const QVarLengthArray<QSGTexture *, 4> &prevTex(pd->textureBindingTable[binding]); QVarLengthArray<QSGTexture *, 4> nextTex = prevTex; const int count = pd->combinedImageSamplerCount[binding]; @@ -3138,7 +3164,14 @@ bool Renderer::prepareRenderMergedBatch(Batch *batch, PreparedRenderBatch *rende bool pendingGStatePop = false; updateMaterialStaticData(sms, renderState, material, batch, &pendingGStatePop); - updateMaterialDynamicData(sms, renderState, material, batch, e, 0, ubufSize); + char *directUpdatePtr = nullptr; + if (batch->ubuf->nativeBuffer().slotCount == 0) + directUpdatePtr = batch->ubuf->beginFullDynamicBufferUpdateForCurrentFrame(); + + updateMaterialDynamicData(sms, renderState, material, batch, e, 0, ubufSize, directUpdatePtr); + + if (directUpdatePtr) + batch->ubuf->endFullDynamicBufferUpdateForCurrentFrame(); #ifndef QT_NO_DEBUG if (qsg_test_and_clear_material_failure()) { @@ -3327,6 +3360,11 @@ bool Renderer::prepareRenderUnmergedBatch(Batch *batch, PreparedRenderBatch *ren QRhiGraphicsPipeline *ps = nullptr; QRhiGraphicsPipeline *depthPostPassPs = nullptr; e = batch->first; + + char *directUpdatePtr = nullptr; + if (batch->ubuf->nativeBuffer().slotCount == 0) + directUpdatePtr = batch->ubuf->beginFullDynamicBufferUpdateForCurrentFrame(); + while (e) { gn = e->node; @@ -3341,7 +3379,7 @@ bool Renderer::prepareRenderUnmergedBatch(Batch *batch, PreparedRenderBatch *ren } QSGMaterialShader::RenderState renderState = state(QSGMaterialShader::RenderState::DirtyStates(int(dirty))); - updateMaterialDynamicData(sms, renderState, material, batch, e, ubufOffset, ubufSize); + updateMaterialDynamicData(sms, renderState, material, batch, e, ubufOffset, ubufSize, directUpdatePtr); #ifndef QT_NO_DEBUG if (qsg_test_and_clear_material_failure()) { @@ -3393,6 +3431,9 @@ bool Renderer::prepareRenderUnmergedBatch(Batch *batch, PreparedRenderBatch *ren e = e->nextInBatch; } + if (directUpdatePtr) + batch->ubuf->endFullDynamicBufferUpdateForCurrentFrame(); + if (pendingGStatePop) m_gstate = m_gstateStack.pop(); @@ -3802,7 +3843,10 @@ void Renderer::beginRenderPass(RenderPassContext *) // we have no choice but to set the flag always // (thus triggering using secondary command // buffers with Vulkan) - QRhiCommandBuffer::ExternalContent); + QRhiCommandBuffer::ExternalContent + // We do not use GPU compute at all at the moment, this means we can + // get a small performance gain with OpenGL by declaring this. + | QRhiCommandBuffer::DoNotTrackResourcesForCompute); if (m_renderPassRecordingCallbacks.start) m_renderPassRecordingCallbacks.start(m_renderPassRecordingCallbacks.userData); diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index 9a024804a7..c0301d1106 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -798,7 +798,8 @@ private: bool ensurePipelineState(Element *e, const ShaderManager::Shader *sms, bool depthPostPass = false); QRhiTexture *dummyTexture(); void updateMaterialDynamicData(ShaderManager::Shader *sms, QSGMaterialShader::RenderState &renderState, - QSGMaterial *material, const Batch *batch, Element *e, int ubufOffset, int ubufRegionSize); + QSGMaterial *material, const Batch *batch, Element *e, int ubufOffset, int ubufRegionSize, + char *directUpdatePtr); void updateMaterialStaticData(ShaderManager::Shader *sms, QSGMaterialShader::RenderState &renderState, QSGMaterial *material, Batch *batch, bool *gstateChanged); void checkLineWidth(QSGGeometry *g); diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp index a9a12a720a..ba85eaf1ef 100644 --- a/src/quick/scenegraph/qsgadaptationlayer.cpp +++ b/src/quick/scenegraph/qsgadaptationlayer.cpp @@ -166,7 +166,12 @@ void QSGDistanceFieldGlyphCache::update() distanceFields.reserve(pendingGlyphsSize); for (int i = 0; i < pendingGlyphsSize; ++i) { GlyphData &gd = glyphData(m_pendingGlyphs.at(i)); - distanceFields.append(QDistanceField(gd.path, + + QSize size = QSize(qCeil(gd.texCoord.width + gd.texCoord.xMargin * 2), + qCeil(gd.texCoord.height + gd.texCoord.yMargin * 2)); + + distanceFields.append(QDistanceField(size, + gd.path, m_pendingGlyphs.at(i), m_doubleGlyphResolution)); gd.path = QPainterPath(); // no longer needed, so release memory used by the painter path diff --git a/src/quick/scenegraph/qsgrhishadereffectnode.cpp b/src/quick/scenegraph/qsgrhishadereffectnode.cpp index 9f634067d5..f1db5804e6 100644 --- a/src/quick/scenegraph/qsgrhishadereffectnode.cpp +++ b/src/quick/scenegraph/qsgrhishadereffectnode.cpp @@ -188,7 +188,7 @@ struct QSGRhiShaderMaterialTypeCache QSGMaterialType *type; }; QHash<Key, MaterialType> m_types; - QVector<QSGMaterialType *> m_graveyard; + QHash<Key, QSGMaterialType *> m_graveyard; }; size_t qHash(const QSGRhiShaderMaterialTypeCache::Key &key, size_t seed = 0) @@ -208,6 +208,14 @@ QSGMaterialType *QSGRhiShaderMaterialTypeCache::ref(const QShader &vs, const QSh return it->type; } + auto reuseIt = m_graveyard.constFind(k); + if (reuseIt != m_graveyard.cend()) { + QSGMaterialType *t = reuseIt.value(); + m_types.insert(k, { 1, t }); + m_graveyard.erase(reuseIt); + return t; + } + QSGMaterialType *t = new QSGMaterialType; m_types.insert(k, { 1, t }); return t; @@ -220,7 +228,7 @@ void QSGRhiShaderMaterialTypeCache::unref(const QShader &vs, const QShader &fs) auto it = m_types.find(k); if (it != m_types.end()) { if (!--it->ref) { - m_graveyard.append(it->type); + m_graveyard.insert(k, it->type); m_types.erase(it); } } diff --git a/src/quick/scenegraph/util/qsgrhiatlastexture.cpp b/src/quick/scenegraph/util/qsgrhiatlastexture.cpp index 246335ef69..cdb8509dd2 100644 --- a/src/quick/scenegraph/util/qsgrhiatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgrhiatlastexture.cpp @@ -160,9 +160,20 @@ void AtlasBase::remove(TextureBase *t) Atlas::Atlas(QSGDefaultRenderContext *rc, const QSize &size) : AtlasBase(rc, size) { - // use RGBA texture internally as that is the only one guaranteed to be always supported m_format = QRhiTexture::RGBA8; + // Mirror QSGPlainTexture by playing nice with ARGB32[_Pre], because due to + // legacy that's what most images come in, not the byte-ordered + // RGBA8888[_Pre]. (i.e. with this the behavior matches 5.15) However, + // QSGPlainTexture can make a separate decision for each image (texture), + // the atlas cannot, so the downside is that now images that come in the + // modern byte-ordered formats need a conversion. So perhaps reconsider this + // at some point in the future. +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + if (rc->rhi()->isTextureFormatSupported(QRhiTexture::BGRA8)) + m_format = QRhiTexture::BGRA8; +#endif + m_debug_overlay = qt_sg_envInt("QSG_ATLAS_OVERLAY", 0); // images smaller than this will retain their QImage. @@ -211,8 +222,12 @@ void Atlas::enqueueTextureUpload(TextureBase *t, QRhiResourceUpdateBatch *resour if (image.isNull()) return; - if (image.format() != QImage::Format_RGBA8888_Premultiplied) + if (m_format == QRhiTexture::BGRA8) { + if (image.format() != QImage::Format_RGB32 && image.format() != QImage::Format_ARGB32_Premultiplied) + image = std::move(image).convertToFormat(QImage::Format_ARGB32_Premultiplied); + } else if (image.format() != QImage::Format_RGBA8888_Premultiplied) { image = std::move(image).convertToFormat(QImage::Format_RGBA8888_Premultiplied); + } if (m_debug_overlay) { QPainter p(&image); |
