Merge lp:~alan-griffiths/mir/fix-1701308 into lp:mir
- fix-1701308
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Alan Griffiths |
Approved revision: | no longer in the source branch. |
Merged at revision: | 4202 |
Proposed branch: | lp:~alan-griffiths/mir/fix-1701308 |
Merge into: | lp:mir |
Diff against target: |
123 lines (+27/-40) 2 files modified
examples/eglapp.c (+12/-23) src/client/mir_connection.cpp (+15/-17) |
To merge this branch: | bzr merge lp:~alan-griffiths/mir/fix-1701308 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mir CI Bot | continuous-integration | Approve | |
Gerry Boland (community) | Approve | ||
Daniel van Vugt | Abstain | ||
Review via email: mp+326582@code.launchpad.net |
Commit message
Handle initial window size being imposed by shell in eglapps.
Description of the change
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:4202
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Alan Griffiths (alan-griffiths) wrote : | # |
> Is this reliable?
>
> I had previously discovered that you can't rely on the resize callback
> occurring before the app starts rendering its first frame:
It is possible for a frame to be rendered at the requested (not actual) size: the "created" callback is, necessarily, called before the "resize" callback.
With our undeprecated the client cannot query the window size in the "created" callback.
> I suggest using the EGL_WIDTH/HEIGHT approach shown above
Remember the server has only sized the window, not the surface. The current RS design relies on the client to implement the surface resize. As discussed in the bug comments there's no quick fix for that.
Daniel van Vugt (vanvugt) wrote : | # |
OK. I don't understand all of that but the last paragraph makes sense at least.
Gerry Boland (gerboland) wrote : | # |
I'm confused, as in eglapp.c after surface spec creation, it uses eglQuerySurface to fetch surface width & height, and has a big comment
* Mir reserves the right to ignore our initial window dimensions and
* resize to whatever it likes. Usually that resize callback has
* occurred by now (see r4150), but libmirclient does not provide a
* solid guarantee of it. Luckily, we don't care... by querying EGL
* buffer dimensions we can get the correct answer without being
* victim to the callback race that's going on in the background...
* If the server has given us dimensions other than what we requested
* then EGL will already know about it, possibly before the initial
* resize event (!).
This patch does fix the delivery of the resize event, but as this comment says, surely the egl surface should have had the correct dimensions anyway?
Alan Griffiths (alan-griffiths) wrote : | # |
> I'm confused, as in eglapp.c after surface spec creation, it uses
> eglQuerySurface to fetch surface width & height, and has a big comment
>
> * Mir reserves the right to ignore our initial window dimensions and
> * resize to whatever it likes. Usually that resize callback has
> * occurred by now (see r4150), but libmirclient does not provide a
> * solid guarantee of it. Luckily, we don't care... by querying EGL
> * buffer dimensions we can get the correct answer without being
> * victim to the callback race that's going on in the background...
> * If the server has given us dimensions other than what we requested
> * then EGL will already know about it, possibly before the initial
> * resize event (!).
>
> This patch does fix the delivery of the resize event, but as this comment
> says, surely the egl surface should have had the correct dimensions anyway?
That comment was obsolete: EGL has the size of the surface (not the window) which is controlled by the client.
Gerry Boland (gerboland) wrote : | # |
Ok, I follow what is happening better now. And testing, it works ok
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:4203
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Gerry Boland (gerboland) : | # |
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:4206
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
1 | === modified file 'examples/eglapp.c' | |||
2 | --- examples/eglapp.c 2017-06-06 15:41:28 +0000 | |||
3 | +++ examples/eglapp.c 2017-06-30 11:36:00 +0000 | |||
4 | @@ -161,7 +161,6 @@ | |||
5 | 161 | 161 | ||
6 | 162 | void mir_eglapp_handle_event(MirWindow* window, MirEvent const* ev, void* unused) | 162 | void mir_eglapp_handle_event(MirWindow* window, MirEvent const* ev, void* unused) |
7 | 163 | { | 163 | { |
8 | 164 | (void) window; | ||
9 | 165 | (void) unused; | 164 | (void) unused; |
10 | 166 | 165 | ||
11 | 167 | switch (mir_event_get_type(ev)) | 166 | switch (mir_event_get_type(ev)) |
12 | @@ -201,13 +200,13 @@ | |||
13 | 201 | 200 | ||
14 | 202 | printf("Resized to %dx%d\n", new_width, new_height); | 201 | printf("Resized to %dx%d\n", new_width, new_height); |
15 | 203 | if (surface) | 202 | if (surface) |
23 | 204 | { | 203 | { |
24 | 205 | mir_render_surface_set_size(surface, new_width, new_height); | 204 | mir_render_surface_set_size(surface, new_width, new_height); |
25 | 206 | MirWindowSpec* spec = mir_create_window_spec(connection); | 205 | MirWindowSpec* spec = mir_create_window_spec(connection); |
26 | 207 | mir_window_spec_add_render_surface(spec, surface, new_width, new_height, 0, 0); | 206 | mir_window_spec_add_render_surface(spec, surface, new_width, new_height, 0, 0); |
27 | 208 | mir_window_apply_spec(window, spec); | 207 | mir_window_apply_spec(window, spec); |
28 | 209 | mir_window_spec_release(spec); | 208 | mir_window_spec_release(spec); |
29 | 210 | } | 209 | } |
30 | 211 | } | 210 | } |
31 | 212 | 211 | ||
32 | 213 | static void show_help(struct mir_eglapp_arg const* const* arg_lists) | 212 | static void show_help(struct mir_eglapp_arg const* const* arg_lists) |
33 | @@ -462,6 +461,8 @@ | |||
34 | 462 | name = p + 1; | 461 | name = p + 1; |
35 | 463 | } | 462 | } |
36 | 464 | mir_window_spec_set_name(spec, name); | 463 | mir_window_spec_set_name(spec, name); |
37 | 464 | mir_window_spec_set_event_handler(spec, mir_eglapp_handle_event, NULL); | ||
38 | 465 | mir_window_spec_set_cursor_name(spec, cursor_name); | ||
39 | 465 | 466 | ||
40 | 466 | if (output_id != mir_display_output_id_invalid) | 467 | if (output_id != mir_display_output_id_invalid) |
41 | 467 | mir_window_spec_set_fullscreen_on_output(spec, output_id); | 468 | mir_window_spec_set_fullscreen_on_output(spec, output_id); |
42 | @@ -471,13 +472,6 @@ | |||
43 | 471 | 472 | ||
44 | 472 | CHECK(mir_window_is_valid(window), "Can't create a window"); | 473 | CHECK(mir_window_is_valid(window), "Can't create a window"); |
45 | 473 | 474 | ||
46 | 474 | mir_window_set_event_handler(window, mir_eglapp_handle_event, NULL); | ||
47 | 475 | |||
48 | 476 | spec = mir_create_window_spec(connection); | ||
49 | 477 | mir_window_spec_set_cursor_name(spec, cursor_name); | ||
50 | 478 | mir_window_apply_spec(window, spec); | ||
51 | 479 | mir_window_spec_release(spec); | ||
52 | 480 | |||
53 | 481 | eglsurface = eglCreateWindowSurface(egldisplay, | 475 | eglsurface = eglCreateWindowSurface(egldisplay, |
54 | 482 | eglconfig, | 476 | eglconfig, |
55 | 483 | (EGLNativeWindowType)surface, | 477 | (EGLNativeWindowType)surface, |
56 | @@ -498,14 +492,9 @@ | |||
57 | 498 | { | 492 | { |
58 | 499 | /* | 493 | /* |
59 | 500 | * Mir reserves the right to ignore our initial window dimensions and | 494 | * Mir reserves the right to ignore our initial window dimensions and |
68 | 501 | * resize to whatever it likes. Usually that resize callback has | 495 | * resize to whatever it likes. In that case, a resize callback to |
69 | 502 | * occurred by now (see r4150), but libmirclient does not provide a | 496 | * mir_eglapp_handle_event() has occurred by now and we have resized |
70 | 503 | * solid guarantee of it. Luckily, we don't care... by querying EGL | 497 | * the eglsurface. |
63 | 504 | * buffer dimensions we can get the correct answer without being | ||
64 | 505 | * victim to the callback race that's going on in the background... | ||
65 | 506 | * If the server has given us dimensions other than what we requested | ||
66 | 507 | * then EGL will already know about it, possibly before the initial | ||
67 | 508 | * resize event (!). | ||
71 | 509 | */ | 498 | */ |
72 | 510 | *width = buf_width; | 499 | *width = buf_width; |
73 | 511 | *height = buf_height; | 500 | *height = buf_height; |
74 | 512 | 501 | ||
75 | === modified file 'src/client/mir_connection.cpp' | |||
76 | --- src/client/mir_connection.cpp 2017-06-09 14:16:54 +0000 | |||
77 | +++ src/client/mir_connection.cpp 2017-06-30 11:36:00 +0000 | |||
78 | @@ -276,21 +276,6 @@ | |||
79 | 276 | MIR_LOG_UNCAUGHT_EXCEPTION(ex); | 276 | MIR_LOG_UNCAUGHT_EXCEPTION(ex); |
80 | 277 | } | 277 | } |
81 | 278 | 278 | ||
82 | 279 | void send_resize_event_if_needed(MirWindow *window, MirWindowSpec const& spec, mir::protobuf::Surface const& surface_proto) | ||
83 | 280 | { | ||
84 | 281 | if (spec.width.is_set() && spec.height.is_set() && spec.event_handler.is_set()) | ||
85 | 282 | { | ||
86 | 283 | mir::geometry::Size requested_size{spec.width.value(), spec.height.value()}; | ||
87 | 284 | mir::geometry::Size actual_size{surface_proto.width(), surface_proto.height()}; | ||
88 | 285 | auto event_handler = spec.event_handler.value(); | ||
89 | 286 | if (requested_size != actual_size) | ||
90 | 287 | { | ||
91 | 288 | auto event = mev::make_event(mf::SurfaceId{surface_proto.id().value()}, actual_size); | ||
92 | 289 | event_handler.callback(window, event.get(), event_handler.context); | ||
93 | 290 | } | ||
94 | 291 | } | ||
95 | 292 | } | ||
96 | 293 | |||
97 | 294 | std::mutex connection_guard; | 279 | std::mutex connection_guard; |
98 | 295 | MirConnection* valid_connections{nullptr}; | 280 | MirConnection* valid_connections{nullptr}; |
99 | 296 | } | 281 | } |
100 | @@ -485,9 +470,22 @@ | |||
101 | 485 | } | 470 | } |
102 | 486 | 471 | ||
103 | 487 | callback(surf.get(), context); | 472 | callback(surf.get(), context); |
104 | 473 | |||
105 | 474 | if (spec.width.is_set() && spec.height.is_set() && spec.event_handler.is_set()) | ||
106 | 475 | { | ||
107 | 476 | mir::geometry::Size requested_size{spec.width.value(), spec.height.value()}; | ||
108 | 477 | mir::geometry::Size actual_size{(*surface_proto).width(), (*surface_proto).height()}; | ||
109 | 478 | auto event_handler = spec.event_handler.value(); | ||
110 | 479 | if (requested_size != actual_size) | ||
111 | 480 | { | ||
112 | 481 | auto event = mir::events::make_event(mir::frontend::SurfaceId{(*surface_proto).id().value()}, actual_size); | ||
113 | 482 | lock.unlock(); | ||
114 | 483 | event_handler.callback(surf.get(), event.get(), event_handler.context); | ||
115 | 484 | lock.lock(); | ||
116 | 485 | } | ||
117 | 486 | } | ||
118 | 487 | |||
119 | 488 | request->wh->result_received(); | 488 | request->wh->result_received(); |
120 | 489 | |||
121 | 490 | send_resize_event_if_needed(surf.get(), spec, *surface_proto); | ||
122 | 491 | surface_requests.erase(request_it); | 489 | surface_requests.erase(request_it); |
123 | 492 | } | 490 | } |
124 | 493 | 491 |
Is this reliable?
I had previously discovered that you can't rely on the resize callback occurring before the app starts rendering its first frame:
https:/ /code.launchpad .net/~vanvugt/ mir/fix- 1686620/ +merge/ 323378
So I guess if you are relying on the callback then the app could render two frames on startup... First at the size it requested, and very soon again at the size the shell requested.
It won't look pretty rendering that first frame at the wrong size so I suggest using the EGL_WIDTH/HEIGHT approach shown above. Sounds like it just got broken by the Mesa-RS changes. So if Mesa is now reporting a bogus EGL_WIDTH/HEIGHT that really needs to be fixed (as a matter of higher priority and also would supersede this proposal).