Merge lp:~albaguirre/qtubuntu/use-mir-rs-api into lp:qtubuntu

Proposed by Alberto Aguirre
Status: Needs review
Proposed branch: lp:~albaguirre/qtubuntu/use-mir-rs-api
Merge into: lp:qtubuntu
Diff against target: 592 lines (+154/-188)
7 files modified
debian/control (+3/-4)
src/ubuntumirclient/qmirclientcursor.cpp (+68/-25)
src/ubuntumirclient/qmirclientinput.cpp (+0/-4)
src/ubuntumirclient/qmirclientintegration.cpp (+1/-2)
src/ubuntumirclient/qmirclientintegration.h (+1/-2)
src/ubuntumirclient/qmirclientwindow.cpp (+80/-150)
src/ubuntumirclient/ubuntumirclient.pro (+1/-1)
To merge this branch: bzr merge lp:~albaguirre/qtubuntu/use-mir-rs-api
Reviewer Review Type Date Requested Status
Unity8 CI Bot continuous-integration Needs Fixing
Gerry Boland (community) Needs Information
Alan Griffiths Needs Information
Review via email: mp+321627@code.launchpad.net

Commit message

Avoid use of deprecated mir EGL related apis.

With the new mesa update, the EGLNativeDisplayType is MirConnection * and the EGLNativeWindowType is a MirRenderSurface *.

Ignore deprecation warnings on use of MirRenderSurface - its "deprecated" because it'll be renamed in mir 1.0.

To post a comment you must log in.
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

This would be nicely simplified by lp:~alan-griffiths/mir/deprecation-macros plus -DMIR_DEPRECATE_RENDERSURFACES=0

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

Looks mostly sensible, but I need to get more familiar with qtubuntu to be sure.

Can we aim to land lp:~alan-griffiths/mir/deprecation-macros and use -DMIR_DEPRECATE_RENDERSURFACES=0 - or building against trunk Mir an issue?

review: Needs Information
Revision history for this message
Gerry Boland (gerboland) wrote :

I have a question about how pixel formats work with the newer Mir API. I see you've removed code where Qt could set a desired pixel format on the mir surface - is this feature impossible to replicate?

This was done because sometimes the EGL config chosen may have an alpha buffer enabled, even if Qt doesn't need it. We used the mir pixel format to inform the Mir compositor that blending is not required in that case - a nice optimisation.

review: Needs Information
Revision history for this message
Gerry Boland (gerboland) wrote :

I agree with Alan that using his deprecation bits would be nice, but I'd be ok with landing this in the current state if we need this to land first.

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

> I have a question about how pixel formats work with the newer Mir API. I see
> you've removed code where Qt could set a desired pixel format on the mir
> surface - is this feature impossible to replicate?

Mir currently has "Window" and "RenderSurface" but not "surface". I assume you mean "RenderSurface"?

> This was done because sometimes the EGL config chosen may have an alpha buffer
> enabled, even if Qt doesn't need it. We used the mir pixel format to inform
> the Mir compositor that blending is not required in that case - a nice
> optimisation.

I don't see that in the RS code, but I'm still learning my way around it.

Revision history for this message
Gerry Boland (gerboland) wrote :

And the obvious question: can we jump to using non-deprecated APIs in one go?

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

> And the obvious question: can we jump to using non-deprecated APIs in one go?

It depends.

The reason for the current situation being that we can't introduce the intended "surface" APIs until we delete the current ones.

The RS APIs are a temporary workaround to enable the "surface" functionality without a name clash.

If we decide not to rename MirRenderSurface => MirSurface in 1.0 we can just remove the deprecation of render surface.

Revision history for this message
Gerry Boland (gerboland) wrote :

+ // Assume that the buffer size matches the surface size at creation time
I'd rather not make that assumption. Does the new API loose this functionality?

Revision history for this message
Gerry Boland (gerboland) wrote :

+bool UbuntuSurface::needsRepaint() const
+{
+ return mNeedsRepaint;

This can totally go away AFAICS, since this changes the buffer "ownership" drastically. Before when we got a surface resize event, we had to keep swapping buffers until we got one sized at the new size - so we had to keep force repainting until that happened. Now since Qt owns the buffer, it can resize immediately.

Removing all the needsRepaint stuff also makes resizing smoother IMO in my tests here.

Revision history for this message
Gerry Boland (gerboland) wrote :

overall looks ok, I just
- miss the pixel format optimisation
- would ultimately like to remove any deprecated api use (but not necessarily in this MP)

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

> I have a question about how pixel formats work with the newer Mir API. I see
> you've removed code where Qt could set a desired pixel format on the mir
> surface - is this feature impossible to replicate?
>
> This was done because sometimes the EGL config chosen may have an alpha buffer
> enabled, even if Qt doesn't need it. We used the mir pixel format to inform
> the Mir compositor that blending is not required in that case - a nice
> optimisation.

The pixel format for EGL rendering is now set through the chosen EGLConfig. The new mir mesa path will actually obey the pixel format selected.

If you want to use mir_pixel_format enums, you can specify a EGL_NATIVE_VISUAL_ID in the attribs list during eglChooseConfig and it'll be respected.

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

> + // Assume that the buffer size matches the surface size at creation time
> I'd rather not make that assumption. Does the new API loose this
> functionality?

If the size chosen by the server is changed, it now gets delivered as a resize event as long as the event handler was registered through the window spec. This means that the same resizing logic is applied.

I tested this slightly by using the fullscreen window manager option in mir's demo server.

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

> overall looks ok, I just
> - miss the pixel format optimisation
I'll look into that, I should just be able to use EGL_NATIVE_VISUAL_ID.

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

> Looks mostly sensible, but I need to get more familiar with qtubuntu to be
> sure.
>
> Can we aim to land lp:~alan-griffiths/mir/deprecation-macros and use
> -DMIR_DEPRECATE_RENDERSURFACES=0 - or building against trunk Mir an issue?

Shouldn't be an issue on a local machine, but qtubuntu's CI would be.

397. By Alberto Aguirre

Cleanup #pragmas and unneeded repaints when resizing.

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)

Unmerged revisions

397. By Alberto Aguirre

Cleanup #pragmas and unneeded repaints when resizing.

396. By Alberto Aguirre

Avoid using mir_window_get_parameters, it will be deprecated

395. By Alberto Aguirre

Remove mir_event_type_key and mir_event_type_motion as they are deprecated.

394. By Alberto Aguirre

Use MirRenderSurface for pixmap cursors.

Creating buffer streams directly will be deprecated in mir in the near future, instead use render surfaces.

393. By Alberto Aguirre

Update resizing now that client can drive the buffer size through mir_render_surface_set_size.

392. By Alberto Aguirre

Avoid use of deprecated mir EGL related apis.

With the new mesa update, the EGLNativeDisplayType is MirConnection and the EGLNativeWindowType is a MirRenderSurface.
Ignore deprecation warnings on use of MirRenderSurface - its "deprecated" because it'll be renamed in mir 1.0.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/control'
--- debian/control 2017-01-10 06:41:48 +0000
+++ debian/control 2017-05-27 01:33:26 +0000
@@ -4,14 +4,13 @@
4Build-Depends: debhelper (>= 9),4Build-Depends: debhelper (>= 9),
5 libatspi2.0-dev,5 libatspi2.0-dev,
6 libcontent-hub-dev (>= 0.2),6 libcontent-hub-dev (>= 0.2),
7 libegl1-mesa-dev,7 libegl1-mesa-dev (>= 17.0.2),
8 libfontconfig1-dev,8 libfontconfig1-dev,
9 libfreetype6-dev,9 libfreetype6-dev,
10 libgles2-mesa-dev,10 libgles2-mesa-dev (>= 17.0.2),
11 libglib2.0-dev,11 libglib2.0-dev,
12 libinput-dev,12 libinput-dev,
13 libmirclient-dev (>= 0.25.0),13 libmirclient-dev (>= 0.26.1),
14 libmirclient-debug-extension-dev,
15 libmtdev-dev,14 libmtdev-dev,
16 libubuntu-application-api-dev (>= 2.9.0),15 libubuntu-application-api-dev (>= 2.9.0),
17 libudev-dev,16 libudev-dev,
1817
=== modified file 'src/ubuntumirclient/qmirclientcursor.cpp'
--- src/ubuntumirclient/qmirclientcursor.cpp 2017-03-28 17:12:13 +0000
+++ src/ubuntumirclient/qmirclientcursor.cpp 2017-05-27 01:33:26 +0000
@@ -138,11 +138,17 @@
138{138{
139public:139public:
140 CursorWindowSpec(MirConnection *connection, const char *name)140 CursorWindowSpec(MirConnection *connection, const char *name)
141 : spec(mir_create_window_spec(connection))141 : CursorWindowSpec(connection)
142 {142 {
143 mir_window_spec_set_cursor_name(spec, name);143 mir_window_spec_set_cursor_name(spec, name);
144 }144 }
145145
146 CursorWindowSpec(MirConnection *connection, MirRenderSurface *surface, int hotspotX, int hotspotY)
147 : CursorWindowSpec(connection)
148 {
149 mir_window_spec_set_cursor_render_surface(spec, surface, hotspotX, hotspotY);
150 }
151
146 ~CursorWindowSpec()152 ~CursorWindowSpec()
147 {153 {
148 mir_window_spec_release(spec);154 mir_window_spec_release(spec);
@@ -153,8 +159,60 @@
153 mir_window_apply_spec(window, spec);159 mir_window_apply_spec(window, spec);
154 }160 }
155private:161private:
162 CursorWindowSpec(MirConnection *connection) : spec(mir_create_window_spec(connection)) {}
156 MirWindowSpec * const spec;163 MirWindowSpec * const spec;
157};164};
165
166class BufferStream
167{
168public:
169 BufferStream(MirRenderSurface *surface, int width, int height)
170 : stream(mir_render_surface_get_buffer_stream(surface, width, height, mir_pixel_format_argb_8888))
171 {
172 }
173
174 void draw(QImage const& image)
175 {
176 MirGraphicsRegion region;
177 const bool validRegion = mir_buffer_stream_get_graphics_region(stream, &region);
178 if (!validRegion)
179 throw std::runtime_error("Could not get graphics region to draw into");
180
181 auto regionLine = region.vaddr;
182 Q_ASSERT(image.bytesPerLine() <= region.stride);
183
184 for (int i = 0; i < image.height(); ++i) {
185 memcpy(regionLine, image.scanLine(i), image.bytesPerLine());
186 regionLine += region.stride;
187 }
188 mir_buffer_stream_swap_buffers_sync(stream);
189 }
190
191private:
192 MirBufferStream * const stream;
193};
194
195class RenderSurface
196{
197public:
198 RenderSurface(MirConnection *connection, int width, int height)
199 : surface(mir_connection_create_render_surface_sync(connection, width, height)),
200 stream(surface, width, height)
201 {
202 if (!mir_render_surface_is_valid(surface)) {
203 throw std::runtime_error(mir_render_surface_get_error_message(surface));
204 }
205 }
206
207 ~RenderSurface() { mir_render_surface_release(surface); }
208 operator MirRenderSurface *() const { return surface; }
209 void draw(QImage const& image) { stream.draw(image); }
210
211private:
212 MirRenderSurface * const surface;
213 BufferStream stream;
214};
215
158} // anonymous namespace216} // anonymous namespace
159217
160void QMirClientCursor::changeCursor(QCursor *windowCursor, QWindow *window)218void QMirClientCursor::changeCursor(QCursor *windowCursor, QWindow *window)
@@ -196,30 +254,15 @@
196 image = image.convertToFormat(QImage::Format_ARGB32);254 image = image.convertToFormat(QImage::Format_ARGB32);
197 }255 }
198256
199 MirBufferStream *bufferStream = mir_connection_create_buffer_stream_sync(mConnection,257 try {
200 image.width(), image.height(), mir_pixel_format_argb_8888, mir_buffer_usage_software);258 RenderSurface surface(mConnection, image.width(), image.height());
201259 surface.draw(image);
202 {260
203 MirGraphicsRegion region;261 CursorWindowSpec spec(mConnection, surface, cursor.hotSpot().x(), cursor.hotSpot().y());
204 mir_buffer_stream_get_graphics_region(bufferStream, &region);262 spec.apply(window);
205263 } catch(std::exception const& e) {
206 char *regionLine = region.vaddr;264 qWarning("Error applying pixmap cursor: %s", e.what());
207 Q_ASSERT(image.bytesPerLine() <= region.stride);265 }
208 for (int i = 0; i < image.height(); ++i) {
209 memcpy(regionLine, image.scanLine(i), image.bytesPerLine());
210 regionLine += region.stride;
211 }
212 }
213
214 mir_buffer_stream_swap_buffers_sync(bufferStream);
215
216 {
217 auto configuration = mir_cursor_configuration_from_buffer_stream(bufferStream, cursor.hotSpot().x(), cursor.hotSpot().y());
218 mir_window_configure_cursor(window, configuration);
219 mir_cursor_configuration_destroy(configuration);
220 }
221
222 mir_buffer_stream_release_sync(bufferStream);
223}266}
224267
225void QMirClientCursor::applyDefaultCursorConfiguration(MirWindow *window)268void QMirClientCursor::applyDefaultCursorConfiguration(MirWindow *window)
226269
=== modified file 'src/ubuntumirclient/qmirclientinput.cpp'
--- src/ubuntumirclient/qmirclientinput.cpp 2017-02-21 18:24:45 +0000
+++ src/ubuntumirclient/qmirclientinput.cpp 2017-05-27 01:33:26 +0000
@@ -232,10 +232,6 @@
232{232{
233 switch (t)233 switch (t)
234 {234 {
235 case mir_event_type_key:
236 return "key";
237 case mir_event_type_motion:
238 return "motion";
239 case mir_event_type_window:235 case mir_event_type_window:
240 return "window";236 return "window";
241 case mir_event_type_resize:237 case mir_event_type_resize:
242238
=== modified file 'src/ubuntumirclient/qmirclientintegration.cpp'
--- src/ubuntumirclient/qmirclientintegration.cpp 2017-04-04 00:46:48 +0000
+++ src/ubuntumirclient/qmirclientintegration.cpp 2017-05-27 01:33:26 +0000
@@ -130,8 +130,7 @@
130 QSurfaceFormat::setDefaultFormat(defaultFormat);130 QSurfaceFormat::setDefaultFormat(defaultFormat);
131131
132 // Initialize EGL.132 // Initialize EGL.
133 mEglNativeDisplay = mir_connection_get_egl_native_display(mMirConnection);133 ASSERT((mEglDisplay = eglGetDisplay(mMirConnection)) != EGL_NO_DISPLAY);
134 ASSERT((mEglDisplay = eglGetDisplay(mEglNativeDisplay)) != EGL_NO_DISPLAY);
135 ASSERT(eglInitialize(mEglDisplay, nullptr, nullptr) == EGL_TRUE);134 ASSERT(eglInitialize(mEglDisplay, nullptr, nullptr) == EGL_TRUE);
136135
137 // Has debug mode been requsted, either with "-testability" switch or QT_LOAD_TESTABILITY env var136 // Has debug mode been requsted, either with "-testability" switch or QT_LOAD_TESTABILITY env var
138137
=== modified file 'src/ubuntumirclient/qmirclientintegration.h'
--- src/ubuntumirclient/qmirclientintegration.h 2017-03-15 09:21:47 +0000
+++ src/ubuntumirclient/qmirclientintegration.h 2017-05-27 01:33:26 +0000
@@ -89,7 +89,7 @@
89 // New methods.89 // New methods.
90 MirConnection *mirConnection() const { return mMirConnection; }90 MirConnection *mirConnection() const { return mMirConnection; }
91 EGLDisplay eglDisplay() const { return mEglDisplay; }91 EGLDisplay eglDisplay() const { return mEglDisplay; }
92 EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; }92 EGLNativeDisplayType eglNativeDisplay() const { return mMirConnection; }
93 QMirClientAppStateController *appStateController() const { return mAppStateController.data(); }93 QMirClientAppStateController *appStateController() const { return mAppStateController.data(); }
94 QMirClientScreenObserver *screenObserver() const { return mScreenObserver.data(); }94 QMirClientScreenObserver *screenObserver() const { return mScreenObserver.data(); }
95 QMirClientDebugExtension *debugExtension() const { return mDebugExtension.data(); }95 QMirClientDebugExtension *debugExtension() const { return mDebugExtension.data(); }
@@ -125,7 +125,6 @@
125125
126 // EGL related126 // EGL related
127 EGLDisplay mEglDisplay{EGL_NO_DISPLAY};127 EGLDisplay mEglDisplay{EGL_NO_DISPLAY};
128 EGLNativeDisplayType mEglNativeDisplay;
129};128};
130129
131#endif // QMIRCLIENTINTEGRATION_H130#endif // QMIRCLIENTINTEGRATION_H
132131
=== modified file 'src/ubuntumirclient/qmirclientwindow.cpp'
--- src/ubuntumirclient/qmirclientwindow.cpp 2017-03-28 17:12:13 +0000
+++ src/ubuntumirclient/qmirclientwindow.cpp 2017-05-27 01:33:26 +0000
@@ -75,12 +75,6 @@
7575
76using Spec = std::unique_ptr<MirWindowSpec, MirSpecDeleter>;76using Spec = std::unique_ptr<MirWindowSpec, MirSpecDeleter>;
7777
78EGLNativeWindowType nativeWindowFor(MirWindow *surf)
79{
80 auto stream = mir_window_get_buffer_stream(surf);
81 return reinterpret_cast<EGLNativeWindowType>(mir_buffer_stream_get_egl_native_window(stream));
82}
83
84const char *qtWindowStateToStr(Qt::WindowState state)78const char *qtWindowStateToStr(Qt::WindowState state)
85{79{
86 switch (state) {80 switch (state) {
@@ -114,24 +108,6 @@
114 Q_UNREACHABLE();108 Q_UNREACHABLE();
115}109}
116110
117const char *mirPixelFormatToStr(MirPixelFormat pixelFormat)
118{
119 switch (pixelFormat) {
120 case mir_pixel_format_invalid: return "invalid";
121 case mir_pixel_format_abgr_8888: return "ABGR8888";
122 case mir_pixel_format_xbgr_8888: return "XBGR8888";
123 case mir_pixel_format_argb_8888: return "ARGB8888";
124 case mir_pixel_format_xrgb_8888: return "XRGB8888";
125 case mir_pixel_format_bgr_888: return "BGR888";
126 case mir_pixel_format_rgb_888: return "RGB888";
127 case mir_pixel_format_rgb_565: return "RGB565";
128 case mir_pixel_format_rgba_5551: return "RGBA5551";
129 case mir_pixel_format_rgba_4444: return "RGBA4444";
130 case mir_pixel_formats: Q_UNREACHABLE();
131 }
132 Q_UNREACHABLE();
133}
134
135const char *mirWindowTypeToStr(MirWindowType type)111const char *mirWindowTypeToStr(MirWindowType type)
136{112{
137 switch (type) {113 switch (type) {
@@ -221,12 +197,23 @@
221 return requiresParent(qtWindowTypeToMirWindowType(type));197 return requiresParent(qtWindowTypeToMirWindowType(type));
222}198}
223199
224Spec makeSurfaceSpec(QWindow *window, MirPixelFormat pixelFormat, QMirClientWindow *parentWindowHandle,200QRect geometryFor(QWindow *window)
225 MirConnection *connection)201{
226{202 auto geometry = window->geometry();
227 const auto geometry = window->geometry();203 if (geometry.width() < 1)
228 const int width = geometry.width() > 0 ? geometry.width() : 1;204 geometry.setWidth(1);
229 const int height = geometry.height() > 0 ? geometry.height() : 1;205 if (geometry.height() < 1)
206 geometry.setHeight(1);
207
208 return geometry;
209}
210
211Spec makeWindowSpec(QWindow *window, QMirClientWindow *parentWindowHandle,
212 MirRenderSurface *surface, MirConnection *connection)
213{
214 const auto geometry = geometryFor(window);
215 const int width = geometry.width();
216 const int height = geometry.height();
230 auto type = qtWindowTypeToMirWindowType(window->type());217 auto type = qtWindowTypeToMirWindowType(window->type());
231218
232 MirRectangle location{geometry.x(), geometry.y(), 0, 0};219 MirRectangle location{geometry.x(), geometry.y(), 0, 0};
@@ -272,7 +259,6 @@
272 // There's no helper function for satellite windows. Guess they're not very popular259 // There's no helper function for satellite windows. Guess they're not very popular
273 spec = Spec{mir_create_window_spec(connection)};260 spec = Spec{mir_create_window_spec(connection)};
274 mir_window_spec_set_type(spec.get(), mir_window_type_satellite);261 mir_window_spec_set_type(spec.get(), mir_window_type_satellite);
275 mir_window_spec_set_buffer_usage(spec.get(), mir_buffer_usage_hardware);
276 mir_window_spec_set_parent(spec.get(), parent);262 mir_window_spec_set_parent(spec.get(), parent);
277 mir_window_spec_set_width(spec.get(), width);263 mir_window_spec_set_width(spec.get(), width);
278 mir_window_spec_set_height(spec.get(), height);264 mir_window_spec_set_height(spec.get(), height);
@@ -282,9 +268,9 @@
282 break;268 break;
283 }269 }
284270
285 mir_window_spec_set_pixel_format(spec.get(), pixelFormat);271 mir_window_spec_add_render_surface(spec.get(), surface, width, height, 0, 0);
286272
287 qCDebug(mirclient, "makeSurfaceSpec(window=%p): %s spec (type=0x%x, position=(%d, %d)px, size=(%dx%d)px)",273 qCDebug(mirclient, "makeWindowSpec(window=%p): %s spec (type=0x%x, position=(%d, %d)px, size=(%dx%d)px)",
288 window, mirWindowTypeToStr(type), window->type(), location.left, location.top, width, height);274 window, mirWindowTypeToStr(type), window->type(), location.left, location.top, width, height);
289275
290 return spec;276 return spec;
@@ -331,14 +317,29 @@
331 mir_window_spec_set_input_shape(spec, rects, count);317 mir_window_spec_set_input_shape(spec, rects, count);
332}318}
333319
320MirRenderSurface *createMirSurface(QWindow *window, MirConnection *connection)
321{
322 const auto geometry = geometryFor(window);
323 const int width = geometry.width();
324 const int height = geometry.height();
325
326 auto surface = mir_connection_create_render_surface_sync(connection, width, height);
327 if (!mir_render_surface_is_valid(surface))
328 {
329 auto errorMsg = mir_render_surface_get_error_message(surface);
330 qFatal("Failed to create mir surface: %s", errorMsg);
331 }
332 return surface;
333}
334
334MirWindow *createMirWindow(QWindow *window, int mirOutputId, QMirClientWindow *parentWindowHandle,335MirWindow *createMirWindow(QWindow *window, int mirOutputId, QMirClientWindow *parentWindowHandle,
335 MirPixelFormat pixelFormat, MirConnection *connection,336 MirRenderSurface *surface, MirConnection *connection,
336 MirWindowEventCallback inputCallback, void *inputContext)337 MirWindowEventCallback eventCallback, void *context)
337{338{
338 auto spec = makeSurfaceSpec(window, pixelFormat, parentWindowHandle, connection);339 auto spec = makeWindowSpec(window, parentWindowHandle, surface, connection);
339340
340 // Install event handler as early as possible341 // Install event handler as early as possible
341 mir_window_spec_set_event_handler(spec.get(), inputCallback, inputContext);342 mir_window_spec_set_event_handler(spec.get(), eventCallback, context);
342343
343 const auto title = window->title().toUtf8();344 const auto title = window->title().toUtf8();
344 mir_window_spec_set_name(spec.get(), title.constData());345 mir_window_spec_set_name(spec.get(), title.constData());
@@ -358,9 +359,14 @@
358 mir_window_spec_set_state(spec.get(), mir_window_state_hidden);359 mir_window_spec_set_state(spec.get(), mir_window_state_hidden);
359 }360 }
360361
361 auto surface = mir_create_window_sync(spec.get());362 auto mirWindow = mir_create_window_sync(spec.get());
362 Q_ASSERT(mir_window_is_valid(surface));363 if (!mir_window_is_valid(mirWindow))
363 return surface;364 {
365 auto errorMsg = mir_window_get_error_message(mirWindow);
366 qFatal("Failed to create mir window: %s", errorMsg);
367 }
368
369 return mirWindow;
364}370}
365371
366QMirClientWindow *getParentIfNecessary(QWindow *window, QMirClientInput *input)372QMirClientWindow *getParentIfNecessary(QWindow *window, QMirClientInput *input)
@@ -377,18 +383,6 @@
377 return parentWindowHandle;383 return parentWindowHandle;
378}384}
379385
380MirPixelFormat disableAlphaBufferIfPossible(MirPixelFormat pixelFormat)
381{
382 switch (pixelFormat) {
383 case mir_pixel_format_abgr_8888:
384 return mir_pixel_format_xbgr_8888;
385 case mir_pixel_format_argb_8888:
386 return mir_pixel_format_xrgb_8888;
387 default: // can do nothing, leave it alone
388 return pixelFormat;
389 }
390}
391
392// FIXME - in order to work around https://bugs.launchpad.net/mir/+bug/1346633386// FIXME - in order to work around https://bugs.launchpad.net/mir/+bug/1346633
393// we need to guess the panel height (3GU)387// we need to guess the panel height (3GU)
394int panelHeight()388int panelHeight()
@@ -426,7 +420,6 @@
426420
427 void onSwapBuffersDone();421 void onSwapBuffersDone();
428 void handleSurfaceResized(int width, int height);422 void handleSurfaceResized(int width, int height);
429 int needsRepaint() const;
430423
431 MirWindowState state() const { return mir_window_get_state(mMirWindow); }424 MirWindowState state() const { return mir_window_get_state(mMirWindow); }
432 void setState(MirWindowState state);425 void setState(MirWindowState state);
@@ -448,7 +441,7 @@
448 QString persistentSurfaceId();441 QString persistentSurfaceId();
449442
450private:443private:
451 static void surfaceEventCallback(MirWindow* surface, const MirEvent *event, void* context);444 static void windowEventCallback(MirWindow* surface, const MirEvent *event, void* context);
452 void postEvent(const MirEvent *event);445 void postEvent(const MirEvent *event);
453446
454 QWindow * const mWindow;447 QWindow * const mWindow;
@@ -458,14 +451,12 @@
458 QMirClientWindow * mParentWindowHandle{nullptr};451 QMirClientWindow * mParentWindowHandle{nullptr};
459452
460 MirWindow* mMirWindow;453 MirWindow* mMirWindow;
454 MirRenderSurface* mMirSurface;
461 const EGLDisplay mEglDisplay;455 const EGLDisplay mEglDisplay;
462 EGLSurface mEglSurface;456 EGLSurface mEglSurface;
463457
464 bool mNeedsRepaint;
465 bool mParented;458 bool mParented;
466 QSize mBufferSize;
467 QSurfaceFormat mFormat;459 QSurfaceFormat mFormat;
468 MirPixelFormat mPixelFormat;
469460
470 QMutex mTargetSizeMutex;461 QMutex mTargetSizeMutex;
471 QSize mTargetSize;462 QSize mTargetSize;
@@ -479,7 +470,6 @@
479 , mInput(input)470 , mInput(input)
480 , mConnection(connection)471 , mConnection(connection)
481 , mEglDisplay(display)472 , mEglDisplay(display)
482 , mNeedsRepaint(false)
483 , mParented(mWindow->transientParent() || mWindow->parent())473 , mParented(mWindow->transientParent() || mWindow->parent())
484 , mFormat(mWindow->requestedFormat())474 , mFormat(mWindow->requestedFormat())
485 , mShellChrome(mWindow->flags() & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal)475 , mShellChrome(mWindow->flags() & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal)
@@ -506,50 +496,33 @@
506496
507 mFormat = q_glFormatFromConfig(display, config, mFormat);497 mFormat = q_glFormatFromConfig(display, config, mFormat);
508498
509 // Have Mir decide the pixel format most suited to the chosen EGLConfig. This is the only way
510 // Mir will know what EGLConfig has been chosen - it cannot deduce it from the buffers.
511 mPixelFormat = mir_connection_get_egl_pixel_format(connection, display, config);
512 // But the chosen EGLConfig might have an alpha buffer enabled, even if not requested by the client.
513 // If that's the case, try to edit the chosen pixel format in order to disable the alpha buffer.
514 // This is an optimization for the compositor, as it can avoid blending this surface.
515 if (mWindow->requestedFormat().alphaBufferSize() < 0) {
516 mPixelFormat = disableAlphaBufferIfPossible(mPixelFormat);
517 }
518
519 const auto outputId = static_cast<QMirClientScreen *>(mWindow->screen()->handle())->mirOutputId();499 const auto outputId = static_cast<QMirClientScreen *>(mWindow->screen()->handle())->mirOutputId();
520500
521 mParentWindowHandle = getParentIfNecessary(mWindow, input);501 mParentWindowHandle = getParentIfNecessary(mWindow, input);
522502
523 mMirWindow = createMirWindow(mWindow, outputId, mParentWindowHandle, mPixelFormat, connection, surfaceEventCallback, this);503 mMirSurface = createMirSurface(mWindow, connection);
524 mEglSurface = eglCreateWindowSurface(mEglDisplay, config, nativeWindowFor(mMirWindow), nullptr);504 mMirWindow = createMirWindow(mWindow, outputId, mParentWindowHandle, mMirSurface, connection, windowEventCallback, this);
505 mEglSurface = eglCreateWindowSurface(mEglDisplay, config, reinterpret_cast<EGLNativeWindowType>(mMirSurface), nullptr);
525506
526 mNeedsExposeCatchup = mir_window_get_visibility(mMirWindow) == mir_window_visibility_occluded;507 mNeedsExposeCatchup = mir_window_get_visibility(mMirWindow) == mir_window_visibility_occluded;
527508
528 // Window manager can give us a final size different from what we asked for509 // Assume that the buffer size matches the surface size at creation time
529 // so let's check what we ended up getting
530 MirWindowParameters parameters;
531 mir_window_get_parameters(mMirWindow, &parameters);
532
533 auto geom = mWindow->geometry();510 auto geom = mWindow->geometry();
534 geom.setWidth(parameters.width);
535 geom.setHeight(parameters.height);
536
537 // Assume that the buffer size matches the surface size at creation time
538 mBufferSize = geom.size();
539 platformWindow->QPlatformWindow::setGeometry(geom);
540 QWindowSystemInterface::handleGeometryChange(mWindow, geom);
541511
542 qCDebug(mirclient) << "Created surface with geometry:" << geom << "title:" << mWindow->title();512 qCDebug(mirclient) << "Created surface with geometry:" << geom << "title:" << mWindow->title();
543 qCDebug(mirclientGraphics)513 qCDebug(mirclientGraphics)
544 << "Requested format:" << mWindow->requestedFormat()514 << "Requested format:" << mWindow->requestedFormat()
545 << "\nActual format:" << mFormat515 << "\nActual format:" << mFormat;
546 << "with associated Mir pixel format:" << mirPixelFormatToStr(mPixelFormat);
547}516}
548517
549UbuntuSurface::~UbuntuSurface()518UbuntuSurface::~UbuntuSurface()
550{519{
551 if (mEglSurface != EGL_NO_SURFACE)520 if (mEglSurface != EGL_NO_SURFACE) {
552 eglDestroySurface(mEglDisplay, mEglSurface);521 eglDestroySurface(mEglDisplay, mEglSurface);
522 }
523 if (mMirSurface) {
524 mir_render_surface_release(mMirSurface);
525 }
553 if (mMirWindow) {526 if (mMirWindow) {
554 mir_window_release_sync(mMirWindow);527 mir_window_release_sync(mMirWindow);
555 }528 }
@@ -606,30 +579,23 @@
606{579{
607 QMutexLocker lock(&mTargetSizeMutex);580 QMutexLocker lock(&mTargetSizeMutex);
608581
609 // mir's resize event is mainly a signal that we need to redraw our content. We use the582 // There could have been a flurry of resize events, only process the latest event
610 // width/height as identifiers to figure out if this is the latest surface resize event583 const bool needsResize = mTargetSize.width() == width && mTargetSize.height() == height;
611 // that has posted, discarding any old ones. This avoids issuing too many redraw events.584 if (needsResize) {
612 // see TODO in postEvent as the ideal way we should handle this.585 // Resize the buffers
613 // The actual buffer size may or may have not changed at this point, so let the rendering586 mir_render_surface_set_size(mMirSurface, width, height);
614 // thread drive the window geometry updates.587
615 mNeedsRepaint = mTargetSize.width() == width && mTargetSize.height() == height;588 //Resize the window
616}589 Spec spec{mir_create_window_spec(mConnection)};
617590 mir_window_spec_add_render_surface(spec.get(), mMirSurface, width, height, 0, 0);
618int UbuntuSurface::needsRepaint() const591 mir_window_apply_spec(mMirWindow, spec.get());
619{592
620 if (mNeedsRepaint) {593 QRect newGeometry = mPlatformWindow->geometry();
621 if (mTargetSize != mBufferSize) {594 newGeometry.setSize(mTargetSize);
622 //If the buffer hasn't changed yet, we need at least two redraws,595
623 //once to get the new buffer size and propagate the geometry changes596 mPlatformWindow->QPlatformWindow::setGeometry(newGeometry);
624 //and the second to redraw the content at the new size597 QWindowSystemInterface::handleGeometryChange(mWindow, newGeometry);
625 return 2;
626 } else {
627 // The buffer size has already been updated so we only need one redraw
628 // to render at the new size
629 return 1;
630 }
631 }598 }
632 return 0;
633}599}
634600
635void UbuntuSurface::setState(MirWindowState state)601void UbuntuSurface::setState(MirWindowState state)
@@ -653,35 +619,13 @@
653 static int sFrameNumber = 0;619 static int sFrameNumber = 0;
654 ++sFrameNumber;620 ++sFrameNumber;
655621
656 EGLint eglSurfaceWidth = -1;622 qCDebug(mirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d]",
657 EGLint eglSurfaceHeight = -1;623 mWindow, sFrameNumber);
658 eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &eglSurfaceWidth);
659 eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &eglSurfaceHeight);
660
661 const bool validSize = eglSurfaceWidth > 0 && eglSurfaceHeight > 0;
662
663 if (validSize && (mBufferSize.width() != eglSurfaceWidth || mBufferSize.height() != eglSurfaceHeight)) {
664
665 qCDebug(mirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - size changed (%d, %d) => (%d, %d)",
666 mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height(), eglSurfaceWidth, eglSurfaceHeight);
667
668 mBufferSize.rwidth() = eglSurfaceWidth;
669 mBufferSize.rheight() = eglSurfaceHeight;
670
671 QRect newGeometry = mPlatformWindow->geometry();
672 newGeometry.setSize(mBufferSize);
673
674 mPlatformWindow->QPlatformWindow::setGeometry(newGeometry);
675 QWindowSystemInterface::handleGeometryChange(mWindow, newGeometry);
676 } else {
677 qCDebug(mirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - buffer size (%d,%d)",
678 mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height());
679 }
680}624}
681625
682void UbuntuSurface::surfaceEventCallback(MirWindow *surface, const MirEvent *event, void* context)626void UbuntuSurface::windowEventCallback(MirWindow *window, const MirEvent *event, void* context)
683{627{
684 Q_UNUSED(surface);628 Q_UNUSED(window);
685 Q_ASSERT(context != nullptr);629 Q_ASSERT(context != nullptr);
686630
687 auto s = static_cast<UbuntuSurface *>(context);631 auto s = static_cast<UbuntuSurface *>(context);
@@ -692,9 +636,8 @@
692{636{
693 const auto eventType = mir_event_get_type(event);637 const auto eventType = mir_event_get_type(event);
694 if (mir_event_type_resize == eventType) {638 if (mir_event_type_resize == eventType) {
695 // TODO: The current event queue just accumulates all resize events;639 // The event queue just accumulates all resize events;
696 // It would be nicer if we could update just one event if that event has not been dispatched.640 // Use the width and height as an identifier of this latest event
697 // As a workaround, we use the width/height as an identifier of this latest event
698 // so the event handler (handleSurfaceResized) can discard/ignore old ones.641 // so the event handler (handleSurfaceResized) can discard/ignore old ones.
699 const auto resizeEvent = mir_event_get_resize_event(event);642 const auto resizeEvent = mir_event_get_resize_event(event);
700 const auto width = mir_resize_event_get_width(resizeEvent);643 const auto width = mir_resize_event_get_width(resizeEvent);
@@ -786,19 +729,6 @@
786 qCDebug(mirclient, "handleSurfaceResize(window=%p, size=(%dx%d)px", window(), width, height);729 qCDebug(mirclient, "handleSurfaceResize(window=%p, size=(%dx%d)px", window(), width, height);
787730
788 mSurface->handleSurfaceResized(width, height);731 mSurface->handleSurfaceResized(width, height);
789
790 // This resize event could have occurred just after the last buffer swap for this window.
791 // This means the client may still be holding a buffer with the older size. The first redraw call
792 // will then render at the old size. After swapping the client now will get a new buffer with the
793 // updated size but it still needs re-rendering so another redraw may be needed.
794 // A mir API to drop the currently held buffer would help here, so that we wouldn't have to redraw twice
795 auto const numRepaints = mSurface->needsRepaint();
796 lock.unlock();
797 qCDebug(mirclient, "handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints);
798 for (int i = 0; i < numRepaints; i++) {
799 qCDebug(mirclient, "handleSurfaceResize(window=%p) repainting size=(%dx%d)dp", window(), geometry().size().width(), geometry().size().height());
800 QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
801 }
802}732}
803733
804void QMirClientWindow::handleSurfaceExposeChange(bool exposed)734void QMirClientWindow::handleSurfaceExposeChange(bool exposed)
805735
=== modified file 'src/ubuntumirclient/ubuntumirclient.pro'
--- src/ubuntumirclient/ubuntumirclient.pro 2017-03-29 13:39:50 +0000
+++ src/ubuntumirclient/ubuntumirclient.pro 2017-05-27 01:33:26 +0000
@@ -6,7 +6,7 @@
66
7CONFIG += plugin no_keywords qpa/genericunixfontdatabase7CONFIG += plugin no_keywords qpa/genericunixfontdatabase
88
9DEFINES += MESA_EGL_NO_X11_HEADERS9DEFINES += MESA_EGL_NO_X11_HEADERS MIR_DEPRECATE_RENDERSURFACES=0 MIR_ENABLE_DEPRECATIONS=0
10# CONFIG += c++11 # only enables C++0x10# CONFIG += c++11 # only enables C++0x
11QMAKE_CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden -std=c++11 -Werror -Wall11QMAKE_CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden -std=c++11 -Werror -Wall
12QMAKE_LFLAGS += -std=c++11 -Wl,-no-undefined12QMAKE_LFLAGS += -std=c++11 -Wl,-no-undefined

Subscribers

People subscribed via source and target branches