renderer-native: Resize legacy onscreen before panting

By creating a pending gbm/EGL surface pair, only setting it on
swap-buffers, we would draw onto a buffer on the old surface, then swap
the buffer from the new surface, causing the first frame after a
hot-plug always having no content.

This was in the past not very noticable since some non-deterministic but
frequent side effect in gnome-shell caused hot-plugging to always render
two new frames, but after "Introduce regional stage rendering", this
side effect did not occur as often, thus making it more visible.

This commit updates the current gbm/EGL surface pair before painting a
frame, so that when the frame is painted, the surface with the correct
size is used and the buffer from correct surface is swapped.

https://bugzilla.gnome.org/show_bug.cgi?id=768976
This commit is contained in:
Jonas Ådahl 2016-07-06 13:17:34 +08:00
parent aecd98b847
commit e891a8b628
2 changed files with 98 additions and 75 deletions

View File

@ -71,9 +71,6 @@ typedef struct _MetaOnscreenNative
struct gbm_bo *next_bo;
gboolean pending_swap_notify;
EGLSurface *pending_egl_surface;
struct gbm_surface *pending_surface;
gboolean pending_set_crtc;
MetaRendererView *view;
@ -606,33 +603,10 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
view = onscreen_native->view;
clutter_stage_view_get_layout (CLUTTER_STAGE_VIEW (view), &view_layout);
if (onscreen_native->pending_egl_surface)
{
CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen);
eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface);
egl_onscreen->egl_surface = onscreen_native->pending_egl_surface;
onscreen_native->pending_egl_surface = NULL;
_cogl_framebuffer_winsys_update_size (fb,
view_layout.width,
view_layout.height);
cogl_context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND;
}
parent_vtable->onscreen_swap_buffers_with_damage (onscreen,
rectangles,
n_rectangles);
if (onscreen_native->pending_surface)
{
free_current_bo (onscreen);
if (onscreen_native->surface)
gbm_surface_destroy (onscreen_native->surface);
onscreen_native->surface = onscreen_native->pending_surface;
onscreen_native->pending_surface = NULL;
}
/* Now we need to set the CRTC to whatever is the front buffer */
onscreen_native->next_bo =
gbm_surface_lock_front_buffer (onscreen_native->surface);
@ -887,14 +861,27 @@ meta_renderer_native_set_legacy_view_size (MetaRendererNative *renderer_native,
if (width != view_layout.width || height != view_layout.height)
{
MetaBackend *backend = meta_get_backend ();
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaMonitorManagerKms *monitor_manager_kms =
META_MONITOR_MANAGER_KMS (monitor_manager);
CoglFramebuffer *framebuffer =
clutter_stage_view_get_framebuffer (stage_view);
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
CoglDisplayEGL *egl_display = cogl_display->winsys;
struct gbm_surface *new_surface;
EGLSurface new_egl_surface;
/*
* Ensure we don't have any pending flips that will want
* to swap the current buffer.
*/
while (onscreen_native->next_fb_id != 0)
meta_monitor_manager_kms_wait_for_flip (monitor_manager_kms);
/* Need to drop the GBM surface and create a new one */
if (!meta_renderer_native_create_surface (renderer_native,
@ -904,29 +891,36 @@ meta_renderer_native_set_legacy_view_size (MetaRendererNative *renderer_native,
error))
return FALSE;
if (egl_onscreen->egl_surface)
{
_cogl_winsys_egl_make_current (cogl_display,
egl_display->dummy_surface,
egl_display->dummy_surface,
egl_display->egl_context);
eglDestroySurface (egl_renderer->edpy,
egl_onscreen->egl_surface);
}
if (onscreen_native->pending_egl_surface)
eglDestroySurface (egl_renderer->edpy,
onscreen_native->pending_egl_surface);
if (onscreen_native->pending_surface)
gbm_surface_destroy (onscreen_native->pending_surface);
/* If there's already a surface, wait until the next swap to switch
* it out, otherwise, if we're just starting up we can use the new
* surface right away.
/*
* Release the current buffer and destroy the associated surface. The
* kernel will deal with keeping the actual buffer alive until its no
* longer used.
*/
if (onscreen_native->surface != NULL)
{
onscreen_native->pending_surface = new_surface;
onscreen_native->pending_egl_surface = new_egl_surface;
}
else
{
onscreen_native->surface = new_surface;
egl_onscreen->egl_surface = new_egl_surface;
free_current_bo (onscreen);
g_clear_pointer (&onscreen_native->surface, gbm_surface_destroy);
_cogl_framebuffer_winsys_update_size (framebuffer, width, height);
}
/*
* Update the active gbm and egl surfaces and make sure they they are
* used for drawing the coming frame.
*/
onscreen_native->surface = new_surface;
egl_onscreen->egl_surface = new_egl_surface;
_cogl_winsys_egl_make_current (cogl_display,
egl_onscreen->egl_surface,
egl_onscreen->egl_surface,
egl_display->egl_context);
_cogl_framebuffer_winsys_update_size (framebuffer, width, height);
}
meta_renderer_native_queue_modes_reset (renderer_native);

View File

@ -43,6 +43,10 @@ struct _MetaStageNative
int64_t presented_frame_counter_sync;
int64_t presented_frame_counter_complete;
gboolean pending_resize;
int pending_width;
int pending_height;
};
static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL;
@ -164,35 +168,9 @@ meta_stage_native_legacy_set_size (MetaStageNative *stage_native,
int width,
int height)
{
MetaBackend *backend = meta_get_backend ();
MetaRenderer *renderer = meta_backend_get_renderer (backend);
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
MetaRendererView *legacy_view;
GError *error = NULL;
cairo_rectangle_int_t view_layout;
legacy_view = get_legacy_view (renderer);
if (!legacy_view)
return;
if (!meta_renderer_native_set_legacy_view_size (renderer_native,
legacy_view,
width, height,
&error))
{
meta_warning ("Applying display configuration failed: %s\n",
error->message);
g_error_free (error);
return;
}
view_layout = (cairo_rectangle_int_t) {
.width = width,
.height = height
};
g_object_set (G_OBJECT (legacy_view),
"layout", &view_layout,
NULL);
stage_native->pending_resize = TRUE;
stage_native->pending_width = width;
stage_native->pending_height = height;
}
static void
@ -282,6 +260,56 @@ meta_stage_native_get_frame_counter (ClutterStageWindow *stage_window)
return meta_renderer_native_get_frame_counter (renderer_native);
}
static void
maybe_resize_legacy_view (MetaStageNative *stage_native)
{
MetaBackend *backend = meta_get_backend ();
MetaRenderer *renderer = meta_backend_get_renderer (backend);
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
MetaRendererView *legacy_view;
int width = stage_native->pending_width;
int height = stage_native->pending_height;
GError *error = NULL;
cairo_rectangle_int_t view_layout;
if (!stage_native->pending_resize)
return;
stage_native->pending_resize = FALSE;
legacy_view = get_legacy_view (renderer);
if (!legacy_view)
return;
if (!meta_renderer_native_set_legacy_view_size (renderer_native,
legacy_view,
width, height,
&error))
{
meta_warning ("Applying display configuration failed: %s\n",
error->message);
g_error_free (error);
return;
}
view_layout = (cairo_rectangle_int_t) {
.width = width,
.height = height
};
g_object_set (G_OBJECT (legacy_view),
"layout", &view_layout,
NULL);
}
static void
meta_stage_native_redraw (ClutterStageWindow *stage_window)
{
MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
maybe_resize_legacy_view (stage_native);
clutter_stage_window_parent_iface->redraw (stage_window);
}
static void
meta_stage_native_finish_frame (ClutterStageWindow *stage_window)
{
@ -315,5 +343,6 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
iface->get_geometry = meta_stage_native_get_geometry;
iface->get_views = meta_stage_native_get_views;
iface->get_frame_counter = meta_stage_native_get_frame_counter;
iface->redraw = meta_stage_native_redraw;
iface->finish_frame = meta_stage_native_finish_frame;
}