commit 170445e630a22a6a38e16f404948dae66660834d
parent 300de285384cdf277c25941854807c449d416375
Author: Michael Forney <mforney@mforney.org>
Date: Thu, 16 Jan 2014 17:46:12 -0800
Refactor planes
Diffstat:
17 files changed, 664 insertions(+), 468 deletions(-)
diff --git a/libswc/compositor.c b/libswc/compositor.c
@@ -20,6 +20,15 @@
#include <wld/drm.h>
#include <xkbcommon/xkbcommon-keysyms.h>
+struct screen
+{
+ struct wld_surface * surface;
+ struct wld_buffer * next_buffer, * current_buffer;
+ struct swc_view * view;
+ struct wl_listener view_listener;
+ struct wl_listener event_listener;
+};
+
struct view
{
struct swc_view base;
@@ -44,12 +53,156 @@ struct view
struct wl_list link;
};
+static void perform_update(void * data);
+
+static void buffer_destroy(void * data)
+{
+ struct swc_buffer * buffer = data;
+
+ swc_buffer_finalize(buffer);
+ free(buffer);
+}
+
+struct swc_buffer * buffer_get(struct wld_buffer * wld)
+{
+ if (wld->destroy_data)
+ return wld->data;
+
+ struct swc_buffer * buffer;
+
+ if (!(buffer = malloc(sizeof *buffer)))
+ goto error0;
+
+ if (!swc_buffer_initialize(buffer, wld))
+ goto error1;
+
+ wld->data = buffer;
+ wld->destroy_data = &buffer_destroy;
+
+ return buffer;
+
+error1:
+ free(buffer);
+error0:
+ return NULL;
+}
+
+static void handle_screen_event(struct wl_listener * listener, void * data)
+{
+ struct swc_event * event = data;
+
+ if (event->type == SWC_SCREEN_DESTROYED)
+ {
+ struct screen * screen
+ = CONTAINER_OF(listener, typeof(*screen), event_listener);
+
+ wld_destroy_surface(screen->surface);
+ free(screen);
+ }
+}
+
+static struct screen * screen_get(struct swc_screen * base)
+{
+ struct wl_listener * listener
+ = wl_signal_get(&base->event_signal, &handle_screen_event);
+ struct screen * screen;
+
+ return listener ? CONTAINER_OF(listener, typeof(*screen), event_listener)
+ : NULL;
+}
+
+static void handle_screen_view_event(struct wl_listener * listener, void * data)
+{
+ struct swc_event * event = data;
+ struct swc_view_event_data * event_data = event->data;
+
+ switch (event->type)
+ {
+ case SWC_VIEW_EVENT_FRAME:
+ {
+ struct swc_screen_internal * base = CONTAINER_OF
+ (event_data->view, typeof(*base), planes.framebuffer.view);
+ struct screen * screen;
+ struct view * view;
+
+ if (!(screen = screen_get(&base->base)))
+ return;
+
+ swc.compositor->pending_flips &= ~swc_screen_mask(base);
+
+ if (swc.compositor->pending_flips == 0)
+ {
+ wl_list_for_each(view, &swc.compositor->views, link)
+ swc_view_frame(&view->base, event_data->frame.time);
+ }
+
+ if (screen->current_buffer)
+ wld_surface_release(screen->surface, screen->current_buffer);
+
+ screen->current_buffer = screen->next_buffer;
+
+ /* If we had scheduled updates that couldn't run because we were
+ * waiting on a page flip, run them now. */
+ if (swc.compositor->scheduled_updates)
+ perform_update(swc.compositor);
+ break;
+ }
+ }
+}
+
+static bool screen_swap_buffers(struct screen * screen)
+{
+ struct swc_buffer * buffer;
+
+ screen->next_buffer = wld_surface_take(screen->surface);
+ buffer = buffer_get(screen->next_buffer);
+
+ if (!swc_view_attach(screen->view, buffer))
+ {
+ ERROR("Failed to attach next frame to screen\n");
+ return false;
+ }
+
+ return true;
+}
+
+static struct screen * screen_new(struct swc_screen_internal * base)
+{
+ struct screen * screen;
+
+ if (!(screen = malloc(sizeof *screen)))
+ goto error0;
+
+ screen->surface = wld_create_surface(swc.drm->context,
+ base->base.geometry.width,
+ base->base.geometry.height,
+ WLD_FORMAT_XRGB8888);
+
+ if (!screen->surface)
+ goto error1;
+
+ screen->view = &base->planes.framebuffer.view;
+ screen->view_listener.notify = &handle_screen_view_event;
+ wl_signal_add(&screen->view->event_signal, &screen->view_listener);
+ screen->event_listener.notify = &handle_screen_event;
+ wl_signal_add(&base->base.event_signal, &screen->event_listener);
+ screen->current_buffer = NULL;
+ screen_swap_buffers(screen);
+
+ return screen;
+
+error1:
+ free(screen);
+error0:
+ return NULL;
+}
+
/* Rendering {{{ */
struct render_target
{
- struct wld_buffer * buffer;
- struct swc_rectangle geometry;
+ struct wld_surface * surface;
+ const struct swc_rectangle * geometry;
uint32_t mask;
};
@@ -78,8 +231,8 @@ static void repaint_view(struct render_target * target, struct view * view,
{
pixman_region32_translate(&view_damage, -geometry->x, -geometry->y);
wld_copy_region(swc.drm->renderer, view->base.buffer->wld,
- geometry->x - target->geometry.x,
- geometry->y - target->geometry.y, &view_damage);
+ geometry->x - target->geometry->x,
+ geometry->y - target->geometry->y, &view_damage);
}
pixman_region32_fini(&view_damage);
@@ -90,7 +243,7 @@ static void repaint_view(struct render_target * target, struct view * view,
DEBUG("\t\tRedrawing border\n");
pixman_region32_translate(&border_damage,
- -target->geometry.x, -target->geometry.y);
+ -target->geometry->x, -target->geometry->y);
wld_fill_region(swc.drm->renderer, view->border.color, &border_damage);
}
@@ -105,14 +258,16 @@ static void renderer_repaint(struct render_target * target,
struct view * view;
DEBUG("Rendering to target { x: %d, y: %d, w: %u, h: %u }\n",
- target->geometry.x, target->geometry.y,
- target->geometry.width, target->geometry.height);
+ target->geometry->x, target->geometry->y,
+ target->geometry->width, target->geometry->height);
+
+ wld_set_target_surface(swc.drm->renderer, target->surface);
/* Paint base damage black. */
if (pixman_region32_not_empty(base_damage))
{
pixman_region32_translate(base_damage,
- -target->geometry.x, -target->geometry.y);
+ -target->geometry->x, -target->geometry->y);
wld_fill_region(swc.drm->renderer, 0xff000000, base_damage);
}
@@ -445,65 +600,53 @@ static void calculate_damage(struct swc_compositor * compositor)
pixman_region32_fini(&surface_opaque);
}
-static void repaint_screen(struct swc_compositor * compositor,
- struct swc_screen_internal * screen,
- pixman_region32_t * damage)
+static void update_screen(struct swc_compositor * compositor,
+ struct swc_screen_internal * base)
{
- struct swc_output * output
- = CONTAINER_OF(screen->outputs.next, typeof(*output), link);
- pixman_region32_t base_damage;
- struct render_target target;
-
- pixman_region32_init(&base_damage);
- pixman_region32_subtract(&base_damage, damage, &compositor->opaque);
-
- target.buffer = swc_plane_get_buffer(&output->framebuffer_plane);
- target.geometry.x = screen->base.geometry.x + output->framebuffer_plane.x;
- target.geometry.y = screen->base.geometry.y + output->framebuffer_plane.y;
- target.geometry.width = target.buffer->width;
- target.geometry.height = target.buffer->height;
- target.mask = swc_screen_mask(screen);
+ struct screen * screen;
+ const struct swc_rectangle * geometry = &base->base.geometry;
+ pixman_region32_t damage;
- renderer_repaint(&target, damage, &base_damage, &compositor->views);
+ if (!(compositor->scheduled_updates & swc_screen_mask(base)))
+ return;
- pixman_region32_fini(&base_damage);
+ if (!(screen = screen_get(&base->base)))
+ return;
- if (!swc_plane_flip(&output->framebuffer_plane))
- fprintf(stderr, "Plane flip failed\n");
-}
+ pixman_region32_init(&damage);
+ pixman_region32_intersect_rect(&damage, &compositor->damage,
+ geometry->x, geometry->y,
+ geometry->width, geometry->height);
+ pixman_region32_translate(&damage, -geometry->x, -geometry->y);
+ pixman_region32_union(&screen->next_buffer->damage,
+ &screen->next_buffer->damage, &damage);
+
+ /* Don't repaint the screen if it is waiting for a page flip. */
+ if (compositor->pending_flips & swc_screen_mask(base))
+ return;
-static void update_output_damage(struct swc_output * output,
- pixman_region32_t * damage)
-{
- struct swc_rectangle * geometry = &output->screen->base.geometry;
+ struct render_target target;
+ pixman_region32_t * total_damage, base_damage;
- pixman_region32_union
- (&output->current_damage, &output->current_damage, damage);
- pixman_region32_intersect_rect
- (&output->current_damage, &output->current_damage,
- geometry->x, geometry->y, geometry->width, geometry->height);
-}
+ total_damage = wld_surface_damage(screen->surface,
+ &screen->next_buffer->damage);
+ pixman_region32_translate(total_damage, geometry->x, geometry->y);
+ pixman_region32_init(&base_damage);
+ pixman_region32_subtract(&base_damage, total_damage, &compositor->opaque);
-static void flush_output_damage(struct swc_output * output,
- pixman_region32_t * damage)
-{
- /* The total damage is composed of the damage from the new frame, and the
- * damage from the last frame. */
- pixman_region32_union(damage,
- &output->current_damage, &output->previous_damage);
+ target.surface = screen->surface;
+ target.mask = swc_screen_mask(base);
+ target.geometry = geometry;
- /* We must save the damage from the previous frame because the back buffer
- * is also damaged in this region. */
- pixman_region32_copy(&output->previous_damage, &output->current_damage);
- pixman_region32_clear(&output->current_damage);
+ renderer_repaint(&target, total_damage, &base_damage, &compositor->views);
+ pixman_region32_fini(&base_damage);
+ screen_swap_buffers(screen);
}
static void perform_update(void * data)
{
struct swc_compositor * compositor = data;
struct swc_screen_internal * screen;
- struct swc_output * output;
- pixman_region32_t damage;
uint32_t updates = compositor->scheduled_updates
& ~compositor->pending_flips;
@@ -513,25 +656,10 @@ static void perform_update(void * data)
DEBUG("Performing update\n");
calculate_damage(compositor);
- pixman_region32_init(&damage);
wl_list_for_each(screen, &swc.screens, link)
- {
- if (!(compositor->scheduled_updates & swc_screen_mask(screen)))
- continue;
+ update_screen(compositor, screen);
- output = CONTAINER_OF(screen->outputs.next, typeof(*output), link);
- update_output_damage(output, &compositor->damage);
-
- /* Don't repaint the output if it is waiting for a page flip. */
- if (compositor->pending_flips & swc_screen_mask(screen))
- continue;
-
- flush_output_damage(output, &damage);
- repaint_screen(compositor, screen, &damage);
- }
-
- pixman_region32_fini(&damage);
/* XXX: Should assert that all damage was covered by some output */
pixman_region32_clear(&compositor->damage);
compositor->pending_flips |= updates;
@@ -568,38 +696,6 @@ static bool handle_motion(struct swc_pointer * pointer, uint32_t time)
return false;
}
-static void handle_drm_event(struct wl_listener * listener, void * data)
-{
- struct swc_event * event = data;
- struct swc_compositor * compositor;
-
- compositor = CONTAINER_OF(listener, typeof(*compositor), drm_listener);
-
- switch (event->type)
- {
- case SWC_DRM_PAGE_FLIP:
- {
- struct swc_drm_event_data * event_data = event->data;
- struct view * view;
-
- compositor->pending_flips &= ~SWC_OUTPUT_MASK(event_data->output);
-
- if (compositor->pending_flips == 0)
- {
- wl_list_for_each(view, &compositor->views, link)
- swc_view_frame(&view->base, event_data->time);
- }
-
- /* If we had scheduled updates that couldn't run because we were
- * waiting on a page flip, run them now. */
- if (compositor->scheduled_updates)
- perform_update(compositor);
-
- break;
- }
- }
-}
-
static void handle_terminate(uint32_t time, uint32_t value, void * data)
{
struct wl_display * display = data;
@@ -664,10 +760,10 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
struct wl_display * display,
struct wl_event_loop * event_loop)
{
+ struct swc_screen_internal * screen;
uint32_t keysym;
compositor->display = display;
- compositor->drm_listener.notify = &handle_drm_event;
compositor->scheduled_updates = 0;
compositor->pending_flips = 0;
compositor->pointer_handler = (struct swc_pointer_handler) {
@@ -675,12 +771,13 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
.motion = &handle_motion
};
- wl_signal_add(&swc.drm->event_signal, &compositor->drm_listener);
-
pixman_region32_init(&compositor->damage);
pixman_region32_init(&compositor->opaque);
wl_list_init(&compositor->views);
+ wl_list_for_each(screen, &swc.screens, link)
+ screen_new(screen);
+
swc_add_key_binding(SWC_MOD_CTRL | SWC_MOD_ALT, XKB_KEY_BackSpace,
&handle_terminate, display);
diff --git a/libswc/compositor.h b/libswc/compositor.h
@@ -28,8 +28,6 @@ struct swc_compositor
};
struct swc_pointer_handler pointer_handler;
-
- struct wl_listener drm_listener;
};
bool swc_compositor_initialize(struct swc_compositor * compositor,
diff --git a/libswc/cursor_plane.c b/libswc/cursor_plane.c
@@ -0,0 +1,107 @@
+/* swc: cursor_plane.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "cursor_plane.h"
+#include "buffer.h"
+#include "drm.h"
+#include "internal.h"
+#include "util.h"
+
+#include <errno.h>
+#include <wld/wld.h>
+#include <wld/drm.h>
+#include <xf86drmMode.h>
+
+static bool update(struct swc_view * view)
+{
+ return true;
+}
+
+static bool attach(struct swc_view * view, struct swc_buffer * buffer)
+{
+ struct swc_cursor_plane * plane = CONTAINER_OF(view, typeof(*plane), view);
+
+ if (buffer)
+ {
+ union wld_object object;
+
+ if (!wld_export(buffer->wld, WLD_DRM_OBJECT_HANDLE, &object))
+ {
+ ERROR("Could not get export buffer to DRM handle\n");
+ return false;
+ }
+
+ if (drmModeSetCursor(swc.drm->fd, plane->crtc, object.u32,
+ buffer->wld->width, buffer->wld->height) != 0)
+ {
+ ERROR("Could not set cursor: %s\n", strerror(errno));
+ return false;
+ }
+ }
+ else
+ {
+ if (drmModeSetCursor(swc.drm->fd, plane->crtc, 0, 0, 0) != 0)
+ {
+ ERROR("Could not unset cursor: %s\n", strerror(errno));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool move(struct swc_view * view, int32_t x, int32_t y)
+{
+ struct swc_cursor_plane * plane = CONTAINER_OF(view, typeof(*plane), view);
+
+ if (drmModeMoveCursor(swc.drm->fd, plane->crtc, x, y) != 0)
+ {
+ ERROR("Could not move cursor: %s\n", strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+static const struct swc_view_impl view_impl = {
+ .update = &update,
+ .attach = &attach,
+ .move = &move
+};
+
+bool swc_cursor_plane_initialize(struct swc_cursor_plane * plane, uint32_t crtc)
+{
+ if (drmModeSetCursor(swc.drm->fd, crtc, 0, 0, 0) != 0)
+ return false;
+
+ plane->crtc = crtc;
+ swc_view_initialize(&plane->view, &view_impl);
+
+ return true;
+}
+
+void swc_cursor_plane_finalize(struct swc_cursor_plane * plane)
+{
+ drmModeSetCursor(swc.drm->fd, plane->crtc, 0, 0, 0);
+}
+
diff --git a/libswc/cursor_plane.h b/libswc/cursor_plane.h
@@ -0,0 +1,41 @@
+/* swc: libswc/cursor_plane.h
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef SWC_CURSOR_PLANE_H
+#define SWC_CURSOR_PLANE_H
+
+#include "view.h"
+
+struct swc_cursor_plane
+{
+ struct swc_view view;
+ uint32_t crtc;
+};
+
+bool swc_cursor_plane_initialize(struct swc_cursor_plane * plane,
+ uint32_t crtc);
+
+void swc_cursor_plane_finalize(struct swc_cursor_plane * plane);
+
+#endif
+
diff --git a/libswc/drm.c b/libswc/drm.c
@@ -26,6 +26,7 @@
#include "internal.h"
#include "output.h"
#include "screen.h"
+#include "util.h"
#include "wayland_buffer.h"
#include <stdio.h>
@@ -267,15 +268,9 @@ static void handle_vblank(int fd, unsigned int sequence, unsigned int sec,
static void handle_page_flip(int fd, unsigned int sequence, unsigned int sec,
unsigned int usec, void * data)
{
- struct swc_output * output = data;
- struct swc_drm_event_data event_data = {
- .time = sec * 1000 + usec / 1000,
- .output = output
- };
-
- /* XXX: It doesn't make sense for multiple things to be listening for page
- * flips (or does it?). Maybe this should be a callback instead? */
- swc_send_event(&swc.drm->event_signal, SWC_DRM_PAGE_FLIP, &event_data);
+ struct swc_drm_handler * handler = data;
+
+ handler->page_flip(handler, sec * 1000 + usec / 1000);
}
static drmEventContext event_context = {
@@ -315,8 +310,6 @@ bool swc_drm_initialize(const char * seat_name)
const char * sysnum;
char * end;
- wl_signal_init(&swc.drm->event_signal);
-
struct udev_device * drm_device = find_primary_drm_device(seat_name);
if (!drm_device)
@@ -468,7 +461,7 @@ bool swc_drm_create_screens(struct wl_list * screens)
break;
}
- if (!(output = swc_output_new(resources->crtcs[crtc_index], connector)))
+ if (!(output = swc_output_new(connector)))
continue;
output->screen = swc_screen_new(resources->crtcs[crtc_index],
diff --git a/libswc/drm.h b/libswc/drm.h
@@ -5,15 +5,9 @@
#include <stdint.h>
#include <wayland-server.h>
-enum swc_drm_event_type
+struct swc_drm_handler
{
- SWC_DRM_PAGE_FLIP
-};
-
-struct swc_drm_event_data
-{
- uint32_t time;
- struct swc_output * output;
+ void (* page_flip)(struct swc_drm_handler * handler, uint32_t time);
};
struct swc_drm
@@ -21,7 +15,6 @@ struct swc_drm
int fd;
struct wld_context * context;
struct wld_renderer * renderer;
- struct wl_signal event_signal;
};
bool swc_drm_initialize(const char * seat);
diff --git a/libswc/framebuffer_plane.c b/libswc/framebuffer_plane.c
@@ -0,0 +1,208 @@
+/* swc: framebuffer_plane.c
+ *
+ * Copyright (c) 2013, 2014 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "framebuffer_plane.h"
+#include "buffer.h"
+#include "drm.h"
+#include "internal.h"
+#include "util.h"
+
+#include <errno.h>
+#include <wld/wld.h>
+#include <wld/drm.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+struct framebuffer
+{
+ uint32_t id;
+ struct wl_listener destroy_listener;
+};
+
+static void handle_buffer_destroy(struct wl_listener * listener, void * data)
+{
+ struct framebuffer * framebuffer
+ = CONTAINER_OF(listener, typeof(*framebuffer), destroy_listener);
+
+ drmModeRmFB(swc.drm->fd, framebuffer->id);
+ free(framebuffer);
+}
+
+static struct framebuffer * framebuffer_get(struct swc_buffer * buffer)
+{
+ struct wl_listener * listener
+ = wl_signal_get(&buffer->destroy_signal, &handle_buffer_destroy);
+ struct framebuffer * framebuffer;
+
+ if (listener)
+ {
+ framebuffer = CONTAINER_OF(listener, typeof(*framebuffer),
+ destroy_listener);
+ }
+ else
+ {
+ struct wld_buffer * wld = buffer->wld;
+ union wld_object object;
+
+ if (!wld_export(wld, WLD_DRM_OBJECT_HANDLE, &object))
+ {
+ ERROR("Could not get buffer handle\n");
+ goto error0;
+ }
+
+
+ if (!(framebuffer = malloc(sizeof *framebuffer)))
+ goto error0;
+
+ if (drmModeAddFB(swc.drm->fd, wld->width, wld->height, 24, 32,
+ wld->pitch, object.u32, &framebuffer->id) != 0)
+ {
+ goto error1;
+ }
+
+ framebuffer->destroy_listener.notify = &handle_buffer_destroy;
+ wl_signal_add(&buffer->destroy_signal, &framebuffer->destroy_listener);
+ }
+
+ return framebuffer;
+
+ error1:
+ free(framebuffer);
+ error0:
+ return NULL;
+}
+
+static bool update(struct swc_view * view)
+{
+ return true;
+}
+
+static bool attach(struct swc_view * view, struct swc_buffer * buffer)
+{
+ struct swc_framebuffer_plane * plane
+ = CONTAINER_OF(view, typeof(*plane), view);
+ struct framebuffer * framebuffer = framebuffer_get(buffer);
+
+ if (!framebuffer)
+ return false;
+
+ if (drmModePageFlip(swc.drm->fd, plane->crtc, framebuffer->id,
+ DRM_MODE_PAGE_FLIP_EVENT, &plane->drm_handler) != 0)
+ {
+ if (errno == EINVAL)
+ {
+ WARNING("Page flip failed with EINVAL, trying to set CRTC\n");
+
+ if (drmModeSetCrtc(swc.drm->fd, plane->crtc, framebuffer->id, 0, 0,
+ plane->connectors.data,
+ plane->connectors.size / 4,
+ &plane->mode.info) == 0)
+ {
+ swc_view_frame(&plane->view, swc_time());
+ }
+ else
+ {
+ ERROR("Could not set CRTC to next framebuffer: %s\n",
+ strerror(errno));
+ return false;
+ }
+ }
+ else
+ {
+ ERROR("Could not schedule page flip: %s\n", strerror(errno));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+const static struct swc_view_impl view_impl = {
+ .update = &update,
+ .attach = &attach
+};
+
+static void handle_page_flip(struct swc_drm_handler * handler, uint32_t time)
+{
+ struct swc_framebuffer_plane * plane
+ = CONTAINER_OF(handler, typeof(*plane), drm_handler);
+
+ swc_view_frame(&plane->view, time);
+}
+
+bool swc_framebuffer_plane_initialize(struct swc_framebuffer_plane * plane,
+ uint32_t crtc, drmModeModeInfoPtr mode,
+ uint32_t * connectors,
+ uint32_t num_connectors)
+{
+ uint32_t * plane_connectors;
+
+ if (!(plane->original_crtc_state = drmModeGetCrtc(swc.drm->fd, crtc)))
+ {
+ ERROR("Failed to get CRTC state for CRTC %u: %s\n",
+ crtc, strerror(errno));
+ goto error0;
+ }
+
+ wl_array_init(&plane->connectors);
+ plane_connectors = wl_array_add(&plane->connectors,
+ num_connectors * sizeof connectors[0]);
+
+ if (!plane_connectors)
+ {
+ ERROR("Failed to allocate connector array\n");
+ goto error1;
+ }
+
+ memcpy(plane_connectors, connectors, num_connectors * sizeof connectors[0]);
+
+ if (drmModeSetCrtc(swc.drm->fd, crtc, -1, 0, 0,
+ connectors, num_connectors, mode) != 0)
+ {
+ ERROR("Failed to set CRTC: %s\n", strerror(errno));
+ goto error2;
+ }
+
+ plane->crtc = crtc;
+ plane->drm_handler.page_flip = &handle_page_flip;
+ swc_view_initialize(&plane->view, &view_impl);
+ swc_mode_initialize(&plane->mode, mode);
+
+ return true;
+
+ error2:
+ wl_array_release(&plane->connectors);
+ error1:
+ drmModeFreeCrtc(plane->original_crtc_state);
+ error0:
+ return false;
+}
+
+void swc_framebuffer_plane_finalize(struct swc_framebuffer_plane * plane)
+{
+ drmModeCrtcPtr crtc = plane->original_crtc_state;
+ drmModeSetCrtc(swc.drm->fd, crtc->crtc_id, crtc->buffer_id,
+ crtc->x, crtc->y, NULL, 0, &crtc->mode);
+ drmModeFreeCrtc(crtc);
+}
+
diff --git a/libswc/framebuffer_plane.h b/libswc/framebuffer_plane.h
@@ -0,0 +1,52 @@
+/* swc: libswc/framebuffer_plane.h
+ *
+ * Copyright (c) 2013 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef SWC_FRAMEBUFFER_PLANE_H
+#define SWC_FRAMEBUFFER_PLANE_H
+
+#include "drm.h"
+#include "mode.h"
+#include "surface.h"
+#include "view.h"
+
+#include <xf86drmMode.h>
+
+struct swc_framebuffer_plane
+{
+ uint32_t crtc;
+ drmModeCrtcPtr original_crtc_state;
+ struct swc_mode mode;
+ struct swc_view view;
+ struct swc_drm_handler drm_handler;
+ struct wl_array connectors;
+};
+
+bool swc_framebuffer_plane_initialize(struct swc_framebuffer_plane * plane,
+ uint32_t crtc, drmModeModeInfoPtr mode,
+ uint32_t * connectors,
+ uint32_t num_connectors);
+
+void swc_framebuffer_plane_finalize(struct swc_framebuffer_plane * plane);
+
+#endif
+
diff --git a/libswc/local.mk b/libswc/local.mk
@@ -33,9 +33,10 @@ SWC_SOURCES = \
libswc/view.c \
libswc/buffer.c \
libswc/wayland_buffer.c \
+ libswc/cursor_plane.c \
+ libswc/framebuffer_plane.c \
libswc/util.c \
libswc/output.c \
- libswc/plane.c \
libswc/surface.c \
libswc/region.c \
libswc/input_focus.c \
diff --git a/libswc/mode.c b/libswc/mode.c
@@ -39,3 +39,10 @@ void swc_mode_finish(struct swc_mode * mode)
{
}
+bool swc_mode_equal(const struct swc_mode * mode1, const struct swc_mode * mode2)
+{
+ return mode1->width == mode2->width
+ && mode1->height == mode2->height
+ && mode1->refresh == mode2->refresh;
+}
+
diff --git a/libswc/mode.h b/libswc/mode.h
@@ -44,5 +44,7 @@ struct swc_mode
bool swc_mode_initialize(struct swc_mode * mode, drmModeModeInfo * mode_info);
void swc_mode_finish(struct swc_mode * mode);
+bool swc_mode_equal(const struct swc_mode * mode1, const struct swc_mode * mode2);
+
#endif
diff --git a/libswc/output.c b/libswc/output.c
@@ -38,7 +38,7 @@ static void bind_output(struct wl_client * client, void * data,
flags = 0;
if (mode->preferred)
flags |= WL_OUTPUT_MODE_PREFERRED;
- if (output->current_mode == mode)
+ if (swc_mode_equal(&screen->planes.framebuffer.mode, mode))
flags |= WL_OUTPUT_MODE_CURRENT;
wl_output_send_mode(resource, flags, mode->width, mode->height,
@@ -49,11 +49,9 @@ static void bind_output(struct wl_client * client, void * data,
wl_output_send_done(resource);
}
-struct swc_output * swc_output_new(uint32_t crtc_id, drmModeConnector * connector)
+struct swc_output * swc_output_new(drmModeConnectorPtr connector)
{
struct swc_output * output;
- drmModeEncoder * encoder;
- drmModeCrtc * current_crtc;
struct swc_mode * modes;
uint32_t index;
@@ -80,46 +78,21 @@ struct swc_output * swc_output_new(uint32_t crtc_id, drmModeConnector * connecto
pixman_region32_init(&output->current_damage);
pixman_region32_init(&output->previous_damage);
- output->crtc = crtc_id;
output->connector = connector->connector_id;
- /* Determine the current CRTC of this output. */
- encoder = drmModeGetEncoder(swc.drm->fd, connector->encoder_id);
- current_crtc = drmModeGetCrtc(swc.drm->fd, encoder->crtc_id);
- drmModeFreeEncoder(encoder);
-
modes = wl_array_add(&output->modes, connector->count_modes * sizeof *modes);
+ if (!modes)
+ goto error2;
+
for (index = 0; index < connector->count_modes; ++index)
{
swc_mode_initialize(&modes[index], &connector->modes[index]);
- if (memcmp(&modes[index].info, ¤t_crtc->mode,
- sizeof(drmModeModeInfo)) == 0)
- output->current_mode = &modes[index];
if (modes[index].preferred)
output->preferred_mode = &modes[index];
}
- if (output->preferred_mode)
- output->current_mode = output->preferred_mode;
-
- output->original_state.crtc = current_crtc;
-
- /* Create output planes */
- if (!swc_plane_initialize(&output->framebuffer_plane,
- &swc_framebuffer_plane, output))
- {
- printf("failed to initialize framebuffer plane\n");
- goto error2;
- }
-
- if (!swc_plane_initialize(&output->cursor_plane, &swc_cursor_plane, output))
- {
- printf("failed to initialize cursor plane\n");
- goto error2;
- }
-
return output;
error2:
@@ -133,15 +106,11 @@ struct swc_output * swc_output_new(uint32_t crtc_id, drmModeConnector * connecto
void swc_output_destroy(struct swc_output * output)
{
struct swc_mode * mode;
- drmModeCrtc * crtc = output->original_state.crtc;
wl_array_for_each(mode, &output->modes)
swc_mode_finish(mode);
wl_array_release(&output->modes);
- drmModeSetCrtc(swc.drm->fd, crtc->crtc_id, crtc->buffer_id, crtc->x,
- crtc->y, &output->connector, 1, &crtc->mode);
- drmModeFreeCrtc(crtc);
wl_global_destroy(output->global);
free(output);
}
diff --git a/libswc/output.h b/libswc/output.h
@@ -1,8 +1,6 @@
#ifndef SWC_OUTPUT_H
#define SWC_OUTPUT_H
-#include "plane.h"
-
#include <stdint.h>
#include <pixman.h>
#include <wayland-util.h>
@@ -18,28 +16,19 @@ struct swc_output
uint32_t physical_width, physical_height;
struct wl_array modes;
- struct swc_mode * current_mode, * preferred_mode;
-
- /* Output planes. */
- struct swc_plane framebuffer_plane;
- struct swc_plane cursor_plane;
+ struct swc_mode * preferred_mode;
pixman_region32_t current_damage, previous_damage;
/* The DRM connector corresponding to this output */
- uint32_t crtc, connector;
-
- struct
- {
- drmModeCrtc * crtc;
- } original_state;
+ uint32_t connector;
struct wl_global * global;
struct wl_list resources;
struct wl_list link;
};
-struct swc_output * swc_output_new(uint32_t crtc_id, drmModeConnector * connector);
+struct swc_output * swc_output_new(drmModeConnector * connector);
void swc_output_destroy(struct swc_output * output);
#endif
diff --git a/libswc/plane.c b/libswc/plane.c
@@ -1,224 +0,0 @@
-/* swc: plane.c
- *
- * Copyright (c) 2013 Michael Forney
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "plane.h"
-#include "drm.h"
-#include "internal.h"
-#include "mode.h"
-#include "output.h"
-#include "screen.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <libdrm/drm.h>
-#include <wld/wld.h>
-#include <wld/drm.h>
-
-struct framebuffer
-{
- struct wld_buffer * buffer;
- uint32_t id;
-};
-
-static bool framebuffer_initialize(struct swc_plane * plane)
-{
- struct framebuffer * fb = swc_double_buffer_front(&plane->double_buffer);
-
- return drmModeSetCrtc(swc.drm->fd, plane->output->crtc,
- fb->id, 0, 0, &plane->output->connector, 1,
- &plane->output->current_mode->info) == 0;
-}
-
-static void * framebuffer_create_buffer(struct swc_plane * plane)
-{
- struct wld_buffer * buffer;
- struct swc_output * output = plane->output;
- struct framebuffer * fb;
- union wld_object object;
-
- if (!(fb = malloc(sizeof *fb)))
- goto error0;
-
- buffer = wld_create_buffer(swc.drm->context,
- output->screen->base.geometry.width,
- output->screen->base.geometry.height,
- WLD_FORMAT_XRGB8888);
-
- if (!buffer)
- {
- fprintf(stderr, "Could not create DRM buffer for framebuffer\n");
- goto error1;
- }
-
- wld_export(buffer, WLD_DRM_OBJECT_HANDLE, &object);
-
- if (drmModeAddFB(swc.drm->fd, buffer->width, buffer->height,
- 24, 32, buffer->pitch, object.u32, &fb->id) != 0)
- {
- fprintf(stderr, "drmModeAddFB failed\n");
- goto error2;
- }
-
- fb->buffer = buffer;
-
- return buffer;
-
- error2:
- wld_destroy_buffer(buffer);
- error1:
- free(buffer);
- error0:
- return NULL;
-}
-
-static void framebuffer_destroy_buffer(struct swc_plane * plane, void * data)
-{
- struct framebuffer * fb = data;
-
- drmModeRmFB(swc.drm->fd, fb->id);
- wld_destroy_buffer(fb->buffer);
-}
-
-static struct wld_buffer * framebuffer_get_buffer(void * data)
-{
- struct framebuffer * fb = data;
-
- return fb->buffer;
-}
-
-static bool framebuffer_flip(struct swc_plane * plane)
-{
- struct swc_output * output = plane->output;
- struct framebuffer * fb = swc_double_buffer_back(&plane->double_buffer);
-
- return drmModePageFlip(swc.drm->fd, output->crtc, fb->id,
- DRM_MODE_PAGE_FLIP_EVENT, output) == 0;
-}
-
-const struct swc_plane_interface swc_framebuffer_plane = {
- .initialize = &framebuffer_initialize,
- .create_buffer = &framebuffer_create_buffer,
- .destroy_buffer = &framebuffer_destroy_buffer,
- .get_buffer = &framebuffer_get_buffer,
- .flip = &framebuffer_flip
-};
-
-static bool cursor_initialize(struct swc_plane * plane)
-{
- return true;
-}
-
-static void * cursor_create_buffer(struct swc_plane * plane)
-{
- return wld_create_buffer(swc.drm->context, 64, 64, WLD_FORMAT_ARGB8888);
-}
-
-static void cursor_destroy_buffer(struct swc_plane * plane, void * data)
-{
- struct wld_buffer * buffer = data;
-
- wld_destroy_buffer(buffer);
-}
-
-static struct wld_buffer * cursor_get_buffer(void * data)
-{
- return data;
-}
-
-static bool cursor_flip(struct swc_plane * plane)
-{
- struct wld_buffer * buffer = swc_double_buffer_back(&plane->double_buffer);
- union wld_object object;
-
- wld_export(buffer, WLD_DRM_OBJECT_HANDLE, &object);
- return drmModeSetCursor(swc.drm->fd, plane->output->crtc,
- object.u32, 64, 64) == 0;
-}
-
-static bool cursor_move(struct swc_plane * plane, int32_t x, int32_t y)
-{
- return drmModeMoveCursor(swc.drm->fd, plane->output->crtc, x, y) == 0;
-}
-
-const struct swc_plane_interface swc_cursor_plane = {
- .initialize = &cursor_initialize,
- .create_buffer = &cursor_create_buffer,
- .destroy_buffer = &cursor_destroy_buffer,
- .get_buffer = &cursor_get_buffer,
- .flip = &cursor_flip,
- .move = &cursor_move
-};
-
-bool swc_plane_initialize(struct swc_plane * plane,
- const struct swc_plane_interface * interface,
- struct swc_output * output)
-{
- plane->interface = interface;
- plane->output = output;
- plane->double_buffer.buffers[0] = interface->create_buffer(plane);
- plane->double_buffer.buffers[1] = interface->create_buffer(plane);
- plane->double_buffer.front = 0;
- plane->x = 0;
- plane->y = 0;
-
- return plane->interface->initialize(plane);
-}
-
-void swc_plane_finish(struct swc_plane * plane)
-{
- plane->interface->destroy_buffer(plane, plane->double_buffer.buffers[0]);
- plane->interface->destroy_buffer(plane, plane->double_buffer.buffers[1]);
-}
-
-bool swc_plane_flip(struct swc_plane * plane)
-{
- if (plane->interface->flip(plane))
- {
- swc_double_buffer_swap(&plane->double_buffer);
-
- return true;
- }
- else
- return false;
-}
-
-bool swc_plane_move(struct swc_plane * plane, int32_t x, int32_t y)
-{
- if (plane->interface->move(plane, x, y))
- {
- plane->x = x;
- plane->y = y;
-
- return true;
- }
- else
- return false;
-}
-
-struct wld_buffer * swc_plane_get_buffer(struct swc_plane * plane)
-{
- void * back = swc_double_buffer_back(&plane->double_buffer);
-
- return plane->interface->get_buffer(back);
-}
-
diff --git a/libswc/plane.h b/libswc/plane.h
@@ -1,66 +0,0 @@
-/* swc: plane.h
- *
- * Copyright (c) 2013 Michael Forney
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef SWC_PLANE_H
-#define SWC_PLANE_H
-
-#include "util.h"
-
-struct swc_plane;
-
-struct swc_plane_interface
-{
- bool (* initialize)(struct swc_plane * plane);
- void * (* create_buffer)(struct swc_plane * plane);
- void (* destroy_buffer)(struct swc_plane * plane, void * data);
- struct wld_buffer * (* get_buffer)(void * data);
- bool (* flip)(struct swc_plane * plane);
- bool (* move)(struct swc_plane * plane, int32_t x, int32_t y);
-};
-
-struct swc_plane
-{
- const struct swc_plane_interface * interface;
- struct swc_output * output;
-
- struct swc_double_buffer double_buffer;
-
- /* Relative to the output's origin. */
- int32_t x, y;
-};
-
-bool swc_plane_initialize(struct swc_plane * plane,
- const struct swc_plane_interface * interface,
- struct swc_output * output);
-
-bool swc_plane_flip(struct swc_plane * plane);
-
-bool swc_plane_move(struct swc_plane * plane, int32_t x, int32_t y);
-
-struct wld_buffer * swc_plane_get_buffer(struct swc_plane * plane);
-
-extern const struct swc_plane_interface swc_framebuffer_plane;
-extern const struct swc_plane_interface swc_cursor_plane;
-
-#endif
-
diff --git a/libswc/screen.c b/libswc/screen.c
@@ -26,6 +26,7 @@
#include "internal.h"
#include "mode.h"
#include "output.h"
+#include "util.h"
#include <stdlib.h>
#include <sys/param.h>
@@ -75,10 +76,28 @@ struct swc_screen_internal * swc_screen_new(uint32_t crtc,
wl_list_init(&screen->outputs);
wl_list_insert(&INTERNAL(screen)->outputs, &output->link);
+ if (!swc_framebuffer_plane_initialize(&screen->planes.framebuffer, crtc,
+ &output->preferred_mode->info,
+ &output->connector, 1))
+ {
+ ERROR("Failed to initialize framebuffer plane\n");
+ goto error1;
+ }
+
+ if (!swc_cursor_plane_initialize(&screen->planes.cursor, crtc))
+ {
+ ERROR("Failed to initialize cursor plane\n");
+ goto error2;
+ }
+
swc.manager->new_screen(&screen->base);
return screen;
+ error2:
+ swc_framebuffer_plane_finalize(&screen->planes.framebuffer);
+ error1:
+ free(screen);
error0:
return NULL;
}
@@ -89,6 +108,8 @@ void swc_screen_destroy(struct swc_screen_internal * screen)
wl_list_for_each_safe(output, next, &screen->outputs, link)
swc_output_destroy(output);
+ swc_framebuffer_plane_finalize(&screen->planes.framebuffer);
+ swc_cursor_plane_finalize(&screen->planes.cursor);
free(screen);
}
diff --git a/libswc/screen.h b/libswc/screen.h
@@ -25,6 +25,8 @@
#define SWC_SCREEN_H
#include "swc.h"
+#include "cursor_plane.h"
+#include "framebuffer_plane.h"
#include <wayland-util.h>
@@ -36,6 +38,12 @@ struct swc_screen_internal
uint8_t id;
+ struct
+ {
+ struct swc_framebuffer_plane framebuffer;
+ struct swc_cursor_plane cursor;
+ } planes;
+
struct wl_list outputs;
struct wl_list modifiers;
struct wl_list link;