Mir

Merge lp:~vanvugt/mir/resize-server-Surfaces into lp:mir

Proposed by Daniel van Vugt
Status: Merged
Approved by: Alan Griffiths
Approved revision: no longer in the source branch.
Merged at revision: 1202
Proposed branch: lp:~vanvugt/mir/resize-server-Surfaces
Merge into: lp:mir
Prerequisite: lp:~vanvugt/mir/resize-BufferStream
Diff against target: 211 lines (+108/-0)
10 files modified
include/server/mir/shell/surface.h (+2/-0)
include/server/mir/surfaces/surface.h (+3/-0)
include/test/mir_test_doubles/mock_surface_state.h (+1/-0)
src/server/shell/surface.cpp (+5/-0)
src/server/surfaces/mutable_surface_state.h (+1/-0)
src/server/surfaces/surface.cpp (+18/-0)
src/server/surfaces/surface_data.cpp (+10/-0)
src/server/surfaces/surface_data.h (+1/-0)
tests/unit-tests/surfaces/test_surface.cpp (+49/-0)
tests/unit-tests/surfaces/test_surface_data.cpp (+18/-0)
To merge this branch: bzr merge lp:~vanvugt/mir/resize-server-Surfaces
Reviewer Review Type Date Requested Status
Alan Griffiths Approve
Alexandros Frantzis (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+193905@code.launchpad.net

Commit message

Implement resize() for the server-side Surface classes.

This is fine for server-owned surfaces, but won't be fully functional with
clients till they get support for resize() too.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Looks good.

A slight concern:

85 + surface_buffer_stream->resize(size);
86 +
87 + // Now the buffer stream has successfully resized, update the state second;
88 + surface_state->resize(size);

There is an opportunity for inconsistency here, but I am not sure if it has any significant effect:
1. buffer stream gets resized
2. external entity gets surface size which hasn't changed (or has it cached from before, because it hasn't received a notification yet), and makes a decision based on this information
3. external entity gets a new buffer which has size != surface size
4. surface state gets updated

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

Alexandros,

That inconsistency is something I have planned for right from the beginning.

You cannot solve the inconsistency completely, because that would mean the server has to /wait/ on and rely on the client to fill new buffers quickly. But we don't and shouldn't trust clients.

So what I've done is treat resizes asynchronously. The surface size changes immediately. But its buffers will take a while to catch up (because they're coming from another process that's an unavoidable fact of life). This means there's no blocking and no interruption to what the user sees. Worst case is that you'll be rendering an old buffer size to the new surface size, so might briefly see some scaling happen while the client catches up. I think this is the ideal approach.

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

Thus, rather than solve the inconsistency which isn't really feasible to solve, we just handle the fact that during rapid resizing the surface size might be different to the buffer size within it. So long as we're aware that's possible and /normal/, it's very easy to handle.

Also, we may choose to clamp instead of scale... as a matter of cosmetics. I'm not sure which looks best, but all existing windowing systems seem to take the clamp approach.

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

OK.

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

LGTM (well nothing about *Surface* really looks good but...)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/server/mir/shell/surface.h'
2--- include/server/mir/shell/surface.h 2013-11-01 14:27:00 +0000
3+++ include/server/mir/shell/surface.h 2013-11-05 11:12:59 +0000
4@@ -89,6 +89,8 @@
5
6 virtual void raise(std::shared_ptr<SurfaceController> const& controller);
7
8+ virtual void resize(geometry::Size const& size);
9+
10 private:
11 bool set_type(MirSurfaceType t); // Use configure() to make public changes
12 bool set_state(MirSurfaceState s);
13
14=== modified file 'include/server/mir/surfaces/surface.h'
15--- include/server/mir/surfaces/surface.h 2013-11-04 09:03:31 +0000
16+++ include/server/mir/surfaces/surface.h 2013-11-05 11:12:59 +0000
17@@ -90,6 +90,9 @@
18 std::shared_ptr<compositor::BufferStream> buffer_stream() const;
19
20 std::shared_ptr<input::Surface> input_surface() const;
21+
22+ void resize(geometry::Size const& size);
23+
24 private:
25 std::shared_ptr<surfaces::SurfaceState> surface_state;
26 std::shared_ptr<compositor::BufferStream> surface_buffer_stream;
27
28=== modified file 'include/test/mir_test_doubles/mock_surface_state.h'
29--- include/test/mir_test_doubles/mock_surface_state.h 2013-10-07 07:56:05 +0000
30+++ include/test/mir_test_doubles/mock_surface_state.h 2013-11-05 11:12:59 +0000
31@@ -52,6 +52,7 @@
32 MOCK_CONST_METHOD0(name, std::string const&());
33 MOCK_METHOD2(apply_rotation, void(float, glm::vec3 const&));
34 MOCK_METHOD1(move_to, void(geometry::Point));
35+ MOCK_METHOD1(resize, void(geometry::Size const&));
36 MOCK_CONST_METHOD1(contains, bool(geometry::Point const&));
37 MOCK_METHOD1(set_input_region, void(std::vector<geometry::Rectangle> const&));
38 MOCK_CONST_METHOD0(alpha, float());
39
40=== modified file 'src/server/shell/surface.cpp'
41--- src/server/shell/surface.cpp 2013-10-15 08:53:10 +0000
42+++ src/server/shell/surface.cpp 2013-11-05 11:12:59 +0000
43@@ -240,3 +240,8 @@
44 {
45 controller->raise(surface);
46 }
47+
48+void msh::Surface::resize(geom::Size const& size)
49+{
50+ surface->resize(size);
51+}
52
53=== modified file 'src/server/surfaces/mutable_surface_state.h'
54--- src/server/surfaces/mutable_surface_state.h 2013-10-03 06:01:11 +0000
55+++ src/server/surfaces/mutable_surface_state.h 2013-11-05 11:12:59 +0000
56@@ -32,6 +32,7 @@
57 {
58 public:
59 virtual void move_to(geometry::Point) = 0;
60+ virtual void resize(geometry::Size const& size) = 0;
61 virtual void frame_posted() = 0;
62 virtual void set_hidden(bool hidden) = 0;
63 virtual void apply_alpha(float alpha) = 0;
64
65=== modified file 'src/server/surfaces/surface.cpp'
66--- src/server/surfaces/surface.cpp 2013-10-23 15:07:55 +0000
67+++ src/server/surfaces/surface.cpp 2013-11-05 11:12:59 +0000
68@@ -168,3 +168,21 @@
69 {
70 surface_state->set_input_region(input_rectangles);
71 }
72+
73+void ms::Surface::resize(geom::Size const& size)
74+{
75+ if (size.width <= geom::Width{0} || size.height <= geom::Height{0})
76+ {
77+ BOOST_THROW_EXCEPTION(std::logic_error("Impossible resize requested"));
78+ }
79+ /*
80+ * Other combinations may still be invalid (like dimensions too big or
81+ * insufficient resources), but those are runtime and platform-specific, so
82+ * not predictable here. Such critical exceptions would arise from
83+ * the platform buffer allocator as a runtime_error via:
84+ */
85+ surface_buffer_stream->resize(size);
86+
87+ // Now the buffer stream has successfully resized, update the state second;
88+ surface_state->resize(size);
89+}
90
91=== modified file 'src/server/surfaces/surface_data.cpp'
92--- src/server/surfaces/surface_data.cpp 2013-10-07 08:25:04 +0000
93+++ src/server/surfaces/surface_data.cpp 2013-11-05 11:12:59 +0000
94@@ -163,6 +163,16 @@
95 notify_change();
96 }
97
98+void ms::SurfaceData::resize(geom::Size const& size)
99+{
100+ {
101+ std::unique_lock<std::mutex> lock(guard);
102+ surface_rect.size = size;
103+ transformation_dirty = true;
104+ }
105+ notify_change();
106+}
107+
108 bool ms::SurfaceData::contains(geom::Point const& point) const
109 {
110 if (hidden)
111
112=== modified file 'src/server/surfaces/surface_data.h'
113--- src/server/surfaces/surface_data.h 2013-10-07 09:53:57 +0000
114+++ src/server/surfaces/surface_data.h 2013-11-05 11:12:59 +0000
115@@ -51,6 +51,7 @@
116
117 //ms::MutableSurfaceState
118 void move_to(geometry::Point);
119+ void resize(geometry::Size const& size);
120 void frame_posted();
121 void set_hidden(bool hidden);
122 void apply_alpha(float alpha);
123
124=== modified file 'tests/unit-tests/surfaces/test_surface.cpp'
125--- tests/unit-tests/surfaces/test_surface.cpp 2013-10-22 16:47:53 +0000
126+++ tests/unit-tests/surfaces/test_surface.cpp 2013-11-05 11:12:59 +0000
127@@ -283,6 +283,55 @@
128 surf.move_to(p);
129 }
130
131+TEST_F(SurfaceCreation, resize_updates_stream_then_state)
132+{
133+ using namespace testing;
134+ geom::Size const new_size{123, 456};
135+
136+ Sequence seq;
137+ EXPECT_CALL(*mock_buffer_stream, resize(new_size))
138+ .InSequence(seq);
139+ EXPECT_CALL(*mock_basic_state, resize(new_size))
140+ .InSequence(seq);
141+
142+ ms::Surface surf(
143+ mock_basic_state,
144+ mock_buffer_stream,
145+ std::shared_ptr<mi::InputChannel>(),
146+ report);
147+ surf.resize(new_size);
148+}
149+
150+TEST_F(SurfaceCreation, impossible_resize_throws)
151+{
152+ using namespace testing;
153+
154+ geom::Size const bad_sizes[] =
155+ {
156+ {0, 123},
157+ {456, 0},
158+ {-1, -1},
159+ {78, -10},
160+ {0, 0}
161+ };
162+
163+ ms::Surface surf(
164+ mock_basic_state,
165+ mock_buffer_stream,
166+ std::shared_ptr<mi::InputChannel>(),
167+ report);
168+
169+ EXPECT_CALL(*mock_buffer_stream, resize(size))
170+ .Times(0);
171+ EXPECT_CALL(*mock_basic_state, resize(size))
172+ .Times(0);
173+
174+ for (auto &size : bad_sizes)
175+ {
176+ EXPECT_THROW(surf.resize(size), std::logic_error);
177+ }
178+}
179+
180 TEST_F(SurfaceCreation, test_surface_set_rotation)
181 {
182 using namespace testing;
183
184=== modified file 'tests/unit-tests/surfaces/test_surface_data.cpp'
185--- tests/unit-tests/surfaces/test_surface_data.cpp 2013-10-07 08:25:04 +0000
186+++ tests/unit-tests/surfaces/test_surface_data.cpp 2013-11-05 11:12:59 +0000
187@@ -87,6 +87,24 @@
188 EXPECT_EQ(new_top_left, storage.position());
189 }
190
191+TEST_F(SurfaceDataTest, update_size)
192+{
193+ geom::Size const new_size{34, 56};
194+
195+ EXPECT_CALL(mock_callback, call())
196+ .Times(1);
197+
198+ ms::SurfaceData storage{name, rect, mock_change_cb, false};
199+ EXPECT_EQ(rect.size, storage.size());
200+ EXPECT_NE(new_size, storage.size());
201+
202+ auto old_transformation = storage.transformation();
203+
204+ storage.resize(new_size);
205+ EXPECT_EQ(new_size, storage.size());
206+ EXPECT_NE(old_transformation, storage.transformation());
207+}
208+
209 TEST_F(SurfaceDataTest, test_surface_set_rotation_updates_transform)
210 {
211 EXPECT_CALL(mock_callback, call())

Subscribers

People subscribed via source and target branches