The amazing lazy-copy-back-repaint-page-flip
Always use pageflipping, but avoid full repaint by copying back dirty regions from front to back. Additionally, we dealy copying back until we're ready to paint the new frame, so we can avoid copying areas that will be repainted anyway. This is the least amount of copying per frame we can get away with at all and at the same time we don't have to worry about stalling the GPU on synchronized blits since we always pageflip.
This commit is contained in:
parent
cb5582c4ab
commit
134ce072e7
@ -115,8 +115,16 @@ handle_configure (void *data, struct wl_shell *shell,
|
|||||||
|
|
||||||
stage_wayland = wl_surface_get_user_data (surface);
|
stage_wayland = wl_surface_get_user_data (surface);
|
||||||
|
|
||||||
|
if ((stage_wayland->allocation.width != width) ||
|
||||||
|
(stage_wayland->allocation.height != height))
|
||||||
|
{
|
||||||
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (stage_wayland->wrapper));
|
||||||
|
}
|
||||||
|
|
||||||
stage_wayland->pending_allocation.x = x;
|
stage_wayland->pending_allocation.x = x;
|
||||||
stage_wayland->pending_allocation.y = y;
|
stage_wayland->pending_allocation.y = y;
|
||||||
|
stage_wayland->pending_allocation.width = width;
|
||||||
|
stage_wayland->pending_allocation.height = height;
|
||||||
stage_wayland->allocation = stage_wayland->pending_allocation;
|
stage_wayland->allocation = stage_wayland->pending_allocation;
|
||||||
|
|
||||||
clutter_actor_set_size (CLUTTER_ACTOR (stage_wayland->wrapper),
|
clutter_actor_set_size (CLUTTER_ACTOR (stage_wayland->wrapper),
|
||||||
|
@ -77,7 +77,10 @@ wayland_create_buffer (ClutterStageWayland *stage_wayland,
|
|||||||
EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SCANOUT_MESA,
|
EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SCANOUT_MESA,
|
||||||
EGL_NONE
|
EGL_NONE
|
||||||
};
|
};
|
||||||
CoglHandle tex;
|
struct wl_visual *visual;
|
||||||
|
EGLint name;
|
||||||
|
EGLint stride;
|
||||||
|
cairo_rectangle_int_t rect;
|
||||||
|
|
||||||
buffer = g_slice_new (ClutterStageWaylandWaylandBuffer);
|
buffer = g_slice_new (ClutterStageWaylandWaylandBuffer);
|
||||||
|
|
||||||
@ -88,16 +91,31 @@ wayland_create_buffer (ClutterStageWayland *stage_wayland,
|
|||||||
glBindTexture (GL_TEXTURE_2D, buffer->texture);
|
glBindTexture (GL_TEXTURE_2D, buffer->texture);
|
||||||
backend_wayland->image_target_texture_2d (GL_TEXTURE_2D, buffer->drm_image);
|
backend_wayland->image_target_texture_2d (GL_TEXTURE_2D, buffer->drm_image);
|
||||||
|
|
||||||
tex = cogl_texture_new_from_foreign (buffer->texture,
|
buffer->tex = cogl_texture_new_from_foreign (buffer->texture,
|
||||||
GL_TEXTURE_2D,
|
GL_TEXTURE_2D,
|
||||||
geom->width,
|
geom->width,
|
||||||
geom->height,
|
geom->height,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
COGL_PIXEL_FORMAT_ARGB_8888);
|
COGL_PIXEL_FORMAT_ARGB_8888);
|
||||||
buffer->offscreen = cogl_offscreen_new_to_texture (tex);
|
buffer->offscreen = cogl_offscreen_new_to_texture (buffer->tex);
|
||||||
cogl_handle_unref (tex);
|
|
||||||
buffer->wayland_buffer = NULL;
|
backend_wayland->export_drm_image (edpy, buffer->drm_image,
|
||||||
|
&name, NULL, &stride);
|
||||||
|
visual =
|
||||||
|
wl_display_get_premultiplied_argb_visual (backend_wayland->wayland_display);
|
||||||
|
buffer->wayland_buffer =
|
||||||
|
wl_drm_create_buffer (backend_wayland->wayland_drm,
|
||||||
|
name,
|
||||||
|
stage_wayland->allocation.width,
|
||||||
|
stage_wayland->allocation.height,
|
||||||
|
stride, visual);
|
||||||
|
|
||||||
|
rect.x = geom->x;
|
||||||
|
rect.y = geom->y;
|
||||||
|
rect.width = geom->width;
|
||||||
|
rect.height = geom->height;
|
||||||
|
buffer->dirty_region = cairo_region_create_rectangle (&rect);
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
@ -109,9 +127,8 @@ wayland_free_buffer (ClutterStageWaylandWaylandBuffer *buffer)
|
|||||||
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
|
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
|
||||||
EGLDisplay edpy = clutter_egl_display ();
|
EGLDisplay edpy = clutter_egl_display ();
|
||||||
|
|
||||||
if (buffer->wayland_buffer)
|
cogl_handle_unref (buffer->tex);
|
||||||
wl_buffer_destroy (buffer->wayland_buffer);
|
wl_buffer_destroy (buffer->wayland_buffer);
|
||||||
|
|
||||||
cogl_handle_unref (buffer->offscreen);
|
cogl_handle_unref (buffer->offscreen);
|
||||||
glDeleteTextures (1, &buffer->texture);
|
glDeleteTextures (1, &buffer->texture);
|
||||||
backend_wayland->destroy_image (edpy, buffer->drm_image);
|
backend_wayland->destroy_image (edpy, buffer->drm_image);
|
||||||
@ -235,9 +252,61 @@ clutter_stage_wayland_resize (ClutterStageWindow *stage_window,
|
|||||||
gint height)
|
gint height)
|
||||||
{
|
{
|
||||||
ClutterStageWayland *stage_wayland = CLUTTER_STAGE_WAYLAND (stage_window);
|
ClutterStageWayland *stage_wayland = CLUTTER_STAGE_WAYLAND (stage_window);
|
||||||
|
cairo_rectangle_int_t rect;
|
||||||
|
|
||||||
|
fprintf (stderr, "resize %dx%d\n", width, height);
|
||||||
|
|
||||||
stage_wayland->pending_allocation.width = width;
|
stage_wayland->pending_allocation.width = width;
|
||||||
stage_wayland->pending_allocation.height = height;
|
stage_wayland->pending_allocation.height = height;
|
||||||
|
|
||||||
|
/* FIXME: Shouldn't the stage repaint everything when it gets resized? */
|
||||||
|
rect.x = stage_wayland->pending_allocation.x;
|
||||||
|
rect.y = stage_wayland->pending_allocation.y;
|
||||||
|
rect.width = stage_wayland->pending_allocation.width;
|
||||||
|
rect.height = stage_wayland->pending_allocation.height;
|
||||||
|
cairo_region_union_rectangle (stage_wayland->repaint_region, &rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CAIRO_REGION_FULL ((cairo_region_t *) 1)
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
clutter_stage_wayland_has_redraw_clips (ClutterStageWindow *stage_window)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
clutter_stage_wayland_ignoring_redraw_clips (ClutterStageWindow *stage_window)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clutter_stage_wayland_add_redraw_clip (ClutterStageWindow *stage_window,
|
||||||
|
ClutterGeometry *stage_clip)
|
||||||
|
{
|
||||||
|
ClutterStageWayland *stage_wayland = CLUTTER_STAGE_WAYLAND (stage_window);
|
||||||
|
cairo_rectangle_int_t rect;
|
||||||
|
|
||||||
|
if (stage_clip == NULL)
|
||||||
|
{
|
||||||
|
rect.x = stage_wayland->allocation.x;
|
||||||
|
rect.y = stage_wayland->allocation.y;
|
||||||
|
rect.width = stage_wayland->allocation.width;
|
||||||
|
rect.height = stage_wayland->allocation.height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rect.x = stage_clip->x;
|
||||||
|
rect.y = stage_clip->y;
|
||||||
|
rect.width = stage_clip->width;
|
||||||
|
rect.height = stage_clip->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stage_wayland->repaint_region == NULL)
|
||||||
|
stage_wayland->repaint_region = cairo_region_create_rectangle (&rect);
|
||||||
|
else
|
||||||
|
cairo_region_union_rectangle (stage_wayland->repaint_region, &rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -254,6 +323,10 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
|
|||||||
iface->resize = clutter_stage_wayland_resize;
|
iface->resize = clutter_stage_wayland_resize;
|
||||||
iface->show = clutter_stage_wayland_show;
|
iface->show = clutter_stage_wayland_show;
|
||||||
iface->hide = clutter_stage_wayland_hide;
|
iface->hide = clutter_stage_wayland_hide;
|
||||||
|
|
||||||
|
iface->add_redraw_clip = clutter_stage_wayland_add_redraw_clip;
|
||||||
|
iface->has_redraw_clips = clutter_stage_wayland_has_redraw_clips;
|
||||||
|
iface->ignoring_redraw_clips = clutter_stage_wayland_ignoring_redraw_clips;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -271,20 +344,6 @@ _clutter_stage_wayland_init (ClutterStageWayland *stage_wayland)
|
|||||||
stage_wayland->save_allocation = stage_wayland->allocation;
|
stage_wayland->save_allocation = stage_wayland->allocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
wayland_free_front_buffer (void *data)
|
|
||||||
{
|
|
||||||
ClutterStageWayland *stage_wayland = data;
|
|
||||||
|
|
||||||
if (stage_wayland->front_buffer)
|
|
||||||
wayland_free_buffer (stage_wayland->front_buffer);
|
|
||||||
stage_wayland->front_buffer = stage_wayland->pending_buffer;
|
|
||||||
stage_wayland->pending_buffer = NULL;
|
|
||||||
|
|
||||||
if (stage_wayland->back_buffer)
|
|
||||||
wayland_swap_buffers (stage_wayland);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
wayland_frame_callback (void *data, uint32_t _time)
|
wayland_frame_callback (void *data, uint32_t _time)
|
||||||
{
|
{
|
||||||
@ -298,38 +357,19 @@ wayland_swap_buffers (ClutterStageWayland *stage_wayland)
|
|||||||
{
|
{
|
||||||
ClutterBackend *backend = clutter_get_default_backend ();
|
ClutterBackend *backend = clutter_get_default_backend ();
|
||||||
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
|
ClutterBackendWayland *backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);
|
||||||
EGLDisplay edpy = clutter_egl_display ();
|
ClutterStageWaylandWaylandBuffer *buffer;
|
||||||
EGLint name;
|
|
||||||
EGLint stride;
|
|
||||||
struct wl_visual *visual;
|
|
||||||
|
|
||||||
if (stage_wayland->pending_buffer)
|
buffer = stage_wayland->front_buffer;
|
||||||
return;
|
stage_wayland->front_buffer = stage_wayland->back_buffer;
|
||||||
|
stage_wayland->back_buffer = buffer;
|
||||||
|
|
||||||
stage_wayland->pending_buffer = stage_wayland->back_buffer;
|
|
||||||
stage_wayland->back_buffer = NULL;
|
|
||||||
|
|
||||||
backend_wayland->export_drm_image (edpy,
|
|
||||||
stage_wayland->pending_buffer->drm_image,
|
|
||||||
&name, NULL, &stride);
|
|
||||||
visual =
|
|
||||||
wl_display_get_premultiplied_argb_visual (backend_wayland->wayland_display);
|
|
||||||
stage_wayland->pending_buffer->wayland_buffer =
|
|
||||||
wl_drm_create_buffer (backend_wayland->wayland_drm,
|
|
||||||
name,
|
|
||||||
stage_wayland->allocation.width,
|
|
||||||
stage_wayland->allocation.height,
|
|
||||||
stride, visual);
|
|
||||||
wl_surface_attach (stage_wayland->wayland_surface,
|
wl_surface_attach (stage_wayland->wayland_surface,
|
||||||
stage_wayland->pending_buffer->wayland_buffer);
|
stage_wayland->front_buffer->wayland_buffer);
|
||||||
wl_surface_map (stage_wayland->wayland_surface,
|
wl_surface_map (stage_wayland->wayland_surface,
|
||||||
stage_wayland->allocation.x,
|
stage_wayland->allocation.x,
|
||||||
stage_wayland->allocation.y,
|
stage_wayland->allocation.y,
|
||||||
stage_wayland->allocation.width,
|
stage_wayland->allocation.width,
|
||||||
stage_wayland->allocation.height);
|
stage_wayland->allocation.height);
|
||||||
wl_display_sync_callback (backend_wayland->wayland_display,
|
|
||||||
wayland_free_front_buffer,
|
|
||||||
stage_wayland);
|
|
||||||
|
|
||||||
stage_wayland->pending_swaps++;
|
stage_wayland->pending_swaps++;
|
||||||
wl_display_frame_callback (backend_wayland->wayland_display,
|
wl_display_frame_callback (backend_wayland->wayland_display,
|
||||||
@ -337,32 +377,157 @@ wayland_swap_buffers (ClutterStageWayland *stage_wayland)
|
|||||||
stage_wayland);
|
stage_wayland);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_clutter_stage_wayland_repair_dirty(ClutterStageWayland *stage_wayland,
|
||||||
|
ClutterStage *stage)
|
||||||
|
{
|
||||||
|
CoglMaterial *outline = NULL;
|
||||||
|
CoglHandle vbo;
|
||||||
|
float vertices[8], texcoords[8];
|
||||||
|
CoglMatrix modelview;
|
||||||
|
cairo_region_t *dirty;
|
||||||
|
cairo_rectangle_int_t rect;
|
||||||
|
int i, count;
|
||||||
|
float width, height;
|
||||||
|
|
||||||
|
dirty = stage_wayland->back_buffer->dirty_region;
|
||||||
|
stage_wayland->back_buffer->dirty_region = NULL;
|
||||||
|
cairo_region_subtract (dirty, stage_wayland->repaint_region);
|
||||||
|
width = stage_wayland->allocation.width;
|
||||||
|
height = stage_wayland->allocation.height;
|
||||||
|
|
||||||
|
/* If this is the first time we render, there is no front buffer to
|
||||||
|
* copy back from, but then the dirty region not covered by the
|
||||||
|
* repaint should be empty, because we repaint the entire stage.
|
||||||
|
*
|
||||||
|
* assert(stage_wayland->front_buffer != NULL) ||
|
||||||
|
* cairo_region_is_empty(dirty);
|
||||||
|
*
|
||||||
|
* FIXME: in test-rotate, the stage never queues a full repaint
|
||||||
|
* initially, it's restricted to the paint box of it's rotating
|
||||||
|
* children.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!stage_wayland->front_buffer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
outline = cogl_material_new ();
|
||||||
|
cogl_material_set_layer (outline, 0, stage_wayland->front_buffer->tex);
|
||||||
|
count = cairo_region_num_rectangles (dirty);
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
cairo_region_get_rectangle (dirty, i, &rect);
|
||||||
|
vbo = cogl_vertex_buffer_new (4);
|
||||||
|
|
||||||
|
vertices[0] = rect.x - 1;
|
||||||
|
vertices[1] = rect.y - 1;
|
||||||
|
vertices[2] = rect.x + rect.width + 1;
|
||||||
|
vertices[3] = rect.y - 1;
|
||||||
|
vertices[4] = rect.x + rect.width + 1;
|
||||||
|
vertices[5] = rect.y + rect.height + 1;
|
||||||
|
vertices[6] = rect.x - 1;
|
||||||
|
vertices[7] = rect.y + rect.height + 1;
|
||||||
|
|
||||||
|
cogl_vertex_buffer_add (vbo,
|
||||||
|
"gl_Vertex",
|
||||||
|
2, /* n_components */
|
||||||
|
COGL_ATTRIBUTE_TYPE_FLOAT,
|
||||||
|
FALSE, /* normalized */
|
||||||
|
0, /* stride */
|
||||||
|
vertices);
|
||||||
|
|
||||||
|
texcoords[0] = vertices[0] / width;
|
||||||
|
texcoords[1] = vertices[1] / height;
|
||||||
|
texcoords[2] = vertices[2] / width;
|
||||||
|
texcoords[3] = vertices[3] / height;
|
||||||
|
texcoords[4] = vertices[4] / width;
|
||||||
|
texcoords[5] = vertices[5] / height;
|
||||||
|
texcoords[6] = vertices[6] / width;
|
||||||
|
texcoords[7] = vertices[7] / height;
|
||||||
|
|
||||||
|
cogl_vertex_buffer_add (vbo,
|
||||||
|
"gl_MultiTexCoord0",
|
||||||
|
2, /* n_components */
|
||||||
|
COGL_ATTRIBUTE_TYPE_FLOAT,
|
||||||
|
FALSE, /* normalized */
|
||||||
|
0, /* stride */
|
||||||
|
texcoords);
|
||||||
|
|
||||||
|
cogl_vertex_buffer_submit (vbo);
|
||||||
|
|
||||||
|
cogl_push_matrix ();
|
||||||
|
cogl_matrix_init_identity (&modelview);
|
||||||
|
_clutter_actor_apply_modelview_transform (CLUTTER_ACTOR (stage),
|
||||||
|
&modelview);
|
||||||
|
cogl_set_modelview_matrix (&modelview);
|
||||||
|
cogl_set_source (outline);
|
||||||
|
cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_TRIANGLE_FAN,
|
||||||
|
0 , 4);
|
||||||
|
cogl_pop_matrix ();
|
||||||
|
cogl_object_unref (vbo);
|
||||||
|
}
|
||||||
|
|
||||||
|
cairo_region_destroy (dirty);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_clutter_stage_wayland_repaint_region (ClutterStageWayland *stage_wayland,
|
||||||
|
ClutterStage *stage)
|
||||||
|
{
|
||||||
|
ClutterGeometry geom;
|
||||||
|
cairo_rectangle_int_t rect;
|
||||||
|
int i, count;
|
||||||
|
|
||||||
|
count = cairo_region_num_rectangles (stage_wayland->repaint_region);
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
cairo_region_get_rectangle (stage_wayland->repaint_region, i, &rect);
|
||||||
|
|
||||||
|
cogl_clip_push_window_rectangle (rect.x - 1, rect.y - 1,
|
||||||
|
rect.width + 2, rect.height + 2);
|
||||||
|
|
||||||
|
geom.x = rect.x;
|
||||||
|
geom.y = rect.y;
|
||||||
|
geom.width = rect.width;
|
||||||
|
geom.height = rect.height;
|
||||||
|
/* FIXME: We should pass geom in as second arg, but some actors
|
||||||
|
* cull themselves a little to much. Disable for now.*/
|
||||||
|
_clutter_stage_do_paint (stage, NULL);
|
||||||
|
|
||||||
|
cogl_clip_pop ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_clutter_stage_wayland_redraw (ClutterStageWayland *stage_wayland,
|
_clutter_stage_wayland_redraw (ClutterStageWayland *stage_wayland,
|
||||||
ClutterStage *stage)
|
ClutterStage *stage)
|
||||||
{
|
{
|
||||||
ClutterActor *wrapper = CLUTTER_ACTOR (stage_wayland->wrapper);
|
|
||||||
|
|
||||||
stage_wayland->allocation = stage_wayland->pending_allocation;
|
stage_wayland->allocation = stage_wayland->pending_allocation;
|
||||||
|
|
||||||
if (stage_wayland->back_buffer)
|
if (!stage_wayland->back_buffer)
|
||||||
{
|
stage_wayland->back_buffer =
|
||||||
wayland_free_buffer (stage_wayland->back_buffer);
|
wayland_create_buffer (stage_wayland, &stage_wayland->allocation);
|
||||||
stage_wayland->back_buffer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
stage_wayland->back_buffer = wayland_create_buffer (stage_wayland,
|
|
||||||
&stage_wayland->allocation);
|
|
||||||
|
|
||||||
cogl_set_framebuffer (stage_wayland->back_buffer->offscreen);
|
cogl_set_framebuffer (stage_wayland->back_buffer->offscreen);
|
||||||
_clutter_stage_maybe_setup_viewport (stage_wayland->wrapper);
|
_clutter_stage_maybe_setup_viewport (stage_wayland->wrapper);
|
||||||
|
|
||||||
clutter_actor_paint (wrapper);
|
_clutter_stage_wayland_repair_dirty (stage_wayland, stage);
|
||||||
|
|
||||||
|
_clutter_stage_wayland_repaint_region (stage_wayland, stage);
|
||||||
|
|
||||||
cogl_flush ();
|
cogl_flush ();
|
||||||
glFlush ();
|
glFlush ();
|
||||||
|
|
||||||
|
wayland_swap_buffers (stage_wayland);
|
||||||
|
|
||||||
|
if (stage_wayland->back_buffer)
|
||||||
|
stage_wayland->back_buffer->dirty_region = stage_wayland->repaint_region;
|
||||||
|
else
|
||||||
|
cairo_region_destroy (stage_wayland->repaint_region);
|
||||||
|
|
||||||
|
stage_wayland->repaint_region = NULL;
|
||||||
|
|
||||||
cogl_set_framebuffer (stage_wayland->pick_buffer->offscreen);
|
cogl_set_framebuffer (stage_wayland->pick_buffer->offscreen);
|
||||||
_clutter_stage_maybe_setup_viewport (stage_wayland->wrapper);
|
_clutter_stage_maybe_setup_viewport (stage_wayland->wrapper);
|
||||||
|
|
||||||
wayland_swap_buffers (stage_wayland);
|
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,8 @@ typedef struct _ClutterStageWaylandWaylandBuffer
|
|||||||
GLuint texture;
|
GLuint texture;
|
||||||
CoglHandle offscreen;
|
CoglHandle offscreen;
|
||||||
struct wl_buffer *wayland_buffer;
|
struct wl_buffer *wayland_buffer;
|
||||||
|
cairo_region_t *dirty_region;
|
||||||
|
CoglHandle tex;
|
||||||
} ClutterStageWaylandWaylandBuffer;
|
} ClutterStageWaylandWaylandBuffer;
|
||||||
|
|
||||||
struct _ClutterStageWayland
|
struct _ClutterStageWayland
|
||||||
@ -77,8 +79,8 @@ struct _ClutterStageWayland
|
|||||||
|
|
||||||
ClutterStageWaylandWaylandBuffer *front_buffer;
|
ClutterStageWaylandWaylandBuffer *front_buffer;
|
||||||
ClutterStageWaylandWaylandBuffer *back_buffer;
|
ClutterStageWaylandWaylandBuffer *back_buffer;
|
||||||
ClutterStageWaylandWaylandBuffer *pending_buffer;
|
|
||||||
ClutterStageWaylandWaylandBuffer *pick_buffer;
|
ClutterStageWaylandWaylandBuffer *pick_buffer;
|
||||||
|
cairo_region_t *repaint_region;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _ClutterStageWaylandClass
|
struct _ClutterStageWaylandClass
|
||||||
|
Loading…
Reference in New Issue
Block a user