Mir

Merge lp:~alan-griffiths/mir/fix-Surface-hierarchy-remove-ClientTrackingSurface into lp:mir

Proposed by Alan Griffiths
Status: Merged
Approved by: kevin gunn
Approved revision: no longer in the source branch.
Merged at revision: 1196
Proposed branch: lp:~alan-griffiths/mir/fix-Surface-hierarchy-remove-ClientTrackingSurface
Merge into: lp:mir
Prerequisite: lp:~alan-griffiths/mir/bump-server-abi
Diff against target: 311 lines (+62/-71)
7 files modified
include/server/mir/frontend/surface.h (+2/-21)
include/server/mir/shell/surface.h (+3/-2)
include/test/mir_test_doubles/mock_frontend_surface.h (+1/-1)
include/test/mir_test_doubles/stub_surface.h (+1/-1)
src/server/frontend/session_mediator.cpp (+50/-29)
src/server/frontend/session_mediator.h (+4/-1)
src/server/frontend/surface.cpp (+1/-16)
To merge this branch: bzr merge lp:~alan-griffiths/mir/fix-Surface-hierarchy-remove-ClientTrackingSurface
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
kevin gunn (community) Approve
Chris Halse Rogers Pending
Alexandros Frantzis Pending
Daniel van Vugt Pending
Review via email: mp+193794@code.launchpad.net

This proposal supersedes a proposal from 2013-11-01.

Commit message

frontend: remove ClientTrackingSurface from the Surface class hierarchy

Description of the change

frontend: remove ClientTrackingSurface from the Surface class hierarchy

Shifts the functionality to SessionMediator where it is actually needed.

To post a comment you must log in.
Revision history for this message
Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal

+ void mf::SessionMediator::advance_buffer(bool& need_full_ipc, SurfaceId surf_id, Surface& surface, std::shared_ptr<graphics::Buffer>& client_buffer)

looks a bit confusing, perphaps it would be more straightforward as:

std::shared_ptr<graphics::Buffer> mf::SessionMediator::advance_buffer(Surface& surface, SurfaceId surf_id, bool& need_full_ipc) ?

review: Needs Fixing
Revision history for this message
Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal

Abstaining in order not to block this.

review: Abstain
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> + void mf::SessionMediator::advance_buffer(bool& need_full_ipc, SurfaceId
> surf_id, Surface& surface, std::shared_ptr<graphics::Buffer>& client_buffer)
>
> looks a bit confusing, perphaps it would be more straightforward as:
>
> std::shared_ptr<graphics::Buffer> mf::SessionMediator::advance_buffer(Surface&
> surface, SurfaceId surf_id, bool& need_full_ipc) ?

I guess I should follow (or fix) our coding guidelines:

 http://unity.ubuntu.com/mir/cppguide/index.html?showone=Function_Parameter_Ordering#Function_Parameter_Ordering

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote : Posted in a previous version of this proposal

LGTM.

Also, tuple unpacking with std::tie! Hurray for learning new C++11isms.

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

A nice step in the right direction.

1. Needs fixing: This is definitely a server ABI break. Please bump MIRSERVER_ABI.

2. Suggest fixing: Repeated use of std::tuple will cause significantly higher code bloat and less readability than simply defining a structure and giving it a name. So I'd prefer to see a struct.

review: Needs Fixing
Revision history for this message
Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal

> 1. Needs fixing: This is definitely a server ABI break. Please bump MIRSERVER_ABI.

Aren't we bumping the ABI once per development-branch -> lp:mir merge?

> 2. Suggest fixing: Repeated use of std::tuple will cause significantly higher code
> bloat and less readability than simply defining a structure and giving it a name.
> So I'd prefer to see a struct.

It's true that using templates increases the code that needs to be compiled per translation unit. However, in most cases it's code that would have to be written anyway in some form, so even if there is a slight increase in build time, there is significant gain from using code that people are familiar with, instead of using custom code. Plus, modern linkers de-duplicate code for identical template instantiations, so the final executable size increase is usually small.

std::tuple and std::tie, in particular, are templates that have minimal impact (if any), as they just do automatically what you suggest doing manually. For a proof of concept try building: http://paste.ubuntu.com/6358068/

Revision history for this message
Alexandros Frantzis (afrantzis) : Posted in a previous version of this proposal
review: Approve
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> A nice step in the right direction.
>
> 1. Needs fixing: This is definitely a server ABI break. Please bump
> MIRSERVER_ABI.

We've been bumping this in a separate MP each time we land development-branch. I'll submit that separately.

> 2. Suggest fixing: Repeated use of std::tuple will cause significantly higher
> code bloat and less readability than simply defining a structure and giving it
> a name. So I'd prefer to see a struct.

I disagree. Writing equivalent functionality by hand will:

1.at best be as efficient as using the standard library at runtime;
2.introduce significant sourcecode bloat; and,
3 eliminate possible link-time optimization if the template is used elsewhere.

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

Resubmitted with an ABI bump as a prerequisite

Revision history for this message
kevin gunn (kgunn72) wrote :

WRT

>> 2. Suggest fixing: Repeated use of std::tuple will cause significantly higher
>> code bloat and less readability than simply defining a structure and giving it
>> a name. So I'd prefer to see a struct.
>
>I disagree. Writing equivalent functionality by hand will:
>
>1.at best be as efficient as using the standard library at runtime;
>2.introduce significant sourcecode bloat; and,
>3 eliminate possible link-time optimization if the template is used elsewhere.

and
>It's true that using templates increases the code that needs to be compiled per
>translation unit. However, in most cases it's code that would have to be
>written anyway in some form, so even if there is a slight increase in build
>time, there is significant gain from using code that people are familiar with,
>instead of using custom code. Plus, modern linkers de-duplicate code for
>identical template instantiations, so the final executable size increase
>is usually small.
>
>std::tuple and std::tie, in particular, are templates that have minimal impact
>(if any), as they just do automatically what you suggest doing manually.
>For a proof of concept try building: http://paste.ubuntu.com/6358068/

I believe the team should strive to utilize std objects (not for the sake of it
...but i'm assuming when the need arises).
Not only for the reasons listed above, but also, customizing lends itself
to generating new errors - rather than something provided by the standard that
should be optimized & debugged (and if not it surely will be over time).
as to the comment about naming (i assume wondering...what's it used for?) surely
we could use more comments in the code - i think that would help

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Actually, we've been bumping ABIs inside the offending MPs. Ever since v0.1.0.

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Alan,

In non-trivial cases like that proposed here, using a tuple is more difficult to read:
    std::tuple<std::shared_ptr<mg::Buffer>, bool> somefunction()
vs:
    SomeType somefunction()
but I understand the argument for verbosity and in some cases naming SomeType could create confusion.

Regarding code bloat, I suggest you compile your own example code:
    http://paste.ubuntu.com/6358068/
You will find the resulting binary with -DUSE_TUPLE is double the size.

Revision history for this message
Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal

> Regarding code bloat, I suggest you compile your own example code:
> http://paste.ubuntu.com/6358068/
> You will find the resulting binary with -DUSE_TUPLE is double the size.

It's double the size only if we don't use an optimization flag. Even -O1 brings them to the same size.

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

That's true, but...

(a) Including debug symbols (-g) as well as optimization, -DUSE_TUPLE can only get to within 132% the size of the struct approach. And generating debug symbols is something all real-world builds will do, including for releases.

(b) Compilation is predictably slower by about 20%.

(c) Needing to use optimization flags is probably not ideal. The best optimizations will always occur before the code sees a compiler.

So it's slower to build, generates bigger code, and is (arguably) harder to read. Such is life with many C++ templates. You just have to use them carefully.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

On 05/11/13 04:16, Daniel van Vugt wrote:
> In non-trivial cases like that proposed here, using a tuple is more difficult to read:
> std::tuple<std::shared_ptr<mg::Buffer>, bool> somefunction()
> vs:
> SomeType somefunction()
> but I understand the argument for verbosity and in some cases naming SomeType could create confusion.

But that's the wrong comparison. The difference is between

    ... std::tuple<std::shared_ptr<mg::Buffer>, bool> ...

and
    ...class { std::shared_ptr<mg::Buffer> first; bool second; }...

For example:

    std::tuple<std::shared_ptr<mg::Buffer>, bool> somefunction()
vs
    class { std::shared_ptr<mg::Buffer> first; bool second; } somefunction()

In any case, there's a clear rationale for using standard library
facilities where they do the job: they are better known, better
specified and better tested than something custom and new.

Anyone not familiar with std::tuple can look it up easily and apply the
knowledge they gain to future encounters. (They will not meet SomeType
again,)

--
Alan Griffiths +44 (0)798 9938 758
Octopull Ltd http://www.octopull.co.uk/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/server/mir/frontend/surface.h'
2--- include/server/mir/frontend/surface.h 2013-10-15 08:53:10 +0000
3+++ include/server/mir/frontend/surface.h 2013-11-04 15:13:14 +0000
4@@ -55,12 +55,7 @@
5 virtual geometry::Size size() const = 0;
6 virtual geometry::PixelFormat pixel_format() const = 0;
7
8- /// Submit the current client buffer, return the next client buffer
9- ///
10- /// \param [out] need_ipc: True if the buffer content must be sent via IPC
11- /// False if only the buffer's ID must be sent.
12- /// \returns The next client buffer
13- virtual std::shared_ptr<graphics::Buffer> advance_client_buffer(bool& need_full_ipc) = 0;
14+ virtual std::shared_ptr<graphics::Buffer> advance_client_buffer() = 0;
15
16 virtual bool supports_input() const = 0;
17 virtual int client_input_fd() const = 0;
18@@ -75,21 +70,7 @@
19
20 auto as_internal_surface(std::shared_ptr<Surface> const& surface)
21 -> std::shared_ptr<graphics::InternalSurface>;
22-
23-class ClientTrackingSurface : public Surface
24-{
25-public:
26- ClientTrackingSurface();
27- virtual ~ClientTrackingSurface() = default;
28-
29- virtual std::shared_ptr<graphics::Buffer> advance_client_buffer(bool& need_full_ipc) override;
30-
31- virtual std::shared_ptr<graphics::Buffer> advance_client_buffer() = 0;
32-private:
33- std::shared_ptr<ClientBufferTracker> client_tracker;
34-};
35-
36-}
37+}
38 }
39
40
41
42=== modified file 'include/server/mir/shell/surface.h'
43--- include/server/mir/shell/surface.h 2013-10-15 08:53:10 +0000
44+++ include/server/mir/shell/surface.h 2013-11-04 15:13:14 +0000
45@@ -44,7 +44,7 @@
46 class SurfaceController;
47 struct SurfaceCreationParameters;
48
49-class Surface : public frontend::ClientTrackingSurface, public shell::SurfaceBufferAccess
50+class Surface : public frontend::Surface, public shell::SurfaceBufferAccess
51 {
52 public:
53 Surface(
54@@ -86,8 +86,9 @@
55 virtual void set_input_region(std::vector<geometry::Rectangle> const& region);
56
57 virtual void allow_framedropping(bool);
58-
59+
60 virtual void raise(std::shared_ptr<SurfaceController> const& controller);
61+
62 private:
63 bool set_type(MirSurfaceType t); // Use configure() to make public changes
64 bool set_state(MirSurfaceState s);
65
66=== modified file 'include/test/mir_test_doubles/mock_frontend_surface.h'
67--- include/test/mir_test_doubles/mock_frontend_surface.h 2013-08-28 03:41:48 +0000
68+++ include/test/mir_test_doubles/mock_frontend_surface.h 2013-11-04 15:13:14 +0000
69@@ -29,7 +29,7 @@
70 {
71 namespace doubles
72 {
73-struct MockFrontendSurface : public frontend::ClientTrackingSurface
74+struct MockFrontendSurface : public frontend::Surface
75 {
76 MockFrontendSurface()
77 {
78
79=== modified file 'include/test/mir_test_doubles/stub_surface.h'
80--- include/test/mir_test_doubles/stub_surface.h 2013-10-15 08:53:10 +0000
81+++ include/test/mir_test_doubles/stub_surface.h 2013-11-04 15:13:14 +0000
82@@ -28,7 +28,7 @@
83 namespace doubles
84 {
85
86-class StubSurface : public frontend::ClientTrackingSurface
87+class StubSurface : public frontend::Surface
88 {
89 public:
90 virtual ~StubSurface() = default;
91
92=== modified file 'src/server/frontend/session_mediator.cpp'
93--- src/server/frontend/session_mediator.cpp 2013-10-25 08:41:50 +0000
94+++ src/server/frontend/session_mediator.cpp 2013-11-04 15:13:14 +0000
95@@ -17,6 +17,8 @@
96 */
97
98 #include "session_mediator.h"
99+#include "client_buffer_tracker.h"
100+
101 #include "mir/frontend/session_mediator_report.h"
102 #include "mir/frontend/shell.h"
103 #include "mir/frontend/session.h"
104@@ -92,7 +94,7 @@
105 std::unique_lock<std::mutex> lock(session_mutex);
106 weak_session = shell->open_session(request->application_name(), event_sink);
107 }
108-
109+
110 auto ipc_package = graphics_platform->get_ipc_package();
111 auto platform = response->mutable_platform();
112
113@@ -111,28 +113,50 @@
114 done->Run();
115 }
116
117+std::tuple<std::shared_ptr<mg::Buffer>, bool>
118+mf::SessionMediator::advance_buffer(SurfaceId surf_id, Surface& surface)
119+{
120+ auto& tracker = client_buffer_tracker[surf_id];
121+ if (!tracker) tracker = std::make_shared<ClientBufferTracker>(client_buffer_cache_size);
122+
123+ auto client_buffer = surface.advance_client_buffer();
124+ auto id = client_buffer->id();
125+ auto need_full_ipc = !tracker->client_has(id);
126+ tracker->add(id);
127+
128+ client_buffer_resource[surf_id] = client_buffer;
129+
130+ return std::tie(client_buffer, need_full_ipc);
131+}
132+
133+
134 void mf::SessionMediator::create_surface(
135 google::protobuf::RpcController* /*controller*/,
136 const mir::protobuf::SurfaceParameters* request,
137 mir::protobuf::Surface* response,
138 google::protobuf::Closure* done)
139 {
140- std::unique_lock<std::mutex> lock(session_mutex);
141-
142- auto session = weak_session.lock();
143-
144- if (session.get() == nullptr)
145- BOOST_THROW_EXCEPTION(std::logic_error("Invalid application session"));
146-
147- report->session_create_surface_called(session->name());
148-
149- auto const surf_id = session->create_surface(msh::SurfaceCreationParameters()
150- .of_name(request->surface_name())
151- .of_size(request->width(), request->height())
152- .of_buffer_usage(static_cast<graphics::BufferUsage>(request->buffer_usage()))
153- .of_pixel_format(static_cast<geometry::PixelFormat>(request->pixel_format()))
154- .with_output_id(graphics::DisplayConfigurationOutputId(request->output_id())));
155+ bool need_full_ipc;
156+ std::shared_ptr<graphics::Buffer> client_buffer;
157+ std::shared_ptr<Session> session;
158+
159 {
160+ std::unique_lock<std::mutex> lock(session_mutex);
161+
162+ session = weak_session.lock();
163+
164+ if (session.get() == nullptr)
165+ BOOST_THROW_EXCEPTION(std::logic_error("Invalid application session"));
166+
167+ report->session_create_surface_called(session->name());
168+
169+ auto const surf_id = session->create_surface(msh::SurfaceCreationParameters()
170+ .of_name(request->surface_name())
171+ .of_size(request->width(), request->height())
172+ .of_buffer_usage(static_cast<graphics::BufferUsage>(request->buffer_usage()))
173+ .of_pixel_format(static_cast<geometry::PixelFormat>(request->pixel_format()))
174+ .with_output_id(graphics::DisplayConfigurationOutputId(request->output_id())));
175+
176 auto surface = session->get_surface(surf_id);
177 response->mutable_id()->set_value(surf_id.as_value());
178 response->set_width(surface->size().width.as_uint32_t());
179@@ -143,16 +167,14 @@
180 if (surface->supports_input())
181 response->add_fd(surface->client_input_fd());
182
183- bool need_full_ipc;
184- auto client_buffer = surface->advance_client_buffer(need_full_ipc);
185- client_buffer_resource[surf_id] = client_buffer;
186-
187- auto buffer = response->mutable_buffer();
188- pack_protobuf_buffer(*buffer, client_buffer, need_full_ipc);
189+ std::tie(client_buffer, need_full_ipc) = advance_buffer(surf_id, *surface);
190 }
191
192+ auto buffer = response->mutable_buffer();
193+ pack_protobuf_buffer(*buffer, client_buffer, need_full_ipc);
194+
195 // TODO: NOTE: We use the ordering here to ensure the shell acts on the surface after the surface ID is sent over the wire.
196- // This guarantees that notifications such as, gained focus, etc, can be correctly interpreted by the client.
197+ // This guarantees that notifications such as, gained focus, etc, can be correctly interpreted by the client.
198 // To achieve this order we rely on done->Run() sending messages synchronously. As documented in mfd::SocketMessenger::send.
199 // this will require additional synchronization if mfd::SocketMessenger::send changes.
200 done->Run();
201@@ -171,14 +193,14 @@
202
203 {
204 std::unique_lock<std::mutex> lock(session_mutex);
205-
206+
207 auto session = weak_session.lock();
208
209 if (session.get() == nullptr)
210 BOOST_THROW_EXCEPTION(std::logic_error("Invalid application session"));
211
212 report->session_next_buffer_called(session->name());
213-
214+
215 // We ensure the client has not powered down the outputs, so that
216 // swap_buffer will not block indefinitely, leaving the client
217 // in a position where it can not turn back on the
218@@ -187,9 +209,7 @@
219
220 auto surface = session->get_surface(surf_id);
221
222- client_buffer_resource[surf_id].reset();
223- client_buffer = surface->advance_client_buffer(need_full_ipc);
224- client_buffer_resource[surf_id] = client_buffer;
225+ std::tie(client_buffer, need_full_ipc) = advance_buffer(surf_id, *surface);
226 }
227
228 pack_protobuf_buffer(*response, client_buffer, need_full_ipc);
229@@ -216,6 +236,7 @@
230 auto const id = SurfaceId(request->value());
231
232 session->destroy_surface(id);
233+ client_buffer_tracker.erase(id);
234 }
235
236 // TODO: We rely on this sending responses synchronously.
237@@ -294,7 +315,7 @@
238
239 auto config = display_changer->active_configuration();
240 for (auto i=0; i < request->display_output_size(); i++)
241- {
242+ {
243 auto& output = request->display_output(i);
244 mg::DisplayConfigurationOutputId output_id{static_cast<int>(output.output_id())};
245 config->configure_output(output_id, output.used(),
246
247=== modified file 'src/server/frontend/session_mediator.h'
248--- src/server/frontend/session_mediator.h 2013-10-24 14:55:07 +0000
249+++ src/server/frontend/session_mediator.h 2013-11-04 15:13:14 +0000
250@@ -42,11 +42,12 @@
251 /// processes and the core of the mir system.
252 namespace frontend
253 {
254+class ClientBufferTracker;
255 class Shell;
256 class Session;
257+class Surface;
258 class ResourceCache;
259 class SessionMediatorReport;
260-class ClientBufferTracker;
261 class EventSink;
262 class DisplayChanger;
263
264@@ -113,6 +114,7 @@
265 std::shared_ptr<graphics::Buffer> const& graphics_buffer,
266 bool need_full_ipc);
267
268+ std::tuple<std::shared_ptr<graphics::Buffer>, bool> advance_buffer(SurfaceId surf_id, Surface& surface);
269 std::shared_ptr<Shell> const shell;
270 std::shared_ptr<graphics::Platform> const graphics_platform;
271
272@@ -125,6 +127,7 @@
273 std::shared_ptr<ResourceCache> const resource_cache;
274
275 std::unordered_map<SurfaceId,std::shared_ptr<graphics::Buffer>> client_buffer_resource;
276+ std::unordered_map<SurfaceId, std::shared_ptr<ClientBufferTracker>> client_buffer_tracker;
277
278 std::mutex session_mutex;
279 std::weak_ptr<Session> weak_session;
280
281=== modified file 'src/server/frontend/surface.cpp'
282--- src/server/frontend/surface.cpp 2013-08-28 03:41:48 +0000
283+++ src/server/frontend/surface.cpp 2013-11-04 15:13:14 +0000
284@@ -39,8 +39,7 @@
285 private:
286 virtual std::shared_ptr<mg::Buffer> advance_client_buffer()
287 {
288- bool unused;
289- return surface->advance_client_buffer(unused);
290+ return surface->advance_client_buffer();
291 }
292 virtual mir::geometry::Size size() const { return surface->size(); }
293 virtual MirPixelFormat pixel_format() const { return static_cast<MirPixelFormat>(surface->pixel_format()); }
294@@ -50,17 +49,3 @@
295
296 return std::make_shared<ForwardingInternalSurface>(surface);
297 }
298-
299-mf::ClientTrackingSurface::ClientTrackingSurface()
300- : client_tracker(std::make_shared<mf::ClientBufferTracker>(mf::client_buffer_cache_size))
301-{
302-}
303-
304-std::shared_ptr<mg::Buffer> mf::ClientTrackingSurface::advance_client_buffer(bool& need_full_ipc)
305-{
306- auto buffer = advance_client_buffer();
307- auto id = buffer->id();
308- need_full_ipc = !client_tracker->client_has(id);
309- client_tracker->add(id);
310- return buffer;
311-}

Subscribers

People subscribed via source and target branches