From 09b7262e124e2f15bbe999575be7bbd1b5aa837d Mon Sep 17 00:00:00 2001 From: Taekyun Kim Date: Wed, 15 Jul 2015 17:09:16 +0900 Subject: [PATCH] pepper: pepper_plane_t and per-plane damage processing Plane is a logical rendering surface maintaing its own damage region. A plane belongs to an output and a view can be on a plane per output at a time. << Overall Data Relationship >> * Compositor - output list - view list in sorted z-order * Output - plane list * Plane - plane entry list - damage region - clip region (obscured by other planes) * View - Geometry (position, size, transform) - plane entries << Output Repaint Scheduling >> * surface.commit() causes all outputs to be scheduled to do repaint. * Repaint is scheduled on an output when one of its plane gets damaged. << Output Repaint Process >> * Update geometry of all views in the compositor. * Build a list of views that overlap with the output rectangle. * Ask output backend to assign a plane of each view in the list. * Build a list of plane entries for the views assigned to each plane. * Accumulate damage for each plane. * Call backend.repaint() << Damage Processing >> * Geometry & Z-order change - Inflict damage instantly with current visible region of the view on each plane where the view belongs to. - Mark it as damaged. Damage accumulation function should add visible region of damaged views to the planes. * Plane move - Inflict damage instantly on previous plane and mark it as damaged. * Surface damage - Added while accumulating plane damage. Change-Id: I7c4bd95f439f0cf0356bcbf2f060b09800ea4528 --- drm/src/drm-internal.h | 2 + drm/src/drm-output.c | 77 +++++--- fbdev/src/fbdev-internal.h | 1 + fbdev/src/fbdev-output.c | 46 ++++- pepper/src/Makefile.am | 3 +- pepper/src/compositor.c | 37 +--- pepper/src/output.c | 146 +++++++-------- pepper/src/pepper-internal.h | 108 ++++++++--- pepper/src/pepper-output-backend.h | 74 ++++++++ pepper/src/pepper.h | 52 ------ pepper/src/plane.c | 164 +++++++++++++++++ pepper/src/surface.c | 2 +- pepper/src/view.c | 349 +++++++++++++++++++----------------- render/src/gl-renderer.c | 2 +- render/src/pepper-render-internal.h | 4 +- render/src/pepper-render.h | 2 +- render/src/pixman-renderer.c | 63 ++----- render/src/renderer.c | 2 +- wayland/src/wayland-internal.h | 2 + wayland/src/wayland-output.c | 49 +++-- x11/src/x11-common.c | 2 +- x11/src/x11-internal.h | 6 +- x11/src/x11-output.c | 97 ++++++---- 23 files changed, 813 insertions(+), 477 deletions(-) create mode 100644 pepper/src/pepper-output-backend.h create mode 100644 pepper/src/plane.c diff --git a/drm/src/drm-internal.h b/drm/src/drm-internal.h index 44a7dd7..1a656ee 100644 --- a/drm/src/drm-internal.h +++ b/drm/src/drm-internal.h @@ -85,6 +85,8 @@ struct drm_output pepper_bool_t vblank_pending; pepper_bool_t page_flip_pending; + pepper_object_t *primary_plane; + /* TODO */ }; diff --git a/drm/src/drm-output.c b/drm/src/drm-output.c index c4ea267..b3b6ada 100644 --- a/drm/src/drm-output.c +++ b/drm/src/drm-output.c @@ -14,6 +14,7 @@ #include "drm-internal.h" +#include #include #include @@ -249,36 +250,68 @@ update_back_buffer(drm_output_t *output) } static void -drm_output_repaint(void *o, const pepper_list_t *view_list, const pixman_region32_t *damage) +drm_output_assign_planes(void *o, const pepper_list_t *view_list) +{ + drm_output_t *output = (drm_output_t *)o; + pepper_list_t *l; + + PEPPER_LIST_FOR_EACH(view_list, l) + { + pepper_object_t *view = l->item; + pepper_view_assign_plane(view, output->base, output->primary_plane); + } +} + +static void +drm_output_repaint(void *o, const pepper_list_t *plane_list) { int ret; drm_output_t *output = (drm_output_t *)o; + pepper_list_t *l; - pepper_renderer_set_target(output->renderer, output->render_target); - pepper_renderer_repaint_output(output->renderer, output->base, view_list, damage); + PEPPER_LIST_FOR_EACH(plane_list, l) + { + pepper_object_t *plane = l->item; - update_back_buffer(output); + if (plane == output->primary_plane) + { + pixman_region32_t *damage = pepper_plane_get_damage_region(plane); + const pepper_list_t *render_list = pepper_plane_get_render_list(plane); - if (!output->back_fb) - return; + pepper_renderer_set_target(output->renderer, output->render_target); + pepper_renderer_repaint_output(output->renderer, output->base, render_list, damage); - if (!output->front_fb) - { - ret = drmModeSetCrtc(output->drm->drm_fd, output->crtc_id, output->back_fb->id, - 0, 0, &output->conn_id, 1, output->current_mode); - } + /* NULL means that whole damage region is updated. + * If only visible damage region is updated, pass that region to this function + * so that pepper core correctly manage remaining damage region. */ + pepper_plane_subtract_damage_region(plane, NULL); - ret = drmModePageFlip(output->drm->drm_fd, output->crtc_id, output->back_fb->id, - DRM_MODE_PAGE_FLIP_EVENT, output); - if (ret < 0) - { - PEPPER_ERROR("Failed to queue pageflip in %s\n", __FUNCTION__); - return; - } + update_back_buffer(output); - output->page_flip_pending = PEPPER_TRUE; + if (!output->back_fb) + return; - /* TODO: set planes */ + if (!output->front_fb) + { + ret = drmModeSetCrtc(output->drm->drm_fd, output->crtc_id, output->back_fb->id, + 0, 0, &output->conn_id, 1, output->current_mode); + } + + ret = drmModePageFlip(output->drm->drm_fd, output->crtc_id, output->back_fb->id, + DRM_MODE_PAGE_FLIP_EVENT, output); + if (ret < 0) + { + PEPPER_ERROR("Failed to queue pageflip in %s\n", __FUNCTION__); + return; + } + + output->page_flip_pending = PEPPER_TRUE; + } + + /* TODO: Cursor plane. */ + + /* TODO: drmModeSetPlane(). */ + } } static void @@ -308,6 +341,7 @@ struct pepper_output_backend drm_output_backend = drm_output_get_mode, drm_output_set_mode, + drm_output_assign_planes, drm_output_repaint, drm_output_attach_surface, drm_output_add_frame_listener, @@ -782,6 +816,7 @@ add_outputs(pepper_drm_t *drm, struct udev_device *device) continue; } + output->primary_plane = pepper_output_add_plane(output->base, NULL); drmModeFreeConnector(conn); } @@ -895,6 +930,8 @@ update_outputs(pepper_drm_t *drm, struct udev_device *device) drmModeFreeConnector(conn); continue; } + + output->primary_plane = pepper_output_add_plane(output->base, NULL); } drmModeFreeConnector(conn); diff --git a/fbdev/src/fbdev-internal.h b/fbdev/src/fbdev-internal.h index f49a33b..0569e0a 100644 --- a/fbdev/src/fbdev-internal.h +++ b/fbdev/src/fbdev-internal.h @@ -54,6 +54,7 @@ struct fbdev_output struct wl_signal mode_change_signal; struct wl_signal frame_signal; + pepper_object_t *primary_plane; /* TODO */ }; diff --git a/fbdev/src/fbdev-output.c b/fbdev/src/fbdev-output.c index cd88fcf..3c4e668 100644 --- a/fbdev/src/fbdev-output.c +++ b/fbdev/src/fbdev-output.c @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -166,16 +167,44 @@ fbdev_output_set_mode(void *o, const pepper_output_mode_t *mode) } static void -fbdev_output_repaint(void *o, const pepper_list_t *view_list, const pixman_region32_t *damage) +fbdev_output_assign_planes(void *o, const pepper_list_t *view_list) { fbdev_output_t *output = (fbdev_output_t *)o; - pepper_renderer_repaint_output(output->renderer, output->base, view_list, damage); + pepper_list_t *l; - /* FIXME: composite with damage? */ - if (output->use_shadow) - pixman_image_composite32(PIXMAN_OP_SRC, output->shadow_image, NULL, - output->frame_buffer_image, 0, 0, 0, 0, 0, 0, - output->w, output->h); + PEPPER_LIST_FOR_EACH(view_list, l) + { + pepper_object_t *view = l->item; + pepper_view_assign_plane(view, output->base, output->primary_plane); + } +} + +static void +fbdev_output_repaint(void *o, const pepper_list_t *plane_list) +{ + fbdev_output_t *output = (fbdev_output_t *)o; + pepper_list_t *l; + + PEPPER_LIST_FOR_EACH(plane_list, l) + { + pepper_object_t *plane = l->item; + + if (plane == output->primary_plane) + { + const pepper_list_t *render_list = pepper_plane_get_render_list(plane); + pixman_region32_t *damage = pepper_plane_get_damage_region(plane); + + pepper_renderer_repaint_output(output->renderer, output->base, render_list, damage); + + /* FIXME: composite with damage? */ + if (output->use_shadow) + pixman_image_composite32(PIXMAN_OP_SRC, output->shadow_image, NULL, + output->frame_buffer_image, 0, 0, 0, 0, 0, 0, + output->w, output->h); + } + + /* TODO: No overlays on fbdev??? */ + } } static void @@ -205,6 +234,7 @@ struct pepper_output_backend fbdev_output_backend = fbdev_output_get_mode, fbdev_output_set_mode, + fbdev_output_assign_planes, fbdev_output_repaint, fbdev_output_attach_surface, fbdev_output_add_frame_listener, @@ -346,7 +376,9 @@ pepper_fbdev_output_create(pepper_fbdev_t *fbdev, const char *renderer) goto error; } + output->primary_plane = pepper_output_add_plane(output->base, NULL); wl_list_insert(&fbdev->output_list, &output->link); + return PEPPER_TRUE; error: diff --git a/pepper/src/Makefile.am b/pepper/src/Makefile.am index 32f3cd4..2f9c06d 100644 --- a/pepper/src/Makefile.am +++ b/pepper/src/Makefile.am @@ -1,5 +1,5 @@ lib_LTLIBRARIES = libpepper.la -include_HEADERS = pepper.h pepper-utils.h +include_HEADERS = pepper.h pepper-utils.h pepper-output-backend.h pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = pepper.pc @@ -20,6 +20,7 @@ libpepper_la_SOURCES = pepper.h \ buffer.c \ data-device.c \ view.c \ + plane.c \ utils-file.c \ utils-map.c \ utils-log.c \ diff --git a/pepper/src/compositor.c b/pepper/src/compositor.c index 30d0fe7..925b59b 100644 --- a/pepper/src/compositor.c +++ b/pepper/src/compositor.c @@ -75,10 +75,8 @@ pepper_compositor_create(const char *socket_name) compositor_bind); wl_list_init(&compositor->surfaces); wl_list_init(&compositor->seat_list); - wl_list_init(&compositor->output_list); + pepper_list_init(&compositor->output_list); wl_list_init(&compositor->event_hook_chain); - - pepper_list_init(&compositor->root_view_list); pepper_list_init(&compositor->view_list); /* Install default input event handler */ @@ -132,36 +130,3 @@ pepper_compositor_get_display(pepper_object_t *cmp) CHECK_MAGIC_AND_NON_NULL(cmp, PEPPER_COMPOSITOR); return compositor->display; } - -void -pepper_compositor_add_damage(pepper_compositor_t *compositor, const pixman_region32_t *region) -{ - pepper_output_t *output; - - CHECK_MAGIC_AND_NON_NULL(&compositor->base, PEPPER_COMPOSITOR); - - wl_list_for_each(output, &compositor->output_list, link) - pepper_output_add_damage(&output->base, region, output->geometry.x, output->geometry.y); -} - -void -pepper_compositor_add_damage_rect(pepper_compositor_t *compositor, - int x, int y, unsigned int w, unsigned int h) -{ - pixman_region32_t region; - - pixman_region32_init_rect(®ion, x, y, w, h); - pepper_compositor_add_damage(compositor, ®ion); - pixman_region32_fini(®ion); -} - -void -pepper_compositor_schedule_repaint(pepper_compositor_t *compositor) -{ - pepper_output_t *output; - - CHECK_MAGIC_AND_NON_NULL(&compositor->base, PEPPER_COMPOSITOR); - - wl_list_for_each(output, &compositor->output_list, link) - pepper_output_schedule_repaint(output); -} diff --git a/pepper/src/output.c b/pepper/src/output.c index 400e4ac..4792822 100644 --- a/pepper/src/output.c +++ b/pepper/src/output.c @@ -125,6 +125,67 @@ handle_mode_change(struct wl_listener *listener, void *data) } static void +output_accumulate_damage(pepper_output_t *output) +{ + pepper_list_t *l; + pixman_region32_t clip; + pixman_region32_t plane_clip; + + pixman_region32_init(&clip); + + PEPPER_LIST_FOR_EACH_REVERSE(&output->plane_list, l) + { + pepper_plane_t *plane = l->item; + + pepper_plane_accumulate_damage(plane, &plane_clip); + pixman_region32_copy(&plane->clip_region, &clip); + pixman_region32_union(&clip, &clip, &plane_clip); + } + + pixman_region32_fini(&clip); +} + +static void +output_repaint(pepper_output_t *output) +{ + pepper_list_t *l; + + PEPPER_LIST_FOR_EACH(&output->compositor->view_list, l) + pepper_view_update_geometry((pepper_view_t *)l->item); + + pepper_list_init(&output->view_list); + + /* Build a list of views in sorted z-order that are visible on the given output. */ + PEPPER_LIST_FOR_EACH(&output->compositor->view_list, l) + { + pepper_view_t *view = l->item; + + if (!view->visibility || !(view->output_overlap & (1 << output->id))) + { + /* Detach from the previously assigned plane. */ + pepper_view_assign_plane(&view->base, &output->base, NULL); + continue; + } + + pepper_list_insert(&output->view_list, &view->link); + view->link.item = view; + } + + output->backend->assign_planes(output->data, &output->view_list); + + PEPPER_LIST_FOR_EACH(&output->plane_list, l) + pepper_plane_update((pepper_plane_t *)l->item, &output->view_list); + + output_accumulate_damage(output); + output->backend->repaint(output->data, &output->plane_list); + + output->frame.pending = PEPPER_TRUE; + output->frame.scheduled = PEPPER_FALSE; + + /* TODO: Send frame done to the callback objects of this output. */ +} + +static void handle_output_frame(struct wl_listener *listener, void *data) { pepper_output_t *output = pepper_container_of(listener, pepper_output_t, frame.frame_listener); @@ -133,7 +194,7 @@ handle_output_frame(struct wl_listener *listener, void *data) /* TODO: Better repaint scheduling by putting a delay before repaint. */ if (output->frame.scheduled) - pepper_output_repaint(output); + output_repaint(output); } static void @@ -144,7 +205,7 @@ idle_repaint(void *data) if (!output->frame.pending) { /* We can repaint a frame immediately if it is not in pending state. */ - pepper_output_repaint(output); + output_repaint(output); } } @@ -162,21 +223,16 @@ pepper_output_schedule_repaint(pepper_output_t *output) output->frame.scheduled = PEPPER_TRUE; } -void -pepper_output_repaint(pepper_output_t *output) +PEPPER_API void +pepper_output_add_damage_region(pepper_object_t *out, pixman_region32_t *region) { - PEPPER_ASSERT(!output->frame.pending); - - pepper_compositor_update_views(output->compositor); - - output->backend->repaint(output->data, &output->compositor->view_list, &output->damage_region); - output->frame.pending = PEPPER_TRUE; - output->frame.scheduled = PEPPER_FALSE; + pepper_list_t *l; + pepper_output_t *output = (pepper_output_t *)out; - /* TODO: Send frame done to the callback objects of this output. */ + CHECK_MAGIC_AND_NON_NULL(out, PEPPER_OUTPUT); - /* Output has been repainted, so damage region is totally consumed. */ - pixman_region32_clear(&output->damage_region); + PEPPER_LIST_FOR_EACH(&output->plane_list, l) + pepper_plane_add_damage_region((pepper_plane_t *)l->item, region); } PEPPER_API pepper_object_t * @@ -239,7 +295,8 @@ pepper_compositor_add_output(pepper_object_t *cmp, output->geometry.w = output->current_mode->w; output->geometry.h = output->current_mode->h; - wl_list_insert(&compositor->output_list, &output->link); + pepper_list_insert(&compositor->output_list, &output->link); + output->link.item = output; /* Install listeners. */ output->data_destroy_listener.notify = handle_output_data_destroy; @@ -251,7 +308,7 @@ pepper_compositor_add_output(pepper_object_t *cmp, output->frame.frame_listener.notify = handle_output_frame; backend->add_frame_listener(data, &output->frame.frame_listener); - pepper_output_add_damage_whole(&output->base); + pepper_list_init(&output->plane_list); return &output->base; } @@ -271,7 +328,7 @@ pepper_output_destroy(pepper_object_t *out) pepper_object_fini(&output->base); output->compositor->output_id_allocator &= ~(1 << output->id); - wl_list_remove(&output->link); + pepper_list_remove(&output->link, NULL); if (output->backend && output->data) output->backend->destroy(output->data); @@ -297,7 +354,7 @@ pepper_output_move(pepper_object_t *out, int32_t x, int32_t y) output->geometry.x = x; output->geometry.y = y; - pepper_output_add_damage_whole(out); + /* TODO: pepper_output_add_damage_whole(out); */ output_send_geometry(output); } } @@ -349,60 +406,9 @@ pepper_output_set_mode(pepper_object_t *out, const pepper_output_mode_t *mode) if (output->backend->set_mode(output->data, mode)) { - pepper_output_add_damage_whole(out); + /* TODO: pepper_output_add_damage_whole(out); */ return PEPPER_TRUE; } return PEPPER_FALSE; } - -PEPPER_API void -pepper_output_add_damage(pepper_object_t *out, - const pixman_region32_t *region, int x, int y) -{ - pepper_output_t *output = (pepper_output_t *)out; - pixman_region32_t damage; - - CHECK_MAGIC_AND_NON_NULL(out, PEPPER_OUTPUT); - - pixman_region32_init(&damage); - pixman_region32_copy(&damage, (pixman_region32_t *)region); - pixman_region32_translate(&damage, x, y); - pixman_region32_intersect_rect(&damage, &damage, 0, 0, output->geometry.w, output->geometry.h); - - if (pixman_region32_not_empty(&damage)) - { - pixman_region32_union(&output->damage_region, &output->damage_region, &damage); - pepper_output_schedule_repaint(output); - } - - pixman_region32_fini(&damage); -} - -PEPPER_API void -pepper_output_add_damage_rect(pepper_object_t *out, int x, int y, unsigned int w, unsigned int h) -{ - pepper_output_t *output = (pepper_output_t *)out; - pixman_region32_t damage; - - CHECK_MAGIC_AND_NON_NULL(out, PEPPER_OUTPUT); - - pixman_region32_init_rect(&damage, x, y, w, h); - pixman_region32_intersect_rect(&damage, &damage, 0, 0, output->geometry.w, output->geometry.h); - - if (pixman_region32_not_empty(&damage)) - pixman_region32_union(&output->damage_region, &output->damage_region, &damage); - - pixman_region32_fini(&damage); - pepper_output_schedule_repaint(output); -} - -PEPPER_API void -pepper_output_add_damage_whole(pepper_object_t *out) -{ - pepper_output_t *output = (pepper_output_t *)out; - - CHECK_MAGIC_AND_NON_NULL(out, PEPPER_OUTPUT); - pixman_region32_init_rect(&output->damage_region, 0, 0, output->geometry.w, output->geometry.h); - pepper_output_schedule_repaint(output); -} diff --git a/pepper/src/pepper-internal.h b/pepper/src/pepper-internal.h index 1f94f52..9304ad0 100644 --- a/pepper/src/pepper-internal.h +++ b/pepper/src/pepper-internal.h @@ -5,6 +5,7 @@ #include "pepper.h" #include #include +#include typedef struct pepper_compositor pepper_compositor_t; typedef struct pepper_output pepper_output_t; @@ -15,6 +16,7 @@ typedef struct pepper_seat pepper_seat_t; typedef struct pepper_pointer pepper_pointer_t; typedef struct pepper_keyboard pepper_keyboard_t; typedef struct pepper_touch pepper_touch_t; +typedef struct pepper_plane pepper_plane_t; #define CHECK_NON_NULL(ptr) \ do { \ @@ -43,10 +45,11 @@ typedef struct pepper_touch pepper_touch_t; CHECK_MAGIC(obj, val); \ } while (0) -#define PEPPER_MAX_OUTPUT_ID 32 +#define PEPPER_MAX_OUTPUT_COUNT 32 typedef struct pepper_region pepper_region_t; typedef struct pepper_surface_state pepper_surface_state_t; +typedef struct pepper_plane_entry pepper_plane_entry_t; typedef struct pepper_data_source pepper_data_source_t; typedef struct pepper_data_device pepper_data_device_t; typedef struct pepper_data_offer pepper_data_offer_t; @@ -62,6 +65,7 @@ enum pepper_magic PEPPER_POINTER = 0x00000007, PEPPER_KEYBOARD = 0x00000008, PEPPER_TOUCH = 0x00000009, + PEPPER_PLANE = 0x0000000a, }; struct pepper_object @@ -90,10 +94,9 @@ struct pepper_compositor struct wl_list surfaces; struct wl_list regions; struct wl_list seat_list; - struct wl_list output_list; + pepper_list_t output_list; uint32_t output_id_allocator; struct wl_list event_hook_chain; - pepper_list_t root_view_list; pepper_list_t view_list; }; @@ -105,7 +108,7 @@ struct pepper_output struct wl_global *global; struct wl_list resources; - struct wl_list link; + pepper_list_t link; pepper_output_geometry_t geometry; int32_t scale; @@ -129,16 +132,13 @@ struct pepper_output struct wl_listener frame_listener; } frame; - /* Region damaged but not repainted. */ - pixman_region32_t damage_region; + pepper_list_t plane_list; + pepper_list_t view_list; }; void pepper_output_schedule_repaint(pepper_output_t *output); -void -pepper_output_repaint(pepper_output_t *output); - struct pepper_buffer { pepper_object_t base; @@ -200,7 +200,7 @@ struct pepper_surface char *role; pepper_map_t *user_data_map; - struct wl_list view_list; + pepper_list_t view_list; }; pepper_surface_t * @@ -306,25 +306,37 @@ struct pepper_data_device pepper_bool_t pepper_data_device_manager_init(struct wl_display *display); +struct pepper_plane_entry +{ + pepper_render_item_t base; + + pepper_plane_t *plane; + struct wl_listener plane_destroy_listener; + pepper_bool_t need_damage; + + pepper_list_t link; +}; + struct pepper_view { pepper_object_t base; pepper_compositor_t *compositor; + pepper_list_t compositor_link; - /* Hierarchy & Z-order. */ + /* Hierarchy. */ pepper_view_t *parent; - pepper_list_t children_list; pepper_list_t parent_link; - pepper_list_t z_link; + pepper_list_t children_list; /* Geometry. */ + pepper_bool_t geometry_dirty; double x, y; int w, h; pepper_mat4_t transform; - pepper_mat4_t matrix_to_parent; - pepper_mat4_t matrix_to_global; + pepper_mat4_t global_transform; + pixman_region32_t bounding_region; - pepper_bool_t geometry_dirty; + pixman_region32_t opaque_region; /* Visibility. */ pepper_bool_t visibility; @@ -332,17 +344,64 @@ struct pepper_view /* Content. */ pepper_surface_t *surface; - struct wl_list surface_link; + pepper_list_t surface_link; struct wl_listener surface_destroy_listener; - pixman_region32_t opaque_region; - pixman_region32_t visible_region; + /* Output info. */ + uint32_t output_overlap; + pepper_plane_entry_t plane_entries[PEPPER_MAX_OUTPUT_COUNT]; - pepper_view_state_t state; + /* Temporary resource. */ + pepper_list_t link; }; void -pepper_compositor_update_views(pepper_compositor_t *compositor); +pepper_view_assign_plane(pepper_object_t *view, pepper_object_t *output, pepper_object_t *plane); + +void +pepper_view_damage_below(pepper_view_t *view); + +void +pepper_view_update_geometry(pepper_view_t *view); + +struct pepper_plane +{ + pepper_object_t base; + pepper_output_t *output; + + pepper_list_t entry_list; + pixman_region32_t damage_region; + pixman_region32_t clip_region; + + pepper_list_t link; +}; + +pepper_object_t * +pepper_plane_create(pepper_object_t *output, pepper_object_t *above_plane); + +void +pepper_plane_destroy(pepper_object_t *plane); + +pixman_region32_t * +pepper_plane_get_damage_region(pepper_object_t *plane); + +pixman_region32_t * +pepper_plane_get_clip_region(pepper_object_t *plane); + +const pepper_list_t * +pepper_plane_get_render_node_list(pepper_object_t *plane); + +void +pepper_plane_subtract_damage_region(pepper_object_t *plane, pixman_region32_t *region); + +void +pepper_plane_add_damage_region(pepper_plane_t *plane, pixman_region32_t *region); + +void +pepper_plane_accumulate_damage(pepper_plane_t *plane, pixman_region32_t *clip); + +void +pepper_plane_update(pepper_plane_t *plane, const pepper_list_t *view_list); /* Event hook */ struct pepper_event_hook @@ -363,13 +422,6 @@ pepper_compositor_event_handler(pepper_object_t *seat, void *data); void -pepper_compositor_add_damage(pepper_compositor_t *compositor, const pixman_region32_t *region); - -void -pepper_compositor_add_damage_rect(pepper_compositor_t *compositor, - int x, int y, unsigned int w, unsigned int h); - -void pepper_surface_flush_damage(pepper_surface_t *surface); #endif /* PEPPER_INTERNAL_H */ diff --git a/pepper/src/pepper-output-backend.h b/pepper/src/pepper-output-backend.h new file mode 100644 index 0000000..6e7784b --- /dev/null +++ b/pepper/src/pepper-output-backend.h @@ -0,0 +1,74 @@ +#ifndef PEPPER_OUTPUT_BACKEND_H +#define PEPPER_OUTPUT_BACKEND_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pepper_output_backend pepper_output_backend_t; +typedef struct pepper_render_item pepper_render_item_t; + +struct pepper_output_backend +{ + void (*destroy)(void *output); + + void (*add_destroy_listener)(void *output, struct wl_listener *listener); + void (*add_mode_change_listener)(void *output, struct wl_listener *listener); + + int32_t (*get_subpixel_order)(void *output); + const char * (*get_maker_name)(void *output); + const char * (*get_model_name)(void *output); + + int (*get_mode_count)(void *output); + void (*get_mode)(void *output, int index, pepper_output_mode_t *mode); + pepper_bool_t (*set_mode)(void *output, const pepper_output_mode_t *mode); + + void (*assign_planes)(void *output, const pepper_list_t *view_list); + void (*repaint)(void *output, const pepper_list_t *plane_list); + void (*attach_surface)(void *output, pepper_object_t *surface, int *w, int *h); + + void (*add_frame_listener)(void *output, struct wl_listener *listener); +}; + +PEPPER_API pepper_object_t * +pepper_compositor_add_output(pepper_object_t *compositor, + const pepper_output_backend_t *backend, void *data); + +struct pepper_render_item +{ + pepper_object_t *view; + pepper_mat4_t transform; + pixman_region32_t visible_region; +}; + +PEPPER_API pepper_object_t * +pepper_output_add_plane(pepper_object_t *output, pepper_object_t *above_plane); + +PEPPER_API void +pepper_plane_destroy(pepper_object_t *plane); + +PEPPER_API pixman_region32_t * +pepper_plane_get_damage_region(pepper_object_t *plane); + +PEPPER_API pixman_region32_t * +pepper_plane_get_clip_region(pepper_object_t *plane); + +PEPPER_API const pepper_list_t * +pepper_plane_get_render_list(pepper_object_t *plane); + +PEPPER_API void +pepper_plane_subtract_damage_region(pepper_object_t *plane, pixman_region32_t *damage); + +PEPPER_API void +pepper_view_assign_plane(pepper_object_t *view, pepper_object_t *output, pepper_object_t *plane); + +PEPPER_API void +pepper_output_add_damage_region(pepper_object_t *output, pixman_region32_t *region); + +#ifdef __cplusplus +} +#endif + +#endif /* PEPPER_OUTPUT_BACKEND_H */ diff --git a/pepper/src/pepper.h b/pepper/src/pepper.h index 27ff4ec..1896885 100644 --- a/pepper/src/pepper.h +++ b/pepper/src/pepper.h @@ -11,27 +11,12 @@ extern "C" { #endif typedef struct pepper_object pepper_object_t; - typedef struct pepper_output_geometry pepper_output_geometry_t; typedef struct pepper_output_mode pepper_output_mode_t; -typedef struct pepper_output_backend pepper_output_backend_t; - typedef struct pepper_seat_backend pepper_seat_backend_t; - typedef struct pepper_input_event pepper_input_event_t; typedef struct pepper_event_hook pepper_event_hook_t; -typedef struct pepper_view_state pepper_view_state_t; - -struct pepper_view_state -{ - pepper_object_t *view; - const pepper_mat4_t *transform; - const pixman_region32_t *bounding; - const pixman_region32_t *opaque; - const pixman_region32_t *visible; -}; - struct pepper_output_geometry { int32_t x; @@ -51,28 +36,6 @@ struct pepper_output_mode int32_t refresh; }; -struct pepper_output_backend -{ - void (*destroy)(void *output); - - void (*add_destroy_listener)(void *output, struct wl_listener *listener); - void (*add_mode_change_listener)(void *output, struct wl_listener *listener); - - int32_t (*get_subpixel_order)(void *output); - const char * (*get_maker_name)(void *output); - const char * (*get_model_name)(void *output); - - int (*get_mode_count)(void *output); - void (*get_mode)(void *output, int index, pepper_output_mode_t *mode); - pepper_bool_t (*set_mode)(void *output, const pepper_output_mode_t *mode); - - void (*repaint)(void *output, - const pepper_list_t *view_list, const pixman_region32_t *damage); - void (*attach_surface)(void *output, pepper_object_t *surface, int *w, int *h); - - void (*add_frame_listener)(void *output, struct wl_listener *listener); -}; - /* Generic object functions. */ PEPPER_API void pepper_object_set_user_data(pepper_object_t *object, const void *key, void *data, @@ -95,11 +58,6 @@ PEPPER_API struct wl_display * pepper_compositor_get_display(pepper_object_t *compositor); PEPPER_API pepper_object_t * -pepper_compositor_add_output(pepper_object_t *compositor, - const pepper_output_backend_t *backend, - void *data); - -PEPPER_API pepper_object_t * pepper_compositor_add_seat(pepper_object_t *compositor, const pepper_seat_backend_t *backend, void *data); @@ -128,16 +86,6 @@ pepper_output_get_mode(pepper_object_t *output, int index); PEPPER_API pepper_bool_t pepper_output_set_mode(pepper_object_t *output, const pepper_output_mode_t *mode); -PEPPER_API void -pepper_output_add_damage(pepper_object_t *output, - const pixman_region32_t *region, int x, int y); - -PEPPER_API void -pepper_output_add_damage_rect(pepper_object_t *output, int x, int y, unsigned int w, unsigned int h); - -PEPPER_API void -pepper_output_add_damage_whole(pepper_object_t *output); - /* Input. */ struct pepper_seat_backend { diff --git a/pepper/src/plane.c b/pepper/src/plane.c new file mode 100644 index 0000000..dc25460 --- /dev/null +++ b/pepper/src/plane.c @@ -0,0 +1,164 @@ +#include "pepper-internal.h" + +void +pepper_plane_update(pepper_plane_t *plane, const pepper_list_t *view_list) +{ + pepper_list_t *l; + double output_x = plane->output->geometry.x; + double output_y = plane->output->geometry.y; + + pepper_list_init(&plane->entry_list); + + PEPPER_LIST_FOR_EACH(view_list, l) + { + pepper_view_t *view = l->item; + pepper_plane_entry_t *entry = &view->plane_entries[plane->output->id]; + + if (entry->plane == plane) + { + pepper_list_insert(&plane->entry_list, &entry->link); + + /* Calculate view transform on output local coordinate space. */ + pepper_mat4_init_translate(&entry->base.transform, -output_x, -output_y, 0.0); + pepper_mat4_multiply(&entry->base.transform, + &entry->base.transform, &view->global_transform); + } + } +} + +void +pepper_plane_accumulate_damage(pepper_plane_t *plane, pixman_region32_t *clip) +{ + pepper_list_t *l; + int x = plane->output->geometry.x; + int y = plane->output->geometry.y; + int w = plane->output->geometry.w; + int h = plane->output->geometry.h; + + pixman_region32_init(clip); + + PEPPER_LIST_FOR_EACH_REVERSE(&plane->entry_list, l) + { + pepper_plane_entry_t *entry = l->item; + pepper_view_t *view = (pepper_view_t *)entry->base.view; + + pixman_region32_subtract(&entry->base.visible_region, &view->bounding_region, clip); + pixman_region32_translate(&entry->base.visible_region, -x, -y); + pixman_region32_intersect_rect(&entry->base.visible_region, + &entry->base.visible_region, 0, 0, w, h); + + pixman_region32_union(clip, clip, &view->opaque_region); + + if (entry->need_damage) + { + pepper_view_damage_below(view); + entry->need_damage = PEPPER_FALSE; + } + } + + pixman_region32_translate(clip, -x, -y); + pixman_region32_intersect_rect(clip, clip, 0, 0, w, h); +} + +PEPPER_API pepper_object_t * +pepper_output_add_plane(pepper_object_t *out, pepper_object_t *above_plane) +{ + pepper_plane_t *plane; + pepper_output_t *output = (pepper_output_t *)out; + pepper_plane_t *above = (pepper_plane_t *)above_plane; + + CHECK_MAGIC_AND_NON_NULL(out, PEPPER_OUTPUT); + CHECK_MAGIC_IF_NON_NULL(above_plane, PEPPER_PLANE); + + if (above && above->output != output) + return NULL; + + plane = (pepper_plane_t *)pepper_object_alloc(sizeof(pepper_plane_t), PEPPER_PLANE); + if (!plane) + return NULL; + + plane->output = output; + plane->link.item = plane; + + if (above) + pepper_list_insert(above->link.prev, &plane->link); + else + pepper_list_insert(output->plane_list.prev, &plane->link); + + pepper_list_init(&plane->entry_list); + pixman_region32_init(&plane->damage_region); + pixman_region32_init(&plane->clip_region); + + return &plane->base; +} + +void +pepper_plane_destroy(pepper_object_t *pln) +{ + pepper_plane_t *plane = (pepper_plane_t *)pln; + pepper_list_t *l; + + CHECK_MAGIC_AND_NON_NULL(pln, PEPPER_PLANE); + + pepper_object_fini(pln); + + PEPPER_LIST_FOR_EACH(&plane->entry_list, l) + { + pepper_plane_entry_t *entry = l->item; + pepper_view_assign_plane(entry->base.view, &plane->output->base, NULL); + } + + pepper_list_remove(&plane->link, NULL); + pixman_region32_fini(&plane->damage_region); + pixman_region32_fini(&plane->clip_region); + + pepper_free(plane); +} + +void +pepper_plane_add_damage_region(pepper_plane_t *plane, pixman_region32_t *damage) +{ + if (!damage) + { + pixman_region32_union_rect(&plane->damage_region, &plane->damage_region, + 0, 0, plane->output->geometry.w, plane->output->geometry.h); + pepper_output_schedule_repaint(plane->output); + } + else if (pixman_region32_not_empty(damage)) + { + pixman_region32_union(&plane->damage_region, &plane->damage_region, damage); + pepper_output_schedule_repaint(plane->output); + } +} + +PEPPER_API pixman_region32_t * +pepper_plane_get_damage_region(pepper_object_t *pln) +{ + pepper_plane_t *plane = (pepper_plane_t *)pln; + CHECK_MAGIC_AND_NON_NULL(pln, PEPPER_PLANE); + return &plane->damage_region; +} + +pixman_region32_t * +pepper_plane_get_clip_region(pepper_object_t *pln) +{ + pepper_plane_t *plane = (pepper_plane_t *)pln; + CHECK_MAGIC_AND_NON_NULL(pln, PEPPER_PLANE); + return &plane->clip_region; +} + +const pepper_list_t * +pepper_plane_get_render_list(pepper_object_t *pln) +{ + pepper_plane_t *plane = (pepper_plane_t *)pln; + CHECK_MAGIC_AND_NON_NULL(pln, PEPPER_PLANE); + return &plane->entry_list; +} + +void +pepper_plane_subtract_damage_region(pepper_object_t *pln, pixman_region32_t *damage) +{ + pepper_plane_t *plane = (pepper_plane_t *)pln; + CHECK_MAGIC_AND_NON_NULL(pln, PEPPER_PLANE); + pixman_region32_subtract(&plane->damage_region, &plane->damage_region, damage); +} diff --git a/pepper/src/surface.c b/pepper/src/surface.c index 72f9554..cfd45f8 100644 --- a/pepper/src/surface.c +++ b/pepper/src/surface.c @@ -259,7 +259,7 @@ pepper_surface_create(pepper_compositor_t *compositor, pixman_region32_init(&surface->input_region); wl_list_init(&surface->frame_callbacks); - wl_list_init(&surface->view_list); + pepper_list_init(&surface->view_list); return surface; } diff --git a/pepper/src/view.c b/pepper/src/view.c index da652b5..80feee5 100644 --- a/pepper/src/view.c +++ b/pepper/src/view.c @@ -2,6 +2,15 @@ #include static void +view_mark_plane_entries_damaged(pepper_view_t *view) +{ + int i; + + for (i = 0; i < PEPPER_MAX_OUTPUT_COUNT; i++) + view->plane_entries[i].need_damage = PEPPER_TRUE; +} + +static void view_handle_surface_destroy(struct wl_listener *listener, void *data) { pepper_view_t *view = pepper_container_of(listener, pepper_view_t, surface_destroy_listener); @@ -18,7 +27,7 @@ view_geometry_dirty(pepper_view_t *view) return; view->geometry_dirty = PEPPER_TRUE; - pepper_compositor_add_damage(view->compositor, &view->visible_region); + pepper_view_damage_below(view); PEPPER_LIST_FOR_EACH(&view->children_list, l) view_geometry_dirty((pepper_view_t *)l->item); @@ -121,134 +130,201 @@ transform_region_bounding(pixman_region32_t *region, const pepper_mat4_t *matrix } static void -view_update_geometry(pepper_view_t *view) +view_update_output_overlap(pepper_view_t *view) { - if (view->parent) - view_update_geometry(view->parent); + pepper_list_t *l; - if (view->geometry_dirty) + view->output_overlap = 0; + + PEPPER_LIST_FOR_EACH(&view->compositor->output_list, l) { - view->matrix_to_parent.m[ 0] = view->transform.m[ 0] + view->transform.m[12] * view->x; - view->matrix_to_parent.m[ 1] = view->transform.m[ 1] + view->transform.m[13] * view->x; - view->matrix_to_parent.m[ 2] = view->transform.m[ 2] + view->transform.m[14] * view->x; - view->matrix_to_parent.m[ 3] = view->transform.m[ 3] + view->transform.m[15] * view->x; - - view->matrix_to_parent.m[ 4] = view->transform.m[ 4] + view->transform.m[12] * view->y; - view->matrix_to_parent.m[ 5] = view->transform.m[ 5] + view->transform.m[13] * view->y; - view->matrix_to_parent.m[ 6] = view->transform.m[ 6] + view->transform.m[14] * view->y; - view->matrix_to_parent.m[ 7] = view->transform.m[ 7] + view->transform.m[15] * view->y; - - view->matrix_to_parent.m[ 8] = view->transform.m[ 8]; - view->matrix_to_parent.m[ 9] = view->transform.m[ 9]; - view->matrix_to_parent.m[10] = view->transform.m[10]; - view->matrix_to_parent.m[11] = view->transform.m[11]; - - view->matrix_to_parent.m[12] = view->transform.m[12]; - view->matrix_to_parent.m[13] = view->transform.m[13]; - view->matrix_to_parent.m[14] = view->transform.m[14]; - view->matrix_to_parent.m[15] = view->transform.m[15]; - - if (view->parent) - { - pepper_mat4_multiply(&view->matrix_to_global, - &view->parent->matrix_to_global, &view->matrix_to_parent); - } - else + pepper_output_t *output = l->item; + pixman_box32_t box = { - pepper_mat4_copy(&view->matrix_to_global, &view->matrix_to_parent); - } + output->geometry.x, + output->geometry.y, + output->geometry.x + output->geometry.w, + output->geometry.y + output->geometry.h + }; + + if (pixman_region32_contains_rectangle(&view->bounding_region, &box) != PIXMAN_REGION_OUT) + view->output_overlap |= (1 << output->id); + } +} + +static pepper_list_t * +view_insert(pepper_view_t *view, pepper_list_t *pos, pepper_bool_t subtree) +{ + if (pos->next != &view->compositor_link) + { + pepper_list_remove(&view->compositor_link, NULL); + pepper_list_insert(pos, &view->compositor_link); - if (view->surface) + if (view->visibility) { - view->w = view->surface->w; - view->h = view->surface->h; + pepper_view_damage_below(view); + view_mark_plane_entries_damaged(view); } + } + + pos = &view->compositor_link; - /* Bounding region. */ - pixman_region32_init_rect(&view->bounding_region, 0, 0, view->w, view->h); - transform_region_bounding(&view->bounding_region, &view->matrix_to_global); + if (subtree) + { + pepper_list_t *l; - /* Opaque region. */ - pixman_region32_init(&view->opaque_region); + PEPPER_LIST_FOR_EACH(&view->children_list, l) + pos = view_insert((pepper_view_t *)l->item, pos, subtree); + } - if (view->surface && pepper_mat4_is_translation(&view->matrix_to_global)) - { - pixman_region32_copy(&view->opaque_region, &view->surface->opaque_region); - pixman_region32_translate(&view->opaque_region, - view->matrix_to_global.m[3], view->matrix_to_global.m[7]); - } + return pos; +} +static void +view_handle_plane_destroy(struct wl_listener *listener, void *data); + +static void +plane_entry_set_plane(pepper_plane_entry_t *entry, pepper_plane_t *plane) +{ + if (entry->plane == plane) + return; + + if (entry->plane) + { + pepper_view_damage_below((pepper_view_t *)entry->base.view); + entry->plane = NULL; + wl_list_remove(&entry->plane_destroy_listener.link); + pixman_region32_fini(&entry->base.visible_region); + } - view->geometry_dirty = PEPPER_FALSE; + entry->plane = plane; + + if (entry->plane) + { + entry->plane_destroy_listener.notify = view_handle_plane_destroy; + pepper_object_add_destroy_listener(&plane->base, &entry->plane_destroy_listener); + pixman_region32_init(&entry->base.visible_region); + entry->need_damage = PEPPER_TRUE; } } +static void +view_handle_plane_destroy(struct wl_listener *listener, void *data) +{ + pepper_plane_entry_t *entry = + pepper_container_of(listener, pepper_plane_entry_t, plane_destroy_listener); + + PEPPER_ASSERT(entry->plane != NULL); + plane_entry_set_plane(entry, NULL); +} + void -pepper_compositor_update_views(pepper_compositor_t *compositor) +pepper_view_assign_plane(pepper_object_t *v, pepper_object_t *out, pepper_object_t *pln) { - pepper_list_t *l; - pixman_region32_t visible; - pixman_region32_t opaque; - pixman_region32_t surface_damage; - pixman_region32_t damage; + pepper_view_t *view = (pepper_view_t *)v; + pepper_output_t *output = (pepper_output_t *)out; + pepper_plane_t *plane = (pepper_plane_t *)pln; - pixman_region32_init(&visible); - pixman_region32_init(&opaque); - pixman_region32_init(&surface_damage); - pixman_region32_init(&damage); + CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW); + CHECK_MAGIC_AND_NON_NULL(out, PEPPER_OUTPUT); + CHECK_MAGIC_IF_NON_NULL(pln, PEPPER_PLANE); - /* Update views from front to back. */ - PEPPER_LIST_FOR_EACH_REVERSE(&compositor->view_list, l) + if (plane && plane->output != output) { - pepper_view_t *view = (pepper_view_t *)(((pepper_view_state_t *)l->item)->view); + PEPPER_ERROR("Output mismatch.\n"); + return; + } - view_update_geometry(view); + plane_entry_set_plane(&view->plane_entries[output->id], plane); +} - /* Calculate updated visible region. */ - pixman_region32_subtract(&visible, &view->bounding_region, &opaque); - pixman_region32_subtract(&damage, &visible, &view->visible_region); +void +pepper_view_damage_below(pepper_view_t *view) +{ + int i; - /* Inflict damage for the visible region change. */ - pepper_compositor_add_damage(view->compositor, &damage); + for (i = 0; i < PEPPER_MAX_OUTPUT_COUNT; i++) + { + pepper_plane_entry_t *entry = &view->plane_entries[i]; - /* Update visible region of the view. */ - pixman_region32_copy(&view->visible_region, &visible); + if (entry->plane) + pepper_plane_add_damage_region(entry->plane, &entry->base.visible_region); + } +} - /* Inflict surface damage. */ - if (pixman_region32_not_empty(&view->surface->damage_region)) - { - pepper_surface_flush_damage(view->surface); +void +pepper_view_update_geometry(pepper_view_t *view) +{ + if (!view->geometry_dirty) + return; - pixman_region32_copy(&surface_damage, &view->surface->damage_region); + pepper_mat4_init_translate(&view->global_transform, view->x, view->y, 0.0); + pepper_mat4_multiply(&view->global_transform, &view->transform, &view->global_transform); - /* Transform surface damage into global coordinate space. */ - transform_region_bounding(&surface_damage, &view->matrix_to_global); + if (view->parent) + { + pepper_view_update_geometry(view->parent); + pepper_mat4_multiply(&view->global_transform, + &view->parent->global_transform, &view->global_transform); + } - /* Clip surface damage with view's bounding region. */ - pixman_region32_intersect(&surface_damage, &surface_damage, &view->bounding_region); + if (view->surface) + { + view->w = view->surface->w; + view->h = view->surface->h; + } - /* Subtract area covered by opaque views. */ - pixman_region32_subtract(&surface_damage, &surface_damage, &opaque); + /* Bounding region. */ + pixman_region32_init_rect(&view->bounding_region, 0, 0, view->w, view->h); + transform_region_bounding(&view->bounding_region, &view->global_transform); - pepper_compositor_add_damage(view->compositor, &surface_damage); - } + /* Opaque region. */ + pixman_region32_init(&view->opaque_region); - /* Accumulate opaque region. */ - pixman_region32_union(&opaque, &opaque, &view->opaque_region); + if (view->surface && pepper_mat4_is_translation(&view->global_transform)) + { + pixman_region32_copy(&view->opaque_region, &view->surface->opaque_region); + pixman_region32_translate(&view->opaque_region, + view->global_transform.m[3], view->global_transform.m[7]); } - pixman_region32_fini(&visible); - pixman_region32_fini(&opaque); - pixman_region32_fini(&surface_damage); - pixman_region32_fini(&damage); + view->geometry_dirty = PEPPER_FALSE; + view_update_output_overlap(view); + view_mark_plane_entries_damaged(view); +} + +static void +view_init(pepper_view_t *view, pepper_compositor_t *compositor) +{ + int i; + + view->compositor = compositor; + view->compositor_link.item = view; + pepper_list_insert(compositor->view_list.prev, &view->compositor_link); + + view->parent_link.item = view; + pepper_list_init(&view->children_list); + + pepper_mat4_init_identity(&view->transform); + pepper_mat4_init_identity(&view->global_transform); + pixman_region32_init(&view->bounding_region); + pixman_region32_init(&view->opaque_region); + + for (i = 0; i < PEPPER_MAX_OUTPUT_COUNT; i++) + { + view->plane_entries[i].base.view = &view->base; + view->plane_entries[i].link.item = &view->plane_entries[i]; + } } + PEPPER_API pepper_object_t * pepper_compositor_add_surface_view(pepper_object_t *comp, pepper_object_t *sfc) { pepper_view_t *view; pepper_compositor_t *compositor = (pepper_compositor_t *)comp; + pepper_surface_t *surface = (pepper_surface_t *)sfc; CHECK_MAGIC_AND_NON_NULL(comp, PEPPER_COMPOSITOR); - CHECK_MAGIC_IF_NON_NULL(sfc, PEPPER_SURFACE); + CHECK_MAGIC_AND_NON_NULL(sfc, PEPPER_SURFACE); view = (pepper_view_t *)pepper_object_alloc(sizeof(pepper_view_t), PEPPER_VIEW); if (!view) @@ -257,50 +333,21 @@ pepper_compositor_add_surface_view(pepper_object_t *comp, pepper_object_t *sfc) return NULL; } - view->compositor = compositor; + view_init(view, compositor); view->x = 0.0; view->y = 0.0; + view->w = surface->w; + view->h = surface->h; - view->w = 0; - view->h = 0; - - pepper_mat4_init_identity(&view->transform); - pepper_mat4_init_identity(&view->matrix_to_parent); - pepper_mat4_init_identity(&view->matrix_to_global); - - view->parent_link.item = (void *)view; - - pepper_list_init(&view->children_list); - pepper_list_insert(compositor->root_view_list.prev, &view->parent_link); - pepper_list_insert(compositor->view_list.prev, &view->z_link); - - if (sfc) - { - pepper_surface_t *surface = (pepper_surface_t *)sfc; - - view->surface = surface; - wl_list_insert(&surface->view_list, &view->surface_link); - - view->surface_destroy_listener.notify = view_handle_surface_destroy; - pepper_object_add_destroy_listener(&surface->base, &view->surface_destroy_listener); - - view->w = surface->w; - view->h = surface->h; - } - - pixman_region32_init_rect(&view->bounding_region, 0, 0, view->w, view->h); - pixman_region32_init(&view->opaque_region); - pixman_region32_init(&view->visible_region); + view->geometry_dirty = PEPPER_TRUE; - view->state.view = &view->base; - view->state.transform = &view->matrix_to_global; - view->state.bounding = &view->bounding_region; - view->state.opaque = &view->opaque_region; - view->state.visible = &view->visible_region; - view->z_link.item = &view->state; + view->surface = surface; + view->surface_link.item = view; + pepper_list_insert(&surface->view_list, &view->surface_link); + view->surface_destroy_listener.notify = view_handle_surface_destroy; + pepper_object_add_destroy_listener(&surface->base, &view->surface_destroy_listener); - view->geometry_dirty = PEPPER_TRUE; return &view->base; } @@ -309,6 +356,7 @@ pepper_view_destroy(pepper_object_t *v) { pepper_view_t *view = (pepper_view_t *)v; pepper_list_t *l, *next; + int i; CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW); @@ -318,22 +366,26 @@ pepper_view_destroy(pepper_object_t *v) pepper_object_fini(&view->base); view_unmap(view); + for (i = 0; i < PEPPER_MAX_OUTPUT_COUNT; i++) + plane_entry_set_plane(&view->plane_entries[i], NULL); + PEPPER_LIST_FOR_EACH_SAFE(&view->children_list, l, next) pepper_view_destroy((pepper_object_t *)(l->item)); PEPPER_ASSERT(pepper_list_empty(&view->children_list)); - pepper_list_remove(&view->parent_link, NULL); - pepper_list_remove(&view->z_link, NULL); + if (view->parent) + pepper_list_remove(&view->parent_link, NULL); + + pepper_list_remove(&view->compositor_link, NULL); if (view->surface) { - wl_list_remove(&view->surface_link); + pepper_list_remove(&view->surface_link, NULL); wl_list_remove(&view->surface_destroy_listener.link); } pixman_region32_fini(&view->opaque_region); - pixman_region32_fini(&view->visible_region); pixman_region32_fini(&view->bounding_region); pepper_free(view); @@ -375,8 +427,6 @@ pepper_view_set_parent(pepper_object_t *v, pepper_object_t *p) if (view->parent) pepper_list_insert(view->parent->children_list.prev, &view->parent_link); - else - pepper_list_insert(view->compositor->root_view_list.prev, &view->parent_link); view_geometry_dirty(view); } @@ -389,31 +439,6 @@ pepper_view_get_parent(pepper_object_t *v) return &view->parent->base; } -static pepper_list_t * -view_insert(pepper_view_t *view, pepper_list_t *pos, pepper_bool_t subtree) -{ - if (pos->next != &view->z_link) - { - pepper_list_remove(&view->z_link, NULL); - pepper_list_insert(pos, &view->z_link); - - if (view->visibility) - pepper_compositor_add_damage(view->compositor, &view->visible_region); - } - - pos = &view->z_link; - - if (subtree) - { - pepper_list_t *l; - - PEPPER_LIST_FOR_EACH(&view->children_list, l) - pos = view_insert((pepper_view_t *)l->item, pos, subtree); - } - - return pos; -} - PEPPER_API pepper_bool_t pepper_view_stack_above(pepper_object_t *v, pepper_object_t *b, pepper_bool_t subtree) { @@ -423,7 +448,7 @@ pepper_view_stack_above(pepper_object_t *v, pepper_object_t *b, pepper_bool_t su CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW); CHECK_MAGIC_AND_NON_NULL(b, PEPPER_VIEW); - view_insert(view, &below->z_link, subtree); + view_insert(view, &below->compositor_link, subtree); return PEPPER_TRUE; } @@ -436,7 +461,7 @@ pepper_view_stack_below(pepper_object_t *v, pepper_object_t *a, pepper_bool_t su CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW); CHECK_MAGIC_AND_NON_NULL(a, PEPPER_VIEW); - view_insert(view, above->z_link.prev, subtree); + view_insert(view, above->compositor_link.prev, subtree); return PEPPER_TRUE; } @@ -461,7 +486,7 @@ pepper_view_get_above(pepper_object_t *v) { pepper_view_t *view = (pepper_view_t *)v; CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW); - return view->z_link.next->item; + return view->compositor_link.next->item; } PEPPER_API pepper_object_t * @@ -469,7 +494,7 @@ pepper_view_get_below(pepper_object_t *v) { pepper_view_t *view = (pepper_view_t *)v; CHECK_MAGIC_AND_NON_NULL(v, PEPPER_VIEW); - return view->z_link.prev->item; + return view->compositor_link.prev->item; } PEPPER_API const pepper_list_t * diff --git a/render/src/gl-renderer.c b/render/src/gl-renderer.c index 873d50a..bc47a00 100644 --- a/render/src/gl-renderer.c +++ b/render/src/gl-renderer.c @@ -488,7 +488,7 @@ gl_renderer_read_pixels(pepper_renderer_t *renderer, static void gl_renderer_repaint_output(pepper_renderer_t *renderer, pepper_object_t *out, - const pepper_list_t *list, const pixman_region32_t *damage) + const pepper_list_t *list, pixman_region32_t *damage) { gl_renderer_t *gr = (gl_renderer_t *)renderer; diff --git a/render/src/pepper-render-internal.h b/render/src/pepper-render-internal.h index b7cea1c..1ce8160 100644 --- a/render/src/pepper-render-internal.h +++ b/render/src/pepper-render-internal.h @@ -33,8 +33,8 @@ struct pepper_renderer void (*repaint_output)(pepper_renderer_t *renderer, pepper_object_t *output, - const pepper_list_t *view_list, - const pixman_region32_t *damage); + const pepper_list_t *render_list, + pixman_region32_t *damage); }; #endif /* PEPPER_RENDER_INTERNAL_H */ diff --git a/render/src/pepper-render.h b/render/src/pepper-render.h index 8640784..ceaf1e3 100644 --- a/render/src/pepper-render.h +++ b/render/src/pepper-render.h @@ -31,7 +31,7 @@ pepper_renderer_flush_surface_damage(pepper_renderer_t *renderer, pepper_object_ PEPPER_API void pepper_renderer_repaint_output(pepper_renderer_t *renderer, pepper_object_t *output, - const pepper_list_t *view_list, const pixman_region32_t *damage); + const pepper_list_t *view_list, pixman_region32_t *damage); PEPPER_API pepper_bool_t pepper_renderer_read_pixels(pepper_renderer_t *renderer, int x, int y, int w, int h, diff --git a/render/src/pixman-renderer.c b/render/src/pixman-renderer.c index e1f1b07..662ddba 100644 --- a/render/src/pixman-renderer.c +++ b/render/src/pixman-renderer.c @@ -1,5 +1,6 @@ #include "pepper-pixman-renderer.h" #include "pepper-render-internal.h" +#include typedef struct pixman_renderer pixman_renderer_t; typedef struct pixman_surface_state pixman_surface_state_t; @@ -228,44 +229,26 @@ pixman_renderer_read_pixels(pepper_renderer_t *renderer, } static void -repaint_view(pepper_renderer_t *renderer, pepper_object_t *output, pepper_view_state_t *view_state, - const pixman_region32_t *global_damage) /* global coordinate */ +repaint_view(pepper_renderer_t *renderer, pepper_render_item_t *node, pixman_region32_t *damage) { pixman_render_target_t *target = (pixman_render_target_t*)renderer->target; pixman_region32_t repaint; - pepper_object_t *view; - pepper_object_t *view_surf; - pixman_surface_state_t *ps; - - view = view_state->view; - PEPPER_ASSERT(view); - - view_surf = pepper_view_get_surface(view); - if (!view_surf) - return; - - ps = get_surface_state(renderer, view_surf); - if (!ps || !ps->image) - return; + pixman_surface_state_t *ps = get_surface_state(renderer, pepper_view_get_surface(node->view)); pixman_region32_init(&repaint); - pixman_region32_intersect(&repaint, (pixman_region32_t*) view_state->visible, - (pixman_region32_t*) global_damage); + pixman_region32_intersect(&repaint, &node->visible_region, damage); if (pixman_region32_not_empty(&repaint)) { - int x, y, w, h; - const pepper_mat4_t *transform = view_state->transform; + int x, y, w, h; - /* set clip on destination */ pixman_image_set_clip_region32(target->image, &repaint); /* TODO: consider transform such as rotation */ - x = transform->m[3]; - y = transform->m[7]; - pepper_view_get_size(view, &w, &h); + x = node->transform.m[3]; + y = node->transform.m[7]; + pepper_view_get_size(node->view, &w, &h); - /* composite */ pixman_image_composite32(PIXMAN_OP_SRC, ps->image, NULL, target->image, 0, 0, /* src_x, src_y */ 0, 0, /* mask_x, mask_y */ @@ -278,31 +261,15 @@ repaint_view(pepper_renderer_t *renderer, pepper_object_t *output, pepper_view_s static void pixman_renderer_repaint_output(pepper_renderer_t *renderer, pepper_object_t *output, - const pepper_list_t *view_list, - const pixman_region32_t *output_damage) + const pepper_list_t *render_list, + pixman_region32_t *damage) { - pixman_render_target_t *target = (pixman_render_target_t *)renderer->target; - - if (target && pixman_region32_not_empty((pixman_region32_t*) output_damage)) + if (pixman_region32_not_empty(damage)) { - const pepper_output_geometry_t *geometry; - pixman_region32_t global_damage; - pepper_list_t *cur_list; - pepper_view_state_t *view_state; - - /* translate damage to global coordinate */ - geometry = pepper_output_get_geometry(output); - pixman_region32_init(&global_damage); - pixman_region32_copy(&global_damage, (pixman_region32_t*) output_damage); - pixman_region32_translate(&global_damage, geometry->x, geometry->y); - - PEPPER_LIST_FOR_EACH_REVERSE(view_list, cur_list) - { - view_state = cur_list->item; - repaint_view(renderer, output, view_state, (const pixman_region32_t *) &global_damage); - } - - pixman_region32_fini(&global_damage); + pepper_list_t *l; + + PEPPER_LIST_FOR_EACH_REVERSE(render_list, l) + repaint_view(renderer, (pepper_render_item_t *)l->item, damage); } } diff --git a/render/src/renderer.c b/render/src/renderer.c index 7a0ad43..04876c9 100644 --- a/render/src/renderer.c +++ b/render/src/renderer.c @@ -43,7 +43,7 @@ pepper_renderer_flush_surface_damage(pepper_renderer_t *renderer, pepper_object_ PEPPER_API void pepper_renderer_repaint_output(pepper_renderer_t *renderer, pepper_object_t *output, - const pepper_list_t *view_list, const pixman_region32_t *damage) + const pepper_list_t *view_list, pixman_region32_t *damage) { renderer->repaint_output(renderer, output, view_list, damage); } diff --git a/wayland/src/wayland-internal.h b/wayland/src/wayland-internal.h index 6372522..cf465e4 100644 --- a/wayland/src/wayland-internal.h +++ b/wayland/src/wayland-internal.h @@ -101,6 +101,8 @@ struct wayland_output struct wl_egl_window *window; } egl; #endif + + pepper_object_t *primary_plane; }; struct wayland_seat diff --git a/wayland/src/wayland-output.c b/wayland/src/wayland-output.c index 346c386..f634dcf 100644 --- a/wayland/src/wayland-output.c +++ b/wayland/src/wayland-output.c @@ -1,6 +1,7 @@ #include "wayland-internal.h" #include #include +#include #include #if ENABLE_WAYLAND_BACKEND_EGL && ENABLE_GL_RENDERER @@ -164,23 +165,49 @@ static const struct wl_callback_listener frame_listener = }; static void -wayland_output_repaint(void *o, const pepper_list_t *view_list, const pixman_region32_t *damage) +wayland_output_assign_planes(void *o, const pepper_list_t *view_list) +{ + wayland_output_t *output = (wayland_output_t *)o; + pepper_list_t *l; + + PEPPER_LIST_FOR_EACH(view_list, l) + { + pepper_object_t *view = l->item; + pepper_view_assign_plane(view, output->base, output->primary_plane); + } +} + +static void +wayland_output_repaint(void *o, const pepper_list_t *plane_list) { wayland_output_t *output = o; struct wl_callback *callback; - if (output->render_pre) - output->render_pre(output); + pepper_list_t *l; - pepper_renderer_repaint_output(output->renderer, output->base, view_list, damage); + PEPPER_LIST_FOR_EACH(plane_list, l) + { + pepper_object_t *plane = l->item; + + if (plane == output->primary_plane) + { + const pepper_list_t *render_list = pepper_plane_get_render_list(plane); + pixman_region32_t *damage = pepper_plane_get_damage_region(plane); + + if (output->render_pre) + output->render_pre(output); - if (output->render_post) - output->render_post(output); + pepper_renderer_repaint_output(output->renderer, output->base, render_list, damage); - callback = wl_surface_frame(output->surface); - wl_callback_add_listener(callback, &frame_listener, output); - wl_surface_commit(output->surface); - wl_display_flush(output->conn->display); + if (output->render_post) + output->render_post(output); + + callback = wl_surface_frame(output->surface); + wl_callback_add_listener(callback, &frame_listener, output); + wl_surface_commit(output->surface); + wl_display_flush(output->conn->display); + } + } } static void @@ -210,6 +237,7 @@ static const pepper_output_backend_t wayland_output_backend = wayland_output_get_mode, wayland_output_set_mode, + wayland_output_assign_planes, wayland_output_repaint, wayland_output_attach_surface, wayland_output_add_frame_listener, @@ -359,5 +387,6 @@ pepper_wayland_output_create(pepper_wayland_t *conn, int32_t w, int32_t h, const return NULL; } + output->primary_plane = pepper_output_add_plane(output->base, NULL); return output->base; } diff --git a/x11/src/x11-common.c b/x11/src/x11-common.c index e7abf5a..020625b 100644 --- a/x11/src/x11-common.c +++ b/x11/src/x11-common.c @@ -76,7 +76,7 @@ x11_handle_event(int fd, uint32_t mask, void *data) if (output) { /* TODO: Damage only newly exposed area. */ - pepper_output_add_damage_whole(output->base); + pepper_output_add_damage_region(output->base, NULL); } } break; diff --git a/x11/src/x11-internal.h b/x11/src/x11-internal.h index d6c35c0..be5376a 100644 --- a/x11/src/x11-internal.h +++ b/x11/src/x11-internal.h @@ -42,8 +42,8 @@ struct x11_shm_image struct x11_output { - pepper_object_t *base; - pepper_x11_connection_t *connection; + pepper_object_t *base; + pepper_x11_connection_t *connection; int32_t x, y; uint32_t w, h; @@ -69,6 +69,8 @@ struct x11_output struct wl_listener conn_destroy_listener; struct wl_list link; + + pepper_object_t *primary_plane; }; struct x11_seat diff --git a/x11/src/x11-output.c b/x11/src/x11-output.c index 9b800f6..609274e 100644 --- a/x11/src/x11-output.c +++ b/x11/src/x11-output.c @@ -1,5 +1,6 @@ #include "x11-internal.h" +#include #include "pepper-gl-renderer.h" #include "pepper-pixman-renderer.h" @@ -444,45 +445,72 @@ x11_output_add_mode_change_listener(void *o, struct wl_listener *listener) } static void -x11_output_repaint(void *o, const pepper_list_t *view_list, const pixman_region32_t *damage) +x11_output_assign_planes(void *o, const pepper_list_t *view_list) { - x11_output_t *output = o; + x11_output_t *output = (x11_output_t *)o; + pepper_list_t *l; - pepper_renderer_set_target(output->renderer, output->target); - pepper_renderer_repaint_output(output->renderer, output->base, view_list, damage); + PEPPER_LIST_FOR_EACH(view_list, l) + { + pepper_object_t *view = l->item; + pepper_view_assign_plane(view, output->base, output->primary_plane); + } +} - if (output->renderer == output->connection->pixman_renderer) +static void +x11_output_repaint(void *o, const pepper_list_t *plane_list) +{ + x11_output_t *output = o; + pepper_list_t *l; + + PEPPER_LIST_FOR_EACH(plane_list, l) { - xcb_void_cookie_t cookie; - xcb_generic_error_t *err; - - cookie = xcb_shm_put_image_checked(output->connection->xcb_connection, - output->window, - output->gc, - output->w * output->scale, /* total_width */ - output->h * output->scale, /* total_height */ - 0, /* src_x */ - 0, /* src_y */ - output->shm.w, /* src_w */ - output->shm.h, /* src_h */ - 0, /* dst_x */ - 0, /* dst_y */ - output->depth, /* depth */ - XCB_IMAGE_FORMAT_Z_PIXMAP, /* format */ - 0, /* send_event */ - output->shm.segment, /* xcb shm segment */ - 0); /* offset */ - - err = xcb_request_check(output->connection->xcb_connection, cookie); - if (err) + pepper_object_t *plane = l->item; + + if (plane == output->primary_plane) { - PEPPER_ERROR("Failed to put shm image, err: %d\n", err->error_code); - free(err); + const pepper_list_t *render_list = pepper_plane_get_render_list(plane); + pixman_region32_t *damage = pepper_plane_get_damage_region(plane); + + pepper_renderer_set_target(output->renderer, output->target); + pepper_renderer_repaint_output(output->renderer, output->base, render_list, damage); + + if (output->renderer == output->connection->pixman_renderer) + { + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; + + cookie = xcb_shm_put_image_checked(output->connection->xcb_connection, + output->window, + output->gc, + output->w * output->scale, /* total_width */ + output->h * output->scale, /* total_height */ + 0, /* src_x */ + 0, /* src_y */ + output->shm.w, /* src_w */ + output->shm.h, /* src_h */ + 0, /* dst_x */ + 0, /* dst_y */ + output->depth, /* depth */ + XCB_IMAGE_FORMAT_Z_PIXMAP, /* format */ + 0, /* send_event */ + output->shm.segment, /* xcb shm segment */ + 0); /* offset */ + + err = xcb_request_check(output->connection->xcb_connection, cookie); + if (err) + { + PEPPER_ERROR("Failed to put shm image, err: %d\n", err->error_code); + free(err); + } + } + + /* XXX: frame_done callback called after 10ms, referenced from weston */ + wl_event_source_timer_update(output->frame_done_timer, 10); } - } - /* XXX: frame_done callback called after 10ms, referenced from weston */ - wl_event_source_timer_update(output->frame_done_timer, 10); + /* TODO: Cursor??? */ + } } static void @@ -513,6 +541,7 @@ static const pepper_output_backend_t x11_output_backend = x11_output_get_mode, x11_output_set_mode, + x11_output_assign_planes, x11_output_repaint, x11_output_attach_surface, x11_output_add_frame_listener, @@ -647,8 +676,7 @@ pepper_x11_output_create(pepper_x11_connection_t *connection, /* Register output object */ base = pepper_compositor_add_output(connection->compositor, - &x11_output_backend, - output); + &x11_output_backend, output); if (!base) { PEPPER_ERROR("pepper_compositor_add_output failed\n"); @@ -657,6 +685,7 @@ pepper_x11_output_create(pepper_x11_connection_t *connection, } output->base = base; + output->primary_plane = pepper_output_add_plane(output->base, NULL); /* X11 input seat create */ if (!connection->use_xinput) -- 2.7.4