Mir

Merge lp:~alan-griffiths/mir/fix-1535894-alt into lp:mir

Proposed by Alan Griffiths
Status: Rejected
Rejected by: Alan Griffiths
Proposed branch: lp:~alan-griffiths/mir/fix-1535894-alt
Merge into: lp:mir
Diff against target: 984 lines (+181/-263)
26 files modified
examples/render_surfaces.cpp (+3/-2)
examples/server_example_adorning_compositor.cpp (+12/-1)
examples/server_example_adorning_compositor.h (+1/-1)
include/server/mir/compositor/display_buffer_compositor.h (+1/-1)
include/server/mir/compositor/scene.h (+0/-10)
include/server/mir/compositor/scene_element.h (+1/-0)
include/test/mir/test/doubles/null_display_buffer_compositor_factory.h (+2/-1)
playground/demo-shell/demo_compositor.cpp (+13/-1)
playground/demo-shell/demo_compositor.h (+1/-1)
src/server/compositor/default_display_buffer_compositor.cpp (+43/-46)
src/server/compositor/default_display_buffer_compositor.h (+1/-1)
src/server/compositor/multi_threaded_compositor.cpp (+3/-11)
src/server/scene/rendering_tracker.cpp (+9/-0)
src/server/scene/rendering_tracker.h (+1/-0)
src/server/scene/surface_stack.cpp (+10/-24)
src/server/scene/surface_stack.h (+0/-1)
tests/acceptance-tests/test_buffer_stream_arrangement.cpp (+2/-2)
tests/acceptance-tests/test_client_scaling.cpp (+2/-1)
tests/acceptance-tests/test_render_override.cpp (+3/-1)
tests/include/mir/test/doubles/stub_scene.h (+0/-4)
tests/include/mir/test/doubles/stub_scene_element.h (+5/-0)
tests/integration-tests/test_server_shutdown.cpp (+1/-1)
tests/unit-tests/compositor/test_compositing_screencast.cpp (+4/-3)
tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp (+44/-10)
tests/unit-tests/compositor/test_multi_threaded_compositor.cpp (+19/-22)
tests/unit-tests/scene/test_surface_stack.cpp (+0/-118)
To merge this branch: bzr merge lp:~alan-griffiths/mir/fix-1535894-alt
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Mir CI Bot continuous-integration Approve
Daniel van Vugt Needs Fixing
Review via email: mp+285223@code.launchpad.net

Commit message

compositor, scene: Use the DisplayBufferCompositor filtering to decide which surface have buffers that may still need compositing.

Description of the change

compositor, scene: Use the DisplayBufferCompositor filtering to decide which surface have buffers that may still need compositing.

This doesn't include logic that allows -c 3274 to be reverted, but if this approach is favoured, then I'll rework that to put the DisplayBufferCompositor(s) in control.

To post a comment you must log in.
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Errors look unrelated:

15:52:50 Setting up libuuid1:amd64 (2.27.1-1ubuntu4) ...
15:52:50 dpkg: error processing package libuuid1:amd64 (--configure):
15:52:50 subprocess installed post-installation script returned error exit status 1
15:52:50 Processing triggers for libc-bin (2.21-0ubuntu5) ...
15:52:51 Errors were encountered while processing:
15:52:51 libuuid1:amd64
15:52:51 W: No sandbox user '_apt' on the system, can not drop privileges
15:52:51 E: Sub-process /usr/bin/dpkg returned an error code (1)
15:52:51 apt-get failed.
15:52:51 Package installation failed

15:52:55 dpkg: error processing package libuuid1:i386 (--configure):
15:52:55 subprocess installed post-installation script returned error exit status 1
15:52:55 Processing triggers for libc-bin (2.21-0ubuntu5) ...
15:52:55 Errors were encountered while processing:
15:52:55 libuuid1:i386
15:52:55 W: No sandbox user '_apt' on the system, can not drop privileges
15:52:55 E: Sub-process /usr/bin/dpkg returned an error code (1)
15:52:55 apt-get failed.
15:52:55 Package installation failed

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3300
https://mir-jenkins.ubuntu.com/job/mir-ci/255/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build/43
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/49
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/45
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/45
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=amd64,compiler=gcc,platform=mesa,release=xenial/45
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=amd64,compiler=gcc,platform=mesa,release=xenial/45/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/45
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/45/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/45
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/45/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=mesa,release=xenial/45
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=mesa,release=xenial/45/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/255/rebuild

review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:3300
http://jenkins.qa.ubuntu.com/job/mir-ci/6231/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5831
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4738
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5787
    FAILURE: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/404/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/555
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/555/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/555
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/555/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5784
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5784/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/8189
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27394
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/400
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/400/artifact/work/output/*zip*/output.zip
    FAILURE: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/254/console
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27397

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/6231/rebuild

review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

1. Needs info: I thought the goal here was to skip rendering on idle displays. That code doesn't seem to be present yet, so maybe it comes later? It would be: composite() returns "I had nothing new to render" so then post() never gets called. You either need to composite and post, or do neither. But never composite without post (wasted of GPU), and never post without composite (uninitialized pixels appear on screen).

Although that raises an important question: Is the bug safe to fix at all under the new display groups architecture? How do we safely tell Android to only post one of the displays in the group but not the other? I'm wondering if it's even possible to fix this under the display group approach... because you must either have one composite and one post, or zero of all.

2. Needs fixing: Please add the FIXME comment back in. It's an important one we shouldn't forget.

I'm also nervous that we're rewriting so much code that covers years of regression fixes. But that's not quite a blocking issue.

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

3. This looks like important code that will cause regressions if removed:
- int result = scene_changed ? 1 : 0;

That tells us to redraw the screen if a window has been dragged, but no windows contents changed. Obviously was missing a test.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

OK, assuming Android has some magic workaround built-in to cope with posting a display group where only half of that group has been rendered, what we actually want instead of this branch is:

bool composited = false
for each compositor:
   composited |= compositor->composite();
if (composited)
   group.post();

That also means you can keep the frame counting logic where it is in the scene. No need to duplicate it into each compositor implementation.

But if Android can't handle half the monitors being rendered and then being told to post the whole group, then we actually can't safely do any of this at all...

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> 1. Needs info: I thought the goal here was to skip rendering on idle displays.
> That code doesn't seem to be present yet, so maybe it comes later? It would
> be: composite() returns "I had nothing new to render" so then post() never
> gets called. You either need to composite and post, or do neither. But never
> composite without post (wasted of GPU), and never post without composite
> (uninitialized pixels appear on screen).

Nope.

The point of *this* MP is that the DisplayBufferCompositor knows which surfaces it has rendered and interrogates them to see if they have further buffers pending.

With the logic in scene we were counting buffers belonging to surfaces that had not contributed to rendering. (And would not be consumed by the consequent render pass.)

In the scenario from the linked bug the nested server would repeatedly schedule a recomposite of whichever display on which nothing had been posted.

> 2. Needs fixing: Please add the FIXME comment back in. It's an important one
> we shouldn't forget.

OK

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> 3. This looks like important code that will cause regressions if removed:
> - int result = scene_changed ? 1 : 0;
>
> That tells us to redraw the screen if a window has been dragged, but no
> windows contents changed. Obviously was missing a test.

Obviously, this code duplicated the effect of CompositingFunctor::schedule_compositing(int num) and was redundant.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Oh cool. That all sounds like good news then. I'll need to re-evaluate later.

review: Abstain
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

(1) Thanks for explaining. So I took some time today adding and analysing some debug logging to try and catch Mir in the act of repeatedly scheduling frames on some display but never consuming them. Unfortunately I can't yet reproduce such a busy wait but that could be just that I'm using desktop, or it could just be bad luck. So I'm assuming there's still a theoretical problem needing fixing.

But now I'm curious: You've clarified you're just fixing a busy wait. Or as I would say it "made Mir sleep properly". That's very good for power management, but only a small piece of the performance story. Even if this branch is working perfectly, you're still re-posting all displays on every frame (including the idle one) while any one of them is animating. So this is really a power management fix, but how is it an improvement to performance? You haven't changed the rendering load, and haven't reduced the number of posts either.

(2) Needs fixing: FIXME comment is still missing.

(4) I'm not yet confident this branch is working. As stated in (1) I can't yet put together a manual test case on desktop to reproduce any issue, and the diff below shows no new regression tests for anything getting fixed. So I think you need to try and write a regression test for the issue.

(5) In theory there's a much simpler solution you should consider. That is just make every call to BasicSurface::generate_renderables acquire its compositor buffer immediately, instead of the lazy acquisition it does in SurfaceSnapshot::buffer(). In theory that's a tiny change, it would solve the same problem, and is easier to test.

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

(1) "You haven't changed the rendering load, and haven't reduced the number of posts either" [while any display is changing anyway]

(5) Here's possible alternative solution:
https://code.launchpad.net/~mir-team/mir/compositing-always-finishes/+merge/285684

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> but only a small piece of the performance story. Even if this branch is
> working perfectly, you're still re-posting all displays on every frame
> (including the idle one) while any one of them is animating.

Remember, this is in the nested server which has a CompositingFunctor for each output.

The earlier change (that you have valid concerns about) ensures that the CompositingFunctor doesn't run for changes that do not apply to its display buffers compositor.

> So this is really
> a power management fix, but how is it an improvement to performance? You
> haven't changed the rendering load, and haven't reduced the number of posts
> either.

The problem this addresses occurs whenever the "idle" CompositingFunctor runs. First it composites the surfaces visible to its DBC and then checks the scene for unconsumed frames. Updates on the other screen cause it to increment frames_scheduled and composite unnecessarily.

By only checking for unconsumed frames in the surfaces that have been rendered we avoid that extra pass.

> (2) Needs fixing: FIXME comment is still missing.
>
> (4) I'm not yet confident this branch is working. As stated in (1) I can't yet
> put together a manual test case on desktop to reproduce any issue, and the
> diff below shows no new regression tests for anything getting fixed. So I
> think you need to try and write a regression test for the issue.

Ack.

3301. By Alan Griffiths

merge lp:mir

3302. By Alan Griffiths

Reinstate FIXME comment

3303. By Alan Griffiths

Remove some unused headers

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

nm. -c 3301 seems to have addressed the problem I was seeing. (Not sure how, so I must have misinterpreted the system behaviour - we need better reporting out of the compositor.)

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3303
https://mir-jenkins.ubuntu.com/job/mir-ci/285/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build/73
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/79
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/75
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/75
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=amd64,compiler=gcc,platform=mesa,release=xenial/75
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=amd64,compiler=gcc,platform=mesa,release=xenial/75/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/75
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/75/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/75
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/75/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=mesa,release=xenial/75
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=mesa,release=xenial/75/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/285/rebuild

review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:3303
http://jenkins.qa.ubuntu.com/job/mir-ci/6271/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5882
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4789
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5838
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/423
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/595
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/595/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/595
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/595/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5835
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5835/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/8232
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27501
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/419
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/419/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/272
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27507

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/6271/rebuild

review: Approve (continuous-integration)

Unmerged revisions

3303. By Alan Griffiths

Remove some unused headers

3302. By Alan Griffiths

Reinstate FIXME comment

3301. By Alan Griffiths

merge lp:mir

3300. By Alan Griffiths

Cleaner code in examples

3299. By Alan Griffiths

Cleaner code (that also passes StaleFrames.* tests)

3298. By Alan Griffiths

Add corresponding DefaultDisplayBufferCompositor tests

3297. By Alan Griffiths

Remove unnecessary Scene::frames_pending()

3296. By Alan Griffiths

Fixup broken test

3295. By Alan Griffiths

First pass at pending buffer count

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'examples/render_surfaces.cpp'
2--- examples/render_surfaces.cpp 2016-01-29 08:18:22 +0000
3+++ examples/render_surfaces.cpp 2016-02-11 14:50:57 +0000
4@@ -241,7 +241,7 @@
5 {
6 }
7
8- void composite(mc::SceneElementSequence&& scene_sequence) override
9+ int composite(mc::SceneElementSequence&& scene_sequence) override
10 {
11 while (!created) std::this_thread::yield();
12 stop_watch.stop();
13@@ -252,12 +252,13 @@
14 stop_watch.restart();
15 }
16
17- db_compositor->composite(std::move(scene_sequence));
18+ auto const result = db_compositor->composite(std::move(scene_sequence));
19
20 for (auto& m : moveables)
21 m.step();
22
23 frames++;
24+ return result;
25 }
26
27 private:
28
29=== modified file 'examples/server_example_adorning_compositor.cpp'
30--- examples/server_example_adorning_compositor.cpp 2016-02-08 17:58:09 +0000
31+++ examples/server_example_adorning_compositor.cpp 2016-02-11 14:50:57 +0000
32@@ -174,7 +174,7 @@
33 }
34 }
35
36-void me::AdorningDisplayBufferCompositor::composite(compositor::SceneElementSequence&& scene_sequence)
37+int me::AdorningDisplayBufferCompositor::composite(compositor::SceneElementSequence&& scene_sequence)
38 {
39 report->began_frame(this);
40
41@@ -250,4 +250,15 @@
42 render_target->swap_buffers();
43
44 report->finished_frame(this);
45+
46+ auto max_pending_buffers = 0;
47+ for (auto const& element : scene_sequence)
48+ {
49+ auto buffers_for_element = element->pending_buffers();
50+
51+ if (max_pending_buffers < buffers_for_element)
52+ max_pending_buffers = buffers_for_element;
53+ }
54+
55+ return max_pending_buffers;
56 }
57
58=== modified file 'examples/server_example_adorning_compositor.h'
59--- examples/server_example_adorning_compositor.h 2016-01-29 08:18:22 +0000
60+++ examples/server_example_adorning_compositor.h 2016-02-11 14:50:57 +0000
61@@ -40,7 +40,7 @@
62 graphics::DisplayBuffer&, std::tuple<float, float, float> const& background_rgb,
63 std::shared_ptr<compositor::CompositorReport> const& report);
64
65- void composite(compositor::SceneElementSequence&& scene_sequence) override;
66+ int composite(compositor::SceneElementSequence&& scene_sequence) override;
67 private:
68 graphics::DisplayBuffer& db;
69 renderer::gl::RenderTarget* const render_target;
70
71=== modified file 'include/server/mir/compositor/display_buffer_compositor.h'
72--- include/server/mir/compositor/display_buffer_compositor.h 2015-02-22 07:46:25 +0000
73+++ include/server/mir/compositor/display_buffer_compositor.h 2016-02-11 14:50:57 +0000
74@@ -32,7 +32,7 @@
75 public:
76 virtual ~DisplayBufferCompositor() = default;
77
78- virtual void composite(SceneElementSequence&& scene_sequence) = 0;
79+ virtual int composite(SceneElementSequence&& scene_sequence) = 0;
80
81 protected:
82 DisplayBufferCompositor() = default;
83
84=== modified file 'include/server/mir/compositor/scene.h'
85--- include/server/mir/compositor/scene.h 2015-02-22 07:46:25 +0000
86+++ include/server/mir/compositor/scene.h 2016-02-11 14:50:57 +0000
87@@ -55,16 +55,6 @@
88 */
89 virtual SceneElementSequence scene_elements_for(CompositorID id) = 0;
90
91- /**
92- * Return the number of additional frames that you need to render to get
93- * fully up to date with the latest data in the scene. For a generic
94- * "scene change" this will be just 1. For surfaces that have multiple
95- * frames queued up however, it could be greater than 1. When the result
96- * reaches zero, you know you have consumed all the latest data from the
97- * scene.
98- */
99- virtual int frames_pending(CompositorID id) const = 0;
100-
101 virtual void register_compositor(CompositorID id) = 0;
102 virtual void unregister_compositor(CompositorID id) = 0;
103
104
105=== modified file 'include/server/mir/compositor/scene_element.h'
106--- include/server/mir/compositor/scene_element.h 2015-06-17 05:20:42 +0000
107+++ include/server/mir/compositor/scene_element.h 2016-02-11 14:50:57 +0000
108@@ -38,6 +38,7 @@
109 virtual std::shared_ptr<graphics::Renderable> renderable() const = 0;
110 virtual void rendered() = 0;
111 virtual void occluded() = 0;
112+ virtual int pending_buffers() const = 0;
113
114 //TODO: Decoration is opaque on purpose. It is only used by an internal example,
115 // and this function should be removed from the public API.
116
117=== modified file 'include/test/mir/test/doubles/null_display_buffer_compositor_factory.h'
118--- include/test/mir/test/doubles/null_display_buffer_compositor_factory.h 2016-01-29 08:18:22 +0000
119+++ include/test/mir/test/doubles/null_display_buffer_compositor_factory.h 2016-02-11 14:50:57 +0000
120@@ -39,11 +39,12 @@
121 {
122 struct NullDisplayBufferCompositor : compositor::DisplayBufferCompositor
123 {
124- void composite(compositor::SceneElementSequence&&)
125+ int composite(compositor::SceneElementSequence&&)
126 {
127 // yield() is needed to ensure reasonable runtime under
128 // valgrind for some tests
129 std::this_thread::yield();
130+ return 0;
131 }
132 };
133
134
135=== modified file 'playground/demo-shell/demo_compositor.cpp'
136--- playground/demo-shell/demo_compositor.cpp 2016-01-29 08:18:22 +0000
137+++ playground/demo-shell/demo_compositor.cpp 2016-02-11 14:50:57 +0000
138@@ -58,7 +58,7 @@
139 f(*i);
140 }
141
142-void me::DemoCompositor::composite(mc::SceneElementSequence&& elements)
143+int me::DemoCompositor::composite(mc::SceneElementSequence&& elements)
144 {
145 report->began_frame(this);
146 //a simple filtering out of renderables that shouldn't be drawn
147@@ -106,6 +106,16 @@
148 nonrenderlist_elements |= embellished;
149 }
150
151+ auto max_pending_buffers = 0;
152+ for (auto const& element : elements)
153+ {
154+ // We're about to render a buffer, so don't count that one
155+ auto buffers_for_element = element->pending_buffers() - 1;
156+
157+ if (max_pending_buffers < buffers_for_element)
158+ max_pending_buffers = buffers_for_element;
159+ }
160+
161 /*
162 * Note: Buffer lifetimes are ensured by the two objects holding
163 * references to them; elements and renderable_list.
164@@ -141,6 +151,8 @@
165 }
166
167 report->finished_frame(this);
168+
169+ return max_pending_buffers;
170 }
171
172 void me::DemoCompositor::on_cursor_movement(
173
174=== modified file 'playground/demo-shell/demo_compositor.h'
175--- playground/demo-shell/demo_compositor.h 2015-02-22 07:46:25 +0000
176+++ playground/demo-shell/demo_compositor.h 2016-02-11 14:50:57 +0000
177@@ -50,7 +50,7 @@
178 std::shared_ptr<compositor::CompositorReport> const& report);
179 ~DemoCompositor();
180
181- void composite(compositor::SceneElementSequence&& elements) override;
182+ int composite(compositor::SceneElementSequence&& elements) override;
183
184 void zoom(float mag);
185 void on_cursor_movement(geometry::Point const& p);
186
187=== modified file 'src/server/compositor/default_display_buffer_compositor.cpp'
188--- src/server/compositor/default_display_buffer_compositor.cpp 2016-01-29 08:18:22 +0000
189+++ src/server/compositor/default_display_buffer_compositor.cpp 2016-02-11 14:50:57 +0000
190@@ -1,5 +1,5 @@
191 /*
192- * Copyright © 2012 Canonical Ltd.
193+ * Copyright © 2012-2016 Canonical Ltd.
194 *
195 * This program is free software: you can redistribute it and/or modify it
196 * under the terms of the GNU General Public License version 3,
197@@ -19,16 +19,13 @@
198
199 #include "default_display_buffer_compositor.h"
200
201-#include "mir/compositor/scene.h"
202 #include "mir/compositor/scene_element.h"
203 #include "mir/compositor/renderer.h"
204 #include "mir/graphics/renderable.h"
205 #include "mir/graphics/display_buffer.h"
206 #include "mir/graphics/buffer.h"
207-#include "mir/compositor/buffer_stream.h"
208 #include "occlusion.h"
209-#include <mutex>
210-#include <cstdlib>
211+
212 #include <algorithm>
213
214 namespace mc = mir::compositor;
215@@ -44,52 +41,52 @@
216 {
217 }
218
219-void mc::DefaultDisplayBufferCompositor::composite(mc::SceneElementSequence&& scene_elements)
220+int mc::DefaultDisplayBufferCompositor::composite(SceneElementSequence&& scene_elements)
221 {
222 report->began_frame(this);
223
224- auto const& view_area = display_buffer.view_area();
225- auto const& occlusions = mc::filter_occlusions_from(scene_elements, view_area);
226-
227- for (auto const& element : occlusions)
228+ for (auto const& element : filter_occlusions_from(scene_elements, display_buffer.view_area()))
229 element->occluded();
230
231- mg::RenderableList renderable_list;
232- renderable_list.reserve(scene_elements.size());
233+ {
234+ mg::RenderableList renderable_list;
235+ renderable_list.reserve(scene_elements.size());
236+
237+ transform(begin(scene_elements), end(scene_elements), back_inserter(renderable_list), [] (auto& element)
238+ {
239+ element->rendered();
240+ return element->renderable();
241+ });
242+
243+ if (display_buffer.post_renderables_if_optimizable(renderable_list))
244+ {
245+ report->renderables_in_frame(this, renderable_list);
246+ renderer->suspend();
247+ }
248+ else
249+ {
250+ renderer->set_rotation(display_buffer.orientation());
251+ renderer->render(renderable_list);
252+
253+ report->renderables_in_frame(this, renderable_list);
254+ report->rendered_frame(this);
255+ }
256+ }
257+
258+ report->finished_frame(this);
259+
260+ auto max_pending_buffers = 0;
261 for (auto const& element : scene_elements)
262 {
263- element->rendered();
264- renderable_list.push_back(element->renderable());
265- }
266-
267- /*
268- * Note: Buffer lifetimes are ensured by the two objects holding
269- * references to them; scene_elements and renderable_list.
270- * So no buffer is going to be released back to the client till
271- * both of those containers get destroyed (end of the function).
272- * Actually, there's a third reference held by the texture cache
273- * in GLRenderer, but that gets released earlier in render().
274- */
275- scene_elements.clear(); // Those in use are still in renderable_list
276-
277- if (display_buffer.post_renderables_if_optimizable(renderable_list))
278- {
279- report->renderables_in_frame(this, renderable_list);
280- renderer->suspend();
281- }
282- else
283- {
284- renderer->set_rotation(display_buffer.orientation());
285- renderer->render(renderable_list);
286-
287- report->renderables_in_frame(this, renderable_list);
288- report->rendered_frame(this);
289-
290- // Release the buffers we did use back to the clients, before starting
291- // on the potentially slow flip().
292- // FIXME: This clear() call is blocking a little because we drive IPC here (LP: #1395421)
293- renderable_list.clear();
294- }
295-
296- report->finished_frame(this);
297+ auto buffers_for_element = element->pending_buffers();
298+
299+ if (max_pending_buffers < buffers_for_element)
300+ max_pending_buffers = buffers_for_element;
301+ }
302+
303+ return max_pending_buffers;
304+
305+ // Returning destroys the local renderable_list and the temporary scene_elements which releases
306+ // the buffers we did use back to the clients, before starting on the potentially slow flip().
307+ // FIXME: releasing the buffers is blocking a little because we drive IPC here (LP: #1395421)
308 }
309
310=== modified file 'src/server/compositor/default_display_buffer_compositor.h'
311--- src/server/compositor/default_display_buffer_compositor.h 2015-04-28 07:54:10 +0000
312+++ src/server/compositor/default_display_buffer_compositor.h 2016-02-11 14:50:57 +0000
313@@ -43,7 +43,7 @@
314 std::shared_ptr<Renderer> const& renderer,
315 std::shared_ptr<CompositorReport> const& report);
316
317- void composite(SceneElementSequence&& scene_sequence) override;
318+ int composite(SceneElementSequence&& scene_sequence) override;
319
320 private:
321 graphics::DisplayBuffer& display_buffer;
322
323=== modified file 'src/server/compositor/multi_threaded_compositor.cpp'
324--- src/server/compositor/multi_threaded_compositor.cpp 2016-02-09 16:40:57 +0000
325+++ src/server/compositor/multi_threaded_compositor.cpp 2016-02-11 14:50:57 +0000
326@@ -131,14 +131,15 @@
327 * frames_scheduled indicates the number of frames that are scheduled
328 * to ensure all surfaces' queues are fully drained.
329 */
330- frames_scheduled--;
331+ int pending = --frames_scheduled;
332 not_posted_yet = false;
333 lock.unlock();
334
335 for (auto& tuple : compositors)
336 {
337 auto& compositor = std::get<1>(tuple);
338- compositor->composite(scene->scene_elements_for(compositor.get()));
339+ auto max_pending_frames = compositor->composite(scene->scene_elements_for(compositor.get()));
340+ if (pending < max_pending_frames) pending = max_pending_frames;
341 }
342 group.post();
343
344@@ -161,15 +162,6 @@
345 * important to re-count number of frames pending, separately
346 * to the initial scene_elements_for()...
347 */
348- int pending = 0;
349- for (auto& compositor : compositors)
350- {
351- auto const comp_id = std::get<1>(compositor).get();
352- int pend = scene->frames_pending(comp_id);
353- if (pend > pending)
354- pending = pend;
355- }
356-
357 if (pending > frames_scheduled)
358 frames_scheduled = pending;
359 }
360
361=== modified file 'src/server/scene/rendering_tracker.cpp'
362--- src/server/scene/rendering_tracker.cpp 2016-01-29 08:18:22 +0000
363+++ src/server/scene/rendering_tracker.cpp 2016-02-11 14:50:57 +0000
364@@ -80,6 +80,15 @@
365 return occlusions.find(cid) == occlusions.end();
366 }
367
368+int ms::RenderingTracker::pending_buffers_for(compositor::CompositorID cid) const
369+{
370+ if (auto const surface = weak_surface.lock())
371+ return surface->buffers_ready_for_compositor(cid);
372+ else
373+ return 0;
374+}
375+
376+
377 bool ms::RenderingTracker::occluded_in_all_active_compositors()
378 {
379 return occlusions == active_compositors_;
380
381=== modified file 'src/server/scene/rendering_tracker.h'
382--- src/server/scene/rendering_tracker.h 2016-01-29 08:18:22 +0000
383+++ src/server/scene/rendering_tracker.h 2016-02-11 14:50:57 +0000
384@@ -43,6 +43,7 @@
385 void occluded_in(compositor::CompositorID cid);
386 void active_compositors(std::set<compositor::CompositorID> const& cids);
387 bool is_exposed_in(compositor::CompositorID cid) const;
388+ int pending_buffers_for(compositor::CompositorID cid) const;
389
390 private:
391 bool occluded_in_all_active_compositors();
392
393=== modified file 'src/server/scene/surface_stack.cpp'
394--- src/server/scene/surface_stack.cpp 2016-01-29 08:18:22 +0000
395+++ src/server/scene/surface_stack.cpp 2016-02-11 14:50:57 +0000
396@@ -73,6 +73,11 @@
397 tracker->occluded_in(cid);
398 }
399
400+ int pending_buffers() const override
401+ {
402+ return tracker->pending_buffers_for(cid);
403+ }
404+
405 std::unique_ptr<mc::Decoration> decoration() const override
406 {
407 return std::make_unique<mc::Decoration>(mc::Decoration::Type::surface, surface_name);
408@@ -108,6 +113,11 @@
409 {
410 }
411
412+ int pending_buffers() const override
413+ {
414+ return 0;
415+ }
416+
417 std::unique_ptr<mc::Decoration> decoration() const override
418 {
419 return std::make_unique<mc::Decoration>();
420@@ -154,30 +164,6 @@
421 return elements;
422 }
423
424-int ms::SurfaceStack::frames_pending(mc::CompositorID id) const
425-{
426- RecursiveReadLock lg(guard);
427-
428- int result = scene_changed ? 1 : 0;
429- for (auto const& surface : surfaces)
430- {
431- if (surface->visible())
432- {
433- auto const tracker = rendering_trackers.find(surface.get());
434- if (tracker != rendering_trackers.end() && tracker->second->is_exposed_in(id))
435- {
436- // Note that we ask the surface and not a Renderable.
437- // This is because we don't want to waste time and resources
438- // on a snapshot till we're sure we need it...
439- int ready = surface->buffers_ready_for_compositor(id);
440- if (ready > result)
441- result = ready;
442- }
443- }
444- }
445- return result;
446-}
447-
448 void ms::SurfaceStack::register_compositor(mc::CompositorID cid)
449 {
450 RecursiveWriteLock lg(guard);
451
452=== modified file 'src/server/scene/surface_stack.h'
453--- src/server/scene/surface_stack.h 2016-01-29 08:18:22 +0000
454+++ src/server/scene/surface_stack.h 2016-02-11 14:50:57 +0000
455@@ -74,7 +74,6 @@
456
457 // From Scene
458 compositor::SceneElementSequence scene_elements_for(compositor::CompositorID id) override;
459- int frames_pending(compositor::CompositorID) const override;
460 void register_compositor(compositor::CompositorID id) override;
461 void unregister_compositor(compositor::CompositorID id) override;
462
463
464=== modified file 'tests/acceptance-tests/test_buffer_stream_arrangement.cpp'
465--- tests/acceptance-tests/test_buffer_stream_arrangement.cpp 2016-01-29 08:18:22 +0000
466+++ tests/acceptance-tests/test_buffer_stream_arrangement.cpp 2016-02-11 14:50:57 +0000
467@@ -167,10 +167,10 @@
468 {
469 }
470
471- void composite(mc::SceneElementSequence&& scene_sequence) override
472+ int composite(mc::SceneElementSequence&& scene_sequence) override
473 {
474 ordering->note_scene_element_sequence(scene_sequence);
475- wrapped->composite(std::move(scene_sequence));
476+ return wrapped->composite(std::move(scene_sequence));
477 }
478
479 std::shared_ptr<mc::DisplayBufferCompositor> const wrapped;
480
481=== modified file 'tests/acceptance-tests/test_client_scaling.cpp'
482--- tests/acceptance-tests/test_client_scaling.cpp 2016-01-29 08:18:22 +0000
483+++ tests/acceptance-tests/test_client_scaling.cpp 2016-02-11 14:50:57 +0000
484@@ -120,10 +120,11 @@
485 {
486 }
487
488- void composite(mc::SceneElementSequence&& seq)
489+ int composite(mc::SceneElementSequence&& seq)
490 {
491 watch->note_renderable_sizes(this, seq);
492 std::this_thread::yield();
493+ return 0;
494 }
495
496 std::shared_ptr<SizeWatcher> const watch;
497
498=== modified file 'tests/acceptance-tests/test_render_override.cpp'
499--- tests/acceptance-tests/test_render_override.cpp 2015-06-17 05:20:42 +0000
500+++ tests/acceptance-tests/test_render_override.cpp 2016-02-11 14:50:57 +0000
501@@ -74,7 +74,7 @@
502 {
503 }
504
505- void composite(mc::SceneElementSequence&& sequence) override
506+ int composite(mc::SceneElementSequence&& sequence) override
507 {
508 for(auto const& element : sequence)
509 {
510@@ -82,6 +82,8 @@
511 renderable->buffer(); //consume buffer to stop compositor from spinning
512 tracker->surface_rendered_with_size(renderable->screen_position().size);
513 }
514+
515+ return 0;
516 }
517 private:
518 std::shared_ptr<CompositionTracker> const tracker;
519
520=== modified file 'tests/include/mir/test/doubles/stub_scene.h'
521--- tests/include/mir/test/doubles/stub_scene.h 2015-02-22 07:46:25 +0000
522+++ tests/include/mir/test/doubles/stub_scene.h 2016-02-11 14:50:57 +0000
523@@ -36,10 +36,6 @@
524 {
525 return {};
526 }
527- int frames_pending(compositor::CompositorID) const override
528- {
529- return 0;
530- }
531 void register_compositor(compositor::CompositorID) override
532 {
533 }
534
535=== modified file 'tests/include/mir/test/doubles/stub_scene_element.h'
536--- tests/include/mir/test/doubles/stub_scene_element.h 2015-06-17 05:20:42 +0000
537+++ tests/include/mir/test/doubles/stub_scene_element.h 2016-02-11 14:50:57 +0000
538@@ -56,6 +56,11 @@
539 {
540 }
541
542+ int pending_buffers() const override
543+ {
544+ return 0;
545+ }
546+
547 std::unique_ptr<compositor::Decoration> decoration() const override
548 {
549 return nullptr;
550
551=== modified file 'tests/integration-tests/test_server_shutdown.cpp'
552--- tests/integration-tests/test_server_shutdown.cpp 2016-01-29 08:18:22 +0000
553+++ tests/integration-tests/test_server_shutdown.cpp 2016-02-11 14:50:57 +0000
554@@ -189,7 +189,7 @@
555 {
556 struct ExceptionThrowingDisplayBufferCompositor : mc::DisplayBufferCompositor
557 {
558- void composite(mc::SceneElementSequence&&) override
559+ int composite(mc::SceneElementSequence&&) override
560 {
561 throw std::runtime_error("ExceptionThrowingDisplayBufferCompositor");
562 }
563
564=== modified file 'tests/unit-tests/compositor/test_compositing_screencast.cpp'
565--- tests/unit-tests/compositor/test_compositing_screencast.cpp 2016-02-01 22:53:06 +0000
566+++ tests/unit-tests/compositor/test_compositing_screencast.cpp 2016-02-11 14:50:57 +0000
567@@ -118,9 +118,10 @@
568
569 struct MockDisplayBufferCompositor : mc::DisplayBufferCompositor
570 {
571- void composite(mc::SceneElementSequence&& seq)
572+ int composite(mc::SceneElementSequence&& seq)
573 {
574 composite_(seq);
575+ return 0;
576 }
577
578 MOCK_METHOD1(composite_, void(mc::SceneElementSequence&));
579@@ -134,9 +135,9 @@
580 {
581 }
582
583- void composite(mc::SceneElementSequence&& elements)
584+ int composite(mc::SceneElementSequence&& elements)
585 {
586- comp.composite(std::move(elements));
587+ return comp.composite(std::move(elements));
588 }
589
590 private:
591
592=== modified file 'tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp'
593--- tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp 2016-01-29 08:18:22 +0000
594+++ tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp 2016-02-11 14:50:57 +0000
595@@ -48,6 +48,7 @@
596
597 namespace mt = mir::test;
598 namespace mtd = mir::test::doubles;
599+using namespace testing;
600
601 namespace
602 {
603@@ -72,6 +73,11 @@
604 {
605 }
606
607+ int pending_buffers() const override
608+ {
609+ return 0;
610+ }
611+
612 std::unique_ptr<mc::Decoration> decoration() const override
613 {
614 return nullptr;
615@@ -97,7 +103,6 @@
616 big(std::make_shared<mtd::FakeRenderable>(geom::Rectangle{{5, 10},{100, 200}})),
617 fullscreen(std::make_shared<mtd::FakeRenderable>(screen))
618 {
619- using namespace testing;
620 ON_CALL(display_buffer, orientation())
621 .WillByDefault(Return(mir_orientation_normal));
622 ON_CALL(display_buffer, view_area())
623@@ -106,7 +111,7 @@
624 .WillByDefault(Return(false));
625 }
626
627- testing::NiceMock<mtd::MockRenderer> mock_renderer;
628+ NiceMock<mtd::MockRenderer> mock_renderer;
629 geom::Rectangle screen{{0, 0}, {1366, 768}};
630 testing::NiceMock<mtd::MockDisplayBuffer> display_buffer;
631 std::shared_ptr<mtd::FakeRenderable> small;
632@@ -132,7 +137,6 @@
633
634 TEST_F(DefaultDisplayBufferCompositor, optimization_skips_composition)
635 {
636- using namespace testing;
637 auto report = std::make_shared<mtd::MockCompositorReport>();
638
639 Sequence seq;
640@@ -190,7 +194,6 @@
641
642 TEST_F(DefaultDisplayBufferCompositor, calls_renderer_in_sequence)
643 {
644- using namespace testing;
645 Sequence render_seq;
646 EXPECT_CALL(mock_renderer, suspend())
647 .Times(0);
648@@ -215,7 +218,6 @@
649
650 TEST_F(DefaultDisplayBufferCompositor, optimization_toggles_seamlessly)
651 {
652- using namespace testing;
653 ON_CALL(display_buffer, view_area())
654 .WillByDefault(Return(screen));
655 ON_CALL(display_buffer, orientation())
656@@ -262,7 +264,6 @@
657
658 TEST_F(DefaultDisplayBufferCompositor, occluded_surfaces_are_not_rendered)
659 {
660- using namespace testing;
661 EXPECT_CALL(display_buffer, view_area())
662 .WillRepeatedly(Return(screen));
663 EXPECT_CALL(display_buffer, orientation())
664@@ -305,13 +306,12 @@
665 MOCK_CONST_METHOD0(decoration, std::unique_ptr<mc::Decoration>());
666 MOCK_METHOD0(rendered, void());
667 MOCK_METHOD0(occluded, void());
668+ MOCK_CONST_METHOD0(pending_buffers, int());
669 };
670 }
671
672 TEST_F(DefaultDisplayBufferCompositor, marks_rendered_scene_elements)
673 {
674- using namespace testing;
675-
676 auto element0_rendered = std::make_shared<NiceMock<MockSceneElement>>(
677 std::make_shared<mtd::FakeRenderable>(geom::Rectangle{{99,99},{2,2}}));
678 auto element1_rendered = std::make_shared<NiceMock<MockSceneElement>>(
679@@ -330,8 +330,6 @@
680
681 TEST_F(DefaultDisplayBufferCompositor, marks_occluded_scene_elements)
682 {
683- using namespace testing;
684-
685 auto element0_occluded = std::make_shared<NiceMock<MockSceneElement>>(
686 std::make_shared<mtd::FakeRenderable>(geom::Rectangle{{10,10},{20,20}}));
687 auto element1_rendered = std::make_shared<NiceMock<MockSceneElement>>(
688@@ -351,3 +349,39 @@
689 compositor.composite({element0_occluded, element1_rendered, element2_occluded});
690 }
691
692+TEST_F(DefaultDisplayBufferCompositor, reports_pending_frames_accurately)
693+{
694+ auto const element = std::make_shared<NiceMock<MockSceneElement>>(
695+ std::make_shared<mtd::FakeRenderable>(geom::Rectangle{{10,10},{20,20}}));
696+
697+ mc::DefaultDisplayBufferCompositor compositor(
698+ display_buffer,
699+ mt::fake_shared(mock_renderer),
700+ mr::null_compositor_report());
701+
702+ EXPECT_THAT(compositor.composite({element}), Eq(0));
703+
704+ auto const pending_frames_before = 3;
705+ auto const pending_frames_after = pending_frames_before-1;
706+
707+ EXPECT_CALL(*element, pending_buffers()).WillOnce(Return(pending_frames_after));
708+ EXPECT_THAT(compositor.composite({element}), Eq(pending_frames_after));
709+}
710+
711+TEST_F(DefaultDisplayBufferCompositor, doesnt_count_pending_frames_from_occluded_surfaces)
712+{
713+ auto const element = std::make_shared<NiceMock<MockSceneElement>>(
714+ std::make_shared<mtd::FakeRenderable>(geom::Rectangle{screen.bottom_right(),{20,20}}));
715+
716+ mc::DefaultDisplayBufferCompositor compositor(
717+ display_buffer,
718+ mt::fake_shared(mock_renderer),
719+ mr::null_compositor_report());
720+
721+ EXPECT_THAT(compositor.composite({element}), Eq(0));
722+
723+ auto const pending_frames = 3;
724+ ON_CALL(*element, pending_buffers()).WillByDefault(Return(pending_frames));
725+
726+ EXPECT_THAT(compositor.composite({element}), Eq(0));
727+}
728
729=== modified file 'tests/unit-tests/compositor/test_multi_threaded_compositor.cpp'
730--- tests/unit-tests/compositor/test_multi_threaded_compositor.cpp 2016-02-01 09:42:10 +0000
731+++ tests/unit-tests/compositor/test_multi_threaded_compositor.cpp 2016-02-11 14:50:57 +0000
732@@ -96,8 +96,8 @@
733 class StubScene : public mtd::StubScene
734 {
735 public:
736- StubScene()
737- : pending{0}, throw_on_add_observer_{false}
738+ StubScene() :
739+ throw_on_add_observer_{false}
740 {
741 }
742
743@@ -136,19 +136,7 @@
744 throw_on_add_observer_ = flag;
745 }
746
747- int frames_pending(mc::CompositorID) const override
748- {
749- return pending;
750- }
751-
752- void set_pending(int n)
753- {
754- pending = n;
755- observer->scene_changed();
756- }
757-
758 private:
759- std::atomic<int> pending;
760 std::mutex observer_mutex;
761 std::shared_ptr<ms::Observer> observer;
762 bool throw_on_add_observer_;
763@@ -157,20 +145,21 @@
764 class RecordingDisplayBufferCompositor : public mc::DisplayBufferCompositor
765 {
766 public:
767- RecordingDisplayBufferCompositor(std::function<void()> const& mark_render_buffer)
768+ RecordingDisplayBufferCompositor(std::function<int()> const& mark_render_buffer)
769 : mark_render_buffer{mark_render_buffer}
770 {
771 }
772
773- void composite(mc::SceneElementSequence&&)
774+ int composite(mc::SceneElementSequence&&)
775 {
776- mark_render_buffer();
777+ auto const result = mark_render_buffer();
778 /* Reduce run-time under valgrind */
779 std::this_thread::yield();
780+ return result;
781 }
782
783 private:
784- std::function<void()> const mark_render_buffer;
785+ std::function<int()> const mark_render_buffer;
786 };
787
788
789@@ -182,12 +171,12 @@
790 auto raw = new RecordingDisplayBufferCompositor{
791 [&display_buffer,this]()
792 {
793- mark_render_buffer(display_buffer);
794+ return mark_render_buffer(display_buffer);
795 }};
796 return std::unique_ptr<RecordingDisplayBufferCompositor>(raw);
797 }
798
799- void mark_render_buffer(mg::DisplayBuffer& display_buffer)
800+ int mark_render_buffer(mg::DisplayBuffer& display_buffer)
801 {
802 std::lock_guard<std::mutex> lk{m};
803
804@@ -196,6 +185,8 @@
805
806 ++records[&display_buffer].first;
807 records[&display_buffer].second.insert(std::this_thread::get_id());
808+
809+ return pending;
810 }
811
812 bool enough_records_gathered(unsigned int nbuffers, unsigned int min_record_count = 1000)
813@@ -264,7 +255,10 @@
814 return true;
815 }
816
817+ void set_pending(int n) { pending = n; }
818+
819 private:
820+ std::atomic<int> pending{0};
821 std::mutex m;
822 typedef std::pair<unsigned int, std::unordered_set<std::thread::id>> Record;
823 std::unordered_map<mg::DisplayBuffer*,Record> records;
824@@ -278,11 +272,12 @@
825 {
826 }
827
828- void composite(mc::SceneElementSequence&&) override
829+ int composite(mc::SceneElementSequence&&) override
830 {
831 fake_surface_update();
832 /* Reduce run-time under valgrind */
833 std::this_thread::yield();
834+ return 0;
835 }
836
837 private:
838@@ -331,6 +326,7 @@
839 {
840 std::lock_guard<std::mutex> lock{thread_names_mutex};
841 thread_names.emplace_back(mt::current_thread_name());
842+ return 0;
843 }};
844 return std::unique_ptr<RecordingDisplayBufferCompositor>(raw);
845 }
846@@ -595,7 +591,8 @@
847 ASSERT_LT(retry, max_retries);
848
849 // Some surface queues up multiple frames
850- scene->set_pending(3);
851+ factory->set_pending(3);
852+ scene->emit_change_event();
853
854 // Make sure they all get composited separately (2 + 3 more)
855 retry = 0;
856
857=== modified file 'tests/unit-tests/scene/test_surface_stack.cpp'
858--- tests/unit-tests/scene/test_surface_stack.cpp 2016-01-29 08:18:22 +0000
859+++ tests/unit-tests/scene/test_surface_stack.cpp 2016-02-11 14:50:57 +0000
860@@ -335,124 +335,6 @@
861 EXPECT_EQ("username@hostname: ~/Documents", decor->name);
862 }
863
864-TEST_F(SurfaceStack, scene_counts_pending_accurately)
865-{
866- using namespace testing;
867- ms::SurfaceStack stack{report};
868- stack.register_compositor(this);
869- mtd::StubBuffer stub_buffer;
870- int ready = 0;
871- auto mock_queue = std::make_shared<testing::NiceMock<mtd::MockBufferBundle>>();
872- ON_CALL(*mock_queue, buffers_ready_for_compositor(_))
873- .WillByDefault(InvokeWithoutArgs([&]{return ready;}));
874- ON_CALL(*mock_queue, client_release(_))
875- .WillByDefault(InvokeWithoutArgs([&]{ready++;}));
876- ON_CALL(*mock_queue, compositor_acquire(_))
877- .WillByDefault(InvokeWithoutArgs([&]{ready--; return mt::fake_shared(stub_buffer); }));
878-
879- auto surface = std::make_shared<ms::BasicSurface>(
880- std::string("stub"),
881- geom::Rectangle{{},{}},
882- false,
883- std::make_shared<mc::BufferStreamSurfaces>(mock_queue),
884- std::shared_ptr<mir::input::InputChannel>(),
885- std::shared_ptr<mir::input::InputSender>(),
886- std::shared_ptr<mg::CursorImage>(),
887- report);
888- stack.add_surface(surface, default_params.input_mode);
889- surface->configure(mir_surface_attrib_visibility,
890- mir_surface_visibility_exposed);
891-
892- EXPECT_EQ(0, stack.frames_pending(this));
893- post_a_frame(*surface);
894- post_a_frame(*surface);
895- post_a_frame(*surface);
896- EXPECT_EQ(3, stack.frames_pending(this));
897-
898- for (int expect = 3; expect >= 0; --expect)
899- {
900- ASSERT_EQ(expect, stack.frames_pending(this));
901- auto snap = stack.scene_elements_for(compositor_id);
902- for (auto& element : snap)
903- {
904- auto consumed = element->renderable()->buffer();
905- }
906- }
907-}
908-
909-TEST_F(SurfaceStack, scene_doesnt_count_pending_frames_from_occluded_surfaces)
910-{ // Regression test for LP: #1418081
911- using namespace testing;
912-
913- ms::SurfaceStack stack{report};
914- stack.register_compositor(this);
915- auto surface = std::make_shared<ms::BasicSurface>(
916- std::string("stub"),
917- geom::Rectangle{{},{}},
918- false,
919- std::make_shared<mtd::StubBufferStream>(),
920- std::shared_ptr<mir::input::InputChannel>(),
921- std::shared_ptr<mir::input::InputSender>(),
922- std::shared_ptr<mg::CursorImage>(),
923- report);
924-
925- stack.add_surface(surface, default_params.input_mode);
926- auto elements = stack.scene_elements_for(this);
927- for (auto const& elem : elements)
928- elem->occluded();
929-
930- EXPECT_EQ(0, stack.frames_pending(this));
931- post_a_frame(*surface);
932- post_a_frame(*surface);
933- post_a_frame(*surface);
934- EXPECT_EQ(0, stack.frames_pending(this));
935-}
936-
937-TEST_F(SurfaceStack, scene_doesnt_count_pending_frames_from_partially_exposed_surfaces)
938-{ // Regression test for LP: #1499039
939- using namespace testing;
940-
941- // Partially exposed means occluded in one compositor but not another
942- ms::SurfaceStack stack{report};
943- auto const comp1 = reinterpret_cast<mc::CompositorID>(0);
944- auto const comp2 = reinterpret_cast<mc::CompositorID>(1);
945-
946- stack.register_compositor(comp1);
947- stack.register_compositor(comp2);
948- auto surface = std::make_shared<ms::BasicSurface>(
949- std::string("stub"),
950- geom::Rectangle{{},{}},
951- false,
952- std::make_shared<mtd::StubBufferStream>(),
953- std::shared_ptr<mir::input::InputChannel>(),
954- std::shared_ptr<mir::input::InputSender>(),
955- std::shared_ptr<mg::CursorImage>(),
956- report);
957-
958- stack.add_surface(surface, default_params.input_mode);
959- post_a_frame(*surface);
960- post_a_frame(*surface);
961- post_a_frame(*surface);
962-
963- EXPECT_EQ(3, stack.frames_pending(comp1));
964- EXPECT_EQ(3, stack.frames_pending(comp2));
965-
966- auto elements = stack.scene_elements_for(comp1);
967- for (auto const& elem : elements)
968- {
969- elem->rendered();
970- }
971-
972- elements = stack.scene_elements_for(comp2);
973- for (auto const& elem : elements)
974- {
975- elem->occluded();
976- }
977-
978- EXPECT_EQ(3, stack.frames_pending(comp1));
979- EXPECT_EQ(0, stack.frames_pending(comp2));
980-}
981-
982 TEST_F(SurfaceStack, surfaces_are_emitted_by_layer)
983 {
984 using namespace testing;

Subscribers

People subscribed via source and target branches