Mir

Merge lp:~kdub/mir/fix-1299977-take3 into lp:mir

Proposed by Kevin DuBois
Status: Rejected
Rejected by: Kevin DuBois
Proposed branch: lp:~kdub/mir/fix-1299977-take3
Merge into: lp:mir
Diff against target: 818 lines (+461/-72)
10 files modified
examples/CMakeLists.txt (+1/-1)
examples/demo-shell/CMakeLists.txt (+2/-0)
examples/demo-shell/demo_compositor.cpp (+96/-0)
examples/demo-shell/demo_compositor.h (+65/-0)
examples/demo-shell/demo_renderer.cpp (+10/-6)
examples/demo-shell/demo_renderer.h (+8/-2)
examples/demo-shell/demo_shell.cpp (+38/-19)
examples/demo-shell/occlusion.cpp (+110/-0)
examples/demo-shell/occlusion.h (+39/-0)
tests/unit-tests/compositor/test_occlusion.cpp (+92/-44)
To merge this branch: bzr merge lp:~kdub/mir/fix-1299977-take3
Reviewer Review Type Date Requested Status
Daniel van Vugt Needs Fixing
PS Jenkins bot (community) continuous-integration Approve
Alexandros Frantzis (community) Approve
Alan Griffiths Approve
Cemil Azizoglu (community) Approve
Review via email: mp+226036@code.launchpad.net

This proposal has been superseded by a proposal from 2014-07-24.

Commit message

fix lp: #1299977 in the demo shell by accounting for the demo shell's additional decorations in the occlusion filtering.

Description of the change

fix lp: #1299977 in the demo shell by accounting for the demo shell's additional decorations in the occlusion filtering.

This is the third attempt at correcting this problem, the first two being:
https://code.launchpad.net/~vanvugt/mir/unocclude/+merge/216690 (delete occlusion filtering), and
https://code.launchpad.net/~kdub/mir/fix-1299977/+merge/222844 (share the production code with the examples).

The problem is that the bug isn't conceptually that tough, but coming to an agreement on how to share/evolve the demo shell vs the usc shell vs the default mir shell vs the qtsg is. Here's where we got to in the previous attempts:
0) We should keep the occlusion filtering (even if there are gaps in the default implementation as of today)
1) We don't want to try to provide an occlusion algorithm for the users, as every user is likely to need something a bit different.
2) Our example code should provide an example of the proper use of the public headers. Example code shouldn't have access to mir internal code that a 'normal user' doesn't have access to.
3) The occlusion code in the default/demo cases is pretty similar, and it goes against the 'don't copy code' instinct to have two algorithms. The demo compositor's needs is largely the same with the exceptions of having to factor in the shadow/titlebar. As time goes on, I'd expect we'd have to factor in more and more stuff.

This attempt satisfies the concerns 0), 1), and 2) at the expense of 3)... the occlusion code is copied from the production code with the additional logic to factor in the titlebar/shadows. This lets the different needs of the different compositors evolve differently. I hope that as time goes on, we'll sift through the code and organically pull the truly universal compositor stuff into a handy library for shell writers.

Note:
I'm interested in this because its blocking me turning on HWC 2d optimizations by default. The demo shell has to start accounting for its decorations if it hopes to use the 2d optimizations on android correctly. My primary interest is having the demo compositor discern when it can use mg::DisplayBuffer::post_renderables_if_optimizable().

To post a comment you must log in.
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 :

I started on a proper solution for bug 1299977 back in May. That involves separating the concepts of window size and client size (as you'll find all existing windowing systems do). Once that's clear, we just switch the occlusion test to use the extents (including frame) of a window instead of its client region.

So the right (and elegant) solution is coming. I'm concerned about any change that appears to fix bug 1299977 without implementing this. It's suspicious but I haven't done a review yet...

If the only goal is to resolve bug 1299977 then I suspect this is probably the wrong answer.

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

I think the disagreement goes a little bit deeper because we haven't come to a consensus about the concepts that we're incorporating into the scene. I argue that we shouldn't have the concept of window size and client size in the scene because we have 1 user that handles this in a custom way (U8) and one user that doesn't need this at all (USC).

Once we start getting the concept of window size vs decoration side, we will have this awkward situation where the android hwc code will just have to start rejecting renderables with decorations.

So really, this solution puts the demo shell on the trajectory of reimplementing the scene in the same way that the users have chosen to reimplement the scene (that is, reimplementing parts of the compositing system at a higher level than the Renderer).

I want to protect the core (buffer swapping, turning the display on, setting up the GL context) from the desktop-style additional needs (animations, window decorations, 'bling', cursor images, etc etc).

My idea/"unconcensussed plan" for this is to have the SceneElement be expandable so that a compositor writer can pack it with data that the core mir will preserve, but this data will be opaque to the "core mir". So for instance, the compositor can 'tag' each SceneElement with a bunch of information about its window decorations, which will be specific to the compositor implementation. On the next pass of the shell's render the data would be preserved (or perhaps updated in some universal way, like timing info).

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

I'm interested in seeing Daniel's solution as well. Since Kevin is blocked by this for hwc optimizations, I'll go ahead with the review.

Minor things:

9 +add_library(mirdraw STATIC graphics_utils.cpp demo-shell/occlusion.cpp)

mirdraw should be a lib that others (besides demo-shell) can use and hence its source should not be part of a particular example program. So occlusion.cpp should move outside demo-shell/.

294 -
295 +namespace mc = mir::compositor;

preserve the blank line?

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

I'm not entirely sure how to validate this but the code looks OK and it runs. We can fix problems later if they arise.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

OK for now.

> SceneElement be expandable so that a compositor writer can pack it with data that the core mir will > preserve, but this data will be opaque to the "core mir"

Interesting idea.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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 don't like to be the spoilsport, but will block this for two reasons:

(1) As mentioned in the description this proposal branches (duplicates) functionality on the assumption we will re-unify it later. I think that's a bad assumption and unlikely to happen.

(2) A generic solution is possible. One that works for all (most?) shells. I think I'd prefer to continue with that (started in May) instead of landing solutions that are shell-specific.

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

P.S. If you want to enable overlay optimizations by default, then you should probably be focusing more on how the Ubuntu touch Qt shell needs it.

In the least you can overlay full-screen surfaces (on the host server when nesting) right now using the bypass detection algorithm. Then worry about enabling hardware overlays in the nested server later. So we can get most of the performance benefits of overlays turned on right now without worrying at all about anything to to with demo shell.

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

Its more that the default occlusion algorithm and the demo occlusion algorithm are doing different things, with the demo occlusion algorithm having to factor in the decorations on the top,bottom & right. There is some overlap because both are rectangle-based occlusion filtering but this is an attempt to satisfy the primary complaints about lp:~kdub/mir/fix-1299977. Namely, we don't want to use a private algorithm in the demos, yet, we don't want to expose the algorithm publicly because its not universal.

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

> (2) A generic solution is possible. One that works for all (most?) shells. I
> think I'd prefer to continue with that (started in May) instead of landing
> solutions that are shell-specific.

If we try to come up with a generic solution that addresses all shells, we will end up with some shells that don't use some of the features. We also end up with some shells trying to jam features into the "one algorithm" that other shells don't want, and we limit those shells if they don't get their special feature landed. (eg, say someone wants an obscure fragment shader that affects occlusion detection). Given the flexibility and extensibility that we're aiming for, I'd rather see compositor writers rewriting things that are specific to that shell's needs, then aiming for one set of behaviors that covers every shell we encounter.

Like, every shell writer can be expected to write GL code, and every shell writer would have the responsibility to do occlusions and visibility detection, based on the unique things that the shell wants to appear on the screen. This is the role of the compositor object, and would let us pop in new compositor objects that have differing behavior (LSP) without changing the correctness of the mir system. (and also without burdening core mir with the responsibility to make the most universal drawing code to assist the shell writers)

As we determine things that are truly universal to all shells we should pull them into core mir. For instance mg::DisplayBuffer is needed by every shell so its proper to have that interface there. Other things like an animation framework might also fit in with core mir. Occlusion seems to me that there are as many variations as there are possible shells, so it seems less likely that it belongs in core mir.

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

> (2) A generic solution is possible. One that works for all (most?) shells. I
> think I'd prefer to continue with that (started in May) instead of landing
> solutions that are shell-specific.

If we try to come up with a generic solution that addresses all shells, we will end up with some shells that don't use some of the features. We also end up with some shells trying to jam features into the "one algorithm" that other shells don't want, and we limit those shells if they don't get their special feature landed. (eg, say someone wants an obscure fragment shader that affects occlusion detection). Given the flexibility and extensibility that we're aiming for, I'd rather see compositor writers rewriting things that are specific to that shell's needs, then aiming for one set of behaviors that covers every shell we encounter.

Like, every shell writer can be expected to write GL code, and every shell writer would have the responsibility to do occlusions and visibility detection, based on the unique things that the shell wants to appear on the screen. This is the role of the compositor object, and would let us pop in new compositor objects that have differing behavior (LSP) without changing the correctness of the mir system. (and also without burdening core mir with the responsibility to make the most universal drawing code to assist the shell writers)

As we determine things that are truly universal to all shells we should pull them into core mir. For instance mg::DisplayBuffer is needed by every shell so its proper to have that interface there. Other things like an animation framework might also fit in with core mir. Occlusion seems to me that there are as many variations as there are possible shells, so it seems less likely that it belongs in core mir.

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

I don't know why Launchpad posted twice, but same content in each posting.

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

Yeah, if you do assume in future every shell should provide its own compositor then this partially makes sense. However I don't think that's a path we want to go down, and have explicitly decided not to. We do want to unify and provide common compositing ability where possible. A shell shouldn't be forced to write a new compositor. If we did it then I'd like to see it done absolutely, and the default compositor removed at the same time (and thus get team agreement on the plan).

Other things like occlusion testing between windows that are kind-of rectangular and have a little bit of shape to them are common problems. We shouldn't re-invent occlusion testing every time a new shell comes along... On the other hand, if we defaulted to no occlusion testing at all and make it an optional feature that some shells can implement then I'm happy with that -- It would not be a required feature to build a shell and bug 1299977 would also be solved.

Back to the primary problem, where occlusion testing needs to deal with decorations, I think there are three good options:
  1. No occlusion testing by default. Put it all in your shell if you want it but make it optional for shells.
  2. Continue with the work I started in May and provide extended region information allowing window-based shells to detect occlusions accurately. This is relatively simple in theory, but blocked by other RTM-related work taking precedent. It also has to be finished to implement correct window placement anyway.
  3. Continue with the plan that everything is a node of the scene graph. Then occlusion testing is a generic graph traversal algorithm that can support any primitives. Not just decorations.

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

I particularly do not want this branch to land because it adds complexity that would be hard to wind back. And we would unwind it as at least options (2) and (3) above are going to be implemented (already begun).

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

Daniel, will you be providing your version soon? If it'll take some time, perhaps we should let kdub proceed and when you get to it, you can put up an MP the way you like it. I just feel that progress should continue. But it's all software and can be changed later.

Or perhaps there is some way that this MP can be fixed in a minimally acceptible (to you) manner. If so, please comment and let Kevin take a stab at it.

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

> Yeah, if you do assume in future every shell should provide its own compositor
> then this partially makes sense. However I don't think that's a path we want
> to go down, and have explicitly decided not to. We do want to unify and
> provide common compositing ability where possible. A shell shouldn't be forced
> to write a new compositor. If we did it then I'd like to see it done
> absolutely, and the default compositor removed at the same time (and thus get
> team agreement on the plan).

In the present we have 3 shells/clients between USC, demo, and unity8, that have all chosen to have different compositor implementations. We've already gone down the path, but haven't been able to shepherd all the implementations into using the interfaces that we intended. :)
This hopefully gets the demo/usc using the mc::Compositor interface like we intended, and we'll have to work more closely to get qtcomp/unity8 not to replace the MultiThreadedCompositor system.

> Other things like occlusion testing between windows that are kind-of
> rectangular and have a little bit of shape to them are common problems. We
> shouldn't re-invent occlusion testing every time a new shell comes along... On
> the other hand, if we defaulted to no occlusion testing at all and make it an
> optional feature that some shells can implement then I'm happy with that -- It
> would not be a required feature to build a shell and bug 1299977 would also be
> solved.

I agree that the easier we make things for the shell writers, but I think its more important not to force the shell writers into extending implementations. So, to put it another way, the best way to make things nice for the shell writers is to have a system of objects that we can plug into the core. Code reuse is good of course, but my first attempt was thwarted because we decided that code reuse doesn't trump exposing an additional 'shell writers api/abi'. The hard problem is how to get those public server interfaces right, and this seems to favor making it a bit easier by rallying around the interfaces that we want the users to implement, and by not introducing a mini-toolkit (or a big swiss army object) that aims to 'make opengl easy' :)
In this case, the judgement call comes at the expense of having occlusion look somewhat the same, but doing different things to factor in the shell's decorations.

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

> Yeah, if you do assume in future every shell should provide its own compositor
> then this partially makes sense. However I don't think that's a path we want
> to go down, and have explicitly decided not to. We do want to unify and
> provide common compositing ability where possible. A shell shouldn't be forced
> to write a new compositor. If we did it then I'd like to see it done
> absolutely, and the default compositor removed at the same time (and thus get
> team agreement on the plan).

In the present we have 3 shells/clients between USC, demo, and unity8, that have all chosen to have different compositor implementations. We've already gone down the path, but haven't been able to shepherd all the implementations into using the interfaces that we intended. :)
This hopefully gets the demo/usc using the mc::Compositor interface like we intended, and we'll have to work more closely to get qtcomp/unity8 not to replace the MultiThreadedCompositor system.

> Other things like occlusion testing between windows that are kind-of
> rectangular and have a little bit of shape to them are common problems. We
> shouldn't re-invent occlusion testing every time a new shell comes along... On
> the other hand, if we defaulted to no occlusion testing at all and make it an
> optional feature that some shells can implement then I'm happy with that -- It
> would not be a required feature to build a shell and bug 1299977 would also be
> solved.

I agree that the easier we make things for the shell writers, but I think its more important not to force the shell writers into extending implementations. So, to put it another way, the best way to make things nice for the shell writers is to have a system of objects that we can plug into the core. Code reuse is good of course, but my first attempt was thwarted because we decided that code reuse doesn't trump exposing an additional 'shell writers api/abi'. The hard problem is how to get those public server interfaces right, and this seems to favor making it a bit easier by rallying around the interfaces that we want the users to implement, and by not introducing a mini-toolkit (or a big swiss army object) that aims to 'make opengl easy' :)
In this case, the judgement call comes at the expense of having occlusion look somewhat the same, but doing different things to factor in the shell's decorations.

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

strange launchpad keeps double-posting me...

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

Yes it does appear people are writing their own compositors despite us recommending against it. And I too want to resolve the blurry seams that have formed between compositor classes and renderers.

OK I can make suggestions for moving forward:

(1) Remove all references to bug 1299977. Because what's proposed here is only for demo shell, and not a generic fix for bug 1299977. We can do enough work to unblock overlay enablement without waiting for a full fix of bug 1299977 to land.

(2) Make demo-shell's flagging of occlusions simple and dumb, so that the word "decoration" is never mentioned. Just allow overlays for the surface that's "on top" (last on the render list). A generic solution which accounts for decorations more carefully will come later. You don't need to wait for that to unblock.

We can argue about the existence of DefaultDisplayByfferCompositor another day.

It's a little bit silly that demo shell should block unity8 progress so let's get over this hump with minimal code change (which also makes it more likely to get backported to stable series 0.5 for RTM).

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

Cool, sounds good to me. Working on fixing.

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

okay, so the new approach of doing a much more simple filtering of the renderable list is significantly different than improving the algorithm, in that it doesn't fix 1299977, it just averts it.

So I'll move this MP to rejected. I'll push the improvements to lp:~kdub/mir/fix-1348330 and submit a new merge proposal (which is mostly the same as this one, but it helps to document the problem better, and remove the references to the 1299977 bug)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'examples/CMakeLists.txt'
2--- examples/CMakeLists.txt 2014-06-11 16:11:32 +0000
3+++ examples/CMakeLists.txt 2014-07-18 18:49:52 +0000
4@@ -95,7 +95,7 @@
5 add_executable(mir_demo_client_prompt_session prompt_session.c)
6 target_link_libraries(mir_demo_client_prompt_session mirclient)
7
8-add_library(mirdraw STATIC graphics_utils.cpp)
9+add_library(mirdraw STATIC graphics_utils.cpp demo-shell/occlusion.cpp)
10 target_link_libraries(mirdraw ${GLESv2_LIBRARIES})
11
12 include_directories(
13
14=== modified file 'examples/demo-shell/CMakeLists.txt'
15--- examples/demo-shell/CMakeLists.txt 2014-03-06 06:05:17 +0000
16+++ examples/demo-shell/CMakeLists.txt 2014-07-18 18:49:52 +0000
17@@ -1,5 +1,6 @@
18 add_executable(mir_demo_server_shell
19 demo_shell.cpp
20+ demo_compositor.cpp
21 demo_renderer.cpp
22 fullscreen_placement_strategy.cpp
23 window_manager.cpp
24@@ -8,6 +9,7 @@
25
26 target_link_libraries(mir_demo_server_shell
27 mirserver
28+ mirdraw
29 )
30
31 install(TARGETS mir_demo_server_shell RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
32
33=== added file 'examples/demo-shell/demo_compositor.cpp'
34--- examples/demo-shell/demo_compositor.cpp 1970-01-01 00:00:00 +0000
35+++ examples/demo-shell/demo_compositor.cpp 2014-07-18 18:49:52 +0000
36@@ -0,0 +1,96 @@
37+/*
38+ * Copyright © 2014 Canonical Ltd.
39+ *
40+ * This program is free software: you can redistribute it and/or modify
41+ * it under the terms of the GNU General Public License version 3 as
42+ * published by the Free Software Foundation.
43+ *
44+ * This program is distributed in the hope that it will be useful,
45+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
46+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47+ * GNU General Public License for more details.
48+ *
49+ * You should have received a copy of the GNU General Public License
50+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
51+ *
52+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
53+ */
54+
55+#include "mir/graphics/display_buffer.h"
56+#include "mir/compositor/compositor_report.h"
57+#include "mir/compositor/scene.h"
58+#include "mir/compositor/scene_element.h"
59+#include "mir/compositor/destination_alpha.h"
60+#include "demo_compositor.h"
61+#include "occlusion.h"
62+
63+namespace me = mir::examples;
64+namespace mg = mir::graphics;
65+namespace mc = mir::compositor;
66+namespace geom = mir::geometry;
67+
68+namespace
69+{
70+mc::DestinationAlpha destination_alpha(mg::DisplayBuffer const& db)
71+{
72+ return db.uses_alpha() ? mc::DestinationAlpha::generate_from_source : mc::DestinationAlpha::opaque;
73+}
74+}
75+
76+me::DemoCompositor::DemoCompositor(
77+ mg::DisplayBuffer& display_buffer,
78+ std::shared_ptr<mc::Scene> const& scene,
79+ mg::GLProgramFactory const& factory,
80+ std::shared_ptr<mc::CompositorReport> const& report) :
81+ display_buffer(display_buffer),
82+ scene(scene),
83+ report(report),
84+ shadow_radius(80),
85+ titlebar_height(30),
86+ renderer(
87+ factory,
88+ display_buffer.view_area(),
89+ destination_alpha(display_buffer),
90+ static_cast<float>(shadow_radius),
91+ static_cast<float>(titlebar_height))
92+{
93+}
94+
95+mg::RenderableList me::DemoCompositor::generate_renderables()
96+{
97+ mg::RenderableList renderable_list;
98+ auto elements = scene->scene_elements_for(this);
99+ auto occluded = me::filter_occlusions_from(elements, display_buffer.view_area(), shadow_radius, titlebar_height);
100+ for(auto const& it : elements)
101+ {
102+ renderable_list.push_back(it->renderable());
103+ it->rendered_in(this);
104+ }
105+ for(auto const& it : occluded)
106+ it->occluded_in(this);
107+
108+ return renderable_list;
109+}
110+
111+void me::DemoCompositor::composite()
112+{
113+ report->began_frame(this);
114+
115+ auto renderable_list = generate_renderables();
116+ if (display_buffer.post_renderables_if_optimizable(renderable_list))
117+ {
118+ renderer.suspend();
119+ report->finished_frame(true, this);
120+ }
121+ else
122+ {
123+ display_buffer.make_current();
124+
125+ renderer.set_rotation(display_buffer.orientation());
126+ renderer.begin();
127+ renderer.render(renderable_list);
128+ display_buffer.post_update();
129+ renderer.end();
130+ report->finished_frame(false, this);
131+ }
132+}
133
134=== added file 'examples/demo-shell/demo_compositor.h'
135--- examples/demo-shell/demo_compositor.h 1970-01-01 00:00:00 +0000
136+++ examples/demo-shell/demo_compositor.h 2014-07-18 18:49:52 +0000
137@@ -0,0 +1,65 @@
138+/*
139+ * Copyright © 2014 Canonical Ltd.
140+ *
141+ * This program is free software: you can redistribute it and/or modify
142+ * it under the terms of the GNU General Public License version 3 as
143+ * published by the Free Software Foundation.
144+ *
145+ * This program is distributed in the hope that it will be useful,
146+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
147+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
148+ * GNU General Public License for more details.
149+ *
150+ * You should have received a copy of the GNU General Public License
151+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
152+ *
153+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
154+ */
155+
156+#ifndef MIR_EXAMPLES_DEMO_COMPOSITOR_H_
157+#define MIR_EXAMPLES_DEMO_COMPOSITOR_H_
158+
159+#include "mir/compositor/display_buffer_compositor.h"
160+#include "mir/compositor/scene.h"
161+#include "mir/graphics/renderable.h"
162+#include "demo_renderer.h"
163+
164+namespace mir
165+{
166+namespace compositor
167+{
168+class Scene;
169+class CompositorReport;
170+}
171+namespace graphics
172+{
173+class DisplayBuffer;
174+}
175+namespace examples
176+{
177+
178+class DemoCompositor : public compositor::DisplayBufferCompositor
179+{
180+public:
181+ DemoCompositor(
182+ graphics::DisplayBuffer& display_buffer,
183+ std::shared_ptr<compositor::Scene> const& scene,
184+ graphics::GLProgramFactory const& factory,
185+ std::shared_ptr<compositor::CompositorReport> const& report);
186+
187+ void composite() override;
188+
189+private:
190+ graphics::RenderableList generate_renderables();
191+ graphics::DisplayBuffer& display_buffer;
192+ std::shared_ptr<compositor::Scene> const scene;
193+ std::shared_ptr<compositor::CompositorReport> const report;
194+ int const shadow_radius;
195+ int const titlebar_height;
196+ DemoRenderer renderer;
197+};
198+
199+} // namespace examples
200+} // namespace mir
201+
202+#endif // MIR_EXAMPLES_DEMO_COMPOSITOR_H_
203
204=== modified file 'examples/demo-shell/demo_renderer.cpp'
205--- examples/demo-shell/demo_renderer.cpp 2014-06-18 12:50:31 +0000
206+++ examples/demo-shell/demo_renderer.cpp 2014-07-18 18:49:52 +0000
207@@ -139,12 +139,16 @@
208 DemoRenderer::DemoRenderer(
209 graphics::GLProgramFactory const& program_factory,
210 geometry::Rectangle const& display_area,
211- compositor::DestinationAlpha dest_alpha)
212- : GLRenderer(program_factory,
213+ compositor::DestinationAlpha dest_alpha,
214+ float shadow_radius,
215+ float titlebar_height) :
216+ GLRenderer(program_factory,
217 std::unique_ptr<graphics::GLTextureCache>(new compositor::RecentlyUsedCache()),
218 display_area,
219- dest_alpha)
220- , corner_radius(0.5f)
221+ dest_alpha),
222+ corner_radius(0.5f),
223+ shadow_radius(shadow_radius),
224+ titlebar_height(titlebar_height)
225 {
226 shadow_corner_tex = generate_shadow_corner_texture(0.4f);
227 titlebar_corner_tex = generate_frame_corner_texture(corner_radius,
228@@ -177,8 +181,8 @@
229 graphics::Renderable const& renderable) const
230 {
231 GLRenderer::tessellate(primitives, renderable);
232- tessellate_shadow(primitives, renderable, 80.0f);
233- tessellate_frame(primitives, renderable, 30.0f);
234+ tessellate_shadow(primitives, renderable, shadow_radius);
235+ tessellate_frame(primitives, renderable, titlebar_height);
236 }
237
238 void DemoRenderer::tessellate_shadow(std::vector<graphics::GLPrimitive>& primitives,
239
240=== modified file 'examples/demo-shell/demo_renderer.h'
241--- examples/demo-shell/demo_renderer.h 2014-06-06 10:03:54 +0000
242+++ examples/demo-shell/demo_renderer.h 2014-07-18 18:49:52 +0000
243@@ -29,8 +29,12 @@
244 class DemoRenderer : public compositor::GLRenderer
245 {
246 public:
247- DemoRenderer(graphics::GLProgramFactory const& factory, geometry::Rectangle const& display_area,
248- compositor::DestinationAlpha dest_alpha);
249+ DemoRenderer(
250+ graphics::GLProgramFactory const& factory,
251+ geometry::Rectangle const& display_area,
252+ compositor::DestinationAlpha dest_alpha,
253+ float shadow_radius,
254+ float titlebar_height);
255 ~DemoRenderer();
256
257 void begin() const override;
258@@ -45,6 +49,8 @@
259
260 private:
261 float const corner_radius;
262+ float const shadow_radius;
263+ float const titlebar_height;
264 GLuint shadow_corner_tex;
265 GLuint titlebar_corner_tex;
266 };
267
268=== modified file 'examples/demo-shell/demo_shell.cpp'
269--- examples/demo-shell/demo_shell.cpp 2014-07-17 07:53:26 +0000
270+++ examples/demo-shell/demo_shell.cpp 2014-07-18 18:49:52 +0000
271@@ -18,7 +18,7 @@
272
273 /// \example demo_shell.cpp A simple mir shell
274
275-#include "demo_renderer.h"
276+#include "demo_compositor.h"
277 #include "window_manager.h"
278 #include "fullscreen_placement_strategy.h"
279 #include "../server_configuration.h"
280@@ -28,6 +28,8 @@
281 #include "mir/report_exception.h"
282 #include "mir/graphics/display.h"
283 #include "mir/input/composite_event_filter.h"
284+#include "mir/compositor/display_buffer_compositor_factory.h"
285+#include "mir/compositor/destination_alpha.h"
286 #include "mir/compositor/renderer_factory.h"
287 #include "mir/shell/host_lifecycle_event_listener.h"
288
289@@ -39,6 +41,7 @@
290 namespace mf = mir::frontend;
291 namespace mi = mir::input;
292 namespace mo = mir::options;
293+namespace mc = mir::compositor;
294 namespace msh = mir::shell;
295
296 namespace mir
297@@ -46,22 +49,30 @@
298 namespace examples
299 {
300
301-class DemoRendererFactory : public compositor::RendererFactory
302+class DisplayBufferCompositorFactory : public mc::DisplayBufferCompositorFactory
303 {
304 public:
305- DemoRendererFactory(std::shared_ptr<graphics::GLProgramFactory> const& gl_program_factory) :
306- gl_program_factory(gl_program_factory)
307- {
308- }
309-
310- std::unique_ptr<compositor::Renderer> create_renderer_for(
311- geometry::Rectangle const& rect,
312- mir::compositor::DestinationAlpha dest_alpha) override
313- {
314- return std::unique_ptr<compositor::Renderer>(new DemoRenderer(*gl_program_factory, rect, dest_alpha));
315- }
316+ DisplayBufferCompositorFactory(
317+ std::shared_ptr<mc::Scene> const& scene,
318+ std::shared_ptr<mg::GLProgramFactory> const& gl_program_factory,
319+ std::shared_ptr<mc::CompositorReport> const& report) :
320+ scene(scene),
321+ gl_program_factory(gl_program_factory),
322+ report(report)
323+ {
324+ }
325+
326+ std::unique_ptr<mc::DisplayBufferCompositor> create_compositor_for(
327+ mg::DisplayBuffer& display_buffer) override
328+ {
329+ return std::unique_ptr<mc::DisplayBufferCompositor>(
330+ new me::DemoCompositor{display_buffer, scene, *gl_program_factory, report});
331+ }
332+
333 private:
334- std::shared_ptr<graphics::GLProgramFactory> const gl_program_factory;
335+ std::shared_ptr<mc::Scene> const scene;
336+ std::shared_ptr<mg::GLProgramFactory> const gl_program_factory;
337+ std::shared_ptr<mc::CompositorReport> const report;
338 };
339
340 class DemoServerConfiguration : public mir::examples::ServerConfiguration
341@@ -84,6 +95,19 @@
342 {
343 }
344
345+
346+ std::shared_ptr<compositor::DisplayBufferCompositorFactory> the_display_buffer_compositor_factory()
347+ {
348+ return display_buffer_compositor_factory(
349+ [this]()
350+ {
351+ return std::make_shared<me::DisplayBufferCompositorFactory>(
352+ the_scene(),
353+ the_gl_program_factory(),
354+ the_compositor_report());
355+ });
356+ }
357+
358 std::shared_ptr<ms::PlacementStrategy> the_placement_strategy() override
359 {
360 return shell_placement_strategy(
361@@ -105,11 +129,6 @@
362 return composite_filter;
363 }
364
365- std::shared_ptr<compositor::RendererFactory> the_renderer_factory() override
366- {
367- return std::make_shared<DemoRendererFactory>(the_gl_program_factory());
368- }
369-
370 class NestedLifecycleEventListener : public msh::HostLifecycleEventListener
371 {
372 public:
373
374=== added file 'examples/demo-shell/occlusion.cpp'
375--- examples/demo-shell/occlusion.cpp 1970-01-01 00:00:00 +0000
376+++ examples/demo-shell/occlusion.cpp 2014-07-18 18:49:52 +0000
377@@ -0,0 +1,110 @@
378+/*
379+ * Copyright © 2014 Canonical Ltd.
380+ *
381+ * This program is free software: you can redistribute it and/or modify
382+ * it under the terms of the GNU General Public License version 3 as
383+ * published by the Free Software Foundation.
384+ *
385+ * This program is distributed in the hope that it will be useful,
386+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
387+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
388+ * GNU General Public License for more details.
389+ *
390+ * You should have received a copy of the GNU General Public License
391+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
392+ *
393+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
394+ *
395+ * based on src/server/compositor/occlusion.cpp, which was:
396+ * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
397+ */
398+
399+#include <mir/graphics/renderable.h>
400+#include <mir/compositor/scene_element.h>
401+#include "occlusion.h"
402+
403+namespace me = mir::examples;
404+namespace mg = mir::graphics;
405+namespace mc = mir::compositor;
406+namespace geom = mir::geometry;
407+
408+namespace
409+{
410+bool renderable_is_occluded(
411+ mg::Renderable const& renderable,
412+ geom::Rectangle const& area,
413+ std::vector<geom::Rectangle>& coverage,
414+ int shadow_radius,
415+ int titlebar_height)
416+{
417+ static const glm::mat4 identity;
418+ if (renderable.transformation() != identity)
419+ return false; // Weirdly transformed. Assume never occluded.
420+
421+ if (!renderable.visible())
422+ return true; //invisible; definitely occluded.
423+
424+ //account for titlebar/shadows that the demo shell adds
425+ auto const& undecorated_window = renderable.screen_position();
426+ using namespace mir::geometry;
427+ geom::Rectangle decorated_window{
428+ geom::Point{
429+ undecorated_window.top_left.x,
430+ undecorated_window.top_left.y - geom::DeltaY{titlebar_height}
431+ },
432+ geom::Size{
433+ undecorated_window.size.width.as_int() + shadow_radius,
434+ undecorated_window.size.height.as_int() + shadow_radius + titlebar_height
435+ }
436+ };
437+
438+ auto const& clipped_decorated_window = decorated_window.intersection_with(area);
439+
440+ if (clipped_decorated_window == geom::Rectangle{})
441+ return true; // Not in the area; definitely occluded.
442+
443+ // Not weirdly transformed but also not on this monitor? Don't care...
444+ if (!area.overlaps(clipped_decorated_window))
445+ return true; // Not on the display; definitely occluded.
446+
447+ bool occluded = false;
448+ for (const auto &r : coverage)
449+ {
450+ if (r.contains(clipped_decorated_window))
451+ {
452+ occluded = true;
453+ break;
454+ }
455+ }
456+
457+ if (!occluded && renderable.alpha() == 1.0f && !renderable.shaped())
458+ coverage.push_back(decorated_window);
459+
460+ return occluded;
461+}
462+}
463+
464+mc::SceneElementSequence me::filter_occlusions_from(
465+ mc::SceneElementSequence& elements_list,
466+ geom::Rectangle const& area,
467+ int shadow_radius,
468+ int titlebar_height)
469+{
470+ mc::SceneElementSequence elements;
471+ std::vector<geom::Rectangle> coverage;
472+ auto it = elements_list.rbegin();
473+ while (it != elements_list.rend())
474+ {
475+ auto const renderable = (*it)->renderable();
476+ if (renderable_is_occluded(*renderable, area, coverage, shadow_radius, titlebar_height))
477+ {
478+ elements.insert(elements.begin(), *it);
479+ it = mc::SceneElementSequence::reverse_iterator(elements_list.erase(std::prev(it.base())));
480+ }
481+ else
482+ {
483+ it++;
484+ }
485+ }
486+ return elements;
487+}
488
489=== added file 'examples/demo-shell/occlusion.h'
490--- examples/demo-shell/occlusion.h 1970-01-01 00:00:00 +0000
491+++ examples/demo-shell/occlusion.h 2014-07-18 18:49:52 +0000
492@@ -0,0 +1,39 @@
493+/*
494+ * Copyright © 2014 Canonical Ltd.
495+ *
496+ * This program is free software: you can redistribute it and/or modify
497+ * it under the terms of the GNU General Public License version 3 as
498+ * published by the Free Software Foundation.
499+ *
500+ * This program is distributed in the hope that it will be useful,
501+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
502+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
503+ * GNU General Public License for more details.
504+ *
505+ * You should have received a copy of the GNU General Public License
506+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
507+ *
508+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
509+ */
510+
511+#ifndef MIR_EXAMPLES_OCCLUSION_H_
512+#define MIR_EXAMPLES_OCCLUSION_H_
513+
514+#include "mir/compositor/scene.h"
515+#include "mir/geometry/rectangle.h"
516+
517+namespace mir
518+{
519+namespace examples
520+{
521+
522+compositor::SceneElementSequence filter_occlusions_from(
523+ compositor::SceneElementSequence& list,
524+ geometry::Rectangle const& area,
525+ int shadow_radius,
526+ int titlebar_height);
527+
528+} // namespace examples
529+} // namespace mir
530+
531+#endif // MIR_EXAMPLES_OCCLUSION_H_
532
533=== modified file 'tests/unit-tests/compositor/test_occlusion.cpp'
534--- tests/unit-tests/compositor/test_occlusion.cpp 2014-07-16 03:38:05 +0000
535+++ tests/unit-tests/compositor/test_occlusion.cpp 2014-07-18 18:49:52 +0000
536@@ -18,6 +18,7 @@
537
538 #include "mir/geometry/rectangle.h"
539 #include "src/server/compositor/occlusion.h"
540+#include "examples/demo-shell/occlusion.h"
541 #include "mir_test_doubles/fake_renderable.h"
542 #include "mir_test_doubles/stub_scene_element.h"
543
544@@ -32,6 +33,49 @@
545
546 namespace
547 {
548+struct DefaultOcclusion
549+{
550+ SceneElementSequence filter(SceneElementSequence& list, Rectangle const& area)
551+ {
552+ return filter_occlusions_from(list, area);
553+ }
554+};
555+
556+struct DecoratedOcclusion
557+{
558+ SceneElementSequence filter(SceneElementSequence& list, Rectangle const& area)
559+ {
560+ return mir::examples::filter_occlusions_from(list, area, 0, 0);
561+ }
562+};
563+
564+SceneElementSequence scene_elements_from(
565+ std::vector<std::shared_ptr<mg::Renderable>> renderables)
566+{
567+ SceneElementSequence elements;
568+ for (auto const& renderable : renderables)
569+ elements.push_back(std::make_shared<mtd::StubSceneElement>(renderable));
570+
571+ return elements;
572+}
573+
574+mg::RenderableList renderables_from(SceneElementSequence const& elements)
575+{
576+ mg::RenderableList renderables;
577+ for (auto const& element : elements)
578+ renderables.push_back(element->renderable());
579+
580+ return renderables;
581+}
582+
583+template<typename T>
584+SceneElementSequence filter(SceneElementSequence& list, Rectangle const& area)
585+{
586+ T filter;
587+ return filter.filter(list, area);
588+}
589+
590+template<typename T>
591 struct OcclusionFilterTest : public Test
592 {
593 OcclusionFilterTest()
594@@ -40,42 +84,25 @@
595 monitor_rect.size = {1920, 1200};
596 }
597
598- SceneElementSequence scene_elements_from(
599- std::vector<std::shared_ptr<mg::Renderable>> renderables)
600- {
601- SceneElementSequence elements;
602- for (auto const& renderable : renderables)
603- elements.push_back(std::make_shared<mtd::StubSceneElement>(renderable));
604-
605- return elements;
606- }
607-
608- mg::RenderableList renderables_from(SceneElementSequence const& elements)
609- {
610- mg::RenderableList renderables;
611- for (auto const& element : elements)
612- renderables.push_back(element->renderable());
613-
614- return renderables;
615- }
616-
617 Rectangle monitor_rect;
618 };
619+typedef ::testing::Types<DefaultOcclusion, DecoratedOcclusion> OcclusionTypes;
620+TYPED_TEST_CASE(OcclusionFilterTest, OcclusionTypes);
621
622 }
623
624-TEST_F(OcclusionFilterTest, single_window_not_occluded)
625+TYPED_TEST(OcclusionFilterTest, single_window_not_occluded)
626 {
627 auto window = std::make_shared<mtd::FakeRenderable>(12, 34, 56, 78);
628 auto elements = scene_elements_from({window});
629-
630- auto const& occlusions = filter_occlusions_from(elements, monitor_rect);
631+
632+ auto const& occlusions = filter<TypeParam>(elements, this->monitor_rect);
633
634 EXPECT_THAT(renderables_from(occlusions), IsEmpty());
635 EXPECT_THAT(renderables_from(elements), ElementsAre(window));
636 }
637
638-TEST_F(OcclusionFilterTest, partially_offscreen_still_visible)
639+TYPED_TEST(OcclusionFilterTest, partially_offscreen_still_visible)
640 { // Regression test for LP: #1301115
641 auto left = std::make_shared<mtd::FakeRenderable>(-10, 10, 100, 100);
642 auto right = std::make_shared<mtd::FakeRenderable>(1900, 10, 100, 100);
643@@ -83,96 +110,96 @@
644 auto bottom = std::make_shared<mtd::FakeRenderable>(200, 1000, 100, 1000);
645 auto elements = scene_elements_from({left, right, top, bottom});
646
647- auto const& occlusions = filter_occlusions_from(elements, monitor_rect);
648+ auto const& occlusions = filter<TypeParam>(elements, this->monitor_rect);
649
650 EXPECT_THAT(renderables_from(occlusions), IsEmpty());
651 EXPECT_THAT(renderables_from(elements), ElementsAre(left, right, top, bottom));
652 }
653
654-TEST_F(OcclusionFilterTest, smaller_window_occluded)
655+TYPED_TEST(OcclusionFilterTest, smaller_window_occluded)
656 {
657 auto top = std::make_shared<mtd::FakeRenderable>(10, 10, 10, 10);
658 auto bottom = std::make_shared<mtd::FakeRenderable>(12, 12, 5, 5);
659 auto elements = scene_elements_from({bottom, top});
660
661- auto const& occlusions = filter_occlusions_from(elements, monitor_rect);
662+ auto const& occlusions = filter<TypeParam>(elements, this->monitor_rect);
663
664 EXPECT_THAT(renderables_from(occlusions), ElementsAre(bottom));
665 EXPECT_THAT(renderables_from(elements), ElementsAre(top));
666 }
667
668-TEST_F(OcclusionFilterTest, translucent_window_occludes_nothing)
669+TYPED_TEST(OcclusionFilterTest, translucent_window_occludes_nothing)
670 {
671 auto top = std::make_shared<mtd::FakeRenderable>(Rectangle{{10, 10}, {10, 10}}, 0.5f);
672 auto bottom = std::make_shared<mtd::FakeRenderable>(Rectangle{{12, 12}, {5, 5}}, 1.0f);
673 auto elements = scene_elements_from({bottom, top});
674
675- auto const& occlusions = filter_occlusions_from(elements, monitor_rect);
676+ auto const& occlusions = filter<TypeParam>(elements, this->monitor_rect);
677
678 EXPECT_THAT(renderables_from(occlusions), IsEmpty());
679 EXPECT_THAT(renderables_from(elements), ElementsAre(bottom, top));
680 }
681
682-TEST_F(OcclusionFilterTest, hidden_window_is_self_occluded)
683+TYPED_TEST(OcclusionFilterTest, hidden_window_is_self_occluded)
684 {
685 auto window = std::make_shared<mtd::FakeRenderable>(Rectangle{{10, 10}, {10, 10}}, 1.0f, true, false);
686 auto elements = scene_elements_from({window});
687
688- auto const& occlusions = filter_occlusions_from(elements, monitor_rect);
689+ auto const& occlusions = filter<TypeParam>(elements, this->monitor_rect);
690
691 EXPECT_THAT(renderables_from(occlusions), ElementsAre(window));
692 EXPECT_THAT(renderables_from(elements), IsEmpty());
693 }
694
695-TEST_F(OcclusionFilterTest, hidden_window_occludes_nothing)
696+TYPED_TEST(OcclusionFilterTest, hidden_window_occludes_nothing)
697 {
698 auto top = std::make_shared<mtd::FakeRenderable>(Rectangle{{10, 10}, {10, 10}}, 1.0f, true, false);
699 auto bottom = std::make_shared<mtd::FakeRenderable>(12, 12, 5, 5);
700 auto elements = scene_elements_from({bottom, top});
701
702- auto const& occlusions = filter_occlusions_from(elements, monitor_rect);
703+ auto const& occlusions = filter<TypeParam>(elements, this->monitor_rect);
704
705 EXPECT_THAT(renderables_from(occlusions), ElementsAre(top));
706 EXPECT_THAT(renderables_from(elements), ElementsAre(bottom));
707 }
708
709-TEST_F(OcclusionFilterTest, shaped_window_occludes_nothing)
710+TYPED_TEST(OcclusionFilterTest, shaped_window_occludes_nothing)
711 {
712 auto top = std::make_shared<mtd::FakeRenderable>(Rectangle{{10, 10}, {10, 10}}, 1.0f, false, true);
713 auto bottom = std::make_shared<mtd::FakeRenderable>(12, 12, 5, 5);
714 auto elements = scene_elements_from({bottom, top});
715
716- auto const& occlusions = filter_occlusions_from(elements, monitor_rect);
717+ auto const& occlusions = filter<TypeParam>(elements, this->monitor_rect);
718
719 EXPECT_THAT(renderables_from(occlusions), IsEmpty());
720 EXPECT_THAT(renderables_from(elements), ElementsAre(bottom, top));
721 }
722
723-TEST_F(OcclusionFilterTest, identical_window_occluded)
724+TYPED_TEST(OcclusionFilterTest, identical_window_occluded)
725 {
726 auto top = std::make_shared<mtd::FakeRenderable>(10, 10, 10, 10);
727 auto bottom = std::make_shared<mtd::FakeRenderable>(10, 10, 10, 10);
728 auto elements = scene_elements_from({bottom, top});
729
730- auto const& occlusions = filter_occlusions_from(elements, monitor_rect);
731+ auto const& occlusions = filter<TypeParam>(elements, this->monitor_rect);
732
733 EXPECT_THAT(renderables_from(occlusions), ElementsAre(bottom));
734 EXPECT_THAT(renderables_from(elements), ElementsAre(top));
735 }
736
737-TEST_F(OcclusionFilterTest, larger_window_never_occluded)
738+TYPED_TEST(OcclusionFilterTest, larger_window_never_occluded)
739 {
740 auto top = std::make_shared<mtd::FakeRenderable>(10, 10, 10, 10);
741 auto bottom = std::make_shared<mtd::FakeRenderable>(9, 9, 12, 12);
742 auto elements = scene_elements_from({bottom, top});
743
744- auto const& occlusions = filter_occlusions_from(elements, monitor_rect);
745+ auto const& occlusions = filter<TypeParam>(elements, this->monitor_rect);
746
747 EXPECT_THAT(renderables_from(occlusions), IsEmpty());
748 EXPECT_THAT(renderables_from(elements), ElementsAre(bottom, top));
749 }
750
751-TEST_F(OcclusionFilterTest, cascaded_windows_never_occluded)
752+TYPED_TEST(OcclusionFilterTest, cascaded_windows_never_occluded)
753 {
754 std::vector<std::shared_ptr<mg::Renderable>> renderables;
755 unsigned int const num_windows{10u};
756@@ -181,13 +208,13 @@
757
758 auto elements = scene_elements_from(renderables);
759
760- auto const& occlusions = filter_occlusions_from(elements, monitor_rect);
761+ auto const& occlusions = filter<TypeParam>(elements, this->monitor_rect);
762
763 EXPECT_THAT(renderables_from(occlusions), IsEmpty());
764 EXPECT_THAT(renderables_from(elements), ElementsAreArray(renderables));
765 }
766
767-TEST_F(OcclusionFilterTest, some_occluded_and_some_not)
768+TYPED_TEST(OcclusionFilterTest, some_occluded_and_some_not)
769 {
770 auto window0 = std::make_shared<mtd::FakeRenderable>(10, 20, 400, 300);
771 auto window1 = std::make_shared<mtd::FakeRenderable>(10, 20, 5, 5);
772@@ -204,13 +231,13 @@
773 window0 //not occluded
774 });
775
776- auto const& occlusions = filter_occlusions_from(elements, monitor_rect);
777+ auto const& occlusions = filter<TypeParam>(elements, this->monitor_rect);
778
779 EXPECT_THAT(renderables_from(occlusions), ElementsAre(window3, window2, window1));
780 EXPECT_THAT(renderables_from(elements), ElementsAre(window5, window4, window0));
781 }
782
783-TEST_F(OcclusionFilterTest,
784+TYPED_TEST(OcclusionFilterTest,
785 occludes_partially_onscreen_window_when_onscreen_part_is_covered_by_another_window)
786 {
787 auto const partially_onscreen = std::make_shared<mtd::FakeRenderable>(-50, 100, 150, 100);
788@@ -220,8 +247,29 @@
789 covering
790 });
791
792- auto const& occlusions = filter_occlusions_from(elements, monitor_rect);
793+ auto const& occlusions = filter<TypeParam>(elements, this->monitor_rect);
794
795 EXPECT_THAT(renderables_from(occlusions), ElementsAre(partially_onscreen));
796 EXPECT_THAT(renderables_from(elements), ElementsAre(covering));
797 }
798+
799+//example compositor
800+TEST(DecoratedOcclusionFilter, accounts_for_decorations_while_filtering) //lp: 1299977
801+{
802+ Rectangle monitor_rect{{0,0},{100, 100}};
803+ auto window0 = std::make_shared<mtd::FakeRenderable>(0, 100, 10, 10);
804+ auto window1 = std::make_shared<mtd::FakeRenderable>(-5, -5, 5, 5);
805+ auto window2 = std::make_shared<mtd::FakeRenderable>(0, 30, 1, 1);
806+ auto window3 = std::make_shared<mtd::FakeRenderable>(0, 30, 15, 15);
807+ auto elements = scene_elements_from({
808+ window0, //surface offscreen, but titlebar should still appear
809+ window1, //surface offscreen, but shadow should still appear
810+ window2, //occluded
811+ window3, //not occluded
812+ });
813+
814+ auto const& occlusions = mir::examples::filter_occlusions_from(elements, monitor_rect, 10, 20);
815+
816+ EXPECT_THAT(renderables_from(occlusions), ElementsAre(window2));
817+ EXPECT_THAT(renderables_from(elements), ElementsAre(window0, window1, window3));
818+}

Subscribers

People subscribed via source and target branches