Mir

Merge lp:~vanvugt/mir/unocclude into lp:mir

Proposed by Daniel van Vugt
Status: Rejected
Rejected by: Daniel van Vugt
Proposed branch: lp:~vanvugt/mir/unocclude
Merge into: lp:mir
Diff against target: 512 lines (+6/-391)
8 files modified
src/server/compositor/CMakeLists.txt (+0/-1)
src/server/compositor/default_display_buffer_compositor.cpp (+0/-2)
src/server/compositor/occlusion.cpp (+0/-78)
src/server/compositor/occlusion.h (+0/-37)
tests/integration-tests/test_surface_first_frame_sync.cpp (+2/-2)
tests/unit-tests/compositor/CMakeLists.txt (+0/-1)
tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp (+4/-68)
tests/unit-tests/compositor/test_occlusion.cpp (+0/-202)
To merge this branch: bzr merge lp:~vanvugt/mir/unocclude
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Kevin DuBois (community) Abstain
Robert Carr (community) Disapprove
Andreas Pokorny (community) Needs Fixing
Alberto Aguirre (community) Disapprove
Mir development team Pending
Review via email: mp+216690@code.launchpad.net

Commit message

Delete the occlusion detection logic. It was never used where it was needed
(on mobile platforms) since platform-api never got fixed. It's also
fundamentally incompatible with the new goals of never blocking clients.
Then again, what we lose in performance we gain in simplicity.

To post a comment you must log in.
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

I thought I needed this as a prerequisite to another fix I have in progress but now am not sure. Still, it's worth discussing.

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

my thoughts:

pros:
* The occlusion detection made it difficult to unify the compositor's behavior around consuming buffers, which in turn made it unclear what the SwitchingBundle's responsibilities were. Consuming every buffer on a compositor pass makes it easier to get the switching logic right, and is at least a consistent requirement for a compositor writer.
* It does seem at odds to try to not consume a buffer, and never block a client.

cons:
* occlusion detection is valuable in reducing workload for the compositor (texture uploads)
* an obscured, visible client that can submit frames fast enough can keep the compositor recompositing the same pixels because of the 'uncomposited_buffers' logic.
* loosing the logic puts us in a worse position if we're ever told to send 'occluded' messages to the client. (although this is a weak point due to YAGNI)

I am interested in what never got fixed in platform-api that made this code unused though.
An alternative compromise between the pros and cons could be to consume the buffer from all surfaces (unifying the behavior of the compositors/BufferBundle), and not calling render() on the occluded surfaces. This would also mean fixing whatever is broken in platform-api?

I think that the benefits of doing this now outweigh the cost, especially as we refine the SurfaceStack/Compositor relationship. I guess I'll 'approve', but am still interested in other's thoughts, so lets not top-approve until a bit more discussion happens.

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

" loosing the logic puts us in a worse position if we're ever told to send 'occluded' messages to the client."

We already have that need. It should go hand-in-hand with the non-blocking swap behavior IMHO.

Clients need to know when their surfaces are no longer visible so they can stop their rendering loop - this is either from having a surface that is no longer visible in any display or from true occlusion.
In the Unity8 case this is currently being handled by the app lifecycle since we don't currently produce those events.

Anpok has a branch in papi that would benefit from the occlusion logic:
https://code.launchpad.net/~andreas-pokorny/platform-api/opaque_by_default/+merge/205259
We should still push through to get that branch merged.

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

> " loosing the logic puts us in a worse position if we're ever told to send
> 'occluded' messages to the client."
>
> We already have that need. It should go hand-in-hand with the non-blocking
> swap behavior IMHO.
>
> Clients need to know when their surfaces are no longer visible so they can
> stop their rendering loop - this is either from having a surface that is no
> longer visible in any display or from true occlusion.
> In the Unity8 case this is currently being handled by the app lifecycle since
> we don't currently produce those events.

Yeah, but where the occlusion code is now is not in a good position to notify clients. Compositors should not have the job of notifying clients of their decisions, the clients should get notifications based on things going on with their associated ms::BasicSurface.

This pushes me to think we have to shift occlusion detection to SurfaceStack, as it seems the common place this could be done. The compositors sure have to have a role in submitting what sort of occlusion they should do, but I don't want the compositors slowed down by having to send IPC events.

Now of course, this is tricky, because we could have multiple compositors, but I think can be done as the SurfaceStack gets a bit smarter about what compositors are viewing the SurfaceStack.

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

> This pushes me to think we have to shift occlusion detection to SurfaceStack,
> as it seems the common place this could be done. The compositors sure have to
> have a role in submitting what sort of occlusion they should do, but I don't
> want the compositors slowed down by having to send IPC events.
>
> Now of course, this is tricky, because we could have multiple compositors, but
> I think can be done as the SurfaceStack gets a bit smarter about what
> compositors are viewing the SurfaceStack.

+1
scene just needs to gain knowledge about the existing outputs. Their position within
the scene - the camera parameters. Those information could also be used to limit compositor
thread wakeups. Additionally that information is necessary to properly dispatch user input
within 3D shells.

We can solve the issue with decoration increasing the size of surfaces in a different way.
Treat decorations and window shadows as separate scene elements with a separate position
and size, that the shell adds to the scene..
Or maybe simpler: Extend the scenes occlusion logic with a filter-filter that filters out
false positives.
  as a graphical effect that extend the size of surfaces, which

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

I think you're planning for the wrong approach. The renderer should never feed back directly to the client as it's just a /view/. The renderer shall never communicate with clients in any way. Instead we should indirectly observe that a client's become occluded. This is easy using BufferConsumingFunctor which observes physical frame completion - if and when lp:~vanvugt/mir/judder lands.

Occlusion detection is designed to block clients that are not visible. That's it's purpose. If we're serious about making things non-blocking then it makes no sense to keep it as it only gets in the way (as mentioned here: https://code.launchpad.net/~vanvugt/mir/judder/+merge/216694)

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

> I think you're planning for the wrong approach. The renderer should never feed
> back directly to the client as it's just a /view/. The renderer shall never
> communicate with clients in any way. Instead we should indirectly observe that
> a client's become occluded. This is easy using BufferConsumingFunctor which
> observes physical frame completion - if and when lp:~vanvugt/mir/judder lands.

Hmm where did somebody indicate that the renderer should feed back to the clients?

> Occlusion detection is designed to block clients that are not visible. That's
> it's purpose. If we're serious about making things non-blocking then it makes
> no sense to keep it as it only gets in the way (as mentioned here:
> https://code.launchpad.net/~vanvugt/mir/judder/+merge/216694)

It also helps avoid unnecessary overdraw.

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

> > I think you're planning for the wrong approach. The renderer should never
> feed
> > back directly to the client as it's just a /view/. The renderer shall never
> > communicate with clients in any way. Instead we should indirectly observe
> that
> > a client's become occluded. This is easy using BufferConsumingFunctor which
> > observes physical frame completion - if and when lp:~vanvugt/mir/judder
> lands.
>
> Hmm where did somebody indicate that the renderer should feed back to the
> clients?

"Compositors should not have the job of notifying clients of their decisions, the clients should get notifications based on things going on with their associated ms::BasicSurface."

Yes, it seems like the thing we agree upon is that nothing in the compositor system (GLRenderer, DefaultDisplayBufferCompositor, MultiThreadedCompositor) should do notifications of occlusion.

The big objection seems to be the future needs of other parts of the system noted by Alberto and Andreas and the loss of the logic by its removal.

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

Hey I don't mind occlusion logic staying, but it is contradictory to non-blocking efforts. Choose one or the other.

I built the occlusion detection logic to block occluded clients. Its purpose is to block occluded clients from rendering, per bug 1227739. And it does that well.

If you choose both to have occlusion detection and non-blocking then you also require extra work (in pending proposals) to make them play together. Because the occlusion detection is only doing its job in blocking client rendering.

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

>> > Occlusion detection is designed to block clients that are not visible. That's
>> > it's purpose. If we're serious about making things non-blocking then it makes
>> > no sense to keep it as it only gets in the way (as mentioned here:
>> > https://code.launchpad.net/~vanvugt/mir/judder/+merge/216694)

Occlusion detection can also be used to prevent overdraw. Clearly whether buffers are returned to the client is a different question than whether buffers are part of the composition pass.

This isn't so different than for example an XRender client under Compiz...client rendering isnt blocked by compositor consumption at all (at least not in the serial queue frame consumption style we have)! Still Compiz will choose to not paint occluded windows. We improve this model by enforcing synchronization while clients are painted on screen, and are free to break this lockstep synchronization guarantee when clients are not rendered.

>> Hey I don't mind occlusion logic staying, but it is contradictory to non-blocking efforts. Choose one or
>> the other.

Not if you allow framedropping for unrendered surfaces.

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

Heh. I'm not bothered either way. In fact, rather amused that other people are defending my code against deletion from myself.

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

I'm still for having the occlusion algorithm as something that's set by the compositing system, but if notifications are to go out about occluded surfaces, that should be something sent from the Scene system, not the compositor. Anyways, given the review comments, it seems that this will be explored differently, so abstain.

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

> I'm still for having the occlusion algorithm as something that's set by the
> compositing system, but if notifications are to go out about occluded
> surfaces, that should be something sent from the Scene system, not the
> compositor. Anyways, given the review comments, it seems that this will be
> explored differently, so abstain.

And that's ok, but until we actually have that alternative -whatever it is - it doesn't make sense to remove functionality until then.

lp:~vanvugt/mir/unocclude updated
1569. By Daniel van Vugt

Merge latest development-branch

1570. By Daniel van Vugt

Merge latest development-branch

1571. By Daniel van Vugt

Merge latest development-branch

1572. By Daniel van Vugt

Merge latest development-branch

1573. By Daniel van Vugt

Merge latest development-branch

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

I'm not entirely sure now how much benefit occlusion detection could provide in the non-blocking world. You lose the benefit of limiting client CPU/GPU usage because you have to force unblocking of clients under the new model.

There's only one benefit remaining. That is to reduce the number of renderables that get thrown at the renderer. But OpenGL has always, by design, optimized out offscreen textures and geometry anyway. So that just gives you one obscure uncommon benefit: A small renderable hidden behind a larger one does not get its texture uploaded on that frame. However this benefit only applies to software surfaces where there is an actual "upload", and is irrelevant if the foreground is fullscreen because that's already optimized by bypass. The benefit of occlusion detection in the non-blocking world seems negligible.

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

Also, when you throw decorations into the mix the current occlusion detection is wrong and buggy (like bug 1299977). With decorations you need even more complicated occlusion detection such that you only test if the client area of the foreground window fully occludes the decorated window frame of the background window.

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

 A small renderable hidden behind a larger one
> does not get its texture uploaded on that frame. However this benefit only
> applies to software surfaces where there is an actual "upload", and is
> irrelevant if the foreground is fullscreen because that's already optimized by
> bypass. The benefit of occlusion detection in the non-blocking world seems
> negligible.

A "small" renderable could be simply one pixel less in width and height than the one that occludes it, which could be 2559x1599 in a nexus 10 for example.
It used to be that qualcomm chipsets were all direct rendering implementations, so it WOULD read that texture since we are drawing back to front. Now it seems it can switch between direct and deferred rendering so maybe it's smart enough not to do that anymore.
The Nexus 10 Mali does tile-based deferred rendering (as does the PowerVR stuff) so I suspect it's not a huge impact there either.

You could also get the additional hit of programming the GPU MMU - some architectures will lazily do that (i.e. they will not "upload" program the mmu until a draw command references it).

But we are both speculating - I would like to see some evidence that the occlusion optimization is negligible.

lp:~vanvugt/mir/unocclude updated
1574. By Daniel van Vugt

Merge latest development-branch and fix conflicts

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

I wrote the texture cache logic in GLRenderer, so I know it behaves the same on any platform and that's not speculation.

The remaining point is whether uploading unused vertices is negligible for the number of surfaces on a desktop. I would argue after a while working on Compiz I got a good idea that yes, it is negligible. So that's a strongly educated guess rather than speculation.

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

Hmm, actually the texture cache isn't relevant because it would be invalidated on frames that are important here. Yes I'm speculating then because the performance hit is now GPU-specific.

Another speculation is that performing occlusion tests at all is fast enough to justify the effort. That's an assumption made in Mir right now. But I know from previous work it doesn't always hold true.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~vanvugt/mir/unocclude updated
1575. By Daniel van Vugt

Merge latest development-branch

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~vanvugt/mir/unocclude updated
1576. By Daniel van Vugt

Merge latest development-branch

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~vanvugt/mir/unocclude updated
1577. By Daniel van Vugt

Merge latest development-branch and fix conflicts

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

Unmerged revisions

1577. By Daniel van Vugt

Merge latest development-branch and fix conflicts

1576. By Daniel van Vugt

Merge latest development-branch

1575. By Daniel van Vugt

Merge latest development-branch

1574. By Daniel van Vugt

Merge latest development-branch and fix conflicts

1573. By Daniel van Vugt

Merge latest development-branch

1572. By Daniel van Vugt

Merge latest development-branch

1571. By Daniel van Vugt

Merge latest development-branch

1570. By Daniel van Vugt

Merge latest development-branch

1569. By Daniel van Vugt

Merge latest development-branch

1568. By Daniel van Vugt

First attempt at removing occlusion detection

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/server/compositor/CMakeLists.txt'
2--- src/server/compositor/CMakeLists.txt 2014-04-27 21:11:15 +0000
3+++ src/server/compositor/CMakeLists.txt 2014-05-06 03:00:37 +0000
4@@ -10,7 +10,6 @@
5 gl_renderer_factory.cpp
6 multi_threaded_compositor.cpp
7 bypass.cpp
8- occlusion.cpp
9 default_configuration.cpp
10 screencast_display_buffer.cpp
11 compositing_screencast.cpp
12
13=== modified file 'src/server/compositor/default_display_buffer_compositor.cpp'
14--- src/server/compositor/default_display_buffer_compositor.cpp 2014-05-05 05:43:02 +0000
15+++ src/server/compositor/default_display_buffer_compositor.cpp 2014-05-06 03:00:37 +0000
16@@ -26,7 +26,6 @@
17 #include "mir/graphics/buffer.h"
18 #include "mir/compositor/buffer_stream.h"
19 #include "bypass.h"
20-#include "occlusion.h"
21 #include <mutex>
22 #include <cstdlib>
23 #include <algorithm>
24@@ -55,7 +54,6 @@
25
26 auto const& view_area = display_buffer.view_area();
27 auto renderable_list = scene->renderable_list_for(this);
28- mc::filter_occlusions_from(renderable_list, view_area);
29
30 //TODO: the DisplayBufferCompositor should not have to figure out if it has to force
31 // a subsequent compositon. The MultiThreadedCompositor should be smart enough to
32
33=== removed file 'src/server/compositor/occlusion.cpp'
34--- src/server/compositor/occlusion.cpp 2014-04-17 01:34:35 +0000
35+++ src/server/compositor/occlusion.cpp 1970-01-01 00:00:00 +0000
36@@ -1,78 +0,0 @@
37-/*
38- * Copyright © 2013 Canonical Ltd.
39- *
40- * This program is free software: you can redistribute it and/or modify it
41- * under the terms of the GNU General Public License version 3,
42- * as 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: Daniel van Vugt <daniel.van.vugt@canonical.com>
53- */
54-
55-#include "mir/geometry/rectangle.h"
56-#include "mir/graphics/renderable.h"
57-#include "occlusion.h"
58-
59-using namespace mir::geometry;
60-using namespace mir::graphics;
61-
62-namespace
63-{
64-bool renderable_is_occluded(
65- Renderable const& renderable,
66- Rectangle const& area,
67- std::vector<Rectangle>& coverage)
68-{
69- static const glm::mat4 identity;
70- if (renderable.transformation() != identity)
71- return false; // Weirdly transformed. Assume never occluded.
72-
73- //TODO: remove this check, why are we getting a non visible renderable
74- // in the list of surfaces?
75- // This will check the surface is not hidden and has been posted.
76- if (!renderable.visible())
77- return true; //invisible; definitely occluded.
78-
79- // Not weirdly transformed but also not on this monitor? Don't care...
80- if (!area.overlaps(renderable.screen_position()))
81- return true; // Not on the display; definitely occluded.
82-
83- bool occluded = false;
84- Rectangle const& window = renderable.screen_position();
85- for (const auto &r : coverage)
86- {
87- if (r.contains(window))
88- {
89- occluded = true;
90- break;
91- }
92- }
93-
94- if (!occluded && renderable.alpha() == 1.0f && !renderable.shaped())
95- coverage.push_back(window);
96-
97- return occluded;
98-}
99-}
100-
101-void mir::compositor::filter_occlusions_from(
102- RenderableList& list,
103- Rectangle const& area)
104-{
105- std::vector<Rectangle> coverage;
106- auto it = list.rbegin();
107- while (it != list.rend())
108- {
109- if (renderable_is_occluded(**it, area, coverage))
110- list.erase(std::prev(it.base()));
111- else
112- it++;
113- }
114-}
115
116=== removed file 'src/server/compositor/occlusion.h'
117--- src/server/compositor/occlusion.h 2014-03-26 16:59:32 +0000
118+++ src/server/compositor/occlusion.h 1970-01-01 00:00:00 +0000
119@@ -1,37 +0,0 @@
120-/*
121- * Copyright © 2013 Canonical Ltd.
122- *
123- * This program is free software: you can redistribute it and/or modify it
124- * under the terms of the GNU General Public License version 3,
125- * as published by the Free Software Foundation.
126- *
127- * This program is distributed in the hope that it will be useful,
128- * but WITHOUT ANY WARRANTY; without even the implied warranty of
129- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
130- * GNU General Public License for more details.
131- *
132- * You should have received a copy of the GNU General Public License
133- * along with this program. If not, see <http://www.gnu.org/licenses/>.
134- *
135- * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
136- */
137-
138-#ifndef MIR_COMPOSITOR_OCCLUSION_H_
139-#define MIR_COMPOSITOR_OCCLUSION_H_
140-
141-#include "mir/graphics/renderable.h"
142-#include "mir/compositor/scene.h"
143-#include <vector>
144-#include <set>
145-
146-namespace mir
147-{
148-namespace compositor
149-{
150-
151-void filter_occlusions_from(graphics::RenderableList& list, geometry::Rectangle const& area);
152-
153-} // namespace compositor
154-} // namespace mir
155-
156-#endif // MIR_COMPOSITOR_OCCLUSION_H_
157
158=== modified file 'tests/integration-tests/test_surface_first_frame_sync.cpp'
159--- tests/integration-tests/test_surface_first_frame_sync.cpp 2014-05-05 05:43:02 +0000
160+++ tests/integration-tests/test_surface_first_frame_sync.cpp 2014-05-06 03:00:37 +0000
161@@ -105,8 +105,8 @@
162 {
163 for (auto const& r : renderables)
164 {
165- (void)r;
166- while (write(render_operations_fd, "a", 1) != 1) continue;
167+ if (r->visible())
168+ while (write(render_operations_fd, "a", 1) != 1) continue;
169 }
170 }
171
172
173=== modified file 'tests/unit-tests/compositor/CMakeLists.txt'
174--- tests/unit-tests/compositor/CMakeLists.txt 2014-04-21 15:56:41 +0000
175+++ tests/unit-tests/compositor/CMakeLists.txt 2014-05-06 03:00:37 +0000
176@@ -6,7 +6,6 @@
177 ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_queue.cpp
178 ${CMAKE_CURRENT_SOURCE_DIR}/test_gl_renderer.cpp
179 ${CMAKE_CURRENT_SOURCE_DIR}/test_bypass.cpp
180- ${CMAKE_CURRENT_SOURCE_DIR}/test_occlusion.cpp
181 ${CMAKE_CURRENT_SOURCE_DIR}/test_screencast_display_buffer.cpp
182 ${CMAKE_CURRENT_SOURCE_DIR}/test_compositing_screencast.cpp
183 )
184
185=== modified file 'tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp'
186--- tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp 2014-05-05 05:43:02 +0000
187+++ tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp 2014-05-06 03:00:37 +0000
188@@ -128,66 +128,6 @@
189 compositor.composite();
190 }
191
192-TEST_F(DefaultDisplayBufferCompositor, skips_scene_that_should_not_be_rendered)
193-{
194- using namespace testing;
195-
196- mtd::StubDisplayBuffer display_buffer{geom::Rectangle{{0,0},{14,14}}};
197- auto mock_renderable1 = std::make_shared<NiceMock<mtd::MockRenderable>>();
198- auto mock_renderable2 = std::make_shared<NiceMock<mtd::MockRenderable>>();
199- auto mock_renderable3 = std::make_shared<NiceMock<mtd::MockRenderable>>();
200-
201- glm::mat4 simple;
202- EXPECT_CALL(*mock_renderable1, transformation())
203- .WillOnce(Return(simple));
204- EXPECT_CALL(*mock_renderable2, transformation())
205- .WillOnce(Return(simple));
206- EXPECT_CALL(*mock_renderable3, transformation())
207- .WillOnce(Return(simple));
208-
209- EXPECT_CALL(*mock_renderable1, visible())
210- .WillRepeatedly(Return(true));
211- EXPECT_CALL(*mock_renderable2, visible())
212- .WillRepeatedly(Return(false));
213- EXPECT_CALL(*mock_renderable3, visible())
214- .WillRepeatedly(Return(true));
215-
216- EXPECT_CALL(*mock_renderable1, alpha())
217- .WillOnce(Return(1.0f));
218- EXPECT_CALL(*mock_renderable3, alpha())
219- .WillOnce(Return(1.0f));
220-
221- EXPECT_CALL(*mock_renderable1, shaped())
222- .WillOnce(Return(false));
223- EXPECT_CALL(*mock_renderable3, shaped())
224- .WillOnce(Return(false));
225-
226- EXPECT_CALL(*mock_renderable1, screen_position())
227- .WillRepeatedly(Return(geom::Rectangle{{1,2}, {3,4}}));
228- EXPECT_CALL(*mock_renderable2, screen_position())
229- .WillRepeatedly(Return(geom::Rectangle{{1,2}, {3,4}}));
230- EXPECT_CALL(*mock_renderable3, screen_position())
231- .WillRepeatedly(Return(geom::Rectangle{{5,6}, {7,8}}));
232-
233- mg::RenderableList list{
234- mock_renderable1,
235- mock_renderable2,
236- mock_renderable3
237- };
238- FakeScene scene(list);
239-
240- mg::RenderableList const visible{mock_renderable1, mock_renderable3};
241- EXPECT_CALL(mock_renderer, render(visible))
242- .Times(1);
243-
244- mc::DefaultDisplayBufferCompositor compositor(
245- display_buffer,
246- mt::fake_shared(scene),
247- mt::fake_shared(mock_renderer),
248- mr::null_compositor_report());
249- compositor.composite();
250-}
251-
252 TEST_F(DefaultDisplayBufferCompositor, bypass_skips_composition)
253 {
254 using namespace testing;
255@@ -304,8 +244,6 @@
256 };
257 FakeScene scene(list);
258
259- mg::RenderableList const visible{fullscreen};
260-
261 EXPECT_CALL(display_buffer, view_area())
262 .WillRepeatedly(Return(screen));
263 EXPECT_CALL(display_buffer, make_current())
264@@ -316,7 +254,7 @@
265 .Times(1);
266 EXPECT_CALL(display_buffer, can_bypass())
267 .WillRepeatedly(Return(false));
268- EXPECT_CALL(mock_renderer, render(visible))
269+ EXPECT_CALL(mock_renderer, render(list))
270 .Times(1);
271
272 mc::DefaultDisplayBufferCompositor compositor(
273@@ -348,8 +286,7 @@
274 };
275 FakeScene scene(list);
276
277- mg::RenderableList const visible{fullscreen};
278- EXPECT_CALL(mock_renderer, render(visible))
279+ EXPECT_CALL(mock_renderer, render(list))
280 .Times(1);
281
282 auto nonbypassable = std::make_shared<mtd::MockBuffer>();
283@@ -437,7 +374,7 @@
284 fullscreen->set_buffer({}); // Avoid GMock complaining about false leaks
285 }
286
287-TEST_F(DefaultDisplayBufferCompositor, occluded_surfaces_are_not_rendered)
288+TEST_F(DefaultDisplayBufferCompositor, occluded_surfaces_are_rendered_too)
289 {
290 using namespace testing;
291 EXPECT_CALL(display_buffer, view_area())
292@@ -462,12 +399,11 @@
293 });
294 FakeScene scene(list);
295
296- mg::RenderableList const visible{window0, window3};
297
298 Sequence seq;
299 EXPECT_CALL(display_buffer, make_current())
300 .InSequence(seq);
301- EXPECT_CALL(mock_renderer, render(visible))
302+ EXPECT_CALL(mock_renderer, render(list))
303 .InSequence(seq);
304 EXPECT_CALL(display_buffer, post_update())
305 .InSequence(seq);
306
307=== removed file 'tests/unit-tests/compositor/test_occlusion.cpp'
308--- tests/unit-tests/compositor/test_occlusion.cpp 2014-04-02 03:10:06 +0000
309+++ tests/unit-tests/compositor/test_occlusion.cpp 1970-01-01 00:00:00 +0000
310@@ -1,202 +0,0 @@
311-/*
312- * Copyright © 2013 Canonical Ltd.
313- *
314- * This program is free software: you can redistribute it and/or modify
315- * it under the terms of the GNU General Public License version 3 as
316- * published by the Free Software Foundation.
317- *
318- * This program is distributed in the hope that it will be useful,
319- * but WITHOUT ANY WARRANTY; without even the implied warranty of
320- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
321- * GNU General Public License for more details.
322- *
323- * You should have received a copy of the GNU General Public License
324- * along with this program. If not, see <http://www.gnu.org/licenses/>.
325- *
326- * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
327- */
328-
329-#include "mir/geometry/rectangle.h"
330-#include "src/server/compositor/occlusion.h"
331-#include "mir_test_doubles/fake_renderable.h"
332-
333-#include <gtest/gtest.h>
334-#include <memory>
335-
336-using namespace testing;
337-using namespace mir::geometry;
338-using namespace mir::compositor;
339-namespace mg = mir::graphics;
340-namespace mtd = mir::test::doubles;
341-
342-struct OcclusionFilterTest : public Test
343-{
344- OcclusionFilterTest()
345- {
346- monitor_rect.top_left = {0, 0};
347- monitor_rect.size = {1920, 1200};
348- }
349-
350- Rectangle monitor_rect;
351-};
352-
353-TEST_F(OcclusionFilterTest, single_window_not_occluded)
354-{
355- auto window = std::make_shared<mtd::FakeRenderable>(12, 34, 56, 78);
356- mg::RenderableList list{window};
357-
358- filter_occlusions_from(list, monitor_rect);
359- ASSERT_EQ(1u, list.size());
360- EXPECT_EQ(window, list.front());
361-}
362-
363-TEST_F(OcclusionFilterTest, partially_offscreen_still_visible)
364-{ // Regression test for LP: #1301115
365- auto left = std::make_shared<mtd::FakeRenderable>(-10, 10, 100, 100);
366- auto right = std::make_shared<mtd::FakeRenderable>(1900, 10, 100, 100);
367- auto top = std::make_shared<mtd::FakeRenderable>(500, -1, 100, 100);
368- auto bottom = std::make_shared<mtd::FakeRenderable>(200, 1000, 100, 1000);
369- mg::RenderableList list{left, right, top, bottom};
370-
371- filter_occlusions_from(list, monitor_rect);
372- EXPECT_EQ(4u, list.size());
373-}
374-
375-TEST_F(OcclusionFilterTest, smaller_window_occluded)
376-{
377- auto top = std::make_shared<mtd::FakeRenderable>(10, 10, 10, 10);
378- auto bottom = std::make_shared<mtd::FakeRenderable>(12, 12, 5, 5);
379- mg::RenderableList list{bottom, top};
380-
381- filter_occlusions_from(list, monitor_rect);
382-
383- ASSERT_EQ(1u, list.size());
384- EXPECT_EQ(top, list.front());
385-}
386-
387-TEST_F(OcclusionFilterTest, translucent_window_occludes_nothing)
388-{
389- auto top = std::make_shared<mtd::FakeRenderable>(10, 10, 10, 10, 0.5f);
390- auto bottom = std::make_shared<mtd::FakeRenderable>(12, 12, 5, 5, 1.0f);
391- mg::RenderableList list{bottom, top};
392-
393- filter_occlusions_from(list, monitor_rect);
394-
395- ASSERT_EQ(2u, list.size());
396- EXPECT_EQ(bottom, list.front());
397- EXPECT_EQ(top, list.back());
398-}
399-
400-TEST_F(OcclusionFilterTest, hidden_window_is_self_occluded)
401-{
402- auto window = std::make_shared<mtd::FakeRenderable>(10, 10, 10, 10, 1.0f, true, false);
403- mg::RenderableList list{window};
404-
405- filter_occlusions_from(list, monitor_rect);
406-
407- EXPECT_EQ(0u, list.size());
408-}
409-
410-TEST_F(OcclusionFilterTest, hidden_window_occludes_nothing)
411-{
412- auto top = std::make_shared<mtd::FakeRenderable>(10, 10, 10, 10, 1.0f, true, false);
413- auto bottom = std::make_shared<mtd::FakeRenderable>(12, 12, 5, 5);
414- mg::RenderableList list{bottom, top};
415-
416- filter_occlusions_from(list, monitor_rect);
417-
418- ASSERT_EQ(1u, list.size());
419- EXPECT_EQ(bottom, list.front());
420-}
421-
422-TEST_F(OcclusionFilterTest, shaped_window_occludes_nothing)
423-{
424- auto top = std::make_shared<mtd::FakeRenderable>(10, 10, 10, 10, 1.0f, false, true);
425- auto bottom = std::make_shared<mtd::FakeRenderable>(12, 12, 5, 5);
426- mg::RenderableList list{bottom, top};
427-
428- filter_occlusions_from(list, monitor_rect);
429-
430- ASSERT_EQ(2u, list.size());
431- EXPECT_EQ(bottom, list.front());
432- EXPECT_EQ(top, list.back());
433-}
434-
435-TEST_F(OcclusionFilterTest, identical_window_occluded)
436-{
437- auto top = std::make_shared<mtd::FakeRenderable>(10, 10, 10, 10);
438- auto bottom = std::make_shared<mtd::FakeRenderable>(10, 10, 10, 10);
439- mg::RenderableList list{bottom, top};
440-
441- filter_occlusions_from(list, monitor_rect);
442-
443- ASSERT_EQ(1u, list.size());
444- EXPECT_EQ(top, list.front());
445-}
446-
447-TEST_F(OcclusionFilterTest, larger_window_never_occluded)
448-{
449- auto top = std::make_shared<mtd::FakeRenderable>(10, 10, 10, 10);
450- auto bottom = std::make_shared<mtd::FakeRenderable>(9, 9, 12, 12);
451- mg::RenderableList list{bottom, top};
452-
453- filter_occlusions_from(list, monitor_rect);
454-
455- ASSERT_EQ(2u, list.size());
456- EXPECT_EQ(bottom, list.front());
457- EXPECT_EQ(top, list.back());
458-}
459-
460-TEST_F(OcclusionFilterTest, cascaded_windows_never_occluded)
461-{
462- mg::RenderableList list;
463- unsigned int const num_windows{10u};
464- for (auto x = 0u; x < num_windows; x++)
465- list.push_back(std::make_shared<mtd::FakeRenderable>(x, x, 200, 100));
466-
467- filter_occlusions_from(list, monitor_rect);
468- EXPECT_EQ(num_windows, list.size());
469-}
470-
471-TEST_F(OcclusionFilterTest, some_occluded_and_some_not)
472-{
473- auto window0 = std::make_shared<mtd::FakeRenderable>(10, 20, 400, 300);
474- auto window1 = std::make_shared<mtd::FakeRenderable>(10, 20, 5, 5);
475- auto window2 = std::make_shared<mtd::FakeRenderable>(100, 100, 20, 20);
476- auto window3 = std::make_shared<mtd::FakeRenderable>(200, 200, 50, 50);
477- auto window4 = std::make_shared<mtd::FakeRenderable>(500, 600, 34, 56);
478- auto window5 = std::make_shared<mtd::FakeRenderable>(200, 200, 1000, 1000);
479- mg::RenderableList list{
480- window5, //not occluded
481- window4, //not occluded
482- window3, //occluded
483- window2, //occluded
484- window1, //occluded
485- window0 //not occluded
486- };
487-
488- filter_occlusions_from(list, monitor_rect);
489-
490- auto expected_size = 3u;
491- ASSERT_EQ(expected_size, list.size());
492- auto it = list.begin();
493- for(auto count = 0u; count < expected_size; count++)
494- {
495- switch (count)
496- {
497- case 0u:
498- EXPECT_EQ(window5, *it);
499- break;
500- case 1u:
501- EXPECT_EQ(window4, *it);
502- break;
503- case 2u:
504- EXPECT_EQ(window0, *it);
505- break;
506- default:
507- FAIL();
508- break;
509- }
510- it++;
511- }
512-}

Subscribers

People subscribed via source and target branches