aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph
Commit message (Collapse)AuthorAgeFilesLines
* QSGThreadedRenderLoop: fix typo in tracingTim Blechmann7 days1-1/+1
| | | | | | Pick-to: 6.11 6.10 6.8 Change-Id: I0f48169d4678fc72dc16946bd6c4bf566ef48729 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Avoid the Shapes gradient texture cache growing without boundsEirik Aavitsland13 days2-32/+74
| | | | | | | | | | | | | | | | | | | | | | | | Nothing was ever removed from the cache, so in case of e.g. an animated gradient, a large number of texture objects would be created and not released, and memory would quickly fill up. Fix by changing the caching implementation with a set maximum number of cached gradient textures. This introduces a soft limit on the supported number of simultaneously displayed different gradients in the application. If exceeded, some objects will show wrong gradient colors. Although unlikely to be reached, the limit is documented and configurable by environment variable. As a driveby, improve the gradient cache key qHash() implementation a bit, presumably giving better spread for the QCache. Fixes: QTBUG-142208 Fixes: QTBUG-136553 Pick-to: 6.11 6.10 6.8 6.5 Change-Id: Ie104f27031572e1c392c0a8ef79d09f4a2ba5a8e Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
* Stop flooding the log with animation timer typeJoni Poikelin2025-11-261-1/+1
| | | | | | | | | | This variable used to be static and the logic still looks like it expects it to be so. Static was probably removed in an error. This causes unnecessary environment variable reading and logs being printed as this function is being called for every frame. Change-Id: Id24d9cfecb0f509f92cef47f6a95800ff529259b Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
* QSGThreadedRenderLoop: Drop dead codeKonstantin Ritt2025-11-121-17/+1
| | | | | | | syncResultedInChanges is not used since 27d674e9ec2 (v6.0.0-alpha1). Change-Id: I13e413dd47b391c279d6fc8a15d23d728fef1e58 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
* Doc: Mark internal APIs with \internal commandJerome Pasion2025-11-074-0/+20
| | | | | | | | | | | These internal APIs have function documentation but are missing class documentation. Adding an internal class documentation fixes QDoc warnings. Task-number: QTBUG-141697 Change-Id: Iecb289d39e34ddaa964fbe0a1404830cd2269caa Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io> Reviewed-by: Paul Wicking <paul.wicking@qt.io>
* Doc: Fix swapped parameters in QDoc link commandsDavid Boddie2025-10-272-2/+2
| | | | | | | | These links coincidentally happened to go to sections with the target name but I assume that the aim was to link to the scene graph overview. Change-Id: I77662158a2f7f8cb679a8585b6c15c61689a3c58 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Software Renderer: Fix artifacts with non pixel aligned contentAndy Nichols2025-10-271-0/+5
| | | | | | | | | | | | | It was possible that we would request to flush more of the backing store than what was actually painted, which could lead to artifacts. Now when there is a difference caused by the pixel alighment conversions, we make sure to mark items behind that content as dirty so that everything necessary to render correctly is painted. Fixes: QTBUG-133368 Pick-to: 6.10 6.8 Change-Id: I9766017eb610792ffa17b745c356b614e4e28752 Reviewed-by: Christian Strømme <christian.stromme@qt.io>
* Software Adaptation: Disable partial updates when fractional scalingAndy Nichols2025-10-202-0/+24
| | | | | | | | | | | | | | | | | | | When using a scaling factor for the UI that is not an integer, the partial update mechanism in the software Adapation can break down and lead to many artifacts. Now we check if we're trying to render with factional scaling and disable partial updates. It's possible to opt-out of this by setting the environment variable: QSG_SOFTWARE_RENDERER_FORCE_PARTIAL_UPDATES=1 It is also possible to disable partial updates using the same variable QSG_SOFTWARE_RENDERER_FORCE_PARTIAL_UPDATES=0 Fixes: QTBUG-136943 Pick-to: 6.10 6.8 Change-Id: If4b0bc403a96ab037f213e89708371a49bc8ae02 Reviewed-by: Christian Strømme <christian.stromme@qt.io>
* software backend: Fix clipped text stylesEskil Abrahamsen Blomfeldt2025-10-142-1/+15
| | | | | | | | | | | | | When we paint text with any other style than Normal, we will offset painting by up to 1 logical pixel. To avoid clipping the style, we need to make sure the bounding rect of the text also accounts for this. This does overestimate the bounding rect in cases where the dpr is not 1, but this is better than underestimating it. Pick-to: 6.10 6.8 Fixes: QTBUG-137404 Change-Id: I670a3709fcc6ac7fd6d58a8d524f534800cafdff Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
* sg: remove an unused variable in QSGMaterialShaderPrivate::prepare()Aurélien Brooke2025-09-231-1/+0
| | | | | | | | | | It seems to have been forgotten in a previous cleanup. Amends b87b3d3d43c200f22f0799ca59ab366d851b5db6. Pick-to: 6.10 Change-Id: Ibabeeea164448b381603252da05a81ff76faccab Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
* Add license headers to new shaders; stop doc bot complainingShawn Rutledge2025-09-122-0/+6
| | | | | Change-Id: I36862f842ece2432733036da18f2ab1cd663a4e9 Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
* Add ShapePath.cosmeticStrokeShawn Rutledge2025-09-1212-93/+547
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | QSvgRenderer already obeys the QPen::isCosmetic() setting. Now we add a ShapePath.cosmeticStroke property and try to support cosmetic stroking both with SVG and with Shapes, in all renderers. The curve renderer now starts with skinny triangles: each segment's end vertices are passed to the vertex shader with their original positions, and the shader uses the normal and the stroke width to expand the stroke triangles outwards as needed. We always add triangles for end caps, regardless whether they are square or round. We get rid of addBevelTriangle and fix bevels, square caps and miters: All three of these cases are done by drawing lines adjusted to the right direction within the respective triangles. And to avoid seeing rounded ends at any reasonable zoom level, we need the line equation coefficients to take the line very far outside the actual triangles. Square caps are really square: we render line segments in those three triangles, not extensions of the adjacent curve or line. Miters are also rendered as straight tangent lines. The bevel's triangle is very short when the join is an acute angle, and almost as tall as the full stroke width when the join is very obtuse. But when the triangle is short, we need to diminish the stroke width rendered in the fragment shader so that the center of the stroke falls on the inner corner of that triangle, and the edge of the stroke is rendered along the outer bevel edge rather than trying to go outside. That's achieved by multiplying the stroke width by the cosine of half the total angle, AKA the dot product. That is now in the normalExt.z vertex attribute. Normals (normalExt.xy) can be premultiplied rather than normalized: in fact some of them already have length > 1. In qsgbatchrenderer, Renderer::prepareAlphaBatches() breaks batches when overlaps occur. Now that we stroke lines with vertices that represent them as zero-width lines (and thus Element.bounds has the same x or y coordinates on both corners), we must consider lines right on top of each other to be overlapping: e.g. the stacks of horizontal (dashed) line segments in paint-stroke-202-t.svg must be in separate batches. At the time QQuickShape::updatePaintNode() is called, the available transform node (from UpdatePaintNodeData or an individual node's parent which is a transform node) does not contain the scaling factor that we need to allow for the stroke width to be adjusted for cosmetic stroking. But in QQuickShapePrivate::sync(), windowToItemTransform() is known, and from bde55ad574ac84440e2cdc9c1122a344bb1cb67a we have a precedent in QSGCurveStrokeMaterialShader::updateUniformData() for using the square root of the matrix determinant as a scaling approximation (ok when the scaling is uniform). QQuickShapeSoftwareRenderer::setNode() was already adjusting a path's bounding rect by its stroke width, and we need a multiplicative factor there to account for cosmetic stroking, to avoid excessive clipping in the software renderer. So now we have another use for the triangulationScale that was introduced in bcfcaeb87be783d8c329b0bc96323f1c9863982d. When QQShapeGenericRenderer is used (rendererType == GeometryRenderer), and any ShapePath has cosmeticStroke, we need it to re-triangulate whenever scale changes. QQuickShapeGenericRenderer::triangulateStroke() calls QTriangulatingStroker::setInvScale(1 / triangulationScale), and QTriangulatingStroker::process() multiplies its m_width by the inverse scale that was set (since 2009). So this tells us that the intended meaning of triangulationScale is the inverse of the factor by which we multiply the pen width. And when QQShapeGenericRenderer is in use, and there are cosmetic strokes, QQuickShape::itemChange triggers re-triangulation on changes in scale. When setting the QQuickShapeCurveRenderer::DebugWireframe debug visualization flag, we need to repeat the vertex shader calculations to expand the "skinny" triangles according to stroke width, just as we do with the actual stroking vertices. For now customTriangulator2 remains as legacy code, to be removed later on. It's poorly named, and returns a list of TriangleData which need to be iterated afterwards ("fix it in post"), looking up the QQuadPath::Element again in that second loop, which can go wrong when a path contains a move command. (For example, it could calculate a bevel between the end-tangent of one subpath and the start-tangent of the next.) customTriangulator2() was called from only one place, processStroke(), to which addStrokeTriangleCallback() is given: so the new way is to just call the callback directly as soon as we've calculated each triangle. Because we are not iterating again afterwards, the switch(type) is not needed in that case, and we no longer need TriangleData::type, except for supporting customTriangulator2(). [ChangeLog][QtQuick][Shapes] ShapePath now has a cosmeticStroke property which causes strokeWidth to be constant despite scaling. Set the environment variable QT_QUICKSHAPES_STROKE_EXPANDING to 1 to enable an experimental method of expanding strokes in the vertex shader, minimizing the need to re-triangulate when strokeWidth changes. Task-number: QTBUG-124638 Change-Id: I4eac0ddcd6f623b79bc70c766ff116f4b77736cb Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io> Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
* Add debug streaming operator to TriangleDataShawn Rutledge2025-09-123-0/+33
| | | | | | | | Also ifndef QT_NO_DEBUG_STREAM around the QQuadPath debug op. Both will be omitted from the build if QT_NO_DEBUG_STREAM is set. Change-Id: Ie86577ba61fc4f2b118d7e0a2b1ab702b318a473 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
* Calculate correct device pixel ratio when rendering to layerEskil Abrahamsen Blomfeldt2025-09-112-2/+13
| | | | | | | | | | | | | | | | | | | When rendering to a layered item, the actual device pixel ratio is determined by the ratio between the width of the texture and the width of the logical rect. For most use cases, using the window's device pixel ratio would be correct, since the texture size is automatically calculated based on this. But in the cases where a manual texture size is set it would be incorrect and this would cause artifacts in the antialiasing for text and shapes. This also adds the correct scale factor to shapes, since this was even missing the device pixel ratio factor. Fixes: QTBUG-139997 Change-Id: Ibf1392f546f5cbcedd062852cbd87c0c0c097460 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
* Cleanup, refactoring and internal docs in curve processor and rendererShawn Rutledge2025-09-104-134/+156
| | | | | | | | | | | | | | | | | | | - calculateJoin() is too big to continue as an internal lambda, and changes to customTriangulator2 (the only user) are coming later; so move it out to a top-level static function - use const - capture simple constants in the tooLong lambda - explicit captures in remaining lambdas - replace some single-letter variables with more meaningful ones - turn some plain comments into internal function docs - a couple of spelling and grammar corrections - init TriangleData::pathElementIndex=INT_MIN by default, to be able to distinguish default-constructed instances. Of course they are usually >= 0, but customTriangulator2() uses small negative indices as special triangle-type indicators. Change-Id: I7b70a02ac56522ee0c6aff26be80ac4e3e546bbd Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
* Make sure to setup viewport and scissors also for RenderNodesDominik Holland2025-08-182-5/+12
| | | | | | Pick-to: 6.8 6.9 6.10 Change-Id: Ie3da3ba0aab73ad61fa32593bcdd19ffcc714a02 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
* QSGThreadedRenderLoop: Handle window hiding at polish stepVlad Zahorodnii2025-08-141-1/+7
| | | | | | | | | | | | | | | | | | | | | A window can be hidden during the polish step. For example, an app may hide its window if the geometry is not good enough. This can result in the following render thread events if the QPA sends sync expose events: - WM_Obscure - WM_TryRelease - WM_RequestSync The WM_RequestSync event comes from the WMSyncEvent. With QtWayland, repainting a window after it has gotten unexposed can lead to the compositor posting a protocol error. There is also matter of keeping code predictable: if the QPA sends an unexpose event, it'd be great if the app stops repainting. Pick-to: 6.10 Change-Id: I1d477436d6f79156aca44960c47a84f2e12ca4d2 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
* sg: optimize Renderer::cleanupBatches() by removing sorting and copyingAurélien Brooke2025-08-131-9/+12
| | | | | | | | | | | | | Replace the previous stable sort + filter approach with an in-place compaction loop that moves valid batches forward and recycles invalid ones immediately. This removes the need for temporary heap storage and avoids redundant copying and sorting, while preserving the original order of valid batches. Change-Id: Icbe2c3d96b5d38a0a1f2c14ce175eb19d45d5a63 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
* Fix QSGGeometryData::hasDirtyIndexData used wrong dirty flagDheerendra Purohit2025-08-131-1/+1
| | | | | | | | | | | The method incorrectly returned m_dirty_vertex_data instead of m_dirty_index_data. Pick-to: 6.10 6.9 6.8 6.7 6.6 Fixes: QTBUG-123988 Change-Id: Ib99175adabc711c8449ff3db755fbade968f7c63 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Andy Nichols <andy.nichols@qt.io>
* Curverenderer: Make QQuadPath::Element::isSubpathEnd() reliableEirik Aavitsland2025-08-121-0/+5
| | | | | | | | | | QQuadpath did not maintain the isSubpathEnd-flag, so it would typically be lost during path processing. Fix to ensure that algorithms that test for it work correctly. Pick-to: 6.10 Change-Id: I793b06ef87087cce4a4545bcd7fd2e20ca3790ad Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
* Curve renderer: Fix filling of certain paths with degenerate partsEirik Aavitsland2025-08-082-15/+45
| | | | | | | | | | | | | Determining the fill side of a segment would fail if the path contained an overlapping segment in the opposite direction. If a subpath started with such a segment, the resulting fill could be incorrect. Fix by iterating over the subpath for a segment with a determinable fill side. Fixes: QTBUG-133247 Pick-to: 6.10 6.9 6.8 Change-Id: I07c4f884d525b19af93609bcb31b412d340bebd5 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
* Don't reuse invalidated distance field cacheEskil Abrahamsen Blomfeldt2025-08-055-13/+104
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When the fonts are invalidated e.g. because application fonts are cleared, there will be a bit of a round-trip where we reset all text components to rematch the fonts they use. Since the scenegraph nodes contain direct pointers to the distance field cache, we cannot delete the cache itself before the text has been reset and a new font has been matched. This caused an issue where an application font was unloaded and a new one was loaded instead. Since they both had the same virtual file name (":qmemoryfonts/0"), however, we would get the glyph cache for the old font when we were resetting the text with the old. Since the glyph indexes referred to the new font, we would end up with random glyphs in the text. The core problem was that the stale caches were still in the hash when the scenegraph was being reset. Instead, we start the sync by either deleting inactive caches or moving the active ones into a separate list. When the text items are reset, the hash is populated with new caches. When the sync is done, we flush the stale caches: Meaning that we delete the ones that are now no longer used. Pick-to: 6.10 Task-number: QTBUG-132108 Change-Id: Iae4bebdbd1acc34ff86a2f9f6f34fdd0d6cbac0e Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
* Always set a minimum padding of 4 for the available render orderDominik Holland2025-07-292-1/+8
| | | | | | | | | | | | | | | | | If a new batch root is added a padding is added to keep some unused orders available for newly created elements inside this batch root. For batch roots with less than 4 children the padding was set to 0 causing a rebuild when new items got added, e.g. by visibility changes. The new minimum padding makes sure that there is more room for new elements without the need to rebuild everything. The padding can also be changed by using the QSG_BATCHRENDERER_MINIMUM_ORDER_PADDING environment variable. Change-Id: Ic015462b7024163dd2aa52566b3566fb98ee555a Reviewed-by: Andy Nichols <andy.nichols@qt.io>
* Fix QSGDefaultRectangleNode::color() always returning invalidDheerendra Purohit2025-07-281-0/+1
| | | | | | | | | | | setColor() updated geometry colors but did not assign the input color to m_color. This caused color() to always return an invalid QColor. Fixed by assigning m_color = color in setColor(). Pick-to: 6.10 6.9 Fixes: QTBUG-138358 Change-Id: Icb00d26e624b7437d48253a3f7ea0dd64e68baf8 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
* Correctly update the current projection matrix for RenderNodesDominik Holland2025-07-281-1/+8
| | | | | | Pick-to: 6.8 6.9 6.10 Change-Id: Idc6257d5ec3942a00869daf737613165c0e60ebc Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
* Curve renderer: Improve debug outputEirik Aavitsland2025-07-231-2/+4
| | | | | | | Include the element curvature info and path hints too. Change-Id: Iffd1229f1fc9ae2562a117f2bffaf9e82276febd Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
* Minor QSGRenderNode doc cleanup to better match Qt 6Laszlo Agocs2025-07-231-76/+44
| | | | | | Pick-to: 6.10 6.9 6.8 Change-Id: Ia2bd028fd2d948aefdc49f5a3044f2cef7371f71 Reviewed-by: Jonas Karlsson <jonas.karlsson@qt.io>
* sg: Fix culling in layersLaszlo Agocs2025-07-225-3/+44
| | | | | | | Pick-to: 6.10 6.9 6.8 Fixes: QTBUG-136611 Change-Id: If2a0a0365ca24360d850ffce98c0bec4a3961976 Reviewed-by: Jonas Karlsson <jonas.karlsson@qt.io>
* Change `6.9` to `6.10` for QSGGeometry functions added after 6.9 FFStan Morris2025-07-181-9/+8
| | | | | | | | | | | | | | | | | | | | | | | The `since 6.9` comments should read `since 6.10` -- the `setVertexCount()` and `setIndexCount()` functions were accepted into `dev` but did not make the Qt 6.9 feature freeze. I added them in [590520](https://codereview.qt-project.org/ c/qt/qtdeclarative/+/590520) to fix [QTBUG-126835](https://bugreports.qt.io/ browse/QTBUG-126835). The whitespace changes correct errors I propagated and the function comments I copied from, as well as removing an extraneous linefeed in a function I touched in the original patch. Summary of changes: * Change all `\since 6.9` to `\since 6.10` * Change all `Since 6.9` to `Since 6.10` * Align closing comment operator to match Doxygen style * Remove extraneous linefeed Fixes: QTBUG-137939 Pick-to: 6.10 Change-Id: I60f7856677e44138443b4ccfa314a3e168f34ada Reviewed-by: Andy Nichols <andy.nichols@qt.io>
* Include what you need: qquaternion.hMarc Mutz2025-07-041-0/+3
| | | | | | | | | | | | | | qmatrix4x4.h will lose its qquaternion.h include, so include qquaternion.h explicitly in all files that mention 'QQuaternion', unless, for a foo.cpp, the own foo.h has already included it. Picking all the way back, even though the include removal won't be picked as far back, because it's the correct thing to do and cannot fail. Pick-to: 6.10 6.9 6.8 6.5 Change-Id: I21bc2ddfda326455d36d5510df596169e1c2d5dc Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Make sure we propely dereference all glyphs in distance field cacheEskil Abrahamsen Blomfeldt2025-06-252-8/+10
| | | | | | | | | | | | | | | | | | | | | | | | | | | When we reference glyphs in QSGDistanceFieldGlyphCache::populate(), we do this before they are added to the cache, so the cache coords have yet to be registered. So even for empty glyphs that cover a 0x0 area, they will be still be registered as referenced in the cache. However, when dereferencing the glyphs, we would skip if the glyph did not occupy any space in the cache. This asymmetrical behavior could lead to a glyph cache mistakenly being counted as active even after deleting all nodes that reference it were gone. Thus it would stay around in the glyph cache when it's invalidated, even though all references are actually gone. As a simple fix, we make sure the referenceGlyphs() and releaseGlyphs() are always called for all glyphs. This means that the list of unused glyphs may sometimes contain empty glyphs, so when we recycle the unused glyphs, we need to make sure we skip that for glyphs that do not occupy any space. Pick-to: 6.8 6.9 6.10 Task-number: QTBUG-132108 Change-Id: I919d8b6a6a2de9bb1f0fccd7c6ffa00436e6ffa5 Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
* Allow triangle fan in QSGGeometry when the underlying API supports itLaszlo Agocs2025-06-242-12/+26
| | | | | | | | | | | | | | Will not work with D3D and Metal. With those we will continue to reject QSGGeometries having a drawing mode of DrawTrangineFan with a warning. Relevant mainly for OpenGL and applications ported from Qt 5. For a cross-platform, portable solution they would need to move away from triangle fans, but in the meantime, if the intent is to function just with OpenGL on Qt 6, it is good for compatibility if we enable this. Pick-to: 6.10 6.9 6.8 Change-Id: Iaa9376234ef854557458e5b6020e39c60666ad91 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
* Doc: Fix QSGGeometryNode docs to use Qt6 compatible codeDheerendra Purohit2025-06-161-1/+1
| | | | | | | | | | | | Updated the documentation snippet for QSGGeometryNode to align with the Qt6 rendering architecture.Replaced deprecated or outdated API usage with Qt 6 compatible code to prevent confusion for developers. Pick-to: 6.10 6.9 6.8 Fixes: QTBUG-94147 Change-Id: I3b49924db67c1ae468d76055cad9fe88584248e2 Reviewed-by: Axel Spoerl <axel.spoerl@qt.io> Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
* sg: Fix recursive layers losing the previous textureLaszlo Agocs2025-06-102-4/+38
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ...under certain conditions, such as when the size changes. The recursive layer itself will likely depend on the texture backing the layer when rendering. Typically, the fragment shader samples it. To make this work, in recursive mode there are two backing textures. There are two problems for recursive mode in the Qt 6 layer implementation. (that in in some ways works quite differently from Qt 5, due to the QRhi migration) 1. When new backing buffers are needed, for example because the item size changes, immediately releasing the main backing texture in favor of a new texture that is correctly sized but has uninitialized content is not ideal, and is not what Qt 5 was doing. Qt 5 continued to use the previous OpenGL texture when rendering for the first time after a size change. As in, exposing the old texture as the layer's backing texture, thus a recursive shader effect was sampling that in the shader. (that the size of that input texture is technically incorrect now is usually not a visible issue, and comes by design with recursive mode) Only once rendering to the new texture has been done for the first time is the old texture released. The new one (which we just rendered into) then takes over as the backing texture returned from rhiTexture() (or the equivalent in Qt 5). Make the Qt 6 implementation of layers to be identical to Qt 5 in this regard. 2. There is an additional problem in the very first frame. Neither Qt 5 nor 6 clears the main backing texture. Because rendering to it does that anyway. In recursive mode however, the very first frame will also sample the texture. And the texture has uninitialized content at that point, similarly to problem #1. The result is that a non-live, recursive effect source exhibits either artifacts, magenta (Metal) content, or just happens to look correct (so not a visible issue usually with Qt 5 and OpenGL) With live: true (the default) this issue is hidden, although the garbage my still flicker in from the first frame. Do an explicit clear now, so the first frame does not sample potential garbage. Pick-to: 6.10 6.9 6.8 Fixes: QTBUG-112355 Change-Id: Ic9d2b0dc4aa6ab1e99d456bcce48ffa9ffbfecfe Reviewed-by: Andy Nichols <andy.nichols@qt.io>
* sg: Fix layers with recursive and MSAALaszlo Agocs2025-06-101-10/+16
| | | | | | | | | | | | | | | | | | | | | | | | The Qt 5 era behavior, where 'recursive: true' combined with a sample count > 1 did not have to involve using an additional backing buffer (unlike 'recursive: true' with no multisampling), is not quite compatible with the QRhi-based system. On Vulkan, for example, multisample rendering into a texture involves an implicit multisample resolve at the end of the render pass. This is different from OpenGL's or D3D11's explicit resolve or blit command. The latter can get away with not caring about the recursive flag whenever MSAA is in use, because the behavior is effectively the same as non-MSAA rendering with recursive set, i.e. render to a dedicated multisample buffer, then resolve (i.e., copy) into the actual non-MSAA texture. But with APIs like Vulkan this cannot work. Sampling the texture that is set as the resolveTexture within the same render pass is wrong. Thus the only choice is to treat non-MSAA and MSAA cases identically when it comes to the recursive flag. Task-number: QTBUG-112355 Task-number: QTBUG-118610 Pick-to: 6.10 6.9 6.8 Change-Id: Ic2f92579eff89d8cf32cccd4ea023556b8e39d1d Reviewed-by: Andy Nichols <andy.nichols@qt.io>
* sg: Fix dpr when grabbing a not-yet-shown QQuickWindowLaszlo Agocs2025-06-021-1/+5
| | | | | | | | | | | | The scenegraph is not initialized when the window has not been exposed yet, and calling QQuickWindow::grabWindow() takes a whole different code path in this case. This was not communicating a scale factor to the renderer at all. Pick-to: 6.10 6.9 6.8 6.5 Fixes: QTBUG-116675 Change-Id: I73b21dfd06a04dbdc2ff3cb1a17bbe0364ca0624 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
* Avoid unnecessary copy and detach in QSGDefaultPainterNodeAllan Sandfeld Jensen2025-05-301-0/+2
| | | | | | | | | | We were setting the texture with a copy of QImage, then changing the original, and setting again. By unsetting before changing the image we avoid detaching, copying, and then discarding the new copy. Pick-to: 6.9 Change-Id: I89b5f90de2165d62c0aae7663026989e20a76e39 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
* Mark rectangle with any radius set as not opaque for software rendererMiika Pernu2025-05-271-1/+5
| | | | | | | | | | | | | | Support for topLeftRadius, topRightRadius etc were added to the software renderer recently but they were not considered when checking whether the rectangle is opaque or not. This resulted in background not being correctly drawn around individually rounded corners. Fixes: QTBUG-133314 Fixes: QTBUG-136738 Pick-to: 6.8 6.9 Change-Id: Id020550d40e800d188a27b943cf9fb1df10f5229 Reviewed-by: Magdalena Stojek <magdalena.stojek@qt.io> Reviewed-by: Matthias Rauter <matthias.rauter@qt.io>
* Doc: Document QSGRenderNode::RenderStateAndreas Eliasson2025-05-221-0/+11
| | | | | | | | | | | The class documentation for QSGRenderNode::RenderState is missing, which results in failed links to its functions. Fixes: QTBUG-96580 Pick-to: 6.9 6.8 6.5 Change-Id: I546c3f499a07096e00714296a1c0c0ffd2f6ea98 Reviewed-by: Topi Reiniö <topi.reinio@qt.io> Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
* Doc: Fix Linking issuesTopi Reinio2025-05-201-2/+2
| | | | | | | | | | | | | | | | - Fix linking to `QtQuickView` Android class - Fix incorrect link target to section - Fix \sa link to QLocale::createSeparatedList() - Remove link to undocumented header `qqmlregistration.h` - Replace link to non-existent QML type HeaderViewDelegate with actual type name(s). - Fix links to (Horizontal|Vertical)HeaderView::delegate property, as the property is documented in the base type. - Remove \sa links to private member QSGTextNode::doAddTextDocument() Pick-to: 6.9 Change-Id: I3bab7155f8d73af6d51f8cfe890ece6d31671f1d Reviewed-by: Nicholas Bennett <nicholas.bennett@qt.io>
* Pass on hasDefaultAlphaBuffer in the format with the software backend tooLaszlo Agocs2025-05-131-0/+2
| | | | | | | | | | | The expectation with setDefaultAlphaBuffer(true) is that alphaBufferSize becomes > 0 in the window's format. Follow this with the software backend too. (because it may matter for the backingstore) Pick-to: 6.9 6.8 Task-number: QTBUG-136755 Change-Id: I07ff34056ea51182c2542a259084dcd746d0450e Reviewed-by: Andy Nichols <andy.nichols@qt.io>
* sg: Correctly bail out when surface size is 0Laszlo Agocs2025-05-131-1/+7
| | | | | | | Pick-to: 6.9 6.8 6.5 Fixes: QTBUG-128864 Change-Id: I18b228579d871e4db259c2eeecf56ef4218fb92a Reviewed-by: Andy Nichols <andy.nichols@qt.io>
* Remove lastDirtyWindow logic from basic render loopLaszlo Agocs2025-05-131-16/+3
| | | | | | | | | | | | | | | | | | | | | Effectively undo eeb320bbd8763f3e72f79369cc3908e999a0da3c and 3df5ad9d247b194401d61c3ffb4b816ec239bded. None of this is relevant to Qt 6 since 331e2effa791bbba4095602c9eb90220c08b162f because the basic render loop also uses dedicated GL contexts per window now. Important in particular because 3df5ad9d247b194401d61c3ffb4b816ec239bded causes regressions in certain cases, when there are multiple windows with one becoming dirty and hidden, preventing deleting the QSGTextures. The patch must not be applied to Qt 5. There the basic loop uses one context for all windows, and so the original fix is important to have. The problem of not releasing textures should be solved in another way for Qt 5. Change-Id: I440836605121d50c6d059d383975249cc070ac25 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
* QSGThreadedRenderLoop: fix race on window pointerDavid Faure2025-05-132-4/+24
| | | | | | | | | | | | | | | | | | | | | | | When the thread is not running yet, we indeed have to set the window pointer. And we can do that without mutex/atomic because starting the thread is a synchronization point. When the thread is already running, however, writing into 'window' races with reads of that variable in the thread. But it's useful to do that, after the thread handled a WM_Obscure event which set the window pointer to nullptr (testcase: tst_qquickwindow destroyShowWithoutHide). We need to set it again if the window is exposed again: use an event to do this in a thread-safe way. WARNING: ThreadSanitizer: data race (pid=427588) Read of size 8 at 0x723400006048 by thread T11: #0 QSGRenderThread::syncAndRender() qsgthreadedrenderloop.cpp:802 Previous write of size 8 at 0x723400006048 by main thread: #0 QSGThreadedRenderLoop::handleExposure(QQuickWindow*) qsgthreadedrenderloop.cpp:1294 Pick-to: 6.9 6.8 6.5 Change-Id: I145bb499628fc0c95c4362a32aecdc7c3d688677 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
* Reuse depth-stencil buffer between layers like Qt 5 didLaszlo Agocs2025-05-024-14/+75
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Port QSGDepthStencilBuffer in a slightly changed form from Qt 5. Two layers in the same scene can use the same single depth-stencil buffer, instead of creating a dedicated one for each. As long as the size and sample count is the same. The render passes are recorded sequentially, and there is no need for the depth-stencil content once a render pass is done. The catch is having to deal with changing sizes, e.g. a window resize often leads to changed sizes for the layers of the scene. We do not want to end up cached renderbuffer objects with sizes that will possibly never be needed again. The Qt 5 approach solves this with reference counting and QShared/WeakPointers. Continue with that approach. If there is actually a depth-stencil buffer that is fully physically backed, that is a different question. With Vulkan for instance, on some GPU architectures we expect that the depth-stencil images will be transient + lazily allocated + no store, so it may matter little how many images we have. Similar things might happen in GLES implementations on tiled GPU architectures. However, generally it is ideal if the Qt 5 behavior is kept, so that no confusion arises from an extra renderbuffer or two showing up when counting and comparing resources in frame captures between Qt 5 and 6. Fixes: QTBUG-135813 Pick-to: 6.9 6.8 Change-Id: I238dc53600f4a00e6ee2f7ccc97ac33ff189e3c5 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
* Fix data race on QSGDistanceFieldGlyphNode::m_totalAllocationDavid Faure2025-04-152-5/+4
| | | | | | | | | | Different instances of QSGRenderThread call into different instances of QSGDistanceFieldGlyphNode concurrently, this static counter needs to be made thread-safe. Pick-to: 6.9 6.8 6.5 Change-Id: Ie8299824e799a9b15bae354314d1fa5c371cf5dc Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
* Port away from QPairZhao Yuhang2025-04-123-11/+11
| | | | | | | | QPair is just an alias of std::pair anyway. Task-number: QTBUG-115841 Change-Id: I26fc90adcc775aac9955ad57304af914dc4ed48f Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Fix misbatching of scenegraph nodes using DrawLineStrip modeEirik Aavitsland2025-04-111-1/+3
| | | | | | | | | | | | The batch renderer assumed nodes having different line widths to be batchable if their drawing mode was anything else than DrawLines. That meant nodes with DrawLineStrip mode could be batched although they differed in line width, leading to wrong rendering. Fixes: QTBUG-135815 Pick-to: 6.9 6.8 Change-Id: Ic0c6cd83ff9e7394f84602c453adee79c6e22641 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
* Fix include in qsgcurveprocesso_p.hMatthias Rauter2025-03-311-1/+1
| | | | | | Pick-to: 6.9 6.8 Change-Id: I91d069b7bb833e4b0b3cb6c4debaebdd3d9d7e7f Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
* QSGBatchRenderer: add missing includeTim Blechmann2025-03-291-0/+1
| | | | | | | | | | QSGBatchRenderer uses QElapsedTimer without including the header. This breaks compilation as used to be included transitively from QtBase, but this seems to be removed. Pick-to: 6.8 6.9 Change-Id: I20e58f4089287120f8e3d38e070f5324980dbaa1 Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>