Mir

Merge lp:~kdub/mir/RFC-surface-arrangements into lp:mir

Proposed by Kevin DuBois
Status: Superseded
Proposed branch: lp:~kdub/mir/RFC-surface-arrangements
Merge into: lp:mir
Prerequisite: lp:~kdub/mir/correct-dbc-public-api
Diff against target: 891 lines (+557/-48)
16 files modified
include/client/mir_toolkit/mir_surface.h (+79/-1)
include/server/mir/compositor/scene_element.h (+4/-7)
playground/demo-shell/demo_compositor.cpp (+2/-2)
playground/demo-shell/demo_renderer.cpp (+2/-2)
playground/demo-shell/demo_renderer.h (+1/-1)
src/client/mir_surface_api.cpp (+31/-4)
src/server/scene/surface_stack.cpp (+10/-4)
tests/acceptance-tests/CMakeLists.txt (+2/-0)
tests/acceptance-tests/test_client_surface_arrangement.cpp (+255/-0)
tests/acceptance-tests/test_render_override.cpp (+130/-0)
tests/include/mir_test_doubles/stub_scene_element.h (+6/-0)
tests/include/mir_test_framework/connected_client_with_a_surface.h (+8/-0)
tests/mir_test_framework/connected_client_with_a_surface.cpp (+1/-10)
tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp (+15/-8)
tests/unit-tests/examples/test_demo_compositor.cpp (+2/-1)
tests/unit-tests/scene/test_surface_stack.cpp (+9/-8)
To merge this branch: bzr merge lp:~kdub/mir/RFC-surface-arrangements
Reviewer Review Type Date Requested Status
Alan Griffiths Needs Information
Daniel van Vugt Needs Fixing
PS Jenkins bot (community) continuous-integration Needs Fixing
Kevin DuBois (community) Needs Resubmitting
Review via email: mp+254447@code.launchpad.net

This proposal has been superseded by a proposal from 2015-04-01.

Commit message

do not land.

Description of the change

Just a RFC branch!

In looking at how to bypass nested servers, it seemed useful that advanced clients (such as a multi-windowed client, a OS virtualizer, or a nested mir server) need a way to specify the ordering of the surfaces that they have created. This obviously has to be done within the SurfaceSpecs to prevent violating the policies the shell has (eg, you can't lower a tooltip beneath your primary surface), but normal surfaces should be arrangeable as the client wishes.

This version has the arrangement done batched together (so multiple changes are applied to the SurfaceStack at once), but I suppose some clients might not care that the arrangement updates are batched.

Also, the arrangement only applies to the surfaces in client's connection, the client neither sets an absolute x,y position, nor an absolute z-ordering.

I got to the point of writing a failing acceptance test for this feature when I thought I'd gather some comments on the client api change.

To post a comment you must log in.
Revision history for this message
Kevin DuBois (kdub) wrote :

Just an RFC on an unimplemented client api change. Resubmit after implementation.

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

(0) I've proposed an attribute batching API that will probably land soon and might be helpful. Check it out:
https://code.launchpad.net/~vanvugt/mir/rename-api/+merge/252864

Using that you could put relative ordering preferences of child surfaces in their MirSurfaceSpec instead. Which I think makes more sense.

(1) I think "order" is a more widely understood term than "arrangement" here. But also think the functions should be different in other ways than just name. See (0).

Instead, child surfaces could have an "int child_depth". Then their final Z-order is determined by (a) the depth of the parent surface within the main stack, plus (b) their relative int child_depth.

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

*Discussion*

I think this only addresses a part of a range of problems and would like to be sure that we have a consistent solution. As Daniel mentions, the stacking order of surfaces should be part of the problem domain here (at least to the extent that a client can e.g. "raise" some of its surfaces). We should also allow a client to shift the focus (or default focus) to a specific surface.

As proposed, this is making requests for a specific action without sufficient semantic content for the server to implement good alternative behavior if the request can't be met in full: if a window encounters an edge to the display should it overlap, resize or have an adjusted position?

Specifying top-left locations of surfaces seems like a simplistic layout rule. We should consider the existing solution domain of layout managers and, at least /consider/, allowing the specification of anchors, insets, fills, weights, etc.

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

> Specifying top-left locations of surfaces seems like a simplistic layout rule.
> We should consider the existing solution domain of layout managers and, at
> least /consider/, allowing the specification of anchors, insets, fills,
> weights, etc.

I'm not saying we can't do something adequate for now and evolve a more complex solution as needed, but that the current proposal is too specific to facilitate that evolution.

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

0) The batching api looks like it could be helpful in making sure that changes are applied at once. Packing the z-order into the MirSurfaceSpec might be more uniform, although I did not see a way to change the z order or the position once the surface was created.
1) I did consider specifying an int-depth as an attribute, but that seemed like additional processing for us, when the client is really just trying to establish a list of its surfaces. Also, if you have 2 surfaces at z-depth 4 and 5, and want 3rd surface in between, the client has to reassign one of the surfaces to fit that surface where they want (which seemed a bit easier to do if its just an array). A list or an array also eliminates the corner case of two surfaces at the same level that we'd have to check for.

I guess the other thing to point out is that I put this as a mir_connection_ function to avoid the idea of parent/child surfaces. It seems more flexible to just have a collection of surfaces ordered by the client in the way it prefers (while still sticking to our policies)

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

> I think this only addresses a part of a range of problems and would like to be
> sure that we have a consistent solution. As Daniel mentions, the stacking
> order of surfaces should be part of the problem domain here (at least to the
> extent that a client can e.g. "raise" some of its surfaces). We should also
> allow a client to shift the focus (or default focus) to a specific surface.

So the intent here is to let the client specify its own surface ordering, we're making no guarantees about what the final z-order or position the surface will be presented in on-screen. Its more that we're guaranteeing the client that their surfaces will be composited in a specific way amongst themselves.

>
> As proposed, this is making requests for a specific action without sufficient
> semantic content for the server to implement good alternative behavior if the
> request can't be met in full: if a window encounters an edge to the display
> should it overlap, resize or have an adjusted position?

I don't know that we want to reinterpret what the client has said it wants to do... If it violates our window policies, we'll reject the request. (or perhaps I've misunderstood the point)

>
> Specifying top-left locations of surfaces seems like a simplistic layout rule.
> We should consider the existing solution domain of layout managers and, at
> least /consider/, allowing the specification of anchors, insets, fills,
> weights, etc.

I'm interested in being able to represent a SceneElementSequence-like specification of the composition that the client wants, although don't mind further expansion.

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

> Specifying top-left locations of surfaces seems like a simplistic layout rule.
> We should consider the existing solution domain of layout managers and, at
> least /consider/, allowing the specification of anchors, insets, fills,
> weights, etc.

I think we need to distinguish between surfaces and renderbuffers/scenelements here. What you wrote would be true for forwarding surfaces...

I do not think this is part of the problem to be solved (at least for now). A solution is needed that allows a nested server to forward all information necessary to allow the hosting server to draw the scene as if the nested server did the composition. At the moment and in the near future the super set of our efficient drawing operations (hwc + setting a scan out buffer + atomic planes) is what DefaultDisplayBufferCompositor implements. Hence the nested server has to submit the information a DefaultDisplayBufferCompositor needs for rendering. Thus a sequence of Renderables (i think we can ignore the Decoration accessor in SceneElement for that, and also put aside the oddness around the semantics Renderable::transformation() vs Renderable::screen_position()).

Still the idea of forwarding surfaces could be interesting too.

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

PS: oops hit save comment too soon.

So I see two different cases, a nested server should be allowed to forward surfaces as surfaces. That would nicely fulfill the case of the OS virtualizer, forwarding all windows of the guest system to the host system, hence the host is supposed to do all the window management and dispatch logic. In that case the nested server creates a surface at the host server for each client surfaces, and relays changes between those.

The other topic is that a nested server should be able to just relay all Renderable changes within the scene and buffer changes to the host server. So as a result a Surface then HasA sequence of Renderables.

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

Back to the nested bypass: On the client maybe:

MirBufferStreamAttachment* mir_surface_create_buffer_stream_attachment(MirSurface*, MirBufferStream*, int relative_pos_x, int relative_pos_y, float* transformation?, float opacity);

and respective setters, and a mir_surface_submit_buffer_stream_changes that sends all pending changes in a single batch. Or make that more generic mir_surfae_submit_changes?

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

So, relevant prior art here is:
http://cgit.freedesktop.org/wayland/wayland/tree/protocol/wayland.xml#n1994 (for the purposes of that section, wl_surface == MirBufferStream, wl_surface.commit == mir_buffer_stream_swap_buffers)

The API contains the three obvious things - set_position, place_above, place_below - but also the non-obvious but important set_sync/set_desync. This serves two purposes - one is to batch up changes into a transaction, which we can easily satisfy by other means, the other is to ensure that the surface content of the whole subsurface tree is consistent.

When in synchronised mode, swap_buffers in all the subsurfaces is deferred until the parent surface enters swap_buffers; this ensures that the client can change the subsurface graph without flashing or components transiently moving out of place.

Like Andreas, I think that Surfaces are the wrong level to do this nesting. Surfaces have a whole bunch of semantics that USC simply doesn't care about, and can't do anything sensible with. What happens with input? Does USC generate enter/leave events? Etc.

Since Robert's animated-cursor branch has landed we've got a client API to create a raw BufferStream; What would seem most sensible to me is for this to add the ability to attach extra buffer streams to a surface.

mir_subsurface_position(MirSurface* in, MirBufferStream* to_place, int x, int y);
mir_subsurface_stack_above(MirSurface* in, MirBufferStream* to_raise, MirBufferStream* below);
mir_subsurface_stack_below(MirSurface* in, MirBufferStream* to_lower, MirBufferStream* above);
... etc

Here we never need to reject a (well-formed) subsurface request; as far as the shell is concerned there is only one surface, just with funky content.

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

> Specifying top-left locations of surfaces seems like a simplistic layout rule.
> We should consider the existing solution domain of layout managers and, at
> least /consider/, allowing the specification of anchors, insets, fills,
> weights, etc.

That's going way too far down the path of making Mir a full-blown toolkit. Making Mir a toolkit with enforced semantics just makes it less welcoming to supporting actual toolkits with their own semantics.

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

If you want a good example of what level of complexity to target this functionality at, have a look at:
  http://tronche.com/gui/x/xlib/window/stacking-order.html

That's _not_ a suggestion for a design, but an example of the level of detail we should be considering.

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

> > I think this only addresses a part of a range of problems and would like to
> be
> > sure that we have a consistent solution. As Daniel mentions, the stacking
> > order of surfaces should be part of the problem domain here (at least to the
> > extent that a client can e.g. "raise" some of its surfaces). We should also
> > allow a client to shift the focus (or default focus) to a specific surface.
>
> So the intent here is to let the client specify its own surface ordering,
> we're making no guarantees about what the final z-order or position the
> surface will be presented in on-screen. Its more that we're guaranteeing the
> client that their surfaces will be composited in a specific way amongst
> themselves.

I think the use case of "raise these surfaces and direct input towards this one" needs more explicit support than having to list all surfaces.

> > As proposed, this is making requests for a specific action without
> sufficient
> > semantic content for the server to implement good alternative behavior if
> the
> > request can't be met in full: if a window encounters an edge to the display
> > should it overlap, resize or have an adjusted position?
>
> I don't know that we want to reinterpret what the client has said it wants to
> do... If it violates our window policies, we'll reject the request. (or
> perhaps I've misunderstood the point)

The general approach we've taken with other requests is that the client makes a request and the server decided what to do and (mostly) tells the client that something happened.

But in the case of positioning the client doesn't know what it has to work with:

  o if a surface has a "snapped" border that limits its positioning.
  o The client is not informed when surfaces are moved by the user.
  o The client usually has no indication which screen(s) its surfaces are on.
  o if the WM is doing tiling there's no information on current tile size.

So, unless we provide more information to the client it can't always determine the perfect layout. Allowing the server the flexibility to make a "best effort" is consistent with other APIs.

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

Yay, the rfc is working (and has generated comments)!

With the client api structuring... (MirConnections have MirSurfaces, etc)
We currently have MirConnections have multiple MirSurfaces, and MirConnections have a single MirBufferStream. I didn't quite see why MirConnections with multiple MirSurfaces, each with multiple BufferStreams is better than keeping the structure that we have.

I think we're all pointing out that some sort of batching of position updates is needed if the client is to request arrangements of its own surfaces. The start of the batching work in Daniel's rename-api branch seems like a sensible starting point. The other suggestion seems to be the one in this original rfc (which seems to underpowered), and the suggestion in the wayland subsurface protocol of having a 'synced' and 'unsynced' surface. I don't know that we need swaps to batch with positioning updates, and I also don't know that we need a 'desynchronized mode'

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

> I think the use case of "raise these surfaces and direct input towards this
> one" needs more explicit support than having to list all surfaces.

Fair enough, and I think the rename-api detaches the user from having to list all the surfaces, and it also avoids the wart of "if you don't specify what to do with a surface, the server can do whatever it wants", as the other surfaces wo,uld just keep their state.

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

> But in the case of positioning the client doesn't know what it has to work
> with:
>
> o if a surface has a "snapped" border that limits its positioning.
> o The client is not informed when surfaces are moved by the user.
> o The client usually has no indication which screen(s) its surfaces are on.
> o if the WM is doing tiling there's no information on current tile size.

It is somewhat the goal to keep the client from knowing what its absolute final position though, and to mesh the preference the client gives us in terms of the coordinates of 'the clients plane' with the other policies that the window manager wants.

Like, if the client says "surface A at 100, 100, surface B at 200,100" the server won't honor that if it violates some of the rules, or if the user goes and moves the surface otherwise. Maybe the client needs a way to know if its request is being honored (or maybe how its being honored) via the event system so it can sort out what it wants to do.

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

> Yay, the rfc is working (and has generated comments)!
>
> With the client api structuring... (MirConnections have MirSurfaces, etc)
> We currently have MirConnections have multiple MirSurfaces, and MirConnections
> have a single MirBufferStream. I didn't quite see why MirConnections with
> multiple MirSurfaces, each with multiple BufferStreams is better than keeping
> the structure that we have.

I think the idea of letting clients do relative positioning of their own surfaces is a poor one - Alan's raised all sorts of issues with it, and to that I'll add “what happens when a user moves one of the surfaces”?

The MirConnection has zero or more MirSurfaces which have one or more MirBufferStreams arrangement resolves this by providing a layer at which the client is in total control. The shell sees and acts on MirConnections and MirSurfaces, and Mir handles compositing (or not) the MirBufferStreams internally. In this case there's never any need to reject a MirBufferStream request (as long as all the objects it references exist and are valid, of course).

> I think we're all pointing out that some sort of batching of position updates
> is needed if the client is to request arrangements of its own surfaces. The
> start of the batching work in Daniel's rename-api branch seems like a sensible
> starting point. The other suggestion seems to be the one in this original rfc
> (which seems to underpowered), and the suggestion in the wayland subsurface
> protocol of having a 'synced' and 'unsynced' surface. I don't know that we
> need swaps to batch with positioning updates,

The obvious case where you need swaps to batch with positioning updates is when you're not drawing anything behind the overlaying surface. When you move the overlaying surface you need the underlay to be updated on the same frame as the move, otherwise you see bits of the unrendered area.

> and I also don't know that we need a 'desynchronized mode'

We don't, really. It's basically a client-courtesy-optimisation, where if you *don't* need frame-accurate moving etc you don't have to continually swap buffers on your main surface.

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

>> I think the idea of letting clients do relative positioning of their own surfaces is a poor >> one - Alan's raised all sorts of issues with it, and to that I'll add “what happens when a >> user moves one of the surfaces”?

>> The MirConnection has zero or more MirSurfaces which have one or more MirBufferStreams
>> arrangement resolves this by providing a layer at which the client is in total control. The >> shell sees and acts on MirConnections and MirSurfaces, and Mir handles compositing (or not) >> the MirBufferStreams internally.

+1

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

54 +/** Specify the position of the stream within the surface. This establishes
55 + * positions relative to the other streams in the surface, and is not a
56 + * guarantee of the final composited ons

You appear to have garbled a comment here ☺. I'm not sure if what the comment says is right; we *should* be able to say that the relative position is guaranteed to be correct, but we guarantee nothing about the position of (0,0) onscreen.

This does raise the question of whether or not we want to clip streams to the parent surface; Wayland doesn't for subsurfaces, and I think GTK uses this for tooltips and such. That said, we know how to position tooltips and such better than the toolkit, so they shouldn't really be using it for this purpose.

I don't know if we should clip to the parent window or not; whichever way we go, we should document and test it, though.

This otherwise looks like sensible API to me. I do think we'll need at least an optional synchronise-on-swap_buffers mode, though.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'include/client/mir_toolkit/mir_surface.h'
--- include/client/mir_toolkit/mir_surface.h 2015-03-31 02:35:42 +0000
+++ include/client/mir_toolkit/mir_surface.h 2015-04-01 19:59:57 +0000
@@ -577,10 +577,88 @@
577 * Change the title (name) of a surface.577 * Change the title (name) of a surface.
578 * \param [in] surface The surface to rename578 * \param [in] surface The surface to rename
579 * \param [in] name The new name579 * \param [in] name The new name
580 * \returns When the change has completed580 * \return When the change has completed
581 */581 */
582MirWaitHandle* mir_surface_set_title(MirSurface* surf, char const* name);582MirWaitHandle* mir_surface_set_title(MirSurface* surf, char const* name);
583583
584
585/** generate a batch of changes to apply to the surface via
586 * mir_surface_spec_commit_changes. The returned spec must be released with
587 * mir_surface_spec_release;
588 * \param [in] surface The surface the changes will take effect on
589 * \return A wait handle that can be passed to mir_wait_for
590 */
591MirSurfaceSpec* mir_surface_begin_changes(MirSurface* surface);
592
593/** Commit the changes accummulated in the MirSurfaceSpect to the surface
594 * \param [in] spec The spec to apply
595 * \return A wait handle that is
596 */
597MirWaitHandle* mir_surface_spec_commit_changes(MirSurfaceSpec* spec);
598
599/** rearrange the ordering of the buffer streams in the connection, placing
600 * stream_to_place above stream_below. If stream_to_place is not associated
601 * the surface, it will become associated with the surface. If it is already
602 * in the ordering of the surface, it will be removed from its current position
603 * and placed in the requested position.
604 *
605 * Associated buffer streams are not owned by the surface and still must be
606 * released.
607 *
608 * \param [in] spec The spec to accumulate the request in
609 * \param [in] stream_to_place The stream to place
610 * \param [in] reference_stream The stream which will be above stream_to_place
611 */
612void mir_surface_spec_place_buffer_stream_below(
613 MirSurfaceSpec* spec, MirBufferStream* stream_to_place, MirBufferStream* reference_stream);
614
615/** Same as mir_surface_spec_place_buffer_stream_below, except placing stream_to_place
616 * below reference_stream.
617 *
618 * \param [in] spec The spec to accumulate the request in
619 * \param [in] stream_to_place The stream to place
620 * \param [in] reference_stream The stream which will be below stream_to_place
621 */
622void mir_surface_spec_place_buffer_stream_above(
623 MirSurfaceSpec* spec, MirBufferStream* stream_to_place, MirBufferStream* reference_stream);
624
625/** Specify the position of the stream within the surface. This establishes
626 * positions relative to the other streams in the surface, and is not a
627 * guarantee of the final composited ons
628 *
629 * If stream_to_place is not associated the surface yet, it will become
630 * associated with the surface at the given position.
631 *
632 * Associated buffer streams are not owned by the surface and still must be
633 * released.
634 *
635 * \param [in] spec The spec to accumulate the request in
636 * \param [in] stream_to_move The stream to movee
637 * \param [in] x The x coordinate of the stream
638 * \param [in] y The x coordinate of the stream
639 */
640void mir_surface_spec_place_buffer_stream_position(
641 MirSurfaceSpec* spec, MirBufferStream* stream_to_move, int x, int y);
642
643/* Returns the number of streams currently associated with surface
644 * \param [in] surface A surface
645 * \return The number of streams associated with surface
646 */
647unsigned int mir_surface_get_number_of_streams(MirSurface* surface);
648
649/* Query the streams associated with this surface and their positions.
650 * streams and positions must have the size of num_streams.
651 * streams and positions are filled in their z-order. (with is streams[0]
652 * being the bottom-most surface)
653 *
654 * \param [in] surface The surface to query
655 * \param [out] streams An array of MirBufferStream* that is of size num_streams
656 * \param [out] positions An array of MirRectangles that is of size num_streams
657 * \param [in] num_streams The size of both positions and streams array
658 */
659void mir_surface_get_streams(
660 MirSurface* surface, MirBufferStream** streams, MirRectangle* positions, unsigned int num_streams);
661
584#ifdef __cplusplus662#ifdef __cplusplus
585}663}
586/**@}*/664/**@}*/
587665
=== modified file 'include/server/mir/compositor/scene_element.h'
--- include/server/mir/compositor/scene_element.h 2015-03-31 02:35:42 +0000
+++ include/server/mir/compositor/scene_element.h 2015-04-01 19:59:57 +0000
@@ -19,7 +19,6 @@
19#ifndef MIR_COMPOSITOR_SCENE_ELEMENT_H_19#ifndef MIR_COMPOSITOR_SCENE_ELEMENT_H_
20#define MIR_COMPOSITOR_SCENE_ELEMENT_H_20#define MIR_COMPOSITOR_SCENE_ELEMENT_H_
2121
22#include "mir/compositor/decoration.h"
23#include <memory>22#include <memory>
2423
25namespace mir24namespace mir
@@ -30,7 +29,7 @@
30}29}
31namespace compositor30namespace compositor
32{31{
3332class Decoration;
34class SceneElement33class SceneElement
35{34{
36public:35public:
@@ -40,11 +39,9 @@
40 virtual void rendered() = 0;39 virtual void rendered() = 0;
41 virtual void occluded() = 0;40 virtual void occluded() = 0;
4241
43 virtual Decoration const& decoration() const42 //TODO: Decoration is opaque on purpose. It is only used by an internal example,
44 {43 // and this function should be removed from the public API.
45 static const Decoration none;44 virtual std::unique_ptr<Decoration> decoration() const = 0;
46 return none;
47 }
4845
49protected:46protected:
50 SceneElement() = default;47 SceneElement() = default;
5148
=== modified file 'playground/demo-shell/demo_compositor.cpp'
--- playground/demo-shell/demo_compositor.cpp 2015-03-31 02:35:42 +0000
+++ playground/demo-shell/demo_compositor.cpp 2015-04-01 19:59:57 +0000
@@ -83,8 +83,8 @@
83 auto embellished = renderer.would_embellish(*renderable, viewport);83 auto embellished = renderer.would_embellish(*renderable, viewport);
84 auto any_part_drawn = (viewport.overlaps(renderable->screen_position()) || embellished);84 auto any_part_drawn = (viewport.overlaps(renderable->screen_position()) || embellished);
85 85
86 if (auto const& decor = it->decoration())86 if (auto decor = it->decoration())
87 decorated[renderable->id()] = decor;87 decorated[renderable->id()] = std::move(decor);
88 if (any_part_drawn)88 if (any_part_drawn)
89 {89 {
90 renderable_list.push_back(renderable);90 renderable_list.push_back(renderable);
9191
=== modified file 'playground/demo-shell/demo_renderer.cpp'
--- playground/demo-shell/demo_renderer.cpp 2015-03-31 02:35:42 +0000
+++ playground/demo-shell/demo_renderer.cpp 2015-04-01 19:59:57 +0000
@@ -221,7 +221,7 @@
221221
222void DemoRenderer::begin(DecorMap&& d) const222void DemoRenderer::begin(DecorMap&& d) const
223{223{
224 decor_map = d;224 decor_map = std::move(d);
225 title_cache.drop_unused();225 title_cache.drop_unused();
226 title_cache.mark_all_unused();226 title_cache.mark_all_unused();
227}227}
@@ -236,7 +236,7 @@
236 auto& decor = d->second;236 auto& decor = d->second;
237 tessellate_shadow(primitives, renderable, shadow_radius);237 tessellate_shadow(primitives, renderable, shadow_radius);
238 tessellate_frame(primitives, renderable, titlebar_height,238 tessellate_frame(primitives, renderable, titlebar_height,
239 decor.name.c_str());239 decor->name.c_str());
240 }240 }
241}241}
242242
243243
=== modified file 'playground/demo-shell/demo_renderer.h'
--- playground/demo-shell/demo_renderer.h 2015-03-31 02:35:42 +0000
+++ playground/demo-shell/demo_renderer.h 2015-04-01 19:59:57 +0000
@@ -39,7 +39,7 @@
39};39};
4040
41typedef std::unordered_map<graphics::Renderable::ID,41typedef std::unordered_map<graphics::Renderable::ID,
42 compositor::Decoration> DecorMap;42 std::unique_ptr<compositor::Decoration>> DecorMap;
4343
44class DemoRenderer : public compositor::GLRenderer44class DemoRenderer : public compositor::GLRenderer
45{45{
4646
=== modified file 'src/client/mir_surface_api.cpp'
--- src/client/mir_surface_api.cpp 2015-03-31 02:35:42 +0000
+++ src/client/mir_surface_api.cpp 2015-04-01 19:59:57 +0000
@@ -580,8 +580,6 @@
580 return nullptr;580 return nullptr;
581}581}
582582
583namespace { // Private for now. TODO: Finalize and publish later (LP: #1422522)
584
585MirSurfaceSpec* mir_surface_begin_changes(MirSurface* surf)583MirSurfaceSpec* mir_surface_begin_changes(MirSurface* surf)
586{584{
587 mir::require(mir_surface_is_valid(surf));585 mir::require(mir_surface_is_valid(surf));
@@ -608,8 +606,6 @@
608 return surface->modify(*spec);606 return surface->modify(*spec);
609}607}
610608
611} // Private namespace. TODO: finalize morphing API and publish.
612
613MirWaitHandle* mir_surface_set_title(MirSurface* surf, char const* name)609MirWaitHandle* mir_surface_set_title(MirSurface* surf, char const* name)
614{610{
615 MirWaitHandle* result = nullptr;611 MirWaitHandle* result = nullptr;
@@ -621,3 +617,34 @@
621 }617 }
622 return result;618 return result;
623}619}
620
621void mir_surface_spec_place_buffer_stream_below(
622 MirSurfaceSpec* spec, MirBufferStream* stream_to_place, MirBufferStream* reference_stream)
623{
624 (void) spec;
625 (void) stream_to_place;
626 (void) reference_stream;
627}
628
629void mir_surface_spec_place_buffer_stream_position(
630 MirSurfaceSpec* spec, MirBufferStream* stream_to_move, int x, int y)
631{
632 (void) spec;
633 (void) stream_to_move;
634 (void) x;
635 (void) y;
636}
637
638unsigned int mir_surface_get_number_of_streams(MirSurface*)
639{
640 return 1;
641}
642
643void mir_surface_get_streams(
644 MirSurface* surface, MirBufferStream** streams, MirRectangle* positions, unsigned int num_streams)
645{
646 (void) surface;
647 (void) streams;
648 (void) positions;
649 (void) num_streams;
650}
624651
=== renamed file 'include/server/mir/compositor/decoration.h' => 'src/include/server/mir/compositor/decoration.h'
=== modified file 'src/server/scene/surface_stack.cpp'
--- src/server/scene/surface_stack.cpp 2015-03-31 02:35:42 +0000
+++ src/server/scene/surface_stack.cpp 2015-04-01 19:59:57 +0000
@@ -23,6 +23,7 @@
23#include "mir/scene/surface.h"23#include "mir/scene/surface.h"
24#include "mir/scene/scene_report.h"24#include "mir/scene/scene_report.h"
25#include "mir/compositor/scene_element.h"25#include "mir/compositor/scene_element.h"
26#include "mir/compositor/decoration.h"
26#include "mir/graphics/renderable.h"27#include "mir/graphics/renderable.h"
2728
28#include <boost/throw_exception.hpp>29#include <boost/throw_exception.hpp>
@@ -52,7 +53,7 @@
52 : renderable_{surface->compositor_snapshot(id)},53 : renderable_{surface->compositor_snapshot(id)},
53 tracker{tracker},54 tracker{tracker},
54 cid{id},55 cid{id},
55 decor(mc::Decoration::Type::surface, surface->name())56 surface_name(surface->name())
56 {57 {
57 }58 }
5859
@@ -71,16 +72,16 @@
71 tracker->occluded_in(cid);72 tracker->occluded_in(cid);
72 }73 }
7374
74 mc::Decoration const& decoration() const override75 std::unique_ptr<mc::Decoration> decoration() const override
75 {76 {
76 return decor;77 return std::make_unique<mc::Decoration>(mc::Decoration::Type::surface, surface_name);
77 }78 }
7879
79private:80private:
80 std::shared_ptr<mg::Renderable> const renderable_;81 std::shared_ptr<mg::Renderable> const renderable_;
81 std::shared_ptr<ms::RenderingTracker> const tracker;82 std::shared_ptr<ms::RenderingTracker> const tracker;
82 mc::CompositorID cid;83 mc::CompositorID cid;
83 mc::Decoration const decor;84 std::string const surface_name;
84};85};
8586
86//note: something different than a 2D/HWC overlay87//note: something different than a 2D/HWC overlay
@@ -106,6 +107,11 @@
106 {107 {
107 }108 }
108109
110 std::unique_ptr<mc::Decoration> decoration() const override
111 {
112 return std::make_unique<mc::Decoration>();
113 }
114
109private:115private:
110 std::shared_ptr<mg::Renderable> const renderable_;116 std::shared_ptr<mg::Renderable> const renderable_;
111};117};
112118
=== modified file 'tests/acceptance-tests/CMakeLists.txt'
--- tests/acceptance-tests/CMakeLists.txt 2015-03-31 02:35:42 +0000
+++ tests/acceptance-tests/CMakeLists.txt 2015-04-01 19:59:57 +0000
@@ -30,6 +30,7 @@
30 test_prompt_session_client_api.cpp30 test_prompt_session_client_api.cpp
31 test_client_screencast.cpp31 test_client_screencast.cpp
32 test_client_surface_visibility.cpp32 test_client_surface_visibility.cpp
33 test_client_surface_arrangement.cpp
33 test_client_with_custom_display_config_deadlock.cpp34 test_client_with_custom_display_config_deadlock.cpp
34 test_server_without_active_outputs.cpp35 test_server_without_active_outputs.cpp
35 test_server_startup.cpp36 test_server_startup.cpp
@@ -39,6 +40,7 @@
39 test_input_device_hub.cpp40 test_input_device_hub.cpp
40 test_latency.cpp41 test_latency.cpp
41 test_shell_control_of_surface_configuration.cpp42 test_shell_control_of_surface_configuration.cpp
43 test_render_override.cpp
42)44)
4345
44if (MIR_TEST_PLATFORM STREQUAL "mesa")46if (MIR_TEST_PLATFORM STREQUAL "mesa")
4547
=== added file 'tests/acceptance-tests/test_client_surface_arrangement.cpp'
--- tests/acceptance-tests/test_client_surface_arrangement.cpp 1970-01-01 00:00:00 +0000
+++ tests/acceptance-tests/test_client_surface_arrangement.cpp 2015-04-01 19:59:57 +0000
@@ -0,0 +1,255 @@
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#include "mir_toolkit/mir_client_library.h"
20#include "mir_test_framework/connected_client_with_a_surface.h"
21#include "mir/compositor/display_buffer_compositor.h"
22#include "mir/compositor/display_buffer_compositor_factory.h"
23#include "mir/compositor/scene_element.h"
24#include "mir/graphics/renderable.h"
25
26#include <mutex>
27#include <condition_variable>
28#include <stdexcept>
29#include <gtest/gtest.h>
30#include <gmock/gmock.h>
31
32namespace mtf = mir_test_framework;
33namespace geom = mir::geometry;
34namespace mc = mir::compositor;
35namespace mg = mir::graphics;
36namespace
37{
38
39MirPixelFormat an_available_format(MirConnection* connection)
40{
41 using namespace testing;
42 MirPixelFormat format{mir_pixel_format_invalid};
43 unsigned int valid_formats{0};
44 mir_connection_get_available_surface_formats(connection, &format, 1, &valid_formats);
45 return format;
46}
47
48struct Stream
49{
50 Stream(MirBufferStream* stream, geom::Point pt) :
51 stream(stream),
52 pos{pt},
53 needs_release{false}
54 {
55 }
56
57 Stream(MirConnection* connection, geom::Rectangle rect) :
58 stream(mir_connection_create_buffer_stream_sync(
59 connection,
60 rect.size.width.as_int(),
61 rect.size.height.as_int(),
62 an_available_format(connection),
63 mir_buffer_usage_hardware)),
64 pos{rect.top_left},
65 needs_release{true}
66 {
67 mir_buffer_stream_swap_buffers_sync(stream);
68 }
69
70 ~Stream()
71 {
72 if (needs_release)
73 mir_buffer_stream_release_sync(stream);
74 }
75
76 operator MirBufferStream*() const
77 {
78 return stream;
79 }
80
81 geom::Point position()
82 {
83 return pos;
84 }
85
86 Stream(Stream const&) = delete;
87 Stream& operator=(Stream const&) = delete;
88private:
89 MirBufferStream* stream;
90 geom::Point const pos;
91 bool const needs_release;
92};
93
94struct Ordering
95{
96 void note_scene_element_sequence(mc::SceneElementSequence const& sequence)
97 {
98 std::unique_lock<decltype(mutex)> lk(mutex);
99 rectangles.clear();
100 for(auto const& element : sequence)
101 rectangles.emplace_back(element->renderable()->screen_position());
102 post_count++;
103 cv.notify_all();
104 }
105
106 template<typename T, typename S>
107 bool wait_for_another_post_within(std::chrono::duration<T,S> duration)
108 {
109 std::unique_lock<decltype(mutex)> lk(mutex);
110 auto count = post_count + 1;
111 return cv.wait_for(lk, duration, [this, count]{return (post_count >= count);});
112 }
113
114 bool ensure_last_ordering_is_consistent_with(
115 std::vector<MirRectangle> const& arrangement)
116 {
117 if (rectangles.size() != arrangement.size())
118 return false;
119 for(auto i = 0u; i < rectangles.size(); i++)
120 {
121 if ((rectangles[i].top_left.x.as_int() != arrangement[i].left) ||
122 (rectangles[i].top_left.y.as_int() != arrangement[i].top))
123 return false;
124 }
125 return true;
126 }
127private:
128 std::mutex mutex;
129 std::condition_variable cv;
130 unsigned int post_count{0};
131 std::vector<geom::Rectangle> rectangles;
132};
133
134struct OrderTrackingDBC : mc::DisplayBufferCompositor
135{
136 OrderTrackingDBC(
137 std::shared_ptr<mc::DisplayBufferCompositor> const& wrapped,
138 std::shared_ptr<Ordering> const& ordering) :
139 wrapped(wrapped),
140 ordering(ordering)
141 {
142 }
143
144 void composite(mc::SceneElementSequence&& scene_sequence) override
145 {
146 ordering->note_scene_element_sequence(scene_sequence);
147 wrapped->composite(std::move(scene_sequence));
148 }
149
150 std::shared_ptr<mc::DisplayBufferCompositor> const wrapped;
151 std::shared_ptr<Ordering> const ordering;
152};
153
154struct OrderTrackingDBCFactory : mc::DisplayBufferCompositorFactory
155{
156 OrderTrackingDBCFactory(
157 std::shared_ptr<mc::DisplayBufferCompositorFactory> const& wrapped,
158 std::shared_ptr<Ordering> const& ordering) :
159 wrapped(wrapped),
160 ordering(ordering)
161 {
162 }
163
164 std::unique_ptr<mc::DisplayBufferCompositor> create_compositor_for(mg::DisplayBuffer& db) override
165 {
166 return std::make_unique<OrderTrackingDBC>(wrapped->create_compositor_for(db), ordering);
167 }
168
169 std::shared_ptr<OrderTrackingDBC> last_dbc{nullptr};
170 std::shared_ptr<mc::DisplayBufferCompositorFactory> const wrapped;
171 std::shared_ptr<Ordering> const ordering;
172};
173
174struct MirSurfaceArrangements : mtf::ConnectedClientWithASurface
175{
176 void SetUp() override
177 {
178 ordering = std::make_shared<Ordering>();
179 server.wrap_display_buffer_compositor_factory(
180 [this](std::shared_ptr<mc::DisplayBufferCompositorFactory> const& wrapped)
181 {
182 order_tracker = std::make_shared<OrderTrackingDBCFactory>(wrapped, ordering);
183 return order_tracker;
184 });
185
186 ConnectedClientWithASurface::SetUp();
187
188 primary_stream = std::unique_ptr<Stream>(
189 new Stream(mir_surface_get_buffer_stream(surface), geom::Point{0,0}));
190
191 int const additional_streams{3};
192 for(auto i = 0; i < additional_streams; i++)
193 {
194 geom::Size size{30 * i + 1, 40* i + 1};
195 geom::Point position{i * 2, i * 3};
196 streams.emplace_back(std::unique_ptr<Stream>(
197 new Stream(connection, geom::Rectangle{position, size})));
198 }
199 }
200
201 void TearDown() override
202 {
203 streams.clear();
204 ConnectedClientWithASurface::TearDown();
205 }
206
207 std::shared_ptr<Ordering> ordering;
208 std::shared_ptr<OrderTrackingDBCFactory> order_tracker{nullptr};
209 std::unique_ptr<Stream> primary_stream;
210 std::vector<std::unique_ptr<Stream>> streams;
211};
212}
213
214TEST_F(MirSurfaceArrangements, arrangements_are_applied)
215{
216 using namespace testing;
217 MirBufferStream* above_stream = *primary_stream;
218 auto change_spec = mir_surface_begin_changes(surface);
219 for(auto& stream : streams)
220 {
221 mir_surface_spec_place_buffer_stream_below(change_spec, *stream, above_stream);
222 mir_surface_spec_place_buffer_stream_position(
223 change_spec, *stream, stream->position().x.as_int(), stream->position().y.as_int());
224 above_stream = *stream;
225 }
226 mir_wait_for(mir_surface_spec_commit_changes(change_spec));
227 mir_surface_spec_release(change_spec);
228
229 unsigned int num_streams = mir_surface_get_number_of_streams(surface);
230 ASSERT_THAT(num_streams, Eq(streams.size() + 1));
231 std::vector<MirBufferStream*> buffer_streams{num_streams};
232 std::vector<MirRectangle> positions{num_streams};
233 mir_surface_get_streams(surface, buffer_streams.data(), positions.data(), num_streams);
234 for(auto i = 0u; i < num_streams; ++i)
235 {
236 geom::Point pt{positions[i].top, positions[i].left};
237 if (i == 0u)
238 {
239 EXPECT_THAT(buffer_streams[i], Eq(static_cast<MirBufferStream*>(*primary_stream)));
240 EXPECT_THAT(pt, Eq(primary_stream->position()));
241 }
242 else
243 {
244 EXPECT_THAT(buffer_streams[i], Eq(static_cast<MirBufferStream*>(*streams[i-1])));
245 EXPECT_THAT(pt, Eq(streams[i-1]->position()));
246 }
247 }
248
249 //check that the compositor rendered correctly
250 using namespace std::literals::chrono_literals;
251 EXPECT_TRUE(ordering->wait_for_another_post_within(1s))
252 << "timed out waiting for another post";
253 EXPECT_TRUE(ordering->ensure_last_ordering_is_consistent_with(positions))
254 << "surface ordering was not consistent with the client request";
255}
0256
=== added file 'tests/acceptance-tests/test_render_override.cpp'
--- tests/acceptance-tests/test_render_override.cpp 1970-01-01 00:00:00 +0000
+++ tests/acceptance-tests/test_render_override.cpp 2015-04-01 19:59:57 +0000
@@ -0,0 +1,130 @@
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#include "mir_toolkit/mir_client_library.h"
20#include "mir_test_framework/connected_client_with_a_surface.h"
21#include "mir/compositor/display_buffer_compositor.h"
22#include "mir/compositor/display_buffer_compositor_factory.h"
23#include "mir/compositor/scene_element.h"
24#include "mir/compositor/compositor.h"
25#include "mir/graphics/renderable.h"
26
27#include <mutex>
28#include <condition_variable>
29#include <gtest/gtest.h>
30#include <gmock/gmock.h>
31
32namespace mtf = mir_test_framework;
33namespace geom = mir::geometry;
34namespace mc = mir::compositor;
35namespace mg = mir::graphics;
36namespace
37{
38struct size_less
39{
40 bool operator() (geom::Size const& a, geom::Size const& b)
41 {
42 return a.width < b.width && a.height < b.height;
43 }
44};
45
46struct CompositionTracker
47{
48 bool wait_until_surface_is_rendered_with_size(geom::Size sz)
49 {
50 using namespace std::literals::chrono_literals;
51 std::unique_lock<decltype(mutex)> lk(mutex);
52 return cv.wait_for(lk, 4s, [this, sz] {
53 return std::find(rendered_sizes.begin(), rendered_sizes.end(), sz) != rendered_sizes.end();
54 });
55 }
56
57 void surface_rendered_with_size(geom::Size sz)
58 {
59 std::unique_lock<decltype(mutex)> lk(mutex);
60 rendered_sizes.emplace(sz);
61 cv.notify_all();
62 }
63
64private:
65 std::set<geom::Size, size_less> rendered_sizes;
66 std::mutex mutex;
67 std::condition_variable cv;
68};
69
70struct CustomDBC : mc::DisplayBufferCompositor
71{
72 CustomDBC(std::shared_ptr<CompositionTracker> const& tracker) :
73 tracker(tracker)
74 {
75 }
76
77 void composite(mc::SceneElementSequence&& sequence) override
78 {
79 for(auto const& element : sequence)
80 {
81 auto renderable = element->renderable();
82 renderable->buffer(); //consume buffer to stop compositor from spinning
83 tracker->surface_rendered_with_size(renderable->screen_position().size);
84 }
85 }
86private:
87 std::shared_ptr<CompositionTracker> const tracker;
88};
89
90struct CustomDBCFactory : mc::DisplayBufferCompositorFactory
91{
92 CustomDBCFactory(std::shared_ptr<CompositionTracker> const& tracker) :
93 tracker(tracker)
94 {
95 }
96
97 std::unique_ptr<mc::DisplayBufferCompositor> create_compositor_for(mg::DisplayBuffer&) override
98 {
99 return std::make_unique<CustomDBC>(tracker);
100 }
101private:
102 std::shared_ptr<CompositionTracker> const tracker;
103};
104
105struct DisplayBufferCompositorOverride : mtf::ConnectedClientWithASurface
106{
107 void SetUp() override
108 {
109 using namespace std::literals::chrono_literals;
110 server.override_the_display_buffer_compositor_factory([this]
111 {
112 return std::make_shared<CustomDBCFactory>(tracker);
113 });
114
115 mtf::ConnectedClientWithASurface::SetUp();
116 }
117 void TearDown() override
118 {
119 mtf::ConnectedClientWithASurface::TearDown();
120 }
121protected:
122 std::shared_ptr<CompositionTracker> const tracker{std::make_shared<CompositionTracker>()};
123};
124}
125
126TEST_F(DisplayBufferCompositorOverride, composite_called_with_surface)
127{
128 mir_buffer_stream_swap_buffers_sync(mir_surface_get_buffer_stream(surface));
129 EXPECT_TRUE(tracker->wait_until_surface_is_rendered_with_size({surface_params.width, surface_params.height}));
130}
0131
=== modified file 'tests/include/mir_test_doubles/stub_scene_element.h'
--- tests/include/mir_test_doubles/stub_scene_element.h 2015-03-31 02:35:42 +0000
+++ tests/include/mir_test_doubles/stub_scene_element.h 2015-04-01 19:59:57 +0000
@@ -20,6 +20,7 @@
20#define MIR_TEST_DOUBLES_STUB_SCENE_ELEMENT_H_20#define MIR_TEST_DOUBLES_STUB_SCENE_ELEMENT_H_
2121
22#include "mir/compositor/scene_element.h"22#include "mir/compositor/scene_element.h"
23#include "mir/compositor/decoration.h"
23#include "stub_renderable.h"24#include "stub_renderable.h"
2425
25namespace mir26namespace mir
@@ -55,6 +56,11 @@
55 {56 {
56 }57 }
5758
59 std::unique_ptr<compositor::Decoration> decoration() const override
60 {
61 return nullptr;
62 }
63
58private:64private:
59 std::shared_ptr<graphics::Renderable> const renderable_;65 std::shared_ptr<graphics::Renderable> const renderable_;
60};66};
6167
=== modified file 'tests/include/mir_test_framework/connected_client_with_a_surface.h'
--- tests/include/mir_test_framework/connected_client_with_a_surface.h 2014-11-18 16:15:00 +0000
+++ tests/include/mir_test_framework/connected_client_with_a_surface.h 2015-04-01 19:59:57 +0000
@@ -26,6 +26,14 @@
26struct ConnectedClientWithASurface : ConnectedClientHeadlessServer26struct ConnectedClientWithASurface : ConnectedClientHeadlessServer
27{27{
28 MirSurface* surface{nullptr};28 MirSurface* surface{nullptr};
29 MirSurfaceParameters const surface_params =
30 {
31 "ConnectedClientWithASurfaceFixtureSurface",
32 640, 480,
33 mir_pixel_format_abgr_8888,
34 mir_buffer_usage_hardware,
35 mir_display_output_id_invalid
36 };
2937
30 void SetUp() override;38 void SetUp() override;
3139
3240
=== modified file 'tests/mir_test_framework/connected_client_with_a_surface.cpp'
--- tests/mir_test_framework/connected_client_with_a_surface.cpp 2014-11-18 16:15:00 +0000
+++ tests/mir_test_framework/connected_client_with_a_surface.cpp 2015-04-01 19:59:57 +0000
@@ -24,16 +24,7 @@
24{24{
25 ConnectedClientHeadlessServer::SetUp();25 ConnectedClientHeadlessServer::SetUp();
2626
27 MirSurfaceParameters request_params =27 surface = mir_connection_create_surface_sync(connection, &surface_params);
28 {
29 __PRETTY_FUNCTION__,
30 640, 480,
31 mir_pixel_format_abgr_8888,
32 mir_buffer_usage_hardware,
33 mir_display_output_id_invalid
34 };
35
36 surface = mir_connection_create_surface_sync(connection, &request_params);
37 ASSERT_TRUE(mir_surface_is_valid(surface));28 ASSERT_TRUE(mir_surface_is_valid(surface));
38}29}
3930
4031
=== modified file 'tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp'
--- tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp 2015-03-31 02:35:42 +0000
+++ tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp 2015-04-01 19:59:57 +0000
@@ -18,12 +18,14 @@
1818
19#include "src/server/compositor/default_display_buffer_compositor.h"19#include "src/server/compositor/default_display_buffer_compositor.h"
20#include "mir/compositor/display_buffer_compositor.h"20#include "mir/compositor/display_buffer_compositor.h"
21#include "mir/compositor/decoration.h"
21#include "src/server/report/null_report_factory.h"22#include "src/server/report/null_report_factory.h"
22#include "mir/compositor/scene.h"23#include "mir/compositor/scene.h"
23#include "mir/compositor/renderer.h"24#include "mir/compositor/renderer.h"
24#include "mir/geometry/rectangle.h"25#include "mir/geometry/rectangle.h"
25#include "mir_test_doubles/mock_renderer.h"26#include "mir_test_doubles/mock_renderer.h"
26#include "mir_test/fake_shared.h"27#include "mir_test/fake_shared.h"
28#include "mir_test/gmock_fixes.h"
27#include "mir_test_doubles/mock_display_buffer.h"29#include "mir_test_doubles/mock_display_buffer.h"
28#include "mir_test_doubles/mock_renderable.h"30#include "mir_test_doubles/mock_renderable.h"
29#include "mir_test_doubles/fake_renderable.h"31#include "mir_test_doubles/fake_renderable.h"
@@ -57,17 +59,22 @@
57 {59 {
58 }60 }
5961
60 std::shared_ptr<mir::graphics::Renderable> renderable() const62 std::shared_ptr<mir::graphics::Renderable> renderable() const override
61 {63 {
62 return renderable_;64 return renderable_;
63 }65 }
6466
65 void rendered()67 void rendered() override
66 {68 {
67 }69 }
6870
69 void occluded()71 void occluded() override
70 {72 {
73 }
74
75 std::unique_ptr<mc::Decoration> decoration() const override
76 {
77 return nullptr;
71 }78 }
7279
73private:80private:
@@ -317,7 +324,7 @@
317 }324 }
318325
319 MOCK_CONST_METHOD0(renderable, std::shared_ptr<mir::graphics::Renderable>());326 MOCK_CONST_METHOD0(renderable, std::shared_ptr<mir::graphics::Renderable>());
320 MOCK_CONST_METHOD0(decoration, mc::Decoration const&());327 MOCK_CONST_METHOD0(decoration, std::unique_ptr<mc::Decoration>());
321 MOCK_METHOD0(rendered, void());328 MOCK_METHOD0(rendered, void());
322 MOCK_METHOD0(occluded, void());329 MOCK_METHOD0(occluded, void());
323};330};
324331
=== modified file 'tests/unit-tests/examples/test_demo_compositor.cpp'
--- tests/unit-tests/examples/test_demo_compositor.cpp 2015-03-31 02:35:42 +0000
+++ tests/unit-tests/examples/test_demo_compositor.cpp 2015-04-01 19:59:57 +0000
@@ -30,6 +30,7 @@
30#include "mir_test_doubles/stub_buffer_stream.h"30#include "mir_test_doubles/stub_buffer_stream.h"
31#include "mir_test_doubles/stub_renderable.h"31#include "mir_test_doubles/stub_renderable.h"
32#include "mir_test/fake_shared.h"32#include "mir_test/fake_shared.h"
33#include "mir_test/gmock_fixes.h"
3334
34#include <gtest/gtest.h>35#include <gtest/gtest.h>
35#include <gmock/gmock.h>36#include <gmock/gmock.h>
@@ -47,7 +48,7 @@
47struct MockSceneElement : mc::SceneElement48struct MockSceneElement : mc::SceneElement
48{49{
49 MOCK_CONST_METHOD0(renderable, std::shared_ptr<mir::graphics::Renderable>());50 MOCK_CONST_METHOD0(renderable, std::shared_ptr<mir::graphics::Renderable>());
50 MOCK_CONST_METHOD0(decoration, mc::Decoration const&());51 MOCK_CONST_METHOD0(decoration, std::unique_ptr<mc::Decoration>());
51 MOCK_METHOD0(rendered, void());52 MOCK_METHOD0(rendered, void());
52 MOCK_METHOD0(occluded, void());53 MOCK_METHOD0(occluded, void());
53};54};
5455
=== modified file 'tests/unit-tests/scene/test_surface_stack.cpp'
--- tests/unit-tests/scene/test_surface_stack.cpp 2015-03-31 02:35:42 +0000
+++ tests/unit-tests/scene/test_surface_stack.cpp 2015-04-01 19:59:57 +0000
@@ -22,6 +22,7 @@
22#include "mir/scene/observer.h"22#include "mir/scene/observer.h"
23#include "mir/scene/surface_creation_parameters.h"23#include "mir/scene/surface_creation_parameters.h"
24#include "mir/compositor/scene_element.h"24#include "mir/compositor/scene_element.h"
25#include "mir/compositor/decoration.h"
25#include "src/server/report/null_report_factory.h"26#include "src/server/report/null_report_factory.h"
26#include "src/server/scene/basic_surface.h"27#include "src/server/scene/basic_surface.h"
27#include "mir/input/input_channel_factory.h"28#include "mir/input/input_channel_factory.h"
@@ -251,10 +252,10 @@
251252
252 auto& element = elements.front();253 auto& element = elements.front();
253254
254 auto const& decor = element->decoration();255 auto decor = element->decoration();
255 EXPECT_TRUE(decor);256 ASSERT_THAT(decor, Ne(nullptr));
256 EXPECT_EQ(mc::Decoration::Type::surface, decor.type);257 EXPECT_EQ(mc::Decoration::Type::surface, decor->type);
257 EXPECT_EQ("Mary had a little lamb", decor.name);258 EXPECT_EQ("Mary had a little lamb", decor->name);
258}259}
259260
260TEST_F(SurfaceStack, gets_surface_renames)261TEST_F(SurfaceStack, gets_surface_renames)
@@ -286,10 +287,10 @@
286287
287 auto& element = elements.front();288 auto& element = elements.front();
288289
289 auto const& decor = element->decoration();290 auto decor = element->decoration();
290 EXPECT_TRUE(decor);291 ASSERT_THAT(decor, Ne(nullptr));
291 EXPECT_EQ(mc::Decoration::Type::surface, decor.type);292 EXPECT_EQ(mc::Decoration::Type::surface, decor->type);
292 EXPECT_EQ("username@hostname: ~/Documents", decor.name);293 EXPECT_EQ("username@hostname: ~/Documents", decor->name);
293}294}
294295
295TEST_F(SurfaceStack, scene_counts_pending_accurately)296TEST_F(SurfaceStack, scene_counts_pending_accurately)

Subscribers

People subscribed via source and target branches