Merge lp://staging/~raof/qtmir/multi-bufferstream-support into lp://staging/qtmir

Proposed by Chris Halse Rogers
Status: Work in progress
Proposed branch: lp://staging/~raof/qtmir/multi-bufferstream-support
Merge into: lp://staging/qtmir
Diff against target: 639 lines (+163/-241)
7 files modified
src/modules/Unity/Application/CMakeLists.txt (+1/-0)
src/modules/Unity/Application/mirsurface.cpp (+144/-63)
src/modules/Unity/Application/mirsurface.h (+5/-13)
src/modules/Unity/Application/mirsurfaceinterface.h (+6/-7)
src/modules/Unity/Application/mirsurfaceitem.cpp (+1/-134)
src/modules/Unity/Application/mirsurfaceitem.h (+0/-17)
tests/modules/common/fake_mirsurface.h (+6/-7)
To merge this branch: bzr merge lp://staging/~raof/qtmir/multi-bufferstream-support
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Gerry Boland (community) Needs Fixing
Review via email: mp+274517@code.staging.launchpad.net

Commit message

MirSurface/MirSurfaceItem: Implement multi-BufferStream surfaces.

Since multi-BufferStream surfaces are trivial scenegraphs themselves, implement this
as QSGNode *MirSurface::updateSubgraph(QSGNode*).

Rather than having the MirSurfaceItem be a textureProvider, use updatePaintNode to
refresh the surface sub-graph.

In turn, store the MirBufferSGTexture in a new QSGMirRenderableNode which owns the
resources and updates them. This frees us from the manual resource management;
everything is owned by the QSGNode, and Qt will clean everything up appropriately.

Description of the change

MirSurface/MirSurfaceItem: Implement multi-BufferStream surfaces.

Since multi-BufferStream surfaces are trivial scenegraphs themselves, implement this
as QSGNode *MirSurface::updateSubgraph(QSGNode*).

Rather than having the MirSurfaceItem be a textureProvider, use updatePaintNode to
refresh the surface sub-graph.

In turn, store the MirBufferSGTexture in a new QSGMirRenderableNode which owns the
resources and updates them. This frees us from the manual resource management;
everything is owned by the QSGNode, and Qt will clean everything up appropriately.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote :

Test with mir_demo_client_multistream

Revision history for this message
Gerry Boland (gerboland) wrote :

demo client is here: https://code.launchpad.net/~raof/mir/bufferstream-example/+merge/274354, and to actually get the client API supported right you need https://code.launchpad.net/~raof/mir/handle-set-streams-in-mir/+merge/274506 (or a trivial extra patch on qtmir I have locally)

Revision history for this message
Chris Halse Rogers (raof) wrote :

Those not versed in Mir internal jargon will probably find substituting “Subsurface” for “BufferStream” helpful in understanding this.

Revision history for this message
Loïc Molinari (loic.molinari) wrote :

- One difference is that MirSurfaceItems sharing the same MirSurface won't share the same texture anymore which in terms of rendering calls will result in surface buffers bound to different textures (instead of a single one). The implied resource management simplification is nice but can you confirm the cost of it (the binding) is not too high?

- The removal of the texture provider will prevent the item to be used in a ShaderEffect (or an UbuntuShape) for post-processing. So this might need to be validated with Unity guys. IMO it's not an issue since we should actually use a custom rendering node (with dedicated shaders) to do that kind of things (the custom node is actually WIP [1]).

- That call in updateSubgraph() is useless since setMatrix() on the transform node does that for you: "transformNode->markDirty(QSGNode::DirtyMatrix);".

- For performance reasons, I think clipping of subsurfaces should be done by setting the QSGMirRenderableNode size and texture coordinates appropriately instead of relying on the QtQuick renderer. The renderer efficiently uses glScissors() when the combined matrix of a node has no rotation, but it uses a slow stencil buffer based solution otherwise (which is the case for all the nodes in spread mode). That can be implemented later though.

[1] https://code.launchpad.net/~loic.molinari/qtmir/qtmir-custom-mirsurfacenode/+merge/274869

Revision history for this message
Loïc Molinari (loic.molinari) wrote :

I'm using this branch as a prerequisite for another one since we're changing the same files. I pushed a few fixes [1] that you might be interested in:

1) Merged trunk and fixed a few conflicts
2) Removed the useless markDirty call as mentioned before
3) Fixed a rendering issue (black surfaces) in spread mode (update() must be called after setAntialiasing() otherwise the node states are not sync'd)
4) Avoid iterating the nodes twice when there are new buffers available (not mandatory but a bit faster)

[1] https://code.launchpad.net/~loic.molinari/qtmir/multi-bufferstream-support-fixes

Revision history for this message
Chris Halse Rogers (raof) wrote :

Ta.

I'll get you the performance (texture bind/unbind numbers etc) figures
you were after soon. Just as soon as this damn laptop updates properly,
as I want to do a proper test with a full unity8 session.

Revision history for this message
Loïc Molinari (loic.molinari) wrote :

OK, good to get some numbers.

I've just tried the stream.cpp example but I'm just getting a red translucent surface and one renderable in generate_renderables(). Is there anything to enable?

Revision history for this message
Loïc Molinari (loic.molinari) wrote :

multi_stream.cpp, I mean.

Revision history for this message
Chris Halse Rogers (raof) wrote :

You'll need to rebuild qtmir against Mir trunk; the configure_streams call doesn't do anything unless you've got recent Mir (or make the same change in mirwindowmanager.cpp modify_surface() that https://code.launchpad.net/~raof/mir/handle-set-streams-in-mir/+merge/274506 makes.

Revision history for this message
Gerry Boland (gerboland) wrote :

+ root->removeChildNode(root->firstChild());
I suspect this is leaking nodes

review: Needs Fixing
Revision history for this message
Loïc Molinari (loic.molinari) wrote :

> + root->removeChildNode(root->firstChild());
> I suspect this is leaking nodes

Hey Gerry. I don't think so because QSGNodes have the OwnedByParent flag set at creation which makes the destruction recursive.

Revision history for this message
Loïc Molinari (loic.molinari) wrote :

There's a change in that MR that will make the rendering different when a QML scene decides to render the MirSurfaceItem at a different size than the MirSurface size (I guess this the case in the spread view on desktop). The reason is the size is not taken from the item anymore but from the renderable. So the current behaviour is a scale and the new behaviour is a an item not respecting its given size anymore (clipped by the renderer when exceeding if the clip property is enabled).

So I guess we should fix that too.

Chris: Is Mir clipping the streams, or should that be done in by the compositor?

Revision history for this message
Chris Halse Rogers (raof) wrote :

Mir is not clipping the streams. I don't think the streams *should* be clipped to the main surface - there are sensible use-cases for allowing it. For example, GTK uses subsurfaces on Wayland to draw its decorations, and they're outside the main surface pretty much by definition.

I'd probably be able to be convinced that clipping the streams to the main surface would be a good idea, though.

Revision history for this message
Chris Halse Rogers (raof) wrote :

Bah! http://doc.qt.io/qtcreator/creator-qml-performance-monitor.html suggests that setting QSG_RENDER_TIMING=1 we should get detailed timing out of the scenegraph - and, indeed, I do get _some_ - but clearly not one-per-frame, and nowhere do I see MirSurface textures being bound.

GAH.

Revision history for this message
Gerry Boland (gerboland) wrote :

> > + root->removeChildNode(root->firstChild());
> > I suspect this is leaking nodes
>
> Hey Gerry. I don't think so because QSGNodes have the OwnedByParent flag set
> at creation which makes the destruction recursive.

Looking at QSGNode::removeChildNode(QSGNode *node) source, I don't see any delete call, and it unparents the node. http://pastebin.ubuntu.com/13008194/

Revision history for this message
Gerry Boland (gerboland) wrote :

> - The removal of the texture provider will prevent the item to be used in a
> ShaderEffect (or an UbuntuShape) for post-processing. So this might need to be
> validated with Unity guys. IMO it's not an issue since we should actually use
> a custom rendering node (with dedicated shaders) to do that kind of things
> (the custom node is actually WIP [1]).

It is a bit of a pity, I had dreams of wobbly windows with a simple QML shader. But can always use an FBO, or else write custom rendering node.

Revision history for this message
Gerry Boland (gerboland) wrote :

> Mir is not clipping the streams. I don't think the streams *should* be clipped
> to the main surface - there are sensible use-cases for allowing it. For
> example, GTK uses subsurfaces on Wayland to draw its decorations, and they're
> outside the main surface pretty much by definition.

Sensible if you're a toolkit and want to deliver client-side decorations automatically to applications in a simple way, but making the window manager/compositors' job much harder.

> I'd probably be able to be convinced that clipping the streams to the main
> surface would be a good idea, though.

What is the geometry of the overall surface if it is made of disjoint subsurfaces? The bounding box geometry?

I can think of ways to abuse this to force my window to be positioned where I'd like.

Aside from window decoration case, are there other use-cases for subsurfaces being positioned outside the parent surface?

Revision history for this message
Gerry Boland (gerboland) wrote :

Conflicts with trunk.

review: Needs Fixing
Revision history for this message
Loïc Molinari (loic.molinari) wrote :

> > > + root->removeChildNode(root->firstChild());
> > > I suspect this is leaking nodes
> >
> > Hey Gerry. I don't think so because QSGNodes have the OwnedByParent flag set
> > at creation which makes the destruction recursive.
>
> Looking at QSGNode::removeChildNode(QSGNode *node) source, I don't see any
> delete call, and it unparents the node. http://pastebin.ubuntu.com/13008194/

Right! The destruction is recursive, but the removal doesn't delete. So yes, the child must be delted after the removal.

Revision history for this message
Chris Halse Rogers (raof) wrote :

> > > > + root->removeChildNode(root->firstChild());
> > > > I suspect this is leaking nodes
> > >
> > > Hey Gerry. I don't think so because QSGNodes have the OwnedByParent flag
> set
> > > at creation which makes the destruction recursive.
> >
> > Looking at QSGNode::removeChildNode(QSGNode *node) source, I don't see any
> > delete call, and it unparents the node. http://pastebin.ubuntu.com/13008194/
>
> Right! The destruction is recursive, but the removal doesn't delete. So yes,
> the child must be delted after the removal.

Well that's super-unintuitive behaviour!

Revision history for this message
Loïc Molinari (loic.molinari) wrote :

I don't know Mir enough to say whether letting clients paint outside of their bounding rect is good or not, but if so, the compositor would sometimes have to switch on clipping based on UI constraints, like for instance in spread mode. (in this case, which seems likeley, I guess we'll have to expose a property like "clipRenderables" on MirSurfaceItem that makes clipping more efficient than the QtQuick default technique, by simply setting vertex positions and texcoords of the renderable textured quads accordingly.)

Revision history for this message
Loïc Molinari (loic.molinari) wrote :

I updated the branch [1] with more fixes.

5) Fixed the node leak.

6) Switched back to stretched fill mode. I had to rework the loop a bit so that the geometry size is updated when the item size changes.

Feel free to merge that if you think it's fine.

[1] https://code.launchpad.net/~loic.molinari/qtmir/multi-bufferstream-support-fixes

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 02/11/2015 14:48, Loïc Molinari wrote:
> I don't know Mir enough to say whether letting clients paint outside of their bounding rect is good or not, but if so, the compositor would sometimes have to switch on clipping based on UI constraints, like for instance in spread mode. (in this case, which seems likeley, I guess we'll have to expose a property like "clipRenderables" on MirSurfaceItem that makes clipping more efficient than the QtQuick default technique, by simply setting vertex positions and texcoords of the renderable textured quads accordingly.)

https://code.launchpad.net/~dandrader/qtmir/surfaceItemFillMode/+merge/274750
does that.

388. By Chris Halse Rogers

Merge fixes from Loïc

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
389. By Chris Halse Rogers

Re-add empty buffer check that got mysteriously dropped

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Loïc Molinari (loic.molinari) wrote :

Thanks.

One last thing that could be different is the check for the emitSizeChanged emission. It's currently using the size of the buffer from the first renderable and the new branch uses the size of the surface. Is that guaranteed to be the same?

Revision history for this message
Chris Halse Rogers (raof) wrote :

No, it's not. The size of the first renderable may be arbitrarily different to the size of the surface; it's not guaranteed to be the “main” stream.

Having discussed it with Gerry, I think the behaviour we'll propose is:
1) All the streams of a surface will be clipped to the surface size, and
2) The surface size will be entirely independent of the size of any particular bufferstream.

Revision history for this message
Chris Halse Rogers (raof) wrote :

Oh, grr. In updating this against latest trunk I discover that we need to make some architectural decisions before qtmir has the information required to do this correctly. See also: https://docs.google.com/document/d/1Se4kbUHZNbgB9e3lrr3EQnVnQgSgFThyiBJ0MDgkZ0c

Unmerged revisions

389. By Chris Halse Rogers

Re-add empty buffer check that got mysteriously dropped

388. By Chris Halse Rogers

Merge fixes from Loïc

387. By Chris Halse Rogers

MirSurface/MirSurfaceItem: Implement multi-BufferStream surfaces.

Since multi-BufferStream surfaces are trivial scenegraphs themselves, implement this
as QSGNode *MirSurface::updateSubgraph(QSGNode*).

Rather than having the MirSurfaceItem be a textureProvider, use updatePaintNode to
refresh the surface sub-graph.

In turn, store the MirBufferSGTexture in a new QSGMirRenderableNode which owns the
resources and updates them. This frees us from the manual resource management;
everything is owned by the QSGNode, and Qt will clean everything up appropriately.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
The diff is not available at this time. You can reload the page or download it.

Subscribers

People subscribed via source and target branches