Mir

Merge lp:~kdub/mir/display-groups into lp:mir

Proposed by Kevin DuBois
Status: Merged
Approved by: Kevin DuBois
Approved revision: no longer in the source branch.
Merged at revision: 2337
Proposed branch: lp:~kdub/mir/display-groups
Merge into: lp:mir
Diff against target: 2071 lines (+552/-390)
53 files modified
benchmarks/frame-uniformity/vsync_simulating_graphics_platform.cpp (+22/-19)
examples/render_overlays.cpp (+9/-5)
examples/render_surfaces.cpp (+5/-2)
examples/render_to_fb.cpp (+14/-10)
include/platform/mir/graphics/display.h (+28/-2)
include/platform/mir/graphics/display_buffer.h (+0/-22)
playground/demo-shell/demo_compositor.cpp (+0/-2)
src/platforms/android/server/configurable_display_buffer.h (+4/-1)
src/platforms/android/server/display.cpp (+1/-1)
src/platforms/android/server/display.h (+1/-1)
src/platforms/android/server/display_buffer.cpp (+9/-4)
src/platforms/android/server/display_buffer.h (+3/-1)
src/platforms/mesa/server/display.cpp (+2/-2)
src/platforms/mesa/server/display.h (+2/-2)
src/platforms/mesa/server/display_buffer.cpp (+23/-17)
src/platforms/mesa/server/display_buffer.h (+9/-4)
src/server/compositor/default_display_buffer_compositor.cpp (+1/-3)
src/server/compositor/multi_threaded_compositor.cpp (+46/-40)
src/server/compositor/screencast_display_buffer.cpp (+0/-4)
src/server/compositor/screencast_display_buffer.h (+0/-1)
src/server/graphics/nested/nested_display.cpp (+24/-7)
src/server/graphics/nested/nested_display.h (+12/-2)
src/server/graphics/nested/nested_output.cpp (+0/-4)
src/server/graphics/nested/nested_output.h (+0/-1)
src/server/graphics/offscreen/display.cpp (+22/-6)
src/server/graphics/offscreen/display.h (+12/-2)
src/server/graphics/offscreen/display_buffer.cpp (+0/-4)
src/server/graphics/offscreen/display_buffer.h (+0/-1)
src/server/input/display_input_region.cpp (+16/-10)
src/server/shell/graphics_display_layout.cpp (+15/-13)
tests/acceptance-tests/test_display_configuration.cpp (+4/-4)
tests/include/mir_test_doubles/mock_display.h (+1/-1)
tests/include/mir_test_doubles/mock_display_buffer.h (+0/-1)
tests/include/mir_test_doubles/null_display.h (+4/-4)
tests/include/mir_test_doubles/null_display_buffer.h (+0/-1)
tests/include/mir_test_doubles/null_display_sync_group.h (+81/-0)
tests/include/mir_test_doubles/stub_display.h (+26/-12)
tests/integration-tests/graphics/android/test_display_integration.cpp (+27/-23)
tests/integration-tests/test_display_info.cpp (+4/-3)
tests/integration-tests/test_display_server_main_loop_events.cpp (+2/-2)
tests/integration-tests/test_surface_first_frame_sync.cpp (+21/-11)
tests/integration-tests/test_surface_stack_with_compositor.cpp (+15/-22)
tests/integration-tests/test_surfaceloop.cpp (+6/-5)
tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp (+0/-10)
tests/unit-tests/compositor/test_multi_threaded_compositor.cpp (+23/-28)
tests/unit-tests/graphics/android/test_display.cpp (+14/-11)
tests/unit-tests/graphics/android/test_display_buffer.cpp (+0/-1)
tests/unit-tests/graphics/mesa/test_display.cpp (+14/-12)
tests/unit-tests/graphics/mesa/test_display_buffer.cpp (+4/-4)
tests/unit-tests/graphics/mesa/test_display_multi_monitor.cpp (+4/-6)
tests/unit-tests/graphics/offscreen/test_offscreen_display.cpp (+9/-9)
tests/unit-tests/graphics/test_display.cpp (+6/-2)
tests/unit-tests/input/test_display_input_region.cpp (+7/-25)
To merge this branch: bzr merge lp:~kdub/mir/display-groups
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Daniel van Vugt Needs Fixing
Robert Carr (community) Abstain
Alberto Aguirre (community) Approve
Andreas Pokorny (community) Approve
Alan Griffiths Approve
Alexandros Frantzis (community) Approve
Review via email: mp+249084@code.launchpad.net

Commit message

graphics: move the post() command from the DisplayBuffers to the new DisplayGroup interface. This allows platforms to designate which DisplayBuffers must be posted in a common function.

Description of the change

graphics: move the post() command from the DisplayBuffers to the new DisplayGroup interface. This allows platforms to designate which DisplayBuffers must be posted in a common function.

This is mostly for android, which requires us to figure out the fencing for the displays, and post one nonblocking function (https://android.googlesource.com/platform/hardware/libhardware/+/master/include/hardware/hwcomposer.h l587). To rephrase android's requirements, we're required to post 2 egl contexts in one post command. (ie, have 1 displaygroup with 2 buffers in it)

Mesa/offscreen/nested remain with one thread per displaybuffer, although the idea of a group of displays posting together isn't foreign to mesa and nested. Particularly these platforms do this in the case where the outputs overlap and share a common scanout buffer. Unfortunately android really needs 2 egl contexts backed by 2 bundles of framebuffers, so it cannot play a similar trick.

It also has the nice benefit that the DisplayBufferCompositor implementations becomes concerned with the content (GL/overlays), and the Compositor implementations now issue the post() command.

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
Alan Griffiths (alan-griffiths) wrote :

262 +class ConfigurableDisplayBuffer : public graphics::DisplayBuffer,
263 + public graphics::DisplayGroup
...
469 +class DisplayBuffer : public graphics::DisplayBuffer,
470 + public graphics::DisplayGroup

I don't feel I understand the relationship between graphics::DisplayBuffer and graphics::DisplayGroup.

My gut says there's a composite pattern hidden in there somewhere, but that the interfaces are not quite right.

review: Abstain
Revision history for this message
Kevin DuBois (kdub) wrote :

> I don't feel I understand the relationship between graphics::DisplayBuffer and
> graphics::DisplayGroup.

DisplayGroups are DisplayBuffers that share a common post() function. The DisplayBuffer becomes an abstraction for the content of the buffer, and the DisplayGroup becomes the abstraction for how that content is flipped to the frontbuffer. In lp:mir right now, DisplayBuffer is the abstraction for the content, and the posting.

> My gut says there's a composite pattern hidden in there somewhere, but that
> the interfaces are not quite right.

For android, I was intending to split the inheritance in the next round of updates. For mesa, I was intending on leaving it, but since having to look at it, the code does become more clean if I switch mgm::DisplayBuffer from inheritance to to composition. I am working on disentangling this too, will propose mesa and android in subsequent MP's, as they're both about 1k lines each.

Revision history for this message
Kevin DuBois (kdub) wrote :

Okay, so I made mgm::DisplayBuffer inherit only from mg::DisplayBuffer, and introduced a mgm::DisplayGroup in this branch lp:~kdub/mir/mesa-display-group. I'll propose that after this, and am working on the android branch (which might have the MM changes).

Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

173 + * This may wait for based on hardware conditions and platform requirements */

Something missing.

178 +private:

(Nit) No need for private, protected will do.

629 + for (auto& compositor : compositors)
630 + {
631 + target.ensure_current(std::get<0>(compositor));
632 + std::get<1>(compositor)->composite(scene->scene_elements_for(comp_id));

(Non-blocking) As discussed on IRC, this approach serializes rendering of multiple outputs on Android (i.e., it's R1,R2,...,Rn,Post vs the ideal Parallel(R1,R2,...,Rn),Post). This could lead to some performance loss for the multimonitor case on Android, so hopefully there is a way to improve this if needed.

1711 +// display->for_each_mock_buffer([](mtd::MockDisplayBuffer& mock_buf)
1712 +// {
1713 +// EXPECT_CALL(mock_buf, make_current()).Times(1);
1714 +// EXPECT_CALL(mock_buf, view_area())
1715 +// .WillOnce(Return(geom::Rectangle()));
1716 +// });

Not needed?

1769 +#if 0
1770 TEST(MultiThreadedCompositor, makes_and_releases_display_buffer_current_target)

?

review: Needs Fixing
Revision history for this message
Kevin DuBois (kdub) wrote :

fixed nits/tests I forgot to reenable.

As for the performance concern, thats true. Ideally two threads would draw, and then one thread would post. This is forced on us somewhat by the android api, although its mitigated by:
* Android (surfaceflinger) would have the same multimonitor performance hit, as it drives rendering from one thread as well.
* mesa, and the other platforms are still driven in sensible way we have it.
* iirc, most android gpus have 2 or more banks of pipeline/contexts for this scenario
* The bottleneck is probably the system bus, instead of the cpu assembly of the gl commands (which is what the two threads would help with)

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

I'm a bit concerned that so much code has been rewritten here. Including many parts where a one line change means life-or-death for performance and multimonitor. Needs some serious manual testing...

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

(1) Found a regression on trunk when testing this. Will work on that now... bug 1420678.

(2) I'm concerned that "groups" are never useful or desirable with real displays;
If you use groups, support for displays with different refresh rates is lost. It's important that we never synchronize between different threads running different displays. Because one could easily be running much faster than the other (24Hz TV + 60Hz laptop in sidebyside mode) and still we need to be posting at the full 60Hz.

628 - display_buffer_compositor->composite(
629 - scene->scene_elements_for(comp_id));
630 + for (auto& compositor : compositors)
631 + {
632 + target.ensure_current(std::get<0>(compositor));
633 + std::get<1>(compositor)->composite(scene->scene_elements_for(comp_id));
634 + }
635 + group.post();

So groups in this way almost never make sense. I'm not sure it's a good idea for Android even. Definitely not desktop. Also, we already have a kind of grouping that we know is more annoying than useful; see bug 1395416.

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

(3) Even if you have multiple displays running at the same rate, they will be out of phase by half a frame on average, sometimes worse. So if you synchronize their post() calls then you're dooming all-but-one display to get a shorter render time than 16ms, and this will often leave insufficient render time to composite a whole frame without missing the next one. Our old workaround of triple buffering saves us here, but that's a step backwards in performance. So you have to choose between high lag or sometimes skipping frames. For this reason, I disapprove of the groups design.
It's important each display's flip() occurs on a separate thread asynchronously, so that its own rendering of the next frame can start immediately and we have a full frame time to render.

We need to reduce our use of grouping logic (bug 1395416) rather than extending it.

If you still need some sort of grouping to resolve Android problems, I suggest utilizing the grouping logic ("overlapping outputs") we already have, and only utilizing it in Android.

review: Disapprove
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

After conversations with Kevin, my understanding is that the Android APIs enforce synchronized posting of all outputs even if their contents are completely independent (i.e. different DisplayBuffers). That's _not_ the same problem we have with clone mode on desktop, where we have a single DisplayBuffer which we can post to different outputs.

I would, too, prefer it if we didn't need to have the DisplayGroup abstraction, but it seems that the Android display architecture forces this design choice. My preference would be use the current DisplayBuffer interface and hide all the synchronization inside the Android platform, but Kevin has tried this and found it to be both complicated and fragile.

> It's important each display's flip() occurs on a separate thread asynchronously, so that its
> own rendering of the next frame can start immediately and we have a full frame time to render.

Unfortunaetly, as described in the first paragraph, this is exactly what's not possible on Android. The bright side is that neither this concern, nor the one I noted in a previous comment affect the desktop, since on the desktop 1 DisplayGroup always contains 1 DisplayBuffer.

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

OK as a intermediate form

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

I think much greater care needs to be taken by all here.

This proposal can and should be improved. The DisplayGroup is not only undesirable for desktop but downright dangerous for a desktop compositor to use. Because there's no way to do so (e.g. with Mesa) without either causing frame skipping, reduced performance or lag.

As such, please hide DisplayGroup from the common code so that desktoppers can't accidentally find themselves using it.

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

At least one way springs to mind in which Android can be supported without DisplayGroup:
Implement a "MultiDisplayBuffer" containing multiple displays attached to a single DisplayBufferCompositor. That way they are composited together and posted together. And the code classes don't need modification.

Alternatively, please consider other ways to avoid touching so much common code. As it stands now, this increases the risk of short and long term regressions (confusion by future developers). And it scares me. We have the ability to pause and try to think of better solutions still.

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

-code classes
+common classes

Even if this seems like the only solution right now, we owe it to ourselves to ponder this a bit more. It's a 2000 line change that touches one of the most highly sensitive portions of Mir. It's only been up less than 48 hours. So just stop and think about other possibilities for a while...

Revision history for this message
Kevin DuBois (kdub) wrote :

@code rewrite:
The current interfaces are insufficient for android multimonitor, because android has a weird commit interface (line 587, https://android.googlesource.com/platform/hardware/libhardware/+/master/include/hardware/hwcomposer.h). Our current platform interfaces do not have explicit hints about threading, and this avoids this by saying "this group of monitors must post together in DisplayGroup".

I tried to work within the existing API and thread model in lp:~kdub/mir/hwc-sync-and-post-external, but this led to some complex, not-universal and heavy-handed synchronization. (eg, You couldn't drive that code from one thread, one thread per display was the only way. Furthermore, the displays were still synced together, making the second thread mostly useless)

(2) Its true that having two DisplayBuffers in one DisplayGroup ties the displays together, but mesa remain 1DisplayBuffer/1DisplayGroup, so mesa can still be driven in its preferred way, that is, one thread that syncs at the vsync rate of the respective monitor. Android also does not wait in mg::DisplayGroup::post(), so the disadvantages of having one thread drive 2 monitors is less severe. I share the sentiment that the android mm interface is strange, but we have to sync between the different display threads for the interface.

(3) Its important to remember that android's set() call does not block, so the timings are quite different than a model that relies on waiting on the vsync of a particular display. The vsync signal and the commit call are detached; the buffers are protected by fences. Its more that we're scheduling work in the kernel as opposed to controlling the timing carefully like in KMS/drm.

I did look into using OverlappingOutputGrouping in the same way that mesa does, that is, to model 2 monitors an 1 DisplayBuffer, with one common scanout buffer. This relies on being able set the scanout buffer of the monitors, which android doesn't let us do. We need one eglContext per display, and cannot force both monitors to read from one bundle of framebuffers.

Revision history for this message
Kevin DuBois (kdub) wrote :

> (3) Even if you have multiple displays running at the same rate, they will be
> out of phase by half a frame on average, sometimes worse. So if you
> synchronize their post() calls then you're dooming all-but-one display to get
> a shorter render time than 16ms, and this will often leave insufficient render
> time to composite a whole frame without missing the next one. Our old
> workaround of triple buffering saves us here, but that's a step backwards in
> performance. So you have to choose between high lag or sometimes skipping
> frames. For this reason, I disapprove of the groups design.

I disapprove of the HWC multimonitor design, but we're stuck with it :).

Given that we really-truly-have-to synchronize and commit from one thread in android, I like DisplayGroups because it keeps the threading model implicit. The alternative is to have an explicit threading model (some sort of "force single threaded composition" flag) or to require the compositor writers to call strange functions that give the android code hints about when it can commit. [1] Both of these are somewhat vague to a compositor writer ("why do I have to call this?, or "what does 'force_single_threading' mean?")

Its also nice that we're splitting DisplayBuffer's concerns. DisplayBuffer is concerned about the content of the buffer, and DisplayGroup is concerned with issuing the commands to post. I chose the execute-around way of giving access to the DisplayBuffers, but down the road, we could probably even give ownership of the DB's.

The other nice thing is that we regain control of the posting, that is, the post() call that drives the display update is now called from MultiThreadedCompositor. The DisplayBufferCompositors are now just what we intended them to be; they are a place where the compositor writers can override to draw different content into the monitors.

[1] specifically, looking at lp:~kdub/mir/hwc-sync-and-post-external, you can see how with the existing model, I can't tell if the external display wants its content updated, so I just make the assumption that we're getting a 1-for-1 buffer update on both displays.

Revision history for this message
Kevin DuBois (kdub) wrote :

> At least one way springs to mind in which Android can be supported without
> DisplayGroup:
> Implement a "MultiDisplayBuffer" containing multiple displays attached to a
> single DisplayBufferCompositor. That way they are composited together and
> posted together. And the code classes don't need modification.

This is generally what this MP is intended to be, except that multiple displays are attached to the DisplayGroup, instead of having the grouping requirements somewhere in DisplayBufferCompositiors. I guess I'd have to see the MultiDisplayBuffer interface to figure out if android's mm requirements can fit within it.

Revision history for this message
Kevin DuBois (kdub) wrote :

> Even if this seems like the only solution right now, we owe it to ourselves to
> ponder this a bit more. It's a 2000 line change that touches one of the most
> highly sensitive portions of Mir. It's only been up less than 48 hours. So
> just stop and think about other possibilities for a while...

Fair enough, we can allot more time to review and consider, and I can chase more reviews as well.

Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

Even if it could be done with a MultiDisplayBuffer approach, I think splitting out the post part looks reasonable.

review: Approve
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

Looks reasonable and becomes clearer when peeking at the next mesa branch.

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

downstream compatibility branch: lp:~kdub/qtmir/display-groups

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

I understand the motivation for DisplayGroup. The concept will make qtmir's multimonitor support complicated however, as QtMir will allocate one QWindow per Display, and expects to be able to call swap buffers on each Display individually.

Individuality being important: if the scene on monitor 2 changes, then its render loop will spin up, draw and call swap buffers for Display2. However if Display2 is part of a DisplayGroup, it would be presumptuous for it to swap the whole DisplayGroup.

What if Display1 (part of DisplayGroup too) was also being rendered, but finished later than Display2? It can't call swapBuffers on the whole DisplayGroup again, so instead need a sync point between the 2 threads where both are done, before calling swap.

But if Display1 doesn't need changing, then Display2 can legitimately call swap on the whole DisplayGroup.

I don't see how I can support this with Qt without some form of synchronization between the render threads which share a DisplayGroup. Is that a correct conclusion?

If so, it'll be work getting Qt to support this.

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

I'd rather see a "MultiDisplayBuffer" or "EverythingDisplayBuffer" that composites multiple outputs together with a single "post" for Android. Then DisplayBufferCompositor doesn't have to change.

The currently proposed design isn't just undesirable for mesa/DRM, but undesirable for any raw platform that flips/blits on post. All our future platforms will also want to avoid DisplayGroups so that the non-primary monitors don't tear or skip frames. So I think it's a better idea to invest in making this more clearly Android-specific.

I can only imagine this works at all on Android without tearing or skipping (does it?) if Android is abstracting and asynchronously deferring the page flipping in the background.

Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

> I understand the motivation for DisplayGroup. The concept will make qtmir's
> multimonitor support complicated however, as QtMir will allocate one QWindow
> per Display, and expects to be able to call swap buffers on each Display
> individually.

Do you mean Display as in mir::graphics::Display? Or rather DisplayBuffer?

> Individuality being important: if the scene on monitor 2 changes, then its
> render loop will spin up, draw and call swap buffers for Display2. However if
> Display2 is part of a DisplayGroup, it would be presumptuous for it to swap
> the whole DisplayGroup.
>
> What if Display1 (part of DisplayGroup too) was also being rendered, but
> finished later than Display2? It can't call swapBuffers on the whole
> DisplayGroup again, so instead need a sync point between the 2 threads where
> both are done, before calling swap.

This problem is a subset of the problem we have with the underlying android API.
So even with this MP the problem still exists.. but it seems slightly simpler, we only need an optional sync point or optional sync time-window? (optional since for nested/offscreen/mesa DisplayGroup : DisplayBuffer will be a 1:1 relation, as I understood)..

Revision history for this message
Kevin DuBois (kdub) wrote :

> I understand the motivation for DisplayGroup. The concept will make qtmir's
> multimonitor support complicated however, as QtMir will allocate one QWindow
> per Display, and expects to be able to call swap buffers on each Display
> individually.
>
> Individuality being important: if the scene on monitor 2 changes, then its
> render loop will spin up, draw and call swap buffers for Display2. However if
> Display2 is part of a DisplayGroup, it would be presumptuous for it to swap
> the whole DisplayGroup.
> What if Display1 (part of DisplayGroup too) was also being rendered, but
> finished later than Display2? It can't call swapBuffers on the whole
> DisplayGroup again, so instead need a sync point between the 2 threads where
> both are done, before calling swap.
>
> But if Display1 doesn't need changing, then Display2 can legitimately call
> swap on the whole DisplayGroup.

Good points, but these are implications of how HWC/multimonitor are driven.
On android, it doesn't cause that much of a performance headache because swap_buffers() can be called independently on each "display buffer"/GL context, and the hwc functions themselves don't block, they just schedule work.

>
> I don't see how I can support this with Qt without some form of
> synchronization between the render threads which share a DisplayGroup. Is that
> a correct conclusion?
>
> If so, it'll be work getting Qt to support this.

Right, so, to rephrase an above comment, this change to DisplayBuffer implicitly gives a hint about how the threads of the compositor should be structured, now that we have a platform that does not prefer 1 thread per monitor, but rather prefers a synchronized submission for all DisplayBuffers.

So, my hope with QtMir and other compositors is that we have MultiThreadedCompositor handle the compositor threads and the compositor notification system, and have the compositors override DisplayBufferCompositor, with the already-existing stipulation that DisplayBufferCompositors have to be threadsafe, as composite() can be called from different threads with different DisplayBuffers.

Revision history for this message
Kevin DuBois (kdub) wrote :

@andreas, correct, this abstraction change in this MP is expanding to cover a goofy requirement (from a 1 thread/monitor world's perspective at least) that the HWC api has. A multithreaded setup on android would hit a lot of the same timing inconveniences in synchronizing, just down in the HwcDevice code, where it is not in the best position to make decisions to wait or continue.

Revision history for this message
Kevin DuBois (kdub) wrote :

> I'd rather see a "MultiDisplayBuffer" or "EverythingDisplayBuffer" that
> composites multiple outputs together with a single "post" for Android. Then
> DisplayBufferCompositor doesn't have to change.
>

I would too, and this is mostly what we get with mesa's OverlappingOutputGroup. Multiple outputs are implemented as one display buffer if they overlap. The reason this is problematic is that android really needs one EGL context per buffer, and cannot set scanout regions as mesa can. For example, with two different display contexts in one DisplayBuffer, mg::DisplayBuffer::make_current() can't know which of the two contexts the user intends to make current. (or swap, etc.)

> The currently proposed design isn't just undesirable for mesa/DRM, but
> undesirable for any raw platform that flips/blits on post. All our future
> platforms will also want to avoid DisplayGroups so that the non-primary
> monitors don't tear or skip frames. So I think it's a better idea to invest in
> making this more clearly Android-specific.

I'd rather see two DisplayBuffers (each modelling content), with a DisplayGroup (which can post to screen) than have a function that mentions that one of our platforms is android, and special steps have to be taken with the threads. Its better to have a universal concept with synchronization implications, than it is to point to one platform and say that its weird in light of another platform. After all, the point of having the platform abstraction is so that the server code doesn't have to be written on a platform-by-platform basis.

> I can only imagine this works at all on Android without tearing or skipping
> (does it?) if Android is abstracting and asynchronously deferring the page
> flipping in the background.

Yes, the kernel helps out to avoid tearing. We're guaranteed that the set() function won't block, so its more that we're scheduling work with the driver and the kernel than controlling the timing of the threads.

Revision history for this message
Robert Carr (robertcarr) wrote :

Lots of review already done so not going in depth. No high level objections though.

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

> > I can only imagine this works at all on Android without tearing or skipping
> > (does it?) if Android is abstracting and asynchronously deferring the page
> > flipping in the background.
>
> Yes, the kernel helps out to avoid tearing. We're guaranteed that the set()
> function won't block, so its more that we're scheduling work with the driver
> and the kernel than controlling the timing of the threads.

Right, so this works for Android because Android isn't a low-level display system. It's a high-level abstraction of displays (and very much OpenGL-only). Native platforms (mesa, nvidia etc) will usually be low-level display systems that need asynchronous posting (hence never use DisplayGroup).

Although I can now imagine some virtual Mir platform in a window. If you wanted to represent multiple virtual outputs for visualization all in a single window then DisplayGroups would be used. But I doubt any such use case beyond Android will really ever be required.

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

Wait a minute, post() is a no-op as is flip() for Android. You must be planning to change this in future if DisplayGroup is to have any function at all...?

Previously Android correctly had an empty flip() (now an empty post()), because it's a high-level platform abstraction that just needs to gl_swap_buffers.

I suggest part of the problem then is that you've misappropriated flip() on a platform that has no flip().

Revision history for this message
Kevin DuBois (kdub) wrote :

> Wait a minute, post() is a no-op as is flip() for Android. You must be
> planning to change this in future if DisplayGroup is to have any function at
> all...?
>

Yes, the subsequent branch uses the interface changes made here:
http://bazaar.launchpad.net/~kdub/mir/android-multimonitor/view/head:/src/platforms/android/server/display_group.cpp#L68

> Previously Android correctly had an empty flip() (now an empty post()),
> because it's a high-level platform abstraction that just needs to
> gl_swap_buffers.
>
> I suggest part of the problem then is that you've misappropriated flip() on a
> platform that has no flip().

Right, a no-op flip() seemed inappropriate for the android platform, as it did a "flip" operation from within gl_swap_buffers(). So, a user of the interface might be calling gl_swap_buffers(), which drives the display on android, and on mesa, it would just be rendering without posting to screen. It seems more appropriate to have gl_swap_buffers handle updating the context, and have flip/post() drive the content making it to the screen.

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

OK, I see the need. And I understand it's a painful thought to redesign the way I've suggested.

As a compromise how about just a rename of DisplayGroup so as to make it less likely that we don't accidentally use it on non-Android platforms; "SynchronousDisplayGroup" or "SyncGroup".

review: Needs Fixing
Revision history for this message
Kevin DuBois (kdub) wrote :

> OK, I see the need. And I understand it's a painful thought to redesign the
> way I've suggested.

Well, its not simply painful, but rather our current interfaces don't allow the android platform to present to the server code what the platform requires as its threading structure to post to the external monitor.

>
> As a compromise how about just a rename of DisplayGroup so as to make it less
> likely that we don't accidentally use it on non-Android platforms;
> "SynchronousDisplayGroup" or "SyncGroup".

Sounds good, how about DisplaySyncGroup?

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

include/platform/mir/graphics/display.h:
Documentation should be improved to point out DisplaySyncGroup is only for virtual display buffer implementations (VMs, Android) that have non-blocking post implementations. And most importantly it should not be used by native platform drivers.

Then I abstain.

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

Also don't say "to their respective monitors" because nobody should flip to real monitors using a DisplaySyncGroup. That would result in bugs.

Revision history for this message
Kevin DuBois (kdub) wrote :

Updated!
I don't know if I agree that Android is somehow "virtual" while mesa is somehow "native". They just have different sync mechanisms.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'benchmarks/frame-uniformity/vsync_simulating_graphics_platform.cpp'
--- benchmarks/frame-uniformity/vsync_simulating_graphics_platform.cpp 2015-02-13 06:12:34 +0000
+++ benchmarks/frame-uniformity/vsync_simulating_graphics_platform.cpp 2015-02-23 13:13:47 +0000
@@ -36,20 +36,21 @@
36namespace36namespace
37{37{
3838
39struct StubDisplayBuffer : mtd::StubDisplayBuffer39struct StubDisplaySyncGroup : mg::DisplaySyncGroup
40{40{
41 StubDisplayBuffer(geom::Size output_size, int vsync_rate_in_hz)41 StubDisplaySyncGroup(geom::Size output_size, int vsync_rate_in_hz) :
42 : mtd::StubDisplayBuffer({{0, 0}, output_size}),42 vsync_rate_in_hz(vsync_rate_in_hz),
43 vsync_rate_in_hz(vsync_rate_in_hz),43 last_sync(std::chrono::high_resolution_clock::now()),
44 last_sync(std::chrono::high_resolution_clock::now())44 buffer({{0, 0}, output_size})
45 {45 {
46 }46 }
47 47
48 void gl_swap_buffers() override48 void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& exec) override
49 {49 {
50 }50 exec(buffer);
5151 }
52 void flip() override52
53 void post() override
53 {54 {
54 auto now = std::chrono::high_resolution_clock::now();55 auto now = std::chrono::high_resolution_clock::now();
55 auto next_sync = last_sync + std::chrono::seconds(1) / vsync_rate_in_hz;56 auto next_sync = last_sync + std::chrono::seconds(1) / vsync_rate_in_hz;
@@ -63,22 +64,24 @@
63 double const vsync_rate_in_hz;64 double const vsync_rate_in_hz;
6465
65 std::chrono::high_resolution_clock::time_point last_sync;66 std::chrono::high_resolution_clock::time_point last_sync;
67
68 mtd::StubDisplayBuffer buffer;
66};69};
6770
68struct StubDisplay : public mtd::StubDisplay71struct StubDisplay : public mtd::StubDisplay
69{72{
70 StubDisplay(geom::Size output_size, int vsync_rate_in_hz)73 StubDisplay(geom::Size output_size, int vsync_rate_in_hz) :
71 : mtd::StubDisplay({{{0,0}, output_size}}),74 mtd::StubDisplay({{{0,0}, output_size}}),
72 buffer(output_size, vsync_rate_in_hz)75 group(output_size, vsync_rate_in_hz)
73 {76 {
74 }77 }
75 78
76 void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& exec) override79 void for_each_display_sync_group(std::function<void(mg::DisplaySyncGroup&)> const& exec) override
77 {80 {
78 exec(buffer);81 exec(group);
79 }82 }
8083
81 StubDisplayBuffer buffer;84 StubDisplaySyncGroup group;
82};85};
8386
84}87}
8588
=== modified file 'examples/render_overlays.cpp'
--- examples/render_overlays.cpp 2015-01-21 09:03:53 +0000
+++ examples/render_overlays.cpp 2015-02-23 13:13:47 +0000
@@ -202,12 +202,16 @@
202202
203 while (running)203 while (running)
204 {204 {
205 display->for_each_display_buffer([&](mg::DisplayBuffer& buffer)205 client1->update_green_channel();
206 client2->update_green_channel();
207 display->for_each_display_sync_group([&](mg::DisplaySyncGroup& group)
206 {208 {
207 buffer.make_current();209 group.for_each_display_buffer([&](mg::DisplayBuffer& buffer)
208 client1->update_green_channel();210 {
209 client2->update_green_channel();211 buffer.make_current();
210 buffer.post_renderables_if_optimizable(renderlist);212 buffer.post_renderables_if_optimizable(renderlist);
213 });
214 group.post();
211 });215 });
212 }216 }
213}217}
214218
=== modified file 'examples/render_surfaces.cpp'
--- examples/render_surfaces.cpp 2015-01-21 07:34:50 +0000
+++ examples/render_surfaces.cpp 2015-02-23 13:13:47 +0000
@@ -337,9 +337,12 @@
337337
338 /* TODO: Get proper configuration */338 /* TODO: Get proper configuration */
339 geom::Rectangles view_area;339 geom::Rectangles view_area;
340 display->for_each_display_buffer([&view_area](mg::DisplayBuffer const& db)340 display->for_each_display_sync_group([&](mg::DisplaySyncGroup& group)
341 {341 {
342 view_area.add(db.view_area());342 group.for_each_display_buffer([&](mg::DisplayBuffer& db)
343 {
344 view_area.add(db.view_area());
345 });
343 });346 });
344 geom::Size const display_size{view_area.bounding_rectangle().size};347 geom::Size const display_size{view_area.bounding_rectangle().size};
345 uint32_t const surface_side{300};348 uint32_t const surface_side{300};
346349
=== modified file 'examples/render_to_fb.cpp'
--- examples/render_to_fb.cpp 2015-01-21 07:34:50 +0000
+++ examples/render_to_fb.cpp 2015-02-23 13:13:47 +0000
@@ -53,22 +53,26 @@
5353
54 mir::draw::glAnimationBasic gl_animation;54 mir::draw::glAnimationBasic gl_animation;
5555
56 display->for_each_display_buffer([&](mg::DisplayBuffer& buffer)56 display->for_each_display_sync_group([&](mg::DisplaySyncGroup& group)
57 {57 {
58 buffer.make_current();58 group.for_each_display_buffer([&](mg::DisplayBuffer& buffer)
59 gl_animation.init_gl();59 {
60 buffer.make_current();
61 gl_animation.init_gl();
62 });
60 });63 });
6164
62 while (running)65 while (running)
63 {66 {
64 display->for_each_display_buffer([&](mg::DisplayBuffer& buffer)67 display->for_each_display_sync_group([&](mg::DisplaySyncGroup& group)
65 {68 {
66 buffer.make_current();69 group.for_each_display_buffer([&](mg::DisplayBuffer& buffer)
6770 {
68 gl_animation.render_gl();71 buffer.make_current();
6972 gl_animation.render_gl();
70 buffer.gl_swap_buffers();73 buffer.gl_swap_buffers();
71 buffer.flip();74 });
75 group.post();
72 });76 });
7377
74 gl_animation.step();78 gl_animation.step();
7579
=== modified file 'include/platform/mir/graphics/display.h'
--- include/platform/mir/graphics/display.h 2015-01-21 07:34:50 +0000
+++ include/platform/mir/graphics/display.h 2015-02-23 13:13:47 +0000
@@ -39,6 +39,32 @@
39typedef std::function<bool()> DisplayResumeHandler;39typedef std::function<bool()> DisplayResumeHandler;
40typedef std::function<void()> DisplayConfigurationChangeHandler;40typedef std::function<void()> DisplayConfigurationChangeHandler;
4141
42/* DisplaySyncGroup allows for multiple displays to be posted together.
43 * A DisplayGroup containing multiple DisplayBuffers should only be used
44 * by platforms that have a nonblocking post implemenation.
45 * One DisplayBuffer per DisplaySyncGroup is preferable for platforms that
46 * wait for the post to complete.
47 */
48class DisplaySyncGroup
49{
50public:
51 /**
52 * Executes a functor that allows the DisplayBuffer contents to be updated
53 **/
54 virtual void for_each_display_buffer(std::function<void(DisplayBuffer&)> const& f) = 0;
55
56 /** Post the content of the DisplayBuffers associated with this DisplaySyncGroup.
57 * The content of all the DisplayBuffers in this DisplaySyncGroup are guaranteed to be onscreen
58 * in the near future. On some platforms, this may wait a potentially long time for vsync.
59 **/
60 virtual void post() = 0;
61 virtual ~DisplaySyncGroup() = default;
62protected:
63 DisplaySyncGroup() = default;
64 DisplaySyncGroup(DisplaySyncGroup const&) = delete;
65 DisplaySyncGroup& operator=(DisplaySyncGroup const&) = delete;
66};
67
42/**68/**
43 * Interface to the display subsystem.69 * Interface to the display subsystem.
44 */70 */
@@ -46,9 +72,9 @@
46{72{
47public:73public:
48 /**74 /**
49 * Executes a functor for each output framebuffer.75 * Executes a functor for each output group.
50 */76 */
51 virtual void for_each_display_buffer(std::function<void(DisplayBuffer&)> const& f) = 0;77 virtual void for_each_display_sync_group(std::function<void(DisplaySyncGroup&)> const& f) = 0;
5278
53 /**79 /**
54 * Gets a copy of the current output configuration.80 * Gets a copy of the current output configuration.
5581
=== modified file 'include/platform/mir/graphics/display_buffer.h'
--- include/platform/mir/graphics/display_buffer.h 2015-01-21 07:34:50 +0000
+++ include/platform/mir/graphics/display_buffer.h 2015-02-23 13:13:47 +0000
@@ -54,28 +54,6 @@
54 */54 */
55 virtual void gl_swap_buffers() = 0;55 virtual void gl_swap_buffers() = 0;
5656
57 /**
58 * After gl_swap_buffers, flip the new front buffer to the screen
59 * This most likely involves a wait for vblank so can be very time
60 * consuming. This function is separate to gl_swap_buffers() because in
61 * real display systems the act of scanning out (or flipping) the
62 * front buffer is a very separate step to the GL buffer swapping. Not
63 * least because "flipping" is a hardware operation that is independent
64 * of the graphics library (OpenGL or other). Also, flip() can be a
65 * dramatically slower operation than gl_swap_buffers() and it would be
66 * an unacceptable performance hit to wait for both before freeing
67 * GL resources.
68 */
69 virtual void flip() = 0;
70
71 /**
72 * \deprecated Please try to implement separate gl_swap_buffers and
73 * flip functions instead. If not possible, just move your old
74 * post_update() logic into gl_swap_buffers.
75 */
76 __attribute__((__deprecated__("Use gl_swap_buffers() and flip(), remembering to release all compositor buffers in the middle.")))
77 void post_update() { gl_swap_buffers(); flip(); }
78
79 /** This will render renderlist to the screen and post the result to the 57 /** This will render renderlist to the screen and post the result to the
80 * screen if there is a hardware optimization that can be done.58 * screen if there is a hardware optimization that can be done.
81 * \param [in] renderlist 59 * \param [in] renderlist
8260
=== modified file 'playground/demo-shell/demo_compositor.cpp'
--- playground/demo-shell/demo_compositor.cpp 2015-01-21 09:03:53 +0000
+++ playground/demo-shell/demo_compositor.cpp 2015-02-23 13:13:47 +0000
@@ -141,8 +141,6 @@
141 // flip() ...141 // flip() ...
142 // FIXME: This clear() call is blocking a little (LP: #1395421)142 // FIXME: This clear() call is blocking a little (LP: #1395421)
143 renderable_list.clear();143 renderable_list.clear();
144
145 display_buffer.flip();
146 }144 }
147145
148 report->finished_frame(this);146 report->finished_frame(this);
149147
=== modified file 'src/platforms/android/server/configurable_display_buffer.h'
--- src/platforms/android/server/configurable_display_buffer.h 2015-01-22 09:00:14 +0000
+++ src/platforms/android/server/configurable_display_buffer.h 2015-02-23 13:13:47 +0000
@@ -19,6 +19,7 @@
19#ifndef MIR_GRAPHICS_ANDROID_CONFIGURABLE_DISPLAY_BUFFER_H_19#ifndef MIR_GRAPHICS_ANDROID_CONFIGURABLE_DISPLAY_BUFFER_H_
20#define MIR_GRAPHICS_ANDROID_CONFIGURABLE_DISPLAY_BUFFER_H_20#define MIR_GRAPHICS_ANDROID_CONFIGURABLE_DISPLAY_BUFFER_H_
2121
22#include "mir/graphics/display.h"
22#include "mir/graphics/display_buffer.h"23#include "mir/graphics/display_buffer.h"
23#include "mir/graphics/display_configuration.h"24#include "mir/graphics/display_configuration.h"
2425
@@ -29,7 +30,9 @@
29namespace android30namespace android
30{31{
3132
32class ConfigurableDisplayBuffer : public graphics::DisplayBuffer33//TODO: break this dependency, android displaybuffers shouldn't be their own DisplaySyncGroups
34class ConfigurableDisplayBuffer : public graphics::DisplayBuffer,
35 public graphics::DisplaySyncGroup
33{36{
34public:37public:
35 virtual void configure(MirPowerMode power_mode, MirOrientation orientation) = 0;38 virtual void configure(MirPowerMode power_mode, MirOrientation orientation) = 0;
3639
=== modified file 'src/platforms/android/server/display.cpp'
--- src/platforms/android/server/display.cpp 2015-02-13 06:12:34 +0000
+++ src/platforms/android/server/display.cpp 2015-02-23 13:13:47 +0000
@@ -218,7 +218,7 @@
218218
219}219}
220220
221void mga::Display::for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f)221void mga::Display::for_each_display_sync_group(std::function<void(mg::DisplaySyncGroup&)> const& f)
222{222{
223 std::lock_guard<decltype(configuration_mutex)> lock{configuration_mutex};223 std::lock_guard<decltype(configuration_mutex)> lock{configuration_mutex};
224 update_configuration(lock);224 update_configuration(lock);
225225
=== modified file 'src/platforms/android/server/display.h'
--- src/platforms/android/server/display.h 2015-02-13 06:12:34 +0000
+++ src/platforms/android/server/display.h 2015-02-23 13:13:47 +0000
@@ -57,7 +57,7 @@
57 OverlayOptimization overlay_option);57 OverlayOptimization overlay_option);
58 ~Display() noexcept;58 ~Display() noexcept;
5959
60 void for_each_display_buffer(std::function<void(graphics::DisplayBuffer&)> const& f) override;60 void for_each_display_sync_group(std::function<void(graphics::DisplaySyncGroup&)> const& f) override;
6161
62 std::unique_ptr<graphics::DisplayConfiguration> configuration() const override;62 std::unique_ptr<graphics::DisplayConfiguration> configuration() const override;
63 void configure(graphics::DisplayConfiguration const&) override;63 void configure(graphics::DisplayConfiguration const&) override;
6464
=== modified file 'src/platforms/android/server/display_buffer.cpp'
--- src/platforms/android/server/display_buffer.cpp 2015-02-13 06:12:34 +0000
+++ src/platforms/android/server/display_buffer.cpp 2015-02-23 13:13:47 +0000
@@ -98,10 +98,6 @@
98 display_device->commit(display_name, *layer_list, gl_context, overlay_program);98 display_device->commit(display_name, *layer_list, gl_context, overlay_program);
99}99}
100100
101void mga::DisplayBuffer::flip()
102{
103}
104
105MirOrientation mga::DisplayBuffer::orientation() const101MirOrientation mga::DisplayBuffer::orientation() const
106{102{
107 /*103 /*
@@ -118,6 +114,15 @@
118 return false;114 return false;
119}115}
120116
117void mga::DisplayBuffer::for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f)
118{
119 f(*this);
120}
121
122void mga::DisplayBuffer::post()
123{
124}
125
121void mga::DisplayBuffer::configure(MirPowerMode power_mode, MirOrientation orientation)126void mga::DisplayBuffer::configure(MirPowerMode power_mode, MirOrientation orientation)
122{127{
123 if (power_mode != mir_power_mode_on)128 if (power_mode != mir_power_mode_on)
124129
=== modified file 'src/platforms/android/server/display_buffer.h'
--- src/platforms/android/server/display_buffer.h 2015-02-13 06:12:34 +0000
+++ src/platforms/android/server/display_buffer.h 2015-02-23 13:13:47 +0000
@@ -59,9 +59,11 @@
59 void make_current() override;59 void make_current() override;
60 void release_current() override;60 void release_current() override;
61 void gl_swap_buffers() override;61 void gl_swap_buffers() override;
62 void flip() override;
63 bool post_renderables_if_optimizable(RenderableList const& renderlist) override;62 bool post_renderables_if_optimizable(RenderableList const& renderlist) override;
6463
64 void for_each_display_buffer(std::function<void(graphics::DisplayBuffer&)> const& f) override;
65 void post() override;
66
65 MirOrientation orientation() const override;67 MirOrientation orientation() const override;
66 bool uses_alpha() const override;68 bool uses_alpha() const override;
67 void configure(MirPowerMode power_mode, MirOrientation orientation) override;69 void configure(MirPowerMode power_mode, MirOrientation orientation) override;
6870
=== modified file 'src/platforms/mesa/server/display.cpp'
--- src/platforms/mesa/server/display.cpp 2015-01-22 09:00:14 +0000
+++ src/platforms/mesa/server/display.cpp 2015-02-23 13:13:47 +0000
@@ -113,8 +113,8 @@
113{113{
114}114}
115115
116void mgm::Display::for_each_display_buffer(116void mgm::Display::for_each_display_sync_group(
117 std::function<void(graphics::DisplayBuffer&)> const& f)117 std::function<void(graphics::DisplaySyncGroup&)> const& f)
118{118{
119 std::lock_guard<std::mutex> lg{configuration_mutex};119 std::lock_guard<std::mutex> lg{configuration_mutex};
120120
121121
=== modified file 'src/platforms/mesa/server/display.h'
--- src/platforms/mesa/server/display.h 2015-01-22 09:00:14 +0000
+++ src/platforms/mesa/server/display.h 2015-02-23 13:13:47 +0000
@@ -61,8 +61,8 @@
61 ~Display();61 ~Display();
6262
63 geometry::Rectangle view_area() const;63 geometry::Rectangle view_area() const;
64 void for_each_display_buffer(64 void for_each_display_sync_group(
65 std::function<void(graphics::DisplayBuffer&)> const& f) override;65 std::function<void(graphics::DisplaySyncGroup&)> const& f) override;
6666
67 std::unique_ptr<DisplayConfiguration> configuration() const override;67 std::unique_ptr<DisplayConfiguration> configuration() const override;
68 void configure(DisplayConfiguration const& conf) override;68 void configure(DisplayConfiguration const& conf) override;
6969
=== modified file 'src/platforms/mesa/server/display_buffer.cpp'
--- src/platforms/mesa/server/display_buffer.cpp 2015-02-12 18:08:46 +0000
+++ src/platforms/mesa/server/display_buffer.cpp 2015-02-23 13:13:47 +0000
@@ -204,11 +204,22 @@
204 auto bypass_it = std::find_if(renderable_list.rbegin(), renderable_list.rend(), bypass_match);204 auto bypass_it = std::find_if(renderable_list.rbegin(), renderable_list.rend(), bypass_match);
205 if (bypass_it != renderable_list.rend())205 if (bypass_it != renderable_list.rend())
206 {206 {
207 auto bypass_buf = (*bypass_it)->buffer();207 auto bypass_buffer = (*bypass_it)->buffer();
208 if ((bypass_buf->native_buffer_handle()->flags & mir_buffer_flag_can_scanout) &&208 auto native = bypass_buffer->native_buffer_handle();
209 bypass_buf->size() == geom::Size{fb_width,fb_height})209 auto gbm_native = static_cast<mgm::GBMNativeBuffer*>(native.get());
210 {210 auto bufobj = get_buffer_object(gbm_native->bo);
211 return flip(bypass_buf);211 if (bufobj &&
212 native->flags & mir_buffer_flag_can_scanout &&
213 bypass_buffer->size() == geom::Size{fb_width,fb_height})
214 {
215 bypass_buf = bypass_buffer;
216 bypass_bufobj = bufobj;
217 return true;
218 }
219 else
220 {
221 bypass_buf = nullptr;
222 bypass_bufobj = nullptr;
212 }223 }
213 }224 }
214 }225 }
@@ -216,19 +227,21 @@
216 return false;227 return false;
217}228}
218229
219void mgm::DisplayBuffer::flip()230void mgm::DisplayBuffer::for_each_display_buffer(
231 std::function<void(graphics::DisplayBuffer&)> const& f)
220{232{
221 flip(nullptr);233 f(*this);
222}234}
223235
224void mgm::DisplayBuffer::gl_swap_buffers()236void mgm::DisplayBuffer::gl_swap_buffers()
225{237{
226 if (!egl.swap_buffers())238 if (!egl.swap_buffers())
227 fatal_error("Failed to perform buffer swap");239 fatal_error("Failed to perform buffer swap");
240 bypass_buf = nullptr;
241 bypass_bufobj = nullptr;
228}242}
229243
230bool mgm::DisplayBuffer::flip(244void mgm::DisplayBuffer::post()
231 std::shared_ptr<graphics::Buffer> bypass_buf)
232{245{
233 /*246 /*
234 * We might not have waited for the previous frame to page flip yet.247 * We might not have waited for the previous frame to page flip yet.
@@ -257,12 +270,7 @@
257 mgm::BufferObject *bufobj;270 mgm::BufferObject *bufobj;
258 if (bypass_buf)271 if (bypass_buf)
259 {272 {
260 auto native = bypass_buf->native_buffer_handle();273 bufobj = bypass_bufobj;
261 auto gbm_native = static_cast<mgm::GBMNativeBuffer*>(native.get());
262 bufobj = get_buffer_object(gbm_native->bo);
263 // If bypass fails, just fall back to compositing.
264 if (!bufobj)
265 return false;
266 }274 }
267 else275 else
268 {276 {
@@ -345,8 +353,6 @@
345353
346 scheduled_bufobj = bufobj;354 scheduled_bufobj = bufobj;
347 }355 }
348
349 return true;
350}356}
351357
352mgm::BufferObject* mgm::DisplayBuffer::get_front_buffer_object()358mgm::BufferObject* mgm::DisplayBuffer::get_front_buffer_object()
353359
=== modified file 'src/platforms/mesa/server/display_buffer.h'
--- src/platforms/mesa/server/display_buffer.h 2015-01-22 09:00:14 +0000
+++ src/platforms/mesa/server/display_buffer.h 2015-02-23 13:13:47 +0000
@@ -20,6 +20,7 @@
20#define MIR_GRAPHICS_MESA_DISPLAY_BUFFER_H_20#define MIR_GRAPHICS_MESA_DISPLAY_BUFFER_H_
2121
22#include "mir/graphics/display_buffer.h"22#include "mir/graphics/display_buffer.h"
23#include "mir/graphics/display.h"
23#include "display_helpers.h"24#include "display_helpers.h"
2425
25#include <vector>26#include <vector>
@@ -41,7 +42,8 @@
41class BufferObject;42class BufferObject;
42class KMSOutput;43class KMSOutput;
4344
44class DisplayBuffer : public graphics::DisplayBuffer45class DisplayBuffer : public graphics::DisplayBuffer,
46 public graphics::DisplaySyncGroup
45{47{
46public:48public:
47 DisplayBuffer(std::shared_ptr<Platform> const& platform,49 DisplayBuffer(std::shared_ptr<Platform> const& platform,
@@ -58,9 +60,12 @@
58 void make_current() override;60 void make_current() override;
59 void release_current() override;61 void release_current() override;
60 void gl_swap_buffers() override;62 void gl_swap_buffers() override;
61 void flip() override;
62 bool post_renderables_if_optimizable(RenderableList const& renderlist) override;63 bool post_renderables_if_optimizable(RenderableList const& renderlist) override;
6364
65 void for_each_display_buffer(
66 std::function<void(graphics::DisplayBuffer&)> const& f) override;
67 void post() override;
68
64 MirOrientation orientation() const override;69 MirOrientation orientation() const override;
65 void set_orientation(MirOrientation const rot, geometry::Rectangle const& a);70 void set_orientation(MirOrientation const rot, geometry::Rectangle const& a);
66 bool uses_alpha() const override;71 bool uses_alpha() const override;
@@ -68,8 +73,6 @@
68 void wait_for_page_flip();73 void wait_for_page_flip();
6974
70private:75private:
71 bool flip(std::shared_ptr<graphics::Buffer> bypass_buf);
72
73 BufferObject* get_front_buffer_object();76 BufferObject* get_front_buffer_object();
74 BufferObject* get_buffer_object(struct gbm_bo *bo);77 BufferObject* get_buffer_object(struct gbm_bo *bo);
75 bool schedule_page_flip(BufferObject* bufobj);78 bool schedule_page_flip(BufferObject* bufobj);
@@ -77,6 +80,8 @@
77 BufferObject* last_flipped_bufobj;80 BufferObject* last_flipped_bufobj;
78 BufferObject* scheduled_bufobj;81 BufferObject* scheduled_bufobj;
79 std::shared_ptr<graphics::Buffer> last_flipped_bypass_buf;82 std::shared_ptr<graphics::Buffer> last_flipped_bypass_buf;
83 std::shared_ptr<Buffer> bypass_buf{nullptr};
84 BufferObject* bypass_bufobj{nullptr};
80 std::shared_ptr<Platform> const platform;85 std::shared_ptr<Platform> const platform;
81 std::shared_ptr<DisplayReport> const listener;86 std::shared_ptr<DisplayReport> const listener;
82 /* DRM helper from mgm::Platform */87 /* DRM helper from mgm::Platform */
8388
=== modified file 'src/server/compositor/default_display_buffer_compositor.cpp'
--- src/server/compositor/default_display_buffer_compositor.cpp 2015-02-13 06:12:34 +0000
+++ src/server/compositor/default_display_buffer_compositor.cpp 2015-02-23 13:13:47 +0000
@@ -88,10 +88,8 @@
8888
89 // Release the buffers we did use back to the clients, before starting89 // Release the buffers we did use back to the clients, before starting
90 // on the potentially slow flip().90 // on the potentially slow flip().
91 // FIXME: This clear() call is blocking a little (LP: #1395421)91 // FIXME: This clear() call is blocking a little because we drive IPC here (LP: #1395421)
92 renderable_list.clear();92 renderable_list.clear();
93
94 display_buffer.flip();
95 }93 }
9694
97 report->finished_frame(this);95 report->finished_frame(this);
9896
=== modified file 'src/server/compositor/multi_threaded_compositor.cpp'
--- src/server/compositor/multi_threaded_compositor.cpp 2015-02-17 11:58:56 +0000
+++ src/server/compositor/multi_threaded_compositor.cpp 2015-02-23 13:13:47 +0000
@@ -71,34 +71,37 @@
71class CurrentRenderingTarget71class CurrentRenderingTarget
72{72{
73public:73public:
74 CurrentRenderingTarget(mg::DisplayBuffer& buffer)74 CurrentRenderingTarget() = default;
75 : buffer(buffer)75 void ensure_current(mg::DisplayBuffer* buffer)
76 {76 {
77 buffer.make_current();77 if ((buffer) && (buffer != current_buffer))
78 buffer->make_current();
79 current_buffer = buffer;
78 }80 }
7981
80 ~CurrentRenderingTarget()82 ~CurrentRenderingTarget()
81 {83 {
82 buffer.release_current();84 if (current_buffer) current_buffer->release_current();
83 }85 }
8486
85private:87private:
86 mg::DisplayBuffer& buffer;88 mg::DisplayBuffer* current_buffer{nullptr};
87};89};
8890
89class CompositingFunctor91class CompositingFunctor
90{92{
91public:93public:
92 CompositingFunctor(std::shared_ptr<mc::DisplayBufferCompositorFactory> const& db_compositor_factory,94 CompositingFunctor(
93 mg::DisplayBuffer& buffer,95 std::shared_ptr<mc::DisplayBufferCompositorFactory> const& db_compositor_factory,
94 std::shared_ptr<mc::Scene> const& scene,96 mg::DisplaySyncGroup& group,
95 std::shared_ptr<CompositorReport> const& report)97 std::shared_ptr<mc::Scene> const& scene,
96 : display_buffer_compositor_factory{db_compositor_factory},98 std::shared_ptr<CompositorReport> const& report) :
97 buffer(buffer),99 compositor_factory{db_compositor_factory},
98 scene(scene),100 group(group),
99 running{true},101 scene(scene),
100 frames_scheduled{0},102 running{true},
101 report{report}103 frames_scheduled{0},
104 report{report}
102 {105 {
103 }106 }
104107
@@ -107,26 +110,25 @@
107 {110 {
108 mir::set_thread_name("Mir/Comp");111 mir::set_thread_name("Mir/Comp");
109112
110 /*113 CurrentRenderingTarget target;
111 * Make the buffer the current rendering target, and release114 auto const comp_id = this;
112 * it when the thread is finished.115 std::vector<std::tuple<mg::DisplayBuffer*, std::unique_ptr<mc::DisplayBufferCompositor>>> compositors;
113 */116 group.for_each_display_buffer(
114 CurrentRenderingTarget target{buffer};117 [this, &compositors, &comp_id, &target](mg::DisplayBuffer& buffer)
115118 {
116 auto display_buffer_compositor = display_buffer_compositor_factory->create_compositor_for(buffer);119 target.ensure_current(&buffer);
117 auto const comp_id = display_buffer_compositor.get();120 compositors.emplace_back(
118121 std::make_tuple(&buffer, compositor_factory->create_compositor_for(buffer)));
119 CompositorReport::SubCompositorId report_id =122
120 display_buffer_compositor.get();123 const auto& r = buffer.view_area();
121124 report->added_display(r.size.width.as_int(), r.size.height.as_int(),
122 const auto& r = buffer.view_area();125 r.top_left.x.as_int(), r.top_left.y.as_int(),
123 report->added_display(r.size.width.as_int(), r.size.height.as_int(),126 CompositorReport::SubCompositorId{comp_id});
124 r.top_left.x.as_int(), r.top_left.y.as_int(),127 });
125 report_id);
126128
127 auto compositor_registration = mir::raii::paired_calls(129 auto compositor_registration = mir::raii::paired_calls(
128 [this,&display_buffer_compositor]{scene->register_compositor(display_buffer_compositor.get());},130 [this,&comp_id]{scene->register_compositor(comp_id);},
129 [this,&display_buffer_compositor]{scene->unregister_compositor(display_buffer_compositor.get());});131 [this,&comp_id]{scene->unregister_compositor(comp_id);});
130132
131 std::unique_lock<std::mutex> lock{run_mutex};133 std::unique_lock<std::mutex> lock{run_mutex};
132 while (running)134 while (running)
@@ -150,8 +152,12 @@
150 frames_scheduled--;152 frames_scheduled--;
151 lock.unlock();153 lock.unlock();
152154
153 display_buffer_compositor->composite(155 for (auto& compositor : compositors)
154 scene->scene_elements_for(comp_id));156 {
157 target.ensure_current(std::get<0>(compositor));
158 std::get<1>(compositor)->composite(scene->scene_elements_for(comp_id));
159 }
160 group.post();
155161
156 lock.lock();162 lock.lock();
157163
@@ -191,8 +197,8 @@
191 }197 }
192198
193private:199private:
194 std::shared_ptr<mc::DisplayBufferCompositorFactory> const display_buffer_compositor_factory;200 std::shared_ptr<mc::DisplayBufferCompositorFactory> const compositor_factory;
195 mg::DisplayBuffer& buffer;201 mg::DisplaySyncGroup& group;
196 std::shared_ptr<mc::Scene> const scene;202 std::shared_ptr<mc::Scene> const scene;
197 bool running;203 bool running;
198 int frames_scheduled;204 int frames_scheduled;
@@ -305,12 +311,12 @@
305void mc::MultiThreadedCompositor::create_compositing_threads()311void mc::MultiThreadedCompositor::create_compositing_threads()
306{312{
307 /* Start the display buffer compositing threads */313 /* Start the display buffer compositing threads */
308 display->for_each_display_buffer([this](mg::DisplayBuffer& buffer)314 display->for_each_display_sync_group([this](mg::DisplaySyncGroup& group)
309 {315 {
310 auto thread_functor = std::make_unique<mc::CompositingFunctor>(316 auto thread_functor = std::make_unique<mc::CompositingFunctor>(
311 display_buffer_compositor_factory, buffer, scene, report);317 display_buffer_compositor_factory, group, scene, report);
312318
313 futures.push_back(thread_pool.run(std::ref(*thread_functor), &buffer));319 futures.push_back(thread_pool.run(std::ref(*thread_functor), &group));
314 thread_functors.push_back(std::move(thread_functor));320 thread_functors.push_back(std::move(thread_functor));
315 });321 });
316322
317323
=== modified file 'src/server/compositor/screencast_display_buffer.cpp'
--- src/server/compositor/screencast_display_buffer.cpp 2015-01-21 07:34:50 +0000
+++ src/server/compositor/screencast_display_buffer.cpp 2015-02-23 13:13:47 +0000
@@ -95,10 +95,6 @@
95 glFinish();95 glFinish();
96}96}
9797
98void mc::ScreencastDisplayBuffer::flip()
99{
100}
101
102MirOrientation mc::ScreencastDisplayBuffer::orientation() const98MirOrientation mc::ScreencastDisplayBuffer::orientation() const
103{99{
104 return mir_orientation_normal;100 return mir_orientation_normal;
105101
=== modified file 'src/server/compositor/screencast_display_buffer.h'
--- src/server/compositor/screencast_display_buffer.h 2015-01-21 07:34:50 +0000
+++ src/server/compositor/screencast_display_buffer.h 2015-02-23 13:13:47 +0000
@@ -62,7 +62,6 @@
62 bool post_renderables_if_optimizable(graphics::RenderableList const&) override;62 bool post_renderables_if_optimizable(graphics::RenderableList const&) override;
6363
64 void gl_swap_buffers() override;64 void gl_swap_buffers() override;
65 void flip() override;
6665
67 MirOrientation orientation() const override;66 MirOrientation orientation() const override;
6867
6968
=== modified file 'src/server/graphics/nested/nested_display.cpp'
--- src/server/graphics/nested/nested_display.cpp 2015-02-17 11:58:56 +0000
+++ src/server/graphics/nested/nested_display.cpp 2015-02-23 13:13:47 +0000
@@ -119,6 +119,22 @@
119 eglTerminate(egl_display);119 eglTerminate(egl_display);
120}120}
121121
122mgn::detail::DisplaySyncGroup::DisplaySyncGroup(
123 std::shared_ptr<mgn::detail::NestedOutput> const& output) :
124 output(output)
125{
126}
127
128void mgn::detail::DisplaySyncGroup::for_each_display_buffer(
129 std::function<void(DisplayBuffer&)> const& f)
130{
131 f(*output);
132}
133
134void mgn::detail::DisplaySyncGroup::post()
135{
136}
137
122mgn::NestedDisplay::NestedDisplay(138mgn::NestedDisplay::NestedDisplay(
123 std::shared_ptr<mg::Platform> const& platform,139 std::shared_ptr<mg::Platform> const& platform,
124 std::shared_ptr<HostConnection> const& connection,140 std::shared_ptr<HostConnection> const& connection,
@@ -144,7 +160,7 @@
144 eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);160 eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
145}161}
146162
147void mgn::NestedDisplay::for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f)163void mgn::NestedDisplay::for_each_display_sync_group(std::function<void(mg::DisplaySyncGroup&)> const& f)
148{164{
149 std::unique_lock<std::mutex> lock(outputs_mutex);165 std::unique_lock<std::mutex> lock(outputs_mutex);
150 for (auto& i : outputs)166 for (auto& i : outputs)
@@ -205,12 +221,13 @@
205221
206 auto const host_surface = connection->create_surface(request_params);222 auto const host_surface = connection->create_surface(request_params);
207223
208 result[output.id] = std::make_shared<mgn::detail::NestedOutput>(224 result[output.id] = std::make_shared<mgn::detail::DisplaySyncGroup>(
209 egl_display,225 std::make_shared<mgn::detail::NestedOutput>(
210 host_surface,226 egl_display,
211 area,227 host_surface,
212 dispatcher,228 area,
213 output.current_format);229 dispatcher,
230 output.current_format));
214 have_output_for_group = true;231 have_output_for_group = true;
215 }232 }
216 });233 });
217234
=== modified file 'src/server/graphics/nested/nested_display.h'
--- src/server/graphics/nested/nested_display.h 2015-01-21 07:34:50 +0000
+++ src/server/graphics/nested/nested_display.h 2015-02-23 13:13:47 +0000
@@ -87,6 +87,16 @@
8787
88class NestedOutput;88class NestedOutput;
8989
90class DisplaySyncGroup : public graphics::DisplaySyncGroup
91{
92public:
93 DisplaySyncGroup(std::shared_ptr<detail::NestedOutput> const& output);
94 void for_each_display_buffer(std::function<void(DisplayBuffer&)> const&) override;
95 void post() override;
96private:
97 std::shared_ptr<detail::NestedOutput> const output;
98};
99
90extern EGLint const nested_egl_context_attribs[];100extern EGLint const nested_egl_context_attribs[];
91}101}
92102
@@ -105,7 +115,7 @@
105115
106 ~NestedDisplay() noexcept;116 ~NestedDisplay() noexcept;
107117
108 void for_each_display_buffer(std::function<void(DisplayBuffer&)>const& f) override;118 void for_each_display_sync_group(std::function<void(DisplaySyncGroup&)>const& f) override;
109119
110 std::unique_ptr<DisplayConfiguration> configuration() const override;120 std::unique_ptr<DisplayConfiguration> configuration() const override;
111 void configure(DisplayConfiguration const&) override;121 void configure(DisplayConfiguration const&) override;
@@ -133,7 +143,7 @@
133 detail::EGLDisplayHandle egl_display;143 detail::EGLDisplayHandle egl_display;
134144
135 std::mutex outputs_mutex;145 std::mutex outputs_mutex;
136 std::unordered_map<DisplayConfigurationOutputId, std::shared_ptr<detail::NestedOutput>> outputs;146 std::unordered_map<DisplayConfigurationOutputId, std::shared_ptr<detail::DisplaySyncGroup>> outputs;
137 DisplayConfigurationChangeHandler my_conf_change_handler;147 DisplayConfigurationChangeHandler my_conf_change_handler;
138 void create_surfaces(mir::graphics::DisplayConfiguration const& configuration);148 void create_surfaces(mir::graphics::DisplayConfiguration const& configuration);
139 void apply_to_connection(mir::graphics::DisplayConfiguration const& configuration);149 void apply_to_connection(mir::graphics::DisplayConfiguration const& configuration);
140150
=== modified file 'src/server/graphics/nested/nested_output.cpp'
--- src/server/graphics/nested/nested_output.cpp 2015-02-13 06:12:34 +0000
+++ src/server/graphics/nested/nested_output.cpp 2015-02-23 13:13:47 +0000
@@ -70,10 +70,6 @@
70 eglSwapBuffers(egl_display, egl_surface);70 eglSwapBuffers(egl_display, egl_surface);
71}71}
7272
73void mgn::detail::NestedOutput::flip()
74{
75}
76
77bool mgn::detail::NestedOutput::post_renderables_if_optimizable(RenderableList const&)73bool mgn::detail::NestedOutput::post_renderables_if_optimizable(RenderableList const&)
78{74{
79 return false;75 return false;
8076
=== modified file 'src/server/graphics/nested/nested_output.h'
--- src/server/graphics/nested/nested_output.h 2015-01-21 07:34:50 +0000
+++ src/server/graphics/nested/nested_output.h 2015-02-23 13:13:47 +0000
@@ -48,7 +48,6 @@
48 void make_current() override;48 void make_current() override;
49 void release_current() override;49 void release_current() override;
50 void gl_swap_buffers() override;50 void gl_swap_buffers() override;
51 void flip() override;
52 MirOrientation orientation() const override;51 MirOrientation orientation() const override;
53 bool uses_alpha() const override;52 bool uses_alpha() const override;
5453
5554
=== modified file 'src/server/graphics/offscreen/display.cpp'
--- src/server/graphics/offscreen/display.cpp 2015-02-17 11:58:56 +0000
+++ src/server/graphics/offscreen/display.cpp 2015-02-23 13:13:47 +0000
@@ -71,6 +71,21 @@
71 eglTerminate(egl_display);71 eglTerminate(egl_display);
72}72}
7373
74mgo::detail::DisplaySyncGroup::DisplaySyncGroup(std::unique_ptr<mg::DisplayBuffer> output) :
75 output(std::move(output))
76{
77}
78
79void mgo::detail::DisplaySyncGroup::for_each_display_buffer(
80 std::function<void(mg::DisplayBuffer&)> const& f)
81{
82 f(*output);
83}
84
85void mgo::detail::DisplaySyncGroup::post()
86{
87}
88
74mgo::Display::Display(89mgo::Display::Display(
75 EGLNativeDisplayType egl_native_display,90 EGLNativeDisplayType egl_native_display,
76 std::shared_ptr<DisplayConfigurationPolicy> const& initial_conf_policy,91 std::shared_ptr<DisplayConfigurationPolicy> const& initial_conf_policy,
@@ -94,13 +109,13 @@
94{109{
95}110}
96111
97void mgo::Display::for_each_display_buffer(112void mgo::Display::for_each_display_sync_group(
98 std::function<void(mg::DisplayBuffer&)> const& f)113 std::function<void(mg::DisplaySyncGroup&)> const& f)
99{114{
100 std::lock_guard<std::mutex> lock{configuration_mutex};115 std::lock_guard<std::mutex> lock{configuration_mutex};
101116
102 for (auto& db_ptr : display_buffers)117 for (auto& dg_ptr : display_sync_groups)
103 f(*db_ptr);118 f(*dg_ptr);
104}119}
105120
106std::unique_ptr<mg::DisplayConfiguration> mgo::Display::configuration() const121std::unique_ptr<mg::DisplayConfiguration> mgo::Display::configuration() const
@@ -120,7 +135,7 @@
120135
121 std::lock_guard<std::mutex> lock{configuration_mutex};136 std::lock_guard<std::mutex> lock{configuration_mutex};
122137
123 display_buffers.clear();138 display_sync_groups.clear();
124139
125 conf.for_each_output(140 conf.for_each_output(
126 [this] (DisplayConfigurationOutput const& output)141 [this] (DisplayConfigurationOutput const& output)
@@ -131,7 +146,8 @@
131 SurfacelessEGLContext{egl_display, egl_context_shared},146 SurfacelessEGLContext{egl_display, egl_context_shared},
132 output.extents()};147 output.extents()};
133148
134 display_buffers.push_back(std::unique_ptr<mg::DisplayBuffer>(raw_db));149 display_sync_groups.emplace_back(
150 new mgo::detail::DisplaySyncGroup(std::unique_ptr<mg::DisplayBuffer>(raw_db)));
135 }151 }
136 });152 });
137}153}
138154
=== modified file 'src/server/graphics/offscreen/display.h'
--- src/server/graphics/offscreen/display.h 2015-01-21 07:34:50 +0000
+++ src/server/graphics/offscreen/display.h 2015-02-23 13:13:47 +0000
@@ -58,6 +58,16 @@
58 EGLDisplay egl_display;58 EGLDisplay egl_display;
59};59};
6060
61class DisplaySyncGroup : public graphics::DisplaySyncGroup
62{
63public:
64 DisplaySyncGroup(std::unique_ptr<DisplayBuffer> output);
65 void for_each_display_buffer(std::function<void(DisplayBuffer&)> const&) override;
66 void post() override;
67private:
68 std::unique_ptr<DisplayBuffer> const output;
69};
70
61}71}
6272
63class Display : public graphics::Display73class Display : public graphics::Display
@@ -68,7 +78,7 @@
68 std::shared_ptr<DisplayReport> const& listener);78 std::shared_ptr<DisplayReport> const& listener);
69 ~Display() noexcept;79 ~Display() noexcept;
7080
71 void for_each_display_buffer(std::function<void(DisplayBuffer&)> const& f) override;81 void for_each_display_sync_group(std::function<void(DisplaySyncGroup&)> const& f) override;
7282
73 std::unique_ptr<graphics::DisplayConfiguration> configuration() const override;83 std::unique_ptr<graphics::DisplayConfiguration> configuration() const override;
74 void configure(graphics::DisplayConfiguration const& conf) override;84 void configure(graphics::DisplayConfiguration const& conf) override;
@@ -93,7 +103,7 @@
93 SurfacelessEGLContext const egl_context_shared;103 SurfacelessEGLContext const egl_context_shared;
94 mutable std::mutex configuration_mutex;104 mutable std::mutex configuration_mutex;
95 DisplayConfiguration current_display_configuration;105 DisplayConfiguration current_display_configuration;
96 std::vector<std::unique_ptr<DisplayBuffer>> display_buffers;106 std::vector<std::unique_ptr<DisplaySyncGroup>> display_sync_groups;
97};107};
98108
99}109}
100110
=== modified file 'src/server/graphics/offscreen/display_buffer.cpp'
--- src/server/graphics/offscreen/display_buffer.cpp 2015-01-21 07:34:50 +0000
+++ src/server/graphics/offscreen/display_buffer.cpp 2015-02-23 13:13:47 +0000
@@ -144,10 +144,6 @@
144 glFinish();144 glFinish();
145}145}
146146
147void mgo::DisplayBuffer::flip()
148{
149}
150
151bool mgo::DisplayBuffer::post_renderables_if_optimizable(RenderableList const&)147bool mgo::DisplayBuffer::post_renderables_if_optimizable(RenderableList const&)
152{148{
153 return false;149 return false;
154150
=== modified file 'src/server/graphics/offscreen/display_buffer.h'
--- src/server/graphics/offscreen/display_buffer.h 2015-01-21 07:34:50 +0000
+++ src/server/graphics/offscreen/display_buffer.h 2015-02-23 13:13:47 +0000
@@ -66,7 +66,6 @@
66 void make_current() override;66 void make_current() override;
67 void release_current() override;67 void release_current() override;
68 void gl_swap_buffers() override;68 void gl_swap_buffers() override;
69 void flip() override;
7069
71 MirOrientation orientation() const override;70 MirOrientation orientation() const override;
72 bool uses_alpha() const override;71 bool uses_alpha() const override;
7372
=== modified file 'src/server/input/display_input_region.cpp'
--- src/server/input/display_input_region.cpp 2014-03-06 06:05:17 +0000
+++ src/server/input/display_input_region.cpp 2015-02-23 13:13:47 +0000
@@ -37,11 +37,14 @@
37{37{
38 geom::Rectangles rectangles;38 geom::Rectangles rectangles;
3939
40 display->for_each_display_buffer(40 display->for_each_display_sync_group([&rectangles](mg::DisplaySyncGroup& group)
41 [&rectangles](mg::DisplayBuffer const& buffer)41 {
42 {42 group.for_each_display_buffer(
43 rectangles.add(buffer.view_area());43 [&rectangles](mg::DisplayBuffer const& buffer)
44 });44 {
45 rectangles.add(buffer.view_area());
46 });
47 });
4548
46 return rectangles.bounding_rectangle();49 return rectangles.bounding_rectangle();
47}50}
@@ -50,11 +53,14 @@
50{53{
51 geom::Rectangles rectangles;54 geom::Rectangles rectangles;
5255
53 display->for_each_display_buffer(56 display->for_each_display_sync_group([&rectangles](mg::DisplaySyncGroup& group)
54 [&rectangles](mg::DisplayBuffer const& buffer)57 {
55 {58 group.for_each_display_buffer(
56 rectangles.add(buffer.view_area());59 [&rectangles](mg::DisplayBuffer const& buffer)
57 });60 {
61 rectangles.add(buffer.view_area());
62 });
63 });
5864
59 rectangles.confine(point);65 rectangles.confine(point);
60}66}
6167
=== modified file 'src/server/shell/graphics_display_layout.cpp'
--- src/server/shell/graphics_display_layout.cpp 2015-01-21 07:34:50 +0000
+++ src/server/shell/graphics_display_layout.cpp 2015-02-23 13:13:47 +0000
@@ -98,20 +98,22 @@
98 int max_area = -1;98 int max_area = -1;
99 geometry::Rectangle best = rect;99 geometry::Rectangle best = rect;
100100
101 display->for_each_display_buffer(101 display->for_each_display_sync_group([&](mg::DisplaySyncGroup& group)
102 [&](mg::DisplayBuffer const& db)102 {
103 {103 group.for_each_display_buffer([&](mg::DisplayBuffer const& db)
104 auto const& screen = db.view_area();
105 auto const& overlap = rect.intersection_with(screen);
106 int area = overlap.size.width.as_int() *
107 overlap.size.height.as_int();
108
109 if (area > max_area)
110 {104 {
111 best = screen;105 auto const& screen = db.view_area();
112 max_area = area;106 auto const& overlap = rect.intersection_with(screen);
113 }107 int area = overlap.size.width.as_int() *
114 });108 overlap.size.height.as_int();
109
110 if (area > max_area)
111 {
112 best = screen;
113 max_area = area;
114 }
115 });
116 });
115117
116 return best;118 return best;
117}119}
118120
=== modified file 'tests/acceptance-tests/test_display_configuration.cpp'
--- tests/acceptance-tests/test_display_configuration.cpp 2015-01-21 07:34:50 +0000
+++ tests/acceptance-tests/test_display_configuration.cpp 2015-02-23 13:13:47 +0000
@@ -24,7 +24,7 @@
24#include "mir_test_framework/connected_client_headless_server.h"24#include "mir_test_framework/connected_client_headless_server.h"
25#include "mir_test_doubles/null_platform.h"25#include "mir_test_doubles/null_platform.h"
26#include "mir_test_doubles/null_display.h"26#include "mir_test_doubles/null_display.h"
27#include "mir_test_doubles/null_display_buffer.h"27#include "mir_test_doubles/null_display_sync_group.h"
28#include "mir_test_doubles/null_platform.h"28#include "mir_test_doubles/null_platform.h"
29#include "mir_test/display_config_matchers.h"29#include "mir_test/display_config_matchers.h"
30#include "mir_test_doubles/stub_display_configuration.h"30#include "mir_test_doubles/stub_display_configuration.h"
@@ -64,9 +64,9 @@
64 {64 {
65 }65 }
6666
67 void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f) override67 void for_each_display_sync_group(std::function<void(mg::DisplaySyncGroup&)> const& f) override
68 {68 {
69 f(display_buffer);69 f(display_sync_group);
70 }70 }
7171
72 std::unique_ptr<mg::DisplayConfiguration> configuration() const override72 std::unique_ptr<mg::DisplayConfiguration> configuration() const override
@@ -111,7 +111,7 @@
111111
112private:112private:
113 std::shared_ptr<mtd::StubDisplayConfig> config;113 std::shared_ptr<mtd::StubDisplayConfig> config;
114 mtd::NullDisplayBuffer display_buffer;114 mtd::NullDisplaySyncGroup display_sync_group;
115 mt::Pipe p;115 mt::Pipe p;
116 std::atomic<bool> handler_called;116 std::atomic<bool> handler_called;
117};117};
118118
=== modified file 'tests/include/mir_test_doubles/mock_display.h'
--- tests/include/mir_test_doubles/mock_display.h 2015-01-21 07:34:50 +0000
+++ tests/include/mir_test_doubles/mock_display.h 2015-02-23 13:13:47 +0000
@@ -35,7 +35,7 @@
35struct MockDisplay : public graphics::Display35struct MockDisplay : public graphics::Display
36{36{
37public:37public:
38 MOCK_METHOD1(for_each_display_buffer, void (std::function<void(graphics::DisplayBuffer&)> const&));38 MOCK_METHOD1(for_each_display_sync_group, void (std::function<void(graphics::DisplaySyncGroup&)> const&));
39 MOCK_CONST_METHOD0(configuration, std::unique_ptr<graphics::DisplayConfiguration>());39 MOCK_CONST_METHOD0(configuration, std::unique_ptr<graphics::DisplayConfiguration>());
40 MOCK_METHOD1(configure, void(graphics::DisplayConfiguration const&));40 MOCK_METHOD1(configure, void(graphics::DisplayConfiguration const&));
41 MOCK_METHOD2(register_configuration_change_handler,41 MOCK_METHOD2(register_configuration_change_handler,
4242
=== modified file 'tests/include/mir_test_doubles/mock_display_buffer.h'
--- tests/include/mir_test_doubles/mock_display_buffer.h 2015-01-21 07:34:50 +0000
+++ tests/include/mir_test_doubles/mock_display_buffer.h 2015-02-23 13:13:47 +0000
@@ -43,7 +43,6 @@
43 MOCK_METHOD0(make_current, void());43 MOCK_METHOD0(make_current, void());
44 MOCK_METHOD0(release_current, void());44 MOCK_METHOD0(release_current, void());
45 MOCK_METHOD0(gl_swap_buffers, void());45 MOCK_METHOD0(gl_swap_buffers, void());
46 MOCK_METHOD0(flip, void());
47 MOCK_METHOD1(post_renderables_if_optimizable, bool(graphics::RenderableList const&));46 MOCK_METHOD1(post_renderables_if_optimizable, bool(graphics::RenderableList const&));
48 MOCK_CONST_METHOD0(orientation, MirOrientation());47 MOCK_CONST_METHOD0(orientation, MirOrientation());
49 MOCK_CONST_METHOD0(uses_alpha, bool());48 MOCK_CONST_METHOD0(uses_alpha, bool());
5049
=== modified file 'tests/include/mir_test_doubles/null_display.h'
--- tests/include/mir_test_doubles/null_display.h 2015-01-21 07:34:50 +0000
+++ tests/include/mir_test_doubles/null_display.h 2015-02-23 13:13:47 +0000
@@ -22,7 +22,7 @@
22#include "mir/graphics/display.h"22#include "mir/graphics/display.h"
23#include "null_gl_context.h"23#include "null_gl_context.h"
24#include "null_display_configuration.h"24#include "null_display_configuration.h"
25#include <thread>25#include "null_display_sync_group.h"
2626
27namespace mir27namespace mir
28{28{
@@ -34,10 +34,9 @@
34class NullDisplay : public graphics::Display34class NullDisplay : public graphics::Display
35{35{
36 public:36 public:
37 void for_each_display_buffer(std::function<void(graphics::DisplayBuffer&)> const&) override37 void for_each_display_sync_group(std::function<void(graphics::DisplaySyncGroup&)> const& f) override
38 {38 {
39 /* yield() is needed to ensure reasonable runtime under valgrind for some tests */39 f(group);
40 std::this_thread::yield();
41 }40 }
42 std::unique_ptr<graphics::DisplayConfiguration> configuration() const override41 std::unique_ptr<graphics::DisplayConfiguration> configuration() const override
43 {42 {
@@ -66,6 +65,7 @@
66 {65 {
67 return std::unique_ptr<NullGLContext>{new NullGLContext()};66 return std::unique_ptr<NullGLContext>{new NullGLContext()};
68 }67 }
68 NullDisplaySyncGroup group;
69};69};
7070
71}71}
7272
=== modified file 'tests/include/mir_test_doubles/null_display_buffer.h'
--- tests/include/mir_test_doubles/null_display_buffer.h 2015-01-21 07:34:50 +0000
+++ tests/include/mir_test_doubles/null_display_buffer.h 2015-02-23 13:13:47 +0000
@@ -35,7 +35,6 @@
35 void make_current() override {}35 void make_current() override {}
36 void release_current() override {}36 void release_current() override {}
37 void gl_swap_buffers() override {}37 void gl_swap_buffers() override {}
38 void flip() override {}
39 bool post_renderables_if_optimizable(graphics::RenderableList const&) override { return false; }38 bool post_renderables_if_optimizable(graphics::RenderableList const&) override { return false; }
40 MirOrientation orientation() const override { return mir_orientation_normal; }39 MirOrientation orientation() const override { return mir_orientation_normal; }
41 bool uses_alpha() const override { return false; }40 bool uses_alpha() const override { return false; }
4241
=== added file 'tests/include/mir_test_doubles/null_display_sync_group.h'
--- tests/include/mir_test_doubles/null_display_sync_group.h 1970-01-01 00:00:00 +0000
+++ tests/include/mir_test_doubles/null_display_sync_group.h 2015-02-23 13:13:47 +0000
@@ -0,0 +1,81 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
17 */
18
19#ifndef MIR_TEST_DOUBLES_NULL_DISPLAY_SYNC_GROUP_H_
20#define MIR_TEST_DOUBLES_NULL_DISPLAY_SYNC_GROUP_H_
21
22#include "mir/graphics/display.h"
23#include "mir/geometry/size.h"
24#include "null_display_buffer.h"
25#include "stub_display_buffer.h"
26#include <thread>
27
28namespace mir
29{
30namespace test
31{
32namespace doubles
33{
34
35struct StubDisplaySyncGroup : graphics::DisplaySyncGroup
36{
37public:
38 StubDisplaySyncGroup(std::vector<geometry::Rectangle> const& output_rects)
39 : output_rects{output_rects}
40 {
41 for (auto const& output_rect : output_rects)
42 display_buffers.emplace_back(output_rect);
43 }
44 StubDisplaySyncGroup(geometry::Size sz) : StubDisplaySyncGroup({{{0,0}, sz}}) {}
45
46 void for_each_display_buffer(std::function<void(graphics::DisplayBuffer&)> const& f) override
47 {
48 for (auto& db : display_buffers)
49 f(db);
50 }
51
52 void post() override
53 {
54 /* yield() is needed to ensure reasonable runtime under valgrind for some tests */
55 std::this_thread::yield();
56 }
57
58private:
59 std::vector<geometry::Rectangle> const output_rects;
60 std::vector<StubDisplayBuffer> display_buffers;
61};
62
63struct NullDisplaySyncGroup : graphics::DisplaySyncGroup
64{
65 void for_each_display_buffer(std::function<void(graphics::DisplayBuffer&)> const& f) override
66 {
67 f(db);
68 }
69 virtual void post() override
70 {
71 /* yield() is needed to ensure reasonable runtime under valgrind for some tests */
72 std::this_thread::yield();
73 }
74 NullDisplayBuffer db;
75};
76
77}
78}
79}
80
81#endif /* MIR_TEST_DOUBLES_NULL_DISPLAY_SYNC_GROUP_H_ */
082
=== modified file 'tests/include/mir_test_doubles/stub_display.h'
--- tests/include/mir_test_doubles/stub_display.h 2015-01-21 07:34:50 +0000
+++ tests/include/mir_test_doubles/stub_display.h 2015-02-23 13:13:47 +0000
@@ -20,6 +20,7 @@
20#define MIR_TEST_DOUBLES_STUB_DISPLAY_H_20#define MIR_TEST_DOUBLES_STUB_DISPLAY_H_
2121
22#include "null_display.h"22#include "null_display.h"
23#include "null_display_sync_group.h"
23#include "stub_display_buffer.h"24#include "stub_display_buffer.h"
24#include "stub_display_configuration.h"25#include "stub_display_configuration.h"
2526
@@ -37,17 +38,22 @@
37class StubDisplay : public NullDisplay38class StubDisplay : public NullDisplay
38{39{
39public:40public:
40 StubDisplay(std::vector<geometry::Rectangle> const& output_rects)41 StubDisplay(std::vector<geometry::Rectangle> const& output_rects) :
41 : output_rects{output_rects}42 output_rects(output_rects)
42 {43 {
43 for (auto const& output_rect : output_rects)44 for (auto const& rect : output_rects)
44 display_buffers.emplace_back(output_rect);45 groups.emplace_back(new StubDisplaySyncGroup({rect}));
45 }46 }
4647
47 void for_each_display_buffer(std::function<void(graphics::DisplayBuffer&)> const& f) override48 StubDisplay(unsigned int nbuffers) :
48 {49 StubDisplay(generate_stub_rects(nbuffers))
49 for (auto& db : display_buffers)50 {
50 f(db);51 }
52
53 void for_each_display_sync_group(std::function<void(graphics::DisplaySyncGroup&)> const& f) override
54 {
55 for (auto& group : groups)
56 f(*group);
51 }57 }
5258
53 std::unique_ptr<graphics::DisplayConfiguration> configuration() const override59 std::unique_ptr<graphics::DisplayConfiguration> configuration() const override
@@ -59,7 +65,15 @@
5965
60 std::vector<geometry::Rectangle> const output_rects;66 std::vector<geometry::Rectangle> const output_rects;
61private:67private:
62 std::vector<StubDisplayBuffer> display_buffers;68 std::vector<geometry::Rectangle> generate_stub_rects(unsigned int nbuffers)
69 {
70 std::vector<geometry::Rectangle> rects;
71 for (auto i = 0u; i < nbuffers; i++)
72 rects.push_back(geometry::Rectangle{{0,0},{1,1}});
73 return rects;
74 }
75
76 std::vector<std::unique_ptr<StubDisplaySyncGroup>> groups;
63};77};
6478
65}79}
6680
=== modified file 'tests/integration-tests/graphics/android/test_display_integration.cpp'
--- tests/integration-tests/graphics/android/test_display_integration.cpp 2015-02-13 06:12:34 +0000
+++ tests/integration-tests/graphics/android/test_display_integration.cpp 2015-02-23 13:13:47 +0000
@@ -81,34 +81,38 @@
8181
82TEST_F(AndroidDisplay, display_can_post)82TEST_F(AndroidDisplay, display_can_post)
83{83{
84 display->for_each_display_buffer([](mg::DisplayBuffer& buffer)84 display->for_each_display_sync_group([](mg::DisplaySyncGroup& group) {
85 {85 group.for_each_display_buffer([](mg::DisplayBuffer& buffer)
86 buffer.make_current();86 {
87 md::glAnimationBasic gl_animation;87 buffer.make_current();
88 gl_animation.init_gl();88 md::glAnimationBasic gl_animation;
8989 gl_animation.init_gl();
90 gl_animation.render_gl();90
91 buffer.gl_swap_buffers();91 gl_animation.render_gl();
92 buffer.flip();92 buffer.gl_swap_buffers();
9393
94 gl_animation.render_gl();94 gl_animation.render_gl();
95 buffer.gl_swap_buffers();95 buffer.gl_swap_buffers();
96 buffer.flip();96 });
97 group.post();
97 });98 });
98}99}
99100
100TEST_F(AndroidDisplay, display_can_post_overlay)101TEST_F(AndroidDisplay, display_can_post_overlay)
101{102{
102 display->for_each_display_buffer([](mg::DisplayBuffer& db)103 display->for_each_display_sync_group([](mg::DisplaySyncGroup& group) {
103 {104 group.for_each_display_buffer([](mg::DisplayBuffer& db)
104 db.make_current();105 {
105 auto area = db.view_area();106 db.make_current();
106 auto buffer = buffer_allocator->alloc_buffer_platform(107 auto area = db.view_area();
107 area.size, mir_pixel_format_abgr_8888, mga::BufferUsage::use_hardware);108 auto buffer = buffer_allocator->alloc_buffer_platform(
108 mg::RenderableList list{109 area.size, mir_pixel_format_abgr_8888, mga::BufferUsage::use_hardware);
109 std::make_shared<mtd::StubRenderable>(buffer, area)110 mg::RenderableList list{
110 };111 std::make_shared<mtd::StubRenderable>(buffer, area)
112 };
111113
112 db.post_renderables_if_optimizable(list);114 db.post_renderables_if_optimizable(list);
115 });
116 group.post();
113 });117 });
114}118}
115119
=== modified file 'tests/integration-tests/test_display_info.cpp'
--- tests/integration-tests/test_display_info.cpp 2015-01-21 07:34:50 +0000
+++ tests/integration-tests/test_display_info.cpp 2015-02-23 13:13:47 +0000
@@ -29,6 +29,7 @@
29#include "mir_test_doubles/null_display.h"29#include "mir_test_doubles/null_display.h"
30#include "mir_test_doubles/null_event_sink.h"30#include "mir_test_doubles/null_event_sink.h"
31#include "mir_test_doubles/null_display_changer.h"31#include "mir_test_doubles/null_display_changer.h"
32#include "mir_test_doubles/null_display_sync_group.h"
32#include "mir_test_doubles/stub_display_buffer.h"33#include "mir_test_doubles/stub_display_buffer.h"
33#include "mir_test_doubles/null_platform.h"34#include "mir_test_doubles/null_platform.h"
34#include "mir_test/display_config_matchers.h"35#include "mir_test/display_config_matchers.h"
@@ -61,13 +62,13 @@
61 {62 {
62 }63 }
6364
64 void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f) override65 void for_each_display_sync_group(std::function<void(mg::DisplaySyncGroup&)> const& f) override
65 {66 {
66 f(display_buffer);67 f(display_sync_group);
67 }68 }
6869
69private:70private:
70 mtd::NullDisplayBuffer display_buffer;71 mtd::NullDisplaySyncGroup display_sync_group;
71};72};
7273
73class StubChanger : public mtd::NullDisplayChanger74class StubChanger : public mtd::NullDisplayChanger
7475
=== modified file 'tests/integration-tests/test_display_server_main_loop_events.cpp'
--- tests/integration-tests/test_display_server_main_loop_events.cpp 2015-02-13 06:12:34 +0000
+++ tests/integration-tests/test_display_server_main_loop_events.cpp 2015-02-23 13:13:47 +0000
@@ -86,9 +86,9 @@
86 {86 {
87 }87 }
8888
89 void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f) override89 void for_each_display_sync_group(std::function<void(mg::DisplaySyncGroup&)> const& f) override
90 {90 {
91 display->for_each_display_buffer(f);91 display->for_each_display_sync_group(f);
92 }92 }
9393
94 std::unique_ptr<mg::DisplayConfiguration> configuration() const94 std::unique_ptr<mg::DisplayConfiguration> configuration() const
9595
=== modified file 'tests/integration-tests/test_surface_first_frame_sync.cpp'
--- tests/integration-tests/test_surface_first_frame_sync.cpp 2015-02-13 06:12:34 +0000
+++ tests/integration-tests/test_surface_first_frame_sync.cpp 2015-02-23 13:13:47 +0000
@@ -56,32 +56,42 @@
56public:56public:
57 SynchronousCompositor(std::shared_ptr<mg::Display> const& display_,57 SynchronousCompositor(std::shared_ptr<mg::Display> const& display_,
58 std::shared_ptr<mc::Scene> const& s,58 std::shared_ptr<mc::Scene> const& s,
59 std::shared_ptr<mc::DisplayBufferCompositorFactory> const& db_compositor_factory)59 std::shared_ptr<mc::DisplayBufferCompositorFactory> const& dbc_factory)
60 : display{display_},60 : display{display_},
61 scene{s}61 scene{s}
62 {62 {
63 display->for_each_display_buffer(63 display->for_each_display_sync_group([this, &dbc_factory](mg::DisplaySyncGroup& group)
64 [this, &db_compositor_factory](mg::DisplayBuffer& display_buffer)64 {
65 group.for_each_display_buffer([this, &dbc_factory](mg::DisplayBuffer& display_buffer)
65 {66 {
66 auto dbc = db_compositor_factory->create_compositor_for(display_buffer);67 auto dbc = dbc_factory->create_compositor_for(display_buffer);
67 scene->register_compositor(dbc.get());68 scene->register_compositor(dbc.get());
68 display_buffer_compositor_map[&display_buffer] = std::move(dbc);69 display_buffer_compositor_map[&display_buffer] = std::move(dbc);
69 });70 });
70 71 });
72
71 auto notify = [this]()73 auto notify = [this]()
72 {74 {
73 display->for_each_display_buffer([this](mg::DisplayBuffer& display_buffer)75 display->for_each_display_sync_group([this](mg::DisplaySyncGroup& group)
74 {76 {
75 auto& dbc = display_buffer_compositor_map[&display_buffer];77 group.for_each_display_buffer([this](mg::DisplayBuffer& display_buffer)
76 dbc->composite(scene->scene_elements_for(dbc.get()));78 {
79 auto& dbc = display_buffer_compositor_map[&display_buffer];
80 dbc->composite(scene->scene_elements_for(dbc.get()));
81 });
82 group.post();
77 });83 });
78 };84 };
79 auto notify2 = [this](int)85 auto notify2 = [this](int)
80 {86 {
81 display->for_each_display_buffer([this](mg::DisplayBuffer& display_buffer)87 display->for_each_display_sync_group([this](mg::DisplaySyncGroup& group)
82 {88 {
83 auto& dbc = display_buffer_compositor_map[&display_buffer];89 group.for_each_display_buffer([this](mg::DisplayBuffer& display_buffer)
84 dbc->composite(scene->scene_elements_for(dbc.get()));90 {
91 auto& dbc = display_buffer_compositor_map[&display_buffer];
92 dbc->composite(scene->scene_elements_for(dbc.get()));
93 });
94 group.post();
85 });95 });
86 };96 };
87 observer = std::make_shared<ms::LegacySceneChangeNotification>(notify, notify2);97 observer = std::make_shared<ms::LegacySceneChangeNotification>(notify, notify2);
8898
=== modified file 'tests/integration-tests/test_surface_stack_with_compositor.cpp'
--- tests/integration-tests/test_surface_stack_with_compositor.cpp 2015-02-12 22:31:44 +0000
+++ tests/integration-tests/test_surface_stack_with_compositor.cpp 2015-02-23 13:13:47 +0000
@@ -30,6 +30,8 @@
30#include "mir_test_doubles/stub_display_buffer.h"30#include "mir_test_doubles/stub_display_buffer.h"
31#include "mir_test_doubles/stub_buffer.h"31#include "mir_test_doubles/stub_buffer.h"
32#include "mir_test_doubles/stub_input_sender.h"32#include "mir_test_doubles/stub_input_sender.h"
33#include "mir_test_doubles/null_surface_configurator.h"
34#include "mir_test_doubles/null_display_sync_group.h"
3335
34#include <condition_variable>36#include <condition_variable>
35#include <mutex>37#include <mutex>
@@ -56,23 +58,14 @@
56 }58 }
57};59};
5860
59struct CountingDisplayBuffer : public mtd::StubDisplayBuffer61struct CountingDisplaySyncGroup : public mtd::StubDisplaySyncGroup
60{62{
61 CountingDisplayBuffer() :63 CountingDisplaySyncGroup() :
62 StubDisplayBuffer({{0,0}, {10, 10}})64 mtd::StubDisplaySyncGroup({100,100})
63 {65 {
64 }66 }
6567
66 bool post_renderables_if_optimizable(mg::RenderableList const&) override68 void post() override
67 {
68 return false;
69 }
70
71 void gl_swap_buffers() override
72 {
73 }
74
75 void flip() override
76 {69 {
77 increment_post_count();70 increment_post_count();
78 }71 }
@@ -101,19 +94,19 @@
10194
102struct StubDisplay : public mtd::NullDisplay95struct StubDisplay : public mtd::NullDisplay
103{96{
104 StubDisplay(mg::DisplayBuffer& primary, mg::DisplayBuffer& secondary)97 StubDisplay(mg::DisplaySyncGroup& primary, mg::DisplaySyncGroup& secondary)
105 : primary(primary),98 : primary(primary),
106 secondary(secondary)99 secondary(secondary)
107 {100 {
108 } 101 }
109 void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& fn) override102 void for_each_display_sync_group(std::function<void(mg::DisplaySyncGroup&)> const& fn) override
110 {103 {
111 fn(primary);104 fn(primary);
112 fn(secondary);105 fn(secondary);
113 }106 }
114private:107private:
115 mg::DisplayBuffer& primary;108 mg::DisplaySyncGroup& primary;
116 mg::DisplayBuffer& secondary;109 mg::DisplaySyncGroup& secondary;
117};110};
118111
119struct SurfaceStackCompositor : public testing::Test112struct SurfaceStackCompositor : public testing::Test
@@ -144,8 +137,8 @@
144 std::shared_ptr<ms::BasicSurface> stub_surface;137 std::shared_ptr<ms::BasicSurface> stub_surface;
145 ms::SurfaceCreationParameters default_params;138 ms::SurfaceCreationParameters default_params;
146 mtd::StubBuffer stubbuf;139 mtd::StubBuffer stubbuf;
147 CountingDisplayBuffer stub_primary_db;140 CountingDisplaySyncGroup stub_primary_db;
148 CountingDisplayBuffer stub_secondary_db;141 CountingDisplaySyncGroup stub_secondary_db;
149 StubDisplay stub_display{stub_primary_db, stub_secondary_db};142 StubDisplay stub_display{stub_primary_db, stub_secondary_db};
150 mc::DefaultDisplayBufferCompositorFactory dbc_factory{143 mc::DefaultDisplayBufferCompositorFactory dbc_factory{
151 mt::fake_shared(renderer_factory),144 mt::fake_shared(renderer_factory),
152145
=== modified file 'tests/integration-tests/test_surfaceloop.cpp'
--- tests/integration-tests/test_surfaceloop.cpp 2015-01-21 07:34:50 +0000
+++ tests/integration-tests/test_surfaceloop.cpp 2015-02-23 13:13:47 +0000
@@ -22,6 +22,7 @@
22#include "mir_test_doubles/stub_buffer_allocator.h"22#include "mir_test_doubles/stub_buffer_allocator.h"
23#include "mir_test_doubles/null_platform.h"23#include "mir_test_doubles/null_platform.h"
24#include "mir_test_doubles/null_display.h"24#include "mir_test_doubles/null_display.h"
25#include "mir_test_doubles/null_display_sync_group.h"
25#include "mir_test_doubles/stub_display_buffer.h"26#include "mir_test_doubles/stub_display_buffer.h"
2627
27#include "mir_test_framework/stubbed_server_configuration.h"28#include "mir_test_framework/stubbed_server_configuration.h"
@@ -75,18 +76,18 @@
75class StubDisplay : public mtd::NullDisplay76class StubDisplay : public mtd::NullDisplay
76{77{
77public:78public:
78 StubDisplay()79 StubDisplay() :
79 : display_buffer{geom::Rectangle{geom::Point{0,0}, geom::Size{1600,1600}}}80 display_sync_group{geom::Size{1600,1600}}
80 {81 {
81 }82 }
8283
83 void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f) override84 void for_each_display_sync_group(std::function<void(mg::DisplaySyncGroup&)> const& f) override
84 {85 {
85 f(display_buffer);86 f(display_sync_group);
86 }87 }
8788
88private:89private:
89 mtd::StubDisplayBuffer display_buffer;90 mtd::StubDisplaySyncGroup display_sync_group;
90};91};
9192
92struct SurfaceSync93struct SurfaceSync
9394
=== modified file 'tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp'
--- tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp 2015-01-21 09:03:53 +0000
+++ tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp 2015-02-23 13:13:47 +0000
@@ -124,8 +124,6 @@
124 .Times(1);124 .Times(1);
125 EXPECT_CALL(display_buffer, gl_swap_buffers())125 EXPECT_CALL(display_buffer, gl_swap_buffers())
126 .Times(1);126 .Times(1);
127 EXPECT_CALL(display_buffer, flip())
128 .Times(1);
129127
130 mc::DefaultDisplayBufferCompositor compositor(128 mc::DefaultDisplayBufferCompositor compositor(
131 display_buffer,129 display_buffer,
@@ -205,8 +203,6 @@
205 .InSequence(render_seq);203 .InSequence(render_seq);
206 EXPECT_CALL(display_buffer, gl_swap_buffers())204 EXPECT_CALL(display_buffer, gl_swap_buffers())
207 .InSequence(render_seq);205 .InSequence(render_seq);
208 EXPECT_CALL(display_buffer, flip())
209 .InSequence(render_seq);
210206
211 mc::DefaultDisplayBufferCompositor compositor(207 mc::DefaultDisplayBufferCompositor compositor(
212 display_buffer,208 display_buffer,
@@ -242,8 +238,6 @@
242 .InSequence(seq);238 .InSequence(seq);
243 EXPECT_CALL(display_buffer, gl_swap_buffers())239 EXPECT_CALL(display_buffer, gl_swap_buffers())
244 .InSequence(seq);240 .InSequence(seq);
245 EXPECT_CALL(display_buffer, flip())
246 .InSequence(seq);
247241
248 EXPECT_CALL(display_buffer, post_renderables_if_optimizable(_))242 EXPECT_CALL(display_buffer, post_renderables_if_optimizable(_))
249 .InSequence(seq)243 .InSequence(seq)
@@ -263,8 +257,6 @@
263 .InSequence(seq);257 .InSequence(seq);
264 EXPECT_CALL(display_buffer, gl_swap_buffers())258 EXPECT_CALL(display_buffer, gl_swap_buffers())
265 .InSequence(seq);259 .InSequence(seq);
266 EXPECT_CALL(display_buffer, flip())
267 .InSequence(seq);
268260
269 mc::DefaultDisplayBufferCompositor compositor(261 mc::DefaultDisplayBufferCompositor compositor(
270 display_buffer,262 display_buffer,
@@ -302,8 +294,6 @@
302 .InSequence(seq);294 .InSequence(seq);
303 EXPECT_CALL(display_buffer, gl_swap_buffers())295 EXPECT_CALL(display_buffer, gl_swap_buffers())
304 .InSequence(seq);296 .InSequence(seq);
305 EXPECT_CALL(display_buffer, flip())
306 .InSequence(seq);
307297
308 mc::DefaultDisplayBufferCompositor compositor(298 mc::DefaultDisplayBufferCompositor compositor(
309 display_buffer,299 display_buffer,
310300
=== modified file 'tests/unit-tests/compositor/test_multi_threaded_compositor.cpp'
--- tests/unit-tests/compositor/test_multi_threaded_compositor.cpp 2015-02-13 06:12:34 +0000
+++ tests/unit-tests/compositor/test_multi_threaded_compositor.cpp 2015-02-23 13:13:47 +0000
@@ -31,6 +31,7 @@
31#include "mir_test_doubles/mock_compositor_report.h"31#include "mir_test_doubles/mock_compositor_report.h"
32#include "mir_test_doubles/mock_scene.h"32#include "mir_test_doubles/mock_scene.h"
33#include "mir_test_doubles/stub_scene.h"33#include "mir_test_doubles/stub_scene.h"
34#include "mir_test_doubles/stub_display.h"
34#include "mir_test_doubles/null_display_buffer_compositor_factory.h"35#include "mir_test_doubles/null_display_buffer_compositor_factory.h"
3536
36#include <boost/throw_exception.hpp>37#include <boost/throw_exception.hpp>
@@ -52,30 +53,12 @@
52namespace mtd = mir::test::doubles;53namespace mtd = mir::test::doubles;
53namespace mt = mir::test;54namespace mt = mir::test;
5455
55namespace
56{
57
58class StubDisplay : public mtd::NullDisplay
59{
60 public:
61 StubDisplay(unsigned int nbuffers) : buffers{nbuffers} {}
62
63 void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f) override
64 {
65 for (auto& db : buffers)
66 f(db);
67 }
68
69private:
70 std::vector<mtd::NullDisplayBuffer> buffers;
71};
72
73class StubDisplayWithMockBuffers : public mtd::NullDisplay56class StubDisplayWithMockBuffers : public mtd::NullDisplay
74{57{
75 public:58public:
76 StubDisplayWithMockBuffers(unsigned int nbuffers) : buffers{nbuffers} {}59 StubDisplayWithMockBuffers(unsigned int nbuffers) : buffers{nbuffers} {}
7760
78 void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f)61 void for_each_display_sync_group(std::function<void(mg::DisplaySyncGroup&)> const& f) override
79 {62 {
80 for (auto& db : buffers)63 for (auto& db : buffers)
81 f(db);64 f(db);
@@ -84,11 +67,21 @@
84 void for_each_mock_buffer(std::function<void(mtd::MockDisplayBuffer&)> const& f)67 void for_each_mock_buffer(std::function<void(mtd::MockDisplayBuffer&)> const& f)
85 {68 {
86 for (auto& db : buffers)69 for (auto& db : buffers)
87 f(db);70 f(db.buffer);
88 }71 }
8972
90private:73private:
91 std::vector<testing::NiceMock<mtd::MockDisplayBuffer>> buffers;74 struct StubDisplaySyncGroup : mg::DisplaySyncGroup
75 {
76 void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f) override
77 {
78 f(buffer);
79 }
80 void post() override {}
81 testing::NiceMock<mtd::MockDisplayBuffer> buffer;
82 };
83
84 std::vector<StubDisplaySyncGroup> buffers;
92};85};
9386
94class StubScene : public mtd::StubScene87class StubScene : public mtd::StubScene
@@ -337,6 +330,8 @@
337 std::vector<std::string> thread_names;330 std::vector<std::string> thread_names;
338};331};
339332
333namespace
334{
340auto const null_report = mr::null_compositor_report();335auto const null_report = mr::null_compositor_report();
341unsigned int const composites_per_update{1};336unsigned int const composites_per_update{1};
342}337}
@@ -347,7 +342,7 @@
347342
348 unsigned int const nbuffers{3};343 unsigned int const nbuffers{3};
349344
350 auto display = std::make_shared<StubDisplay>(nbuffers);345 auto display = std::make_shared<mtd::StubDisplay>(nbuffers);
351 auto scene = std::make_shared<StubScene>();346 auto scene = std::make_shared<StubScene>();
352 auto db_compositor_factory = std::make_shared<RecordingDisplayBufferCompositorFactory>();347 auto db_compositor_factory = std::make_shared<RecordingDisplayBufferCompositorFactory>();
353 mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, null_report, true};348 mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, null_report, true};
@@ -422,7 +417,7 @@
422417
423 unsigned int const nbuffers = 3;418 unsigned int const nbuffers = 3;
424419
425 auto display = std::make_shared<StubDisplay>(nbuffers);420 auto display = std::make_shared<mtd::StubDisplay>(nbuffers);
426 auto scene = std::make_shared<StubScene>();421 auto scene = std::make_shared<StubScene>();
427 auto db_compositor_factory = std::make_shared<RecordingDisplayBufferCompositorFactory>();422 auto db_compositor_factory = std::make_shared<RecordingDisplayBufferCompositorFactory>();
428 mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, null_report, true};423 mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, null_report, true};
@@ -482,7 +477,7 @@
482477
483 unsigned int const nbuffers = 3;478 unsigned int const nbuffers = 3;
484479
485 auto display = std::make_shared<StubDisplay>(nbuffers);480 auto display = std::make_shared<mtd::StubDisplay>(nbuffers);
486 auto scene = std::make_shared<StubScene>();481 auto scene = std::make_shared<StubScene>();
487 auto factory = std::make_shared<RecordingDisplayBufferCompositorFactory>();482 auto factory = std::make_shared<RecordingDisplayBufferCompositorFactory>();
488 mc::MultiThreadedCompositor compositor{display, scene, factory,483 mc::MultiThreadedCompositor compositor{display, scene, factory,
@@ -555,7 +550,7 @@
555550
556 unsigned int const nbuffers = 3;551 unsigned int const nbuffers = 3;
557552
558 auto display = std::make_shared<StubDisplay>(nbuffers);553 auto display = std::make_shared<mtd::StubDisplay>(nbuffers);
559 auto scene = std::make_shared<StubScene>();554 auto scene = std::make_shared<StubScene>();
560 auto db_compositor_factory = std::make_shared<RecordingDisplayBufferCompositorFactory>();555 auto db_compositor_factory = std::make_shared<RecordingDisplayBufferCompositorFactory>();
561 mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, null_report, false};556 mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, null_report, false};
@@ -578,7 +573,7 @@
578573
579 unsigned int const nbuffers = 3;574 unsigned int const nbuffers = 3;
580575
581 auto display = std::make_shared<StubDisplay>(nbuffers);576 auto display = std::make_shared<mtd::StubDisplay>(nbuffers);
582 auto scene = std::make_shared<StubScene>();577 auto scene = std::make_shared<StubScene>();
583 auto db_compositor_factory = std::make_shared<RecordingDisplayBufferCompositorFactory>();578 auto db_compositor_factory = std::make_shared<RecordingDisplayBufferCompositorFactory>();
584 mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, null_report, false};579 mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, null_report, false};
@@ -613,7 +608,7 @@
613608
614 unsigned int const nbuffers{3};609 unsigned int const nbuffers{3};
615610
616 auto display = std::make_shared<StubDisplay>(nbuffers);611 auto display = std::make_shared<mtd::StubDisplay>(nbuffers);
617 auto scene = std::make_shared<StubScene>();612 auto scene = std::make_shared<StubScene>();
618 auto db_compositor_factory = std::make_shared<SurfaceUpdatingDisplayBufferCompositorFactory>(scene);613 auto db_compositor_factory = std::make_shared<SurfaceUpdatingDisplayBufferCompositorFactory>(scene);
619 mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, null_report, true};614 mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, null_report, true};
620615
=== modified file 'tests/unit-tests/graphics/android/test_display.cpp'
--- tests/unit-tests/graphics/android/test_display.cpp 2015-02-13 06:12:34 +0000
+++ tests/unit-tests/graphics/android/test_display.cpp 2015-02-23 13:13:47 +0000
@@ -656,25 +656,28 @@
656 null_display_report,656 null_display_report,
657 mga::OverlayOptimization::enabled);657 mga::OverlayOptimization::enabled);
658658
659 auto db_count = 0;659 auto group_count = 0;
660 display.for_each_display_buffer([&](mg::DisplayBuffer&){ db_count++; });660 auto db_group_counter = [&](mg::DisplaySyncGroup&) {
661 EXPECT_THAT(db_count, Eq(2));661 group_count++;
662 };
663 display.for_each_display_sync_group(db_group_counter);
664 EXPECT_THAT(group_count, Eq(2));
662665
663 //hotplug external away666 //hotplug external away
664 external_connected = false;667 external_connected = false;
665 hotplug_fn();668 hotplug_fn();
666669
667 db_count = 0;670 group_count = 0;
668 display.for_each_display_buffer([&](mg::DisplayBuffer&){ db_count++; });671 display.for_each_display_sync_group(db_group_counter);
669 EXPECT_THAT(db_count, Eq(1));672 EXPECT_THAT(group_count, Eq(1));
670673
671 //hotplug external back 674 //hotplug external back
672 external_connected = true;675 external_connected = true;
673 hotplug_fn();676 hotplug_fn();
674677
675 db_count = 0;678 group_count = 0;
676 display.for_each_display_buffer([&](mg::DisplayBuffer&){ db_count++; });679 display.for_each_display_sync_group(db_group_counter);
677 EXPECT_THAT(db_count, Eq(2));680 EXPECT_THAT(group_count, Eq(2));
678}681}
679682
680TEST_F(Display, turns_external_display_on_with_hotplug)683TEST_F(Display, turns_external_display_on_with_hotplug)
@@ -715,12 +718,12 @@
715 //hotplug external away718 //hotplug external away
716 external_connected = false;719 external_connected = false;
717 hotplug_fn();720 hotplug_fn();
718 display.for_each_display_buffer([](mg::DisplayBuffer&){});721 display.for_each_display_sync_group([](mg::DisplaySyncGroup&){});
719722
720 //hotplug external back 723 //hotplug external back
721 external_connected = true;724 external_connected = true;
722 hotplug_fn();725 hotplug_fn();
723 display.for_each_display_buffer([](mg::DisplayBuffer&){});726 display.for_each_display_sync_group([](mg::DisplaySyncGroup&){});
724}727}
725728
726TEST_F(Display, configures_external_display)729TEST_F(Display, configures_external_display)
727730
=== modified file 'tests/unit-tests/graphics/android/test_display_buffer.cpp'
--- tests/unit-tests/graphics/android/test_display_buffer.cpp 2015-02-13 06:12:34 +0000
+++ tests/unit-tests/graphics/android/test_display_buffer.cpp 2015-02-23 13:13:47 +0000
@@ -104,7 +104,6 @@
104 mga::OverlayOptimization::enabled};104 mga::OverlayOptimization::enabled};
105105
106 db.gl_swap_buffers();106 db.gl_swap_buffers();
107 db.flip();
108}107}
109108
110TEST_F(DisplayBuffer, posts_overlay_list_returns_display_device_decision)109TEST_F(DisplayBuffer, posts_overlay_list_returns_display_device_decision)
111110
=== modified file 'tests/unit-tests/graphics/mesa/test_display.cpp'
--- tests/unit-tests/graphics/mesa/test_display.cpp 2015-01-22 09:00:14 +0000
+++ tests/unit-tests/graphics/mesa/test_display.cpp 2015-02-23 13:13:47 +0000
@@ -438,10 +438,11 @@
438438
439 auto display = create_display(create_platform());439 auto display = create_display(create_platform());
440440
441 display->for_each_display_buffer([](mg::DisplayBuffer& db)441 display->for_each_display_sync_group([](mg::DisplaySyncGroup& group) {
442 {442 group.for_each_display_buffer([](mg::DisplayBuffer& db) {
443 db.gl_swap_buffers();443 db.gl_swap_buffers();
444 db.flip();444 });
445 group.post();
445 });446 });
446}447}
447448
@@ -476,11 +477,11 @@
476 EXPECT_THROW(477 EXPECT_THROW(
477 {478 {
478 auto display = create_display(create_platform());479 auto display = create_display(create_platform());
479480 display->for_each_display_sync_group([](mg::DisplaySyncGroup& group) {
480 display->for_each_display_buffer([](mg::DisplayBuffer& db)481 group.for_each_display_buffer([](mg::DisplayBuffer& db) {
481 {482 db.gl_swap_buffers();
482 db.gl_swap_buffers();483 });
483 db.flip();484 group.post();
484 });485 });
485 }, std::runtime_error);486 }, std::runtime_error);
486}487}
@@ -622,9 +623,10 @@
622623
623 int callback_count{0};624 int callback_count{0};
624625
625 display->for_each_display_buffer([&](mg::DisplayBuffer&)626 display->for_each_display_sync_group([&](mg::DisplaySyncGroup& group) {
626 {627 group.for_each_display_buffer([&](mg::DisplayBuffer&) {
627 callback_count++;628 callback_count++;
629 });
628 });630 });
629631
630 EXPECT_NE(0, callback_count);632 EXPECT_NE(0, callback_count);
631633
=== modified file 'tests/unit-tests/graphics/mesa/test_display_buffer.cpp'
--- tests/unit-tests/graphics/mesa/test_display_buffer.cpp 2015-02-12 22:46:39 +0000
+++ tests/unit-tests/graphics/mesa/test_display_buffer.cpp 2015-02-23 13:13:47 +0000
@@ -312,7 +312,7 @@
312 mock_egl.fake_egl_context);312 mock_egl.fake_egl_context);
313313
314 db.gl_swap_buffers();314 db.gl_swap_buffers();
315 db.flip();315 db.post();
316}316}
317317
318TEST_F(MesaDisplayBufferTest, single_mode_first_post_flips_with_wait)318TEST_F(MesaDisplayBufferTest, single_mode_first_post_flips_with_wait)
@@ -333,7 +333,7 @@
333 mock_egl.fake_egl_context);333 mock_egl.fake_egl_context);
334334
335 db.gl_swap_buffers();335 db.gl_swap_buffers();
336 db.flip();336 db.post();
337}337}
338338
339TEST_F(MesaDisplayBufferTest, clone_mode_waits_for_page_flip_on_second_flip)339TEST_F(MesaDisplayBufferTest, clone_mode_waits_for_page_flip_on_second_flip)
@@ -362,10 +362,10 @@
362 mock_egl.fake_egl_context);362 mock_egl.fake_egl_context);
363363
364 db.gl_swap_buffers();364 db.gl_swap_buffers();
365 db.flip();365 db.post();
366366
367 db.gl_swap_buffers();367 db.gl_swap_buffers();
368 db.flip();368 db.post();
369}369}
370370
371TEST_F(MesaDisplayBufferTest, skips_bypass_because_of_incompatible_list)371TEST_F(MesaDisplayBufferTest, skips_bypass_because_of_incompatible_list)
372372
=== modified file 'tests/unit-tests/graphics/mesa/test_display_multi_monitor.cpp'
--- tests/unit-tests/graphics/mesa/test_display_multi_monitor.cpp 2015-02-13 06:12:34 +0000
+++ tests/unit-tests/graphics/mesa/test_display_multi_monitor.cpp 2015-02-23 13:13:47 +0000
@@ -358,18 +358,16 @@
358 auto display = create_display_cloned(create_platform());358 auto display = create_display_cloned(create_platform());
359359
360 /* First frame: Page flips are scheduled, but not waited for */360 /* First frame: Page flips are scheduled, but not waited for */
361 display->for_each_display_buffer([](mg::DisplayBuffer& buffer)361 display->for_each_display_sync_group([](mg::DisplaySyncGroup& group)
362 {362 {
363 buffer.gl_swap_buffers();363 group.post();
364 buffer.flip();
365 });364 });
366365
367 /* Second frame: Previous page flips finish (drmHandleEvent) and new ones366 /* Second frame: Previous page flips finish (drmHandleEvent) and new ones
368 are scheduled */367 are scheduled */
369 display->for_each_display_buffer([](mg::DisplayBuffer& buffer)368 display->for_each_display_sync_group([](mg::DisplaySyncGroup& group)
370 {369 {
371 buffer.gl_swap_buffers();370 group.post();
372 buffer.flip();
373 });371 });
374}372}
375373
376374
=== modified file 'tests/unit-tests/graphics/offscreen/test_offscreen_display.cpp'
--- tests/unit-tests/graphics/offscreen/test_offscreen_display.cpp 2015-02-13 06:12:34 +0000
+++ tests/unit-tests/graphics/offscreen/test_offscreen_display.cpp 2015-02-23 13:13:47 +0000
@@ -68,12 +68,12 @@
68 mr::null_display_report()};68 mr::null_display_report()};
6969
70 int count = 0;70 int count = 0;
71 display.for_each_display_buffer(71 display.for_each_display_sync_group([&](mg::DisplaySyncGroup& group) {
72 [&](mg::DisplayBuffer& db)72 group.for_each_display_buffer([&](mg::DisplayBuffer& db) {
73 {
74 ++count;73 ++count;
75 EXPECT_EQ(mir_orientation_normal, db.orientation());74 EXPECT_EQ(mir_orientation_normal, db.orientation());
76 });75 });
76 });
7777
78 EXPECT_TRUE(count);78 EXPECT_TRUE(count);
79}79}
@@ -107,9 +107,8 @@
107 Mock::VerifyAndClearExpectations(&mock_gl);107 Mock::VerifyAndClearExpectations(&mock_gl);
108108
109 /* Binds the GL framebuffer objects */109 /* Binds the GL framebuffer objects */
110 display.for_each_display_buffer(110 display.for_each_display_sync_group([&](mg::DisplaySyncGroup& group) {
111 [this](mg::DisplayBuffer& db)111 group.for_each_display_buffer([&](mg::DisplayBuffer& db) {
112 {
113 EXPECT_CALL(mock_egl, eglMakeCurrent(_,_,_,Ne(EGL_NO_CONTEXT)));112 EXPECT_CALL(mock_egl, eglMakeCurrent(_,_,_,Ne(EGL_NO_CONTEXT)));
114 EXPECT_CALL(mock_gl, glBindFramebuffer(_,Ne(0)));113 EXPECT_CALL(mock_gl, glBindFramebuffer(_,Ne(0)));
115114
@@ -118,13 +117,14 @@
118 Mock::VerifyAndClearExpectations(&mock_egl);117 Mock::VerifyAndClearExpectations(&mock_egl);
119 Mock::VerifyAndClearExpectations(&mock_gl);118 Mock::VerifyAndClearExpectations(&mock_gl);
120 });119 });
120 });
121121
122 /* Contexts are released at teardown */122 /* Contexts are released at teardown */
123 display.for_each_display_buffer(123 display.for_each_display_sync_group([&](mg::DisplaySyncGroup& group) {
124 [this](mg::DisplayBuffer&)124 group.for_each_display_buffer([&](mg::DisplayBuffer&) {
125 {
126 EXPECT_CALL(mock_egl, eglMakeCurrent(_,_,_,EGL_NO_CONTEXT));125 EXPECT_CALL(mock_egl, eglMakeCurrent(_,_,_,EGL_NO_CONTEXT));
127 });126 });
127 });
128}128}
129129
130TEST_F(OffscreenDisplayTest, restores_previous_state_on_fbo_setup_failure)130TEST_F(OffscreenDisplayTest, restores_previous_state_on_fbo_setup_failure)
131131
=== modified file 'tests/unit-tests/graphics/test_display.cpp'
--- tests/unit-tests/graphics/test_display.cpp 2015-01-21 07:34:50 +0000
+++ tests/unit-tests/graphics/test_display.cpp 2015-02-23 13:13:47 +0000
@@ -191,7 +191,9 @@
191 auto display = create_display();191 auto display = create_display();
192 int db_count{0};192 int db_count{0};
193193
194 display->for_each_display_buffer([&] (mg::DisplayBuffer&) { ++db_count; });194 display->for_each_display_sync_group([&](mg::DisplaySyncGroup& group) {
195 group.for_each_display_buffer([&] (mg::DisplayBuffer&) { ++db_count; });
196 });
195 EXPECT_THAT(db_count, Eq(1));197 EXPECT_THAT(db_count, Eq(1));
196198
197 auto conf = display->configuration();199 auto conf = display->configuration();
@@ -204,6 +206,8 @@
204 display->configure(*conf);206 display->configure(*conf);
205207
206 db_count = 0;208 db_count = 0;
207 display->for_each_display_buffer([&] (mg::DisplayBuffer&) { ++db_count; });209 display->for_each_display_sync_group([&](mg::DisplaySyncGroup& group) {
210 group.for_each_display_buffer([&] (mg::DisplayBuffer&) { ++db_count; });
211 });
208 EXPECT_THAT(db_count, Eq(0));212 EXPECT_THAT(db_count, Eq(0));
209}213}
210214
=== modified file 'tests/unit-tests/input/test_display_input_region.cpp'
--- tests/unit-tests/input/test_display_input_region.cpp 2014-03-06 06:05:17 +0000
+++ tests/unit-tests/input/test_display_input_region.cpp 2015-02-23 13:13:47 +0000
@@ -19,7 +19,7 @@
19#include "src/server/input/display_input_region.h"19#include "src/server/input/display_input_region.h"
2020
21#include "mir_test_doubles/null_display.h"21#include "mir_test_doubles/null_display.h"
22#include "mir_test_doubles/stub_display_buffer.h"22#include "mir_test_doubles/stub_display.h"
2323
24#include <vector>24#include <vector>
25#include <tuple>25#include <tuple>
@@ -33,35 +33,17 @@
3333
34namespace34namespace
35{35{
3636std::vector<geom::Rectangle> const rects{
37class StubDisplay : public mtd::NullDisplay37 geom::Rectangle{{0,0}, {800,600}},
38{38 geom::Rectangle{{0,600}, {100,100}},
39public:39 geom::Rectangle{{800,0}, {100,100}}
40 StubDisplay()
41 : display_buffers{
42 mtd::StubDisplayBuffer{geom::Rectangle{geom::Point{0,0}, geom::Size{800,600}}},
43 mtd::StubDisplayBuffer{geom::Rectangle{geom::Point{0,600}, geom::Size{100,100}}},
44 mtd::StubDisplayBuffer{geom::Rectangle{geom::Point{800,0}, geom::Size{100,100}}}}
45 {
46
47 }
48
49 void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f) override
50 {
51 for (auto& db : display_buffers)
52 f(db);
53 }
54
55private:
56 std::vector<mtd::StubDisplayBuffer> display_buffers;
57};40};
58
59}41}
6042
61TEST(DisplayInputRegionTest, returns_correct_bounding_rectangle)43TEST(DisplayInputRegionTest, returns_correct_bounding_rectangle)
62{44{
63 geom::Rectangle const expected_bounding_rect{geom::Point{0,0}, geom::Size{900,700}};45 geom::Rectangle const expected_bounding_rect{geom::Point{0,0}, geom::Size{900,700}};
64 auto stub_display = std::make_shared<StubDisplay>();46 auto stub_display = std::make_shared<mtd::StubDisplay>(rects);
6547
66 mi::DisplayInputRegion input_region{stub_display};48 mi::DisplayInputRegion input_region{stub_display};
6749
@@ -71,7 +53,7 @@
7153
72TEST(DisplayInputRegionTest, confines_point_to_closest_valid_position)54TEST(DisplayInputRegionTest, confines_point_to_closest_valid_position)
73{55{
74 auto stub_display = std::make_shared<StubDisplay>();56 auto stub_display = std::make_shared<mtd::StubDisplay>(rects);
7557
76 mi::DisplayInputRegion input_region{stub_display};58 mi::DisplayInputRegion input_region{stub_display};
7759

Subscribers

People subscribed via source and target branches