From 72e722cd63273a01cbf9dbb0cef9ead3dcd7d25c Mon Sep 17 00:00:00 2001 From: Taekyun Kim Date: Wed, 2 Sep 2015 13:52:03 +0900 Subject: [PATCH] drm: Refactoring Split into several implementation files. Rudimentary support for frame buffer plane. Bug fix in damage accumulation for pixman renderer. Change-Id: I7d4d842b787ef3a39ce58350880440d4e5775de6 --- src/lib/drm/Makefile.am | 5 +- src/lib/drm/drm-buffer.c | 201 +++++++ src/lib/drm/drm-common.c | 222 ++++++- src/lib/drm/drm-connector.c | 117 ++++ src/lib/drm/drm-internal.h | 193 +++--- src/lib/drm/drm-output.c | 1395 +++++++++---------------------------------- src/lib/drm/drm-plane.c | 35 ++ src/lib/drm/pepper-drm.h | 5 +- src/samples/drm-backend.c | 2 +- 9 files changed, 951 insertions(+), 1224 deletions(-) create mode 100644 src/lib/drm/drm-buffer.c create mode 100644 src/lib/drm/drm-connector.c create mode 100644 src/lib/drm/drm-plane.c diff --git a/src/lib/drm/Makefile.am b/src/lib/drm/Makefile.am index 1567a66..c846940 100644 --- a/src/lib/drm/Makefile.am +++ b/src/lib/drm/Makefile.am @@ -10,4 +10,7 @@ libpepper_drm_la_LIBADD = $(PEPPER_DRM_LIBS) libpepper_drm_la_SOURCES = drm-internal.h \ drm-common.c \ - drm-output.c + drm-output.c \ + drm-connector.c \ + drm-plane.c \ + drm-buffer.c diff --git a/src/lib/drm/drm-buffer.c b/src/lib/drm/drm-buffer.c new file mode 100644 index 0000000..558b0a6 --- /dev/null +++ b/src/lib/drm/drm-buffer.c @@ -0,0 +1,201 @@ +#include "drm-internal.h" +#include +#include + +static void +destroy_buffer_gbm(struct gbm_bo *bo, void *data) +{ + drm_buffer_t *buffer = data; + + drmModeRmFB(buffer->drm->fd, buffer->id); + free(buffer); +} + +drm_buffer_t * +drm_buffer_create_dumb(pepper_drm_t *drm, uint32_t w, uint32_t h) +{ + drm_buffer_t *buffer; + struct drm_mode_create_dumb create_arg; + struct drm_mode_map_dumb map_arg; + int ret; + + buffer = calloc(1, sizeof(drm_buffer_t)); + PEPPER_CHECK(buffer, return NULL, "calloc() failed.\n"); + + buffer->drm = drm; + buffer->type = DRM_BUFFER_TYPE_DUMB; + buffer->w = w; + buffer->h = h; + + memset(&create_arg, 0x00, sizeof(create_arg)); + create_arg.bpp = 32; + create_arg.width = w; + create_arg.height = h; + + ret = drmIoctl(drm->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg); + PEPPER_CHECK(ret == 0, goto error, "drmIoctl() failed.\n"); + + buffer->handle = create_arg.handle; + buffer->stride = create_arg.pitch; + buffer->size = create_arg.size; + + ret = drmModeAddFB(drm->fd, w, h, 24, 32, buffer->stride, buffer->handle, &buffer->id); + PEPPER_CHECK(ret == 0, goto error, "drmModeAddFB() failed.\n"); + + memset(&map_arg, 0, sizeof(map_arg)); + map_arg.handle = buffer->handle; + + ret = drmIoctl(drm->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg); + PEPPER_CHECK(ret == 0, goto error, "drmIoctl() failed.\n"); + + buffer->map = mmap(0, buffer->size, PROT_WRITE, MAP_SHARED, drm->fd, map_arg.offset); + PEPPER_CHECK(buffer->map != MAP_FAILED, goto error, "mmap() failed.\n"); + + buffer->pixman_render_target = pepper_pixman_renderer_create_target(PEPPER_FORMAT_XRGB8888, + buffer->map, + buffer->stride, + buffer->w, buffer->h); + PEPPER_CHECK(buffer->pixman_render_target, goto error, + "pepper_pixman_render_create_target() failed.\n"); + + return buffer; + +error: + if (buffer->map) + munmap(buffer->map, buffer->size); + + if (buffer->id) + drmModeRmFB(drm->fd, buffer->id); + + if (buffer->handle) + { + struct drm_mode_destroy_dumb destroy_arg; + + memset(&destroy_arg, 0x00, sizeof(destroy_arg)); + destroy_arg.handle = buffer->handle; + drmIoctl(drm->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg); + } + + free(buffer); + return NULL; +} + +static inline pepper_bool_t +init_buffer_gbm(drm_buffer_t *buffer, pepper_drm_t *drm, struct gbm_bo *bo) +{ + int ret; + uint32_t handles[4], strides[4], offsets[4]; + + buffer->drm = drm; + buffer->handle = gbm_bo_get_handle(bo).u32; + buffer->w = gbm_bo_get_width(bo); + buffer->h = gbm_bo_get_height(bo); + buffer->stride = gbm_bo_get_stride(bo); + buffer->size = buffer->h * buffer->stride; + + handles[0] = buffer->handle; + strides[0] = buffer->stride; + offsets[0] = 0; + + ret = drmModeAddFB2(drm->fd, buffer->w, buffer->h, gbm_bo_get_format(bo), + handles, strides, offsets, &buffer->id , 0); + PEPPER_CHECK(ret, return PEPPER_FALSE, "drmModeAddFB2() failed.\n"); + + ret = drmModeAddFB(drm->fd, buffer->w, buffer->h, 24, 32, + buffer->stride, buffer->handle, &buffer->id); + PEPPER_CHECK(ret, return PEPPER_FALSE, "drmModeAddFB() failed.\n"); + + return PEPPER_TRUE; +} + +drm_buffer_t * +drm_buffer_create_gbm(pepper_drm_t *drm, struct gbm_surface *surface, struct gbm_bo *bo) +{ + drm_buffer_t *buffer; + + buffer = calloc(1, sizeof(drm_buffer_t)); + PEPPER_CHECK(buffer, return NULL, "calloc() failed.\n"); + + if (!init_buffer_gbm(buffer, drm, bo)) + { + free(buffer); + return NULL; + } + + buffer->type = DRM_BUFFER_TYPE_GBM; + buffer->surface = surface; + buffer->bo = bo; + gbm_bo_set_user_data(bo, buffer, destroy_buffer_gbm); + + return buffer; +} + +drm_buffer_t * +drm_buffer_create_pepper(pepper_drm_t *drm, pepper_buffer_t *pb) +{ + struct gbm_bo *bo; + drm_buffer_t *buffer; + struct wl_resource *resource = pepper_buffer_get_resource(pb); + + buffer = calloc(1, sizeof(drm_buffer_t)); + PEPPER_CHECK(buffer, return NULL, "calloc() failed.\n"); + + bo = gbm_bo_import(drm->gbm_device, GBM_BO_IMPORT_WL_BUFFER, resource, GBM_BO_USE_SCANOUT); + if (!bo) + { + free(buffer); + return NULL; + } + + if (!init_buffer_gbm(buffer, drm, bo)) + { + gbm_bo_destroy(bo); + free(buffer); + return NULL; + } + + buffer->type = DRM_BUFFER_TYPE_CLIENT; + buffer->client_buffer = pb; + buffer->bo = bo; + pepper_buffer_reference(pb); + + return buffer; +} + +void +drm_buffer_release(drm_buffer_t *buffer) +{ + if (buffer->type == DRM_BUFFER_TYPE_GBM) + gbm_surface_release_buffer(buffer->surface, buffer->bo); + else if (buffer->type == DRM_BUFFER_TYPE_CLIENT) + drm_buffer_destroy(buffer); +} + +void +drm_buffer_destroy(drm_buffer_t *buffer) +{ + drmModeRmFB(buffer->drm->fd, buffer->id); + + if (buffer->type == DRM_BUFFER_TYPE_DUMB) + { + struct drm_mode_destroy_dumb destroy_arg; + + munmap(buffer->map, buffer->size); + + memset(&destroy_arg, 0x00, sizeof(destroy_arg)); + destroy_arg.handle = buffer->handle; + drmIoctl(buffer->drm->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg); + } + else if (buffer->type == DRM_BUFFER_TYPE_GBM) + { + gbm_bo_set_user_data(buffer->bo, NULL, NULL); + gbm_surface_release_buffer(buffer->surface, buffer->bo); + } + else if (buffer->type == DRM_BUFFER_TYPE_CLIENT) + { + pepper_buffer_unreference(buffer->client_buffer); + gbm_bo_destroy(buffer->bo); + } + + free(buffer); +} diff --git a/src/lib/drm/drm-common.c b/src/lib/drm/drm-common.c index df2fcdf..3eeab5c 100644 --- a/src/lib/drm/drm-common.c +++ b/src/lib/drm/drm-common.c @@ -1,39 +1,196 @@ #include +#include #include -#include -#include - #include "drm-internal.h" -PEPPER_API pepper_drm_t * -pepper_drm_create(pepper_compositor_t *compositor, struct udev *udev, - const char *device, const char *renderer) +static struct udev_device * +find_primary_gpu(struct udev *udev) /* FIXME: copied from weston */ { - pepper_drm_t *drm; + struct udev_enumerate *e; + struct udev_list_entry *entry; + struct udev_device *pci, *device, *drm_device = NULL; + const char *path, *device_seat, *id; - drm = (pepper_drm_t *)calloc(1, sizeof(pepper_drm_t)); - if (!drm) + e = udev_enumerate_new(udev); + udev_enumerate_add_match_subsystem(e, "drm"); + udev_enumerate_add_match_sysname(e, "card[0-9]*"); + udev_enumerate_scan_devices(e); + + udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) { - PEPPER_ERROR("Failed to allocate memory in %s\n", __FUNCTION__); - goto error; + path = udev_list_entry_get_name(entry); + device = udev_device_new_from_syspath(udev, path); + if (!device) + continue; + device_seat = udev_device_get_property_value(device, "ID_SEAT"); + if (!device_seat) + device_seat = "seat0"; + if (strcmp(device_seat, "seat0" /* FIXME: default seat? */)) + { + udev_device_unref(device); + continue; + } + + pci = udev_device_get_parent_with_subsystem_devtype(device, "pci", NULL); + if (pci) + { + id = udev_device_get_sysattr_value(pci, "boot_vga"); + if (id && !strcmp(id, "1")) + { + if (drm_device) + udev_device_unref(drm_device); + drm_device = device; + break; + } + } + + if (!drm_device) + drm_device = device; + else + udev_device_unref(device); } + udev_enumerate_unref(e); + return drm_device; +} + +static int +handle_drm_event(int fd, uint32_t mask, void *data) +{ + pepper_drm_t *drm = data; + drmHandleEvent(fd, &drm->drm_event_context); + return 0; +} + +static int +handle_udev_event(int fd, uint32_t mask, void *data) +{ + pepper_drm_t *drm = (pepper_drm_t *)data; + struct udev_device *device; + + const char *sysnum; + const char *value; + + device = udev_monitor_receive_device(drm->udev_monitor); + + sysnum = udev_device_get_sysnum(device); + if (!sysnum || atoi(sysnum) != drm->sysnum) + goto done; + + value = udev_device_get_property_value(device, "HOTPLUG"); + if (!value || strcmp(value, "1")) + goto done; + + drm_update_connectors(drm); + +done: + udev_device_unref(device); + return 0; +} + +PEPPER_API pepper_drm_t * +pepper_drm_create(pepper_compositor_t *compositor, struct udev *udev, const char *device) +{ + pepper_drm_t *drm = NULL; + struct udev_device *udev_device = NULL; + const char *sysnum_str = NULL; + const char *filepath; + struct stat s; + int ret; + struct wl_event_loop *loop; + drm_magic_t magic; + + drm = calloc(1, sizeof(pepper_drm_t)); + PEPPER_CHECK(drm, goto error, "calloc() failed.\n"); + drm->compositor = compositor; - drm->udev = udev; - pepper_list_init(&drm->output_list); - pepper_list_init(&drm->plane_list); + drm->fd = -1; - if (!pepper_drm_output_create(drm, renderer)) - { - PEPPER_ERROR("Failed to connect drm output in %s\n", __FUNCTION__); - goto error; - } + /* Find primary GPU udev device. Usually card0. */ + udev_device = find_primary_gpu(udev); + PEPPER_CHECK(udev_device, goto error, "find_primary_gpu() failed.\n"); + + /* Get sysnum for the device. */ + sysnum_str = udev_device_get_sysnum(udev_device); + PEPPER_CHECK(sysnum_str, goto error, "udev_device_get_sysnum() failed.\n"); + + drm->sysnum = atoi(sysnum_str); + PEPPER_CHECK(drm->sysnum >= 0, goto error, "Invalid sysnum.\n"); + + /* Get device file path. */ + filepath = udev_device_get_devnode(udev_device); + PEPPER_CHECK(filepath, goto error, "udev_device_get_devnode() failed.\n"); + + /* Open DRM device file and check validity. */ + drm->fd = open(filepath, O_RDWR | O_CLOEXEC); + PEPPER_CHECK(drm->fd != -1, goto error, "open(%s, O_RDWR | O_CLOEXEC) failed.\n", filepath); + + ret = fstat(drm->fd, &s); + PEPPER_CHECK(ret != -1, goto error, "fstat() failed %s.\n", filepath); + + ret = major(s.st_rdev); + PEPPER_CHECK(ret == 226, goto error, "Not a drm device file %s.\n", filepath); + + ret = drmGetMagic(drm->fd, &magic); + PEPPER_CHECK(ret == 0, goto error, "drmGetMagic() failed.\n"); + + ret = drmAuthMagic(drm->fd, magic); + PEPPER_CHECK(ret == 0, goto error, "drmAuthMagic() failed.\n"); + + /* Create udev event monitor. */ + drm->udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); + PEPPER_CHECK(drm->udev_monitor, goto error, "udev_monitor_new_from_netlink() failed.\n"); + udev_monitor_filter_add_match_subsystem_devtype(drm->udev_monitor, "drm", NULL); + + /* Add DRM event FDs to the compositor's display. */ + loop = wl_display_get_event_loop(pepper_compositor_get_display(compositor)); + + drm->drm_event_source = wl_event_loop_add_fd(loop, drm->fd, WL_EVENT_READABLE, + handle_drm_event, drm); + PEPPER_CHECK(drm->drm_event_source, goto error, "wl_event_loop_add() failed.\n"); + + drm->udev_event_source = wl_event_loop_add_fd(loop, udev_monitor_get_fd(drm->udev_monitor), + WL_EVENT_READABLE, handle_udev_event, drm); + PEPPER_CHECK(drm->udev_event_source, goto error, "wl_event_loop_add() failed.\n"); + + drm->drm_event_context.version = DRM_EVENT_CONTEXT_VERSION; + drm->drm_event_context.vblank_handler = drm_handle_vblank; + drm->drm_event_context.page_flip_handler = drm_handle_page_flip; + + ret = udev_monitor_enable_receiving(drm->udev_monitor); + PEPPER_CHECK(ret >= 0, goto error, "udev_monitor_enable_receiving() failed.\n"); + + drm->resources = drmModeGetResources(drm->fd); + PEPPER_CHECK(drm->resources, goto error, "drmModeGetResources() failed.\n"); + + pepper_list_init(&drm->plane_list); + drm_init_connectors(drm); + drm_init_planes(drm); + udev_device_unref(udev_device); return drm; error: if (drm) - pepper_drm_destroy(drm); + { + if (drm->resources) + drmModeFreeResources(drm->resources); + + if (drm->udev_event_source) + wl_event_source_remove(drm->udev_event_source); + + if (drm->drm_event_source) + wl_event_source_remove(drm->drm_event_source); + + if (drm->udev_monitor) + udev_monitor_unref(drm->udev_monitor); + + if (drm->fd != -1) + close(drm->fd); + } + + if (udev_device) + udev_device_unref(udev_device); return NULL; } @@ -41,9 +198,28 @@ error: PEPPER_API void pepper_drm_destroy(pepper_drm_t *drm) { - if (!drm) - return; + drm_connector_t *conn; + drm_plane_t *plane; + + pepper_list_for_each(conn, &drm->connector_list, link) + { + if (conn->output) + drm_output_destroy(conn->output); + + drm_connector_destroy(conn); + } + + pepper_list_for_each(plane, &drm->plane_list, link) + drm_plane_destroy(plane); + +/* if (drm->pixman_renderer) + pepper_renderer_destroy(drm->pixman_renderer); + + if (drm->gl_renderer) + pepper_renderer_destroy(drm->gl_renderer);*/ + + if (drm->resources) + drmModeFreeResources(drm->resources); - pepper_drm_output_destroy(drm); free(drm); } diff --git a/src/lib/drm/drm-connector.c b/src/lib/drm/drm-connector.c new file mode 100644 index 0000000..6458b16 --- /dev/null +++ b/src/lib/drm/drm-connector.c @@ -0,0 +1,117 @@ +#include "drm-internal.h" +#include + +static const char *connector_type_names[] = +{ + "None", + "VGA", + "DVI", + "DVI", + "DVI", + "Composite", + "TV", + "LVDS", + "CTV", + "DIN", + "DP", + "HDMI", + "HDMI", + "TV", + "eDP", +}; + +static inline void +get_connector_name(char *str, drmModeConnector *conn) +{ + const char *type_name; + + if (conn->connector_type < PEPPER_ARRAY_LENGTH(connector_type_names)) + type_name = connector_type_names[conn->connector_type]; + else + type_name = "UNKNOWN"; + + snprintf(str, 32, "%s%d", type_name, conn->connector_type_id); +} + +static inline void +add_connector(pepper_drm_t *drm, drmModeConnector *connector) +{ + drm_connector_t *conn; + + conn = calloc(1, sizeof(drm_connector_t)); + PEPPER_CHECK(conn, return, "calloc() failed.\n"); + + conn->connector = connector; +} + +void +drm_init_connectors(pepper_drm_t *drm) +{ + int i; + + pepper_list_init(&drm->connector_list); + + for (i = 0; i < drm->resources->count_connectors; i++) + { + drm_connector_t *conn = calloc(1, sizeof(drm_connector_t)); + PEPPER_CHECK(conn, continue, "calloc() failed.\n"); + + conn->drm = drm; + conn->id = drm->resources->connectors[i]; + conn->connector = drmModeGetConnector(drm->fd, conn->id); + if (!conn->connector) + { + PEPPER_ERROR("drmModeGetConnector() failed.\n"); + free(conn); + continue; + } + + get_connector_name(&conn->name[0], conn->connector); + conn->connected = conn->connector->connection == DRM_MODE_CONNECTED; + pepper_list_insert(drm->connector_list.prev, &conn->link); + + if (conn->connected) + drm_output_create(conn); + } +} + +void +drm_update_connectors(pepper_drm_t *drm) +{ + drm_connector_t *conn; + + pepper_list_for_each(conn, &drm->connector_list, link) + { + if (conn->connector) + drmModeFreeConnector(conn->connector); + + /* XXX: Do I have to get connector again here??? */ + conn->connector = drmModeGetConnector(drm->fd, conn->id); + PEPPER_CHECK(conn->connector, continue, "drmModeGetConnector() failed.\n"); + + if (conn->connected && conn->connector->connection != DRM_MODE_CONNECTED) + { + /* Disconnected. */ + if (conn->output) + drm_output_destroy(conn->output); + } + else if (!conn->connected && conn->connector->connection == DRM_MODE_CONNECTED) + { + /* Newly connected. */ + PEPPER_ASSERT(conn->output == NULL); + drm_output_create(conn); + } + } +} + +void +drm_connector_destroy(drm_connector_t *conn) +{ + if (conn->output) + drm_output_destroy(conn->output); + + if (conn->connector) + drmModeFreeConnector(conn->connector); + + pepper_list_remove(&conn->link); +} diff --git a/src/lib/drm/drm-internal.h b/src/lib/drm/drm-internal.h index 92446ab..e589963 100644 --- a/src/lib/drm/drm-internal.h +++ b/src/lib/drm/drm-internal.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -11,125 +12,167 @@ #include "pepper-drm.h" -#define DUMB_FB_COUNT 2 - typedef struct drm_output drm_output_t; -typedef struct drm_fb drm_fb_t; +typedef struct drm_buffer drm_buffer_t; typedef struct drm_plane drm_plane_t; +typedef struct drm_connector drm_connector_t; -struct pepper_drm +typedef enum drm_buffer_type { - pepper_compositor_t *compositor; + DRM_BUFFER_TYPE_DUMB, + DRM_BUFFER_TYPE_GBM, + DRM_BUFFER_TYPE_CLIENT, +} drm_buffer_type_t; - pepper_list_t output_list; +typedef enum drm_render_type +{ + DRM_RENDER_TYPE_PIXMAN, + DRM_RENDER_TYPE_GL, +} drm_render_type_t; - uint32_t *crtcs; - uint32_t count_crtcs; +struct pepper_drm +{ + pepper_compositor_t *compositor; - uint32_t min_width, min_height; - uint32_t max_width, max_height; + int fd; + int sysnum; + struct udev_monitor *udev_monitor; - int drm_fd; - int drm_sysnum; + drmEventContext drm_event_context; struct wl_event_source *drm_event_source; + struct wl_event_source *udev_event_source; - struct udev *udev; - struct udev_monitor *udev_monitor; - struct wl_event_source *udev_monitor_source; + pepper_list_t connector_list; + uint32_t used_crtcs; + pepper_list_t plane_list; + drmModeRes *resources; struct gbm_device *gbm_device; - char *renderer; pepper_renderer_t *pixman_renderer; pepper_renderer_t *gl_renderer; +}; - pepper_list_t plane_list; +struct drm_connector +{ + pepper_drm_t *drm; + char name[32]; + uint32_t id; + pepper_bool_t connected; + drm_output_t *output; + drmModeConnector *connector; + + pepper_list_t link; }; -struct drm_output +void +drm_init_connectors(pepper_drm_t *drm); + +void +drm_update_connectors(pepper_drm_t *drm); + +void +drm_connector_destroy(drm_connector_t *conn); + +struct drm_buffer { - pepper_drm_t *drm; - pepper_output_t *base; - char name[32]; - pepper_list_t link; + pepper_drm_t *drm; + drm_buffer_type_t type; + uint32_t id; + uint32_t handle; + + uint32_t w, h; + uint32_t stride; + uint32_t size; + + pepper_buffer_t *client_buffer; + struct gbm_surface *surface; + struct gbm_bo *bo; + void *map; + pepper_render_target_t *pixman_render_target; +}; - int32_t subpixel; - uint32_t w, h; +drm_buffer_t * +drm_buffer_create_dumb(pepper_drm_t *drm, uint32_t w, uint32_t h); - int32_t crtc_index; - uint32_t crtc_id; - uint32_t conn_id; +drm_buffer_t * +drm_buffer_create_gbm(pepper_drm_t *drm, struct gbm_surface *surface, struct gbm_bo *bo); - int mode_count; - drmModeModeInfo *modes; - drmModeModeInfo *current_mode; +drm_buffer_t * +drm_buffer_create_pepper(pepper_drm_t *drm, pepper_buffer_t *buffer); + +void +drm_buffer_release(drm_buffer_t *buffer); - drmModeCrtc *saved_crtc; +void +drm_buffer_destroy(drm_buffer_t *buffer); + +struct drm_output +{ + pepper_drm_t *drm; + pepper_output_t *base; - struct gbm_surface *gbm_surface; + drm_connector_t *conn; + int32_t crtc_index; + uint32_t crtc_id; + drmModeCrtc *saved_crtc; + int32_t subpixel; + drmModeModeInfo *mode; - drm_fb_t *front_fb; - drm_fb_t *back_fb; + pepper_bool_t page_flip_pending; + int vblank_pending; - pepper_renderer_t *renderer; - pepper_render_target_t *render_target; - pepper_render_target_t *gl_render_target; + pepper_plane_t *cursor_plane; + pepper_plane_t *primary_plane; + pepper_plane_t *fb_plane; - pepper_bool_t use_pixman; - drm_fb_t *dumb_fb[DUMB_FB_COUNT]; - int back_fb_index; + drm_render_type_t render_type; + pepper_renderer_t *renderer; + pepper_render_target_t *render_target; - pepper_bool_t vblank_pending; - pepper_bool_t page_flip_pending; + /* pixman */ + drm_buffer_t *fb[2]; + int back_fb_index; + pixman_region32_t previous_damage; - pepper_view_t *cursor_view; - pepper_plane_t *cursor_plane; - pepper_plane_t *primary_plane; + /* OpenGL */ + struct gbm_surface *gbm_surface; - /* TODO */ + drm_buffer_t *front, *back; }; -struct drm_fb -{ - drm_output_t *output; +drm_output_t * +drm_output_create(drm_connector_t *conn); - int fd; - uint32_t id; - uint32_t handle; +void +drm_output_destroy(void *o); - uint32_t w, h; - uint32_t stride; - uint32_t size; +void +drm_handle_vblank(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data); - struct gbm_bo *bo; - void *map; - pepper_render_target_t *target; -}; +void +drm_handle_page_flip(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data); struct drm_plane { - pepper_drm_t *drm; - pepper_plane_t *base; - drm_output_t *output; - - uint32_t possible_crtcs; - uint32_t plane_id; + pepper_drm_t *drm; + uint32_t id; + drmModePlane *plane; - drm_fb_t *front_fb; - drm_fb_t *back_fb; + drm_output_t *output; + pepper_plane_t *base; - int sx, sy, sw, sh; /* src *//* FIXME: uint32_t? */ - int dx, dy, dw, dh; /* dst *//* FIXME: uint32_t? */ + drm_buffer_t *front, *back; + int dx, dy, dw, dh; + int sx, sy, sw, sh; - /* TODO */ - - pepper_list_t link; + pepper_list_t link; }; -pepper_bool_t -pepper_drm_output_create(pepper_drm_t *drm, const char *renderer); +void +drm_init_planes(pepper_drm_t *drm); void -pepper_drm_output_destroy(pepper_drm_t *drm); +drm_plane_destroy(drm_plane_t *plane); #endif /* DRM_INTERNAL_H */ diff --git a/src/lib/drm/drm-output.c b/src/lib/drm/drm-output.c index c2dd9c6..7aac7f9 100644 --- a/src/lib/drm/drm-output.c +++ b/src/lib/drm/drm-output.c @@ -1,55 +1,11 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include #include #include #include #include "drm-internal.h" - #include #include -#define DRM_CURSOR_WIDTH 64 -#define DRM_CURSOR_HEIGHT 64 - -static pepper_bool_t -init_renderer(drm_output_t *output, const char *renderer); - -static void -fini_renderer(drm_output_t *output); - -static void -drm_output_destroy(void *o) -{ - drm_output_t *output = (drm_output_t *)o; - - pepper_list_remove(&output->link); - - if (output->saved_crtc) - { - drmModeCrtc *c = output->saved_crtc; - drmModeSetCrtc(output->drm->drm_fd, c->crtc_id, c->buffer_id, c->x, c->y, - &output->conn_id, 1, &c->mode); - drmModeFreeCrtc(c); - } - - fini_renderer(output); - - if (output->modes) - free(output->modes); - - free(output); -} - static int32_t drm_output_get_subpixel_order(void *data) { @@ -91,65 +47,57 @@ drm_output_get_model_name(void *output) static int drm_output_get_mode_count(void *o) { - drm_output_t *output = (drm_output_t *)o; - drmModeConnector *c = drmModeGetConnector(output->drm->drm_fd, output->conn_id); - int count = c->count_modes; + drm_output_t *output = (drm_output_t *)o; + return output->conn->connector->count_modes; +} - drmModeFreeConnector(c); +static uint32_t +get_refresh_rate(const drmModeModeInfo *info) +{ + return (info->clock * 1000000LL / info->vtotal + info->vtotal / 2) / info->vtotal; +} - return count; +static pepper_bool_t +same_mode(const drmModeModeInfo *info, const pepper_output_mode_t *mode) +{ + return info->hdisplay == mode->w && info->vdisplay == mode->h && + get_refresh_rate(info) == (uint32_t)mode->refresh; } static void drm_output_get_mode(void *o, int index, pepper_output_mode_t *mode) { - drm_output_t *output = (drm_output_t *)o; - drmModeModeInfo *m = &(output->modes[index]); + drm_output_t *output = (drm_output_t *)o; + drmModeModeInfo *info = &output->conn->connector->modes[index]; mode->flags = 0; - mode->w = m->hdisplay; - mode->h = m->vdisplay; - mode->refresh = 60000/* FIXME */; + mode->w = info->hdisplay; + mode->h = info->vdisplay; + mode->refresh = get_refresh_rate(info); - if (m->type & DRM_MODE_TYPE_PREFERRED) + if (info->type & DRM_MODE_TYPE_PREFERRED) mode->flags |= WL_OUTPUT_MODE_PREFERRED; - if (m == output->current_mode) + if (info == output->mode) mode->flags |= WL_OUTPUT_MODE_CURRENT; } static pepper_bool_t drm_output_set_mode(void *o, const pepper_output_mode_t *mode) { - int i; - drm_output_t *output = (drm_output_t *)o; - - /* - * typedef struct _drmModeModeInfo { - * uint32_t clock; - * uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew; - * uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan; - * - * uint32_t vrefresh; - * - * uint32_t flags; - * uint32_t type; - * char name[DRM_DISPLAY_MODE_LEN]; - * } drmModeModeInfo, *drmModeModeInfoPtr; - */ - for (i = 0; i < output->mode_count; i++) - { - drmModeModeInfo *m = &(output->modes[i]); - if ((m->hdisplay == mode->w) && (m->vdisplay == mode->h)) /* FIXME */ - { - /* TODO: drmModeSetCrtc() with current front buffer with the mode. */ + int i; + drm_output_t *output = (drm_output_t *)o; - output->current_mode = m; - output->w = m->hdisplay; - output->h = m->vdisplay; + if (same_mode(output->mode, mode)) + return PEPPER_TRUE; - /* TODO: Resize handleing. */ + for (i = 0; i < output->conn->connector->count_modes; i++) + { + drmModeModeInfo *info = &output->conn->connector->modes[i]; + if (same_mode(info, mode)) + { + output->mode = info; pepper_output_update_mode(output->base); return PEPPER_TRUE; } @@ -158,251 +106,137 @@ drm_output_set_mode(void *o, const pepper_output_mode_t *mode) return PEPPER_FALSE; } -static void -destroy_fb(struct gbm_bo *bo, void *data) +static pepper_plane_t * +assign_cursor_plane(drm_output_t *output, pepper_view_t *view) { - drm_fb_t *fb = (drm_fb_t *)data; - - if (fb->id) - drmModeRmFB(fb->fd, fb->id); - - free(fb); + /* TODO: */ + return NULL; } -static drm_fb_t * -get_fb(drm_output_t *output, struct gbm_bo *bo) +static pepper_plane_t * +assign_fb_plane(drm_output_t *output, pepper_view_t *view) { - int ret = -1; - uint32_t handles[4], pitches[4], offsets[4]; - drm_fb_t *fb = (drm_fb_t *)gbm_bo_get_user_data(bo); - - if (fb) - return fb; - - /* Create drm_fb for the new comer. */ - fb = (drm_fb_t *)calloc(1, sizeof(drm_fb_t)); - if (!fb) - { - PEPPER_ERROR("Failed to allocate memory in %s\n", __FUNCTION__); - return NULL; - } - - fb->fd = output->drm->drm_fd; - fb->handle = gbm_bo_get_handle(bo).u32; - - fb->w = gbm_bo_get_width(bo); - fb->h = gbm_bo_get_height(bo); - fb->stride = gbm_bo_get_stride(bo); - fb->size = fb->stride * fb->h; - fb->bo = bo; - - handles[0] = fb->handle; - pitches[0] = fb->stride; - offsets[0] = 0; - - ret = drmModeAddFB2(fb->fd, fb->w, fb->h, GBM_FORMAT_XRGB8888 /* FIXME */, - handles, pitches, offsets, &fb->id, 0); - if (ret) - printf("Failed to call drmModeAddFB2\n"); - - if (ret && drmModeAddFB(fb->fd, fb->w, fb->h, 24, 32, fb->stride, fb->handle, &fb->id)) - { - PEPPER_ERROR("Failed to add fb in %s\n", __FUNCTION__); - free(fb); - return NULL; - } - - gbm_bo_set_user_data(bo, fb, destroy_fb); - return fb; + /* TODO: */ + return NULL; } -static void -update_back_buffer(drm_output_t *output) +static pepper_plane_t * +assign_overlay_plane(drm_output_t *output, pepper_view_t *view) { - if (output->renderer == output->drm->gl_renderer) - { - struct gbm_bo *bo = gbm_surface_lock_front_buffer(output->gbm_surface); - - if (!bo) - { - PEPPER_ERROR("gbm_surface_lock_front_buffer() failed.\n"); - output->back_fb = NULL; - return; - } - - output->back_fb = get_fb(output, bo); - if (!output->back_fb) - { - PEPPER_ERROR("Failed to get drm_fb from gbm_bo.\n"); - return; - } - } - else if (output->renderer == output->drm->pixman_renderer) - { - output->back_fb = output->dumb_fb[output->back_fb_index]; - } - else - { - output->back_fb = NULL; - } + /* TODO: */ + return NULL; } -static pepper_bool_t -assign_cursor_plane(drm_output_t *output, pepper_view_t *view) +static void +drm_output_assign_planes(void *o, const pepper_list_t *view_list) { - int w, h; + pepper_list_t *l; + drm_output_t *output = o; - pepper_view_get_size(view, &w, &h); - if ((w > DRM_CURSOR_WIDTH/* FIXME */) || (h > DRM_CURSOR_HEIGHT/* FIXME */)) - return PEPPER_FALSE; + pepper_list_for_each_list(l, view_list) + { + pepper_view_t *view = l->item; + pepper_plane_t *plane = NULL; - if (!output->drm->gbm_device) - return PEPPER_FALSE; + if (plane == NULL) + plane = assign_cursor_plane(output, view); - if (!output->cursor_plane) - return PEPPER_FALSE; + if (plane == NULL) + plane = assign_fb_plane(output, view); - /* TODO */ + if (plane == NULL) + plane = assign_overlay_plane(output, view); - output->cursor_view = view; - pepper_view_assign_plane(view, output->base, output->cursor_plane); + if (plane == NULL) + plane = output->primary_plane; - return PEPPER_TRUE; + pepper_view_assign_plane(view, output->base, plane); + } } -static pepper_bool_t -assign_drm_plane(drm_output_t *output, pepper_view_t *view, drm_plane_t *plane) +static void +drm_output_render(drm_output_t *output) { - pepper_surface_t *surface; - pepper_buffer_t *buffer; - struct wl_resource *resource; - struct gbm_bo *bo; - - double x, y; - int w, h; - - if (!output->drm->gbm_device) - return PEPPER_FALSE; + const pepper_list_t *render_list = pepper_plane_get_render_list(output->primary_plane); + pixman_region32_t *damage = pepper_plane_get_damage_region(output->primary_plane); + pixman_region32_t total_damage; - if (plane->output || plane->back_fb) - return PEPPER_FALSE; - - surface = pepper_view_get_surface(view); - if (!surface) - return PEPPER_FALSE; - - buffer = pepper_surface_get_buffer(surface); - if (!buffer) - return PEPPER_FALSE; - - resource = pepper_buffer_get_resource(buffer); - if (!resource) - return PEPPER_FALSE; - - if (wl_shm_buffer_get(resource)) - return PEPPER_FALSE; - - /* TODO: check conditions */ - - bo = gbm_bo_import(output->drm->gbm_device, GBM_BO_IMPORT_WL_BUFFER, resource, - GBM_BO_USE_SCANOUT); + if (output->render_type == DRM_RENDER_TYPE_PIXMAN) + { + pixman_region32_init(&total_damage); + pixman_region32_union(&total_damage, damage, &output->previous_damage); + pixman_region32_copy(&output->previous_damage, damage); + damage = &total_damage; - if (!bo) - return PEPPER_FALSE; + output->render_target = output->fb[output->back_fb_index]->pixman_render_target; + output->back_fb_index ^= 1; + } - /* TODO: check format */ + pepper_renderer_set_target(output->renderer, output->render_target); + pepper_renderer_repaint_output(output->renderer, output->base, render_list, damage); + pepper_plane_clear_damage_region(output->primary_plane); - plane->back_fb = get_fb(output, bo); - if (!plane->back_fb) + if (output->render_type == DRM_RENDER_TYPE_PIXMAN) { - gbm_bo_destroy(bo); - return PEPPER_FALSE; + output->back = output->fb[output->back_fb_index]; + pixman_region32_fini(&total_damage); } + else if (output->render_type == DRM_RENDER_TYPE_GL) + { + struct gbm_bo *bo = gbm_surface_lock_front_buffer(output->gbm_surface); + PEPPER_CHECK(bo, return, "gbm_surface_lock_front_buffer() failed.\n"); - /* set position */ - pepper_view_get_position(view, &x, &y); - pepper_view_get_size(view, &w, &h); - plane->dx = (int)x; - plane->dy = (int)y; - plane->dw = w; - plane->dh = h; - - plane->sx = 0 /* FIXME */ << 16; - plane->sy = 0 /* FIXME */ << 16; - plane->sw = w << 16; - plane->sh = h << 16; - - plane->output = output; - - pepper_view_assign_plane(view, output->base, plane->base); + output->back = gbm_bo_get_user_data(bo); - return PEPPER_TRUE; + if (!output->back) + output->back = drm_buffer_create_gbm(output->drm, output->gbm_surface, bo); + } } static void -drm_output_assign_planes(void *o, const pepper_list_t *view_list) +drm_output_repaint(void *o, const pepper_list_t *plane_list) { - drm_output_t *output = (drm_output_t *)o; - pepper_drm_t *drm = output->drm; - pepper_list_t *l, *p; + drm_output_t *output = o; + drm_plane_t *plane; + int ret; - p = drm->plane_list.next; + if (!output->back) + drm_output_render(output); - pepper_list_for_each_list(l, view_list) + if (output->back) { - pepper_view_t *view = (pepper_view_t *)l->item; - drm_plane_t *plane = (drm_plane_t *)p->item; - - if (!output->cursor_view && assign_cursor_plane(output, view)) - continue; - - while (plane && !(plane->possible_crtcs & (1 << output->crtc_index))) + if (!output->front) { - p = p->next; - plane = (drm_plane_t *)p->item; - } - - if (plane && assign_drm_plane(output, view, plane)) - { - p = p->next; - continue; + ret = drmModeSetCrtc(output->drm->fd, output->crtc_id, output->back->id, 0, 0, + &output->conn->id, 1, output->mode); } - pepper_view_assign_plane(view, output->base, output->primary_plane); + ret = drmModePageFlip(output->drm->fd, output->crtc_id, output->back->id, + DRM_MODE_PAGE_FLIP_EVENT, output); + PEPPER_CHECK(ret == 0, , "page flip failed.\n"); } -} - -static void -set_planes(drm_output_t *output) -{ - drm_plane_t *plane; pepper_list_for_each(plane, &output->drm->plane_list, link) { - drmVBlank vbl; + drmVBlank vbl; - if (plane->output != output) + if (plane->output != output || plane->back == NULL) continue; - if (!plane->back_fb) - continue; + vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; - if (drmModeSetPlane(output->drm->drm_fd, plane->plane_id, output->crtc_id, - plane->back_fb->id, 0 /* FIXME: flags */, - plane->dx, plane->dy, plane->dw, plane->dh, - plane->sx, plane->sy, plane->sw, plane->sh)) - { - PEPPER_ERROR("Failed to set plane\n"); - /* TODO: handle error */ - continue; - } + ret = drmModeSetPlane(output->drm->fd, plane->id, + output->crtc_id, plane->back->id, 0, + plane->dx, plane->dy, plane->dw, plane->dh, + plane->sx, plane->sy, plane->sw, plane->sh); - vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; + PEPPER_CHECK(ret == 0, continue, "drmModeSetPlane() failed.\n"); + pepper_plane_clear_damage_region(plane->base); - if (output->crtc_index > 1) /* FIXME */ + if (output->crtc_index > 1) { - vbl.request.type |= ((output->crtc_index << DRM_VBLANK_HIGH_CRTC_SHIFT) & - DRM_VBLANK_HIGH_CRTC_MASK); + vbl.request.type |= (output->crtc_index << DRM_VBLANK_HIGH_CRTC_SHIFT) & + DRM_VBLANK_HIGH_CRTC_MASK; } else if (output->crtc_index > 0) { @@ -412,69 +246,18 @@ set_planes(drm_output_t *output) vbl.request.sequence = 1; vbl.request.signal = (unsigned long)plane; - if (drmWaitVBlank(output->drm->drm_fd, &vbl)) - { - PEPPER_ERROR("Failed to request vblank event\n"); - /* TODO: handle error */ - continue; - } - - output->vblank_pending = PEPPER_TRUE; - } -} - -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_list_for_each_list(l, plane_list) - { - pepper_plane_t *plane = l->item; - - 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); - - pepper_renderer_set_target(output->renderer, output->render_target); - pepper_renderer_repaint_output(output->renderer, output->base, render_list, damage); - pepper_plane_clear_damage_region(plane); + ret = drmWaitVBlank(output->drm->fd, &vbl); + PEPPER_CHECK(ret == 0, continue, "drmWaitVBlank() failed.\n"); - update_back_buffer(output); - - if (!output->back_fb) - return; - - 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; - } + output->vblank_pending++; } - - /* TODO: Cursor plane. */ - - set_planes(output); } static void drm_output_attach_surface(void *o, pepper_surface_t *surface, int *w, int *h) { - pepper_renderer_attach_surface(((drm_output_t *)o)->renderer, surface, w, h); + drm_output_t *output = o; + pepper_renderer_attach_surface(output->renderer, surface, w, h); } struct pepper_output_backend drm_output_backend = @@ -494,907 +277,277 @@ struct pepper_output_backend drm_output_backend = drm_output_attach_surface, }; -static struct udev_device * -find_primary_gpu(struct udev *udev) /* FIXME: copied from weston */ -{ - struct udev_enumerate *e; - struct udev_list_entry *entry; - struct udev_device *pci, *device, *drm_device = NULL; - const char *path, *device_seat, *id; - - e = udev_enumerate_new(udev); - udev_enumerate_add_match_subsystem(e, "drm"); - udev_enumerate_add_match_sysname(e, "card[0-9]*"); - udev_enumerate_scan_devices(e); - - udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) - { - path = udev_list_entry_get_name(entry); - device = udev_device_new_from_syspath(udev, path); - if (!device) - continue; - device_seat = udev_device_get_property_value(device, "ID_SEAT"); - if (!device_seat) - device_seat = "seat0"; - if (strcmp(device_seat, "seat0" /* FIXME: default seat? */)) - { - udev_device_unref(device); - continue; - } - - pci = udev_device_get_parent_with_subsystem_devtype(device, "pci", NULL); - if (pci) - { - id = udev_device_get_sysattr_value(pci, "boot_vga"); - if (id && !strcmp(id, "1")) - { - if (drm_device) - udev_device_unref(drm_device); - drm_device = device; - break; - } - } - - if (!drm_device) - drm_device = device; - else - udev_device_unref(device); - } - - udev_enumerate_unref(e); - return drm_device; -} - static int -drm_open(const char *path, int flags) +find_crtc_for_connector(drm_connector_t *conn) { - int fd; - struct stat s; - drm_magic_t m; + int i, j; - fd = open(path, flags | O_CLOEXEC); - if (fd == -1) + for (i = 0; i < conn->connector->count_encoders; i++) { - PEPPER_ERROR("Failed to open file[%s] in %s\n", path, __FUNCTION__); - goto error; - } + int32_t possible_crtcs; + drmModeEncoder *encoder = drmModeGetEncoder(conn->drm->fd, conn->connector->encoders[i]); - if (fstat(fd, &s) == -1) - { - PEPPER_ERROR("Failed to get file[%s] state in %s\n", path, __FUNCTION__); - goto error; - } + PEPPER_CHECK(encoder, continue, "drmModeGetEncoder() failed.\n"); - if (major(s.st_rdev) != 226/*drm major*/) - { - PEPPER_ERROR("File %s is not a drm device file\n", path); - goto error; - } + possible_crtcs = encoder->possible_crtcs; + drmModeFreeEncoder(encoder); - if ((drmGetMagic(fd, &m) != 0) || (drmAuthMagic(fd, m) != 0)) - { - PEPPER_ERROR("drm fd is not master\n"); - goto error; - } - - return fd; - -error: - if (fd > 0) - close(fd); - return -1; -} - -static int -find_crtc(pepper_drm_t *drm, drmModeRes *res, drmModeConnector *conn) -{ - int i, j; - drmModeEncoder *enc; - - for (i = 0; i < conn->count_encoders; i++) - { - enc = drmModeGetEncoder(drm->drm_fd, conn->encoders[i]); - if (!enc) - continue; - - for (j = 0; j < res->count_crtcs; j++) + for (j = 0; j < conn->drm->resources->count_crtcs; j++) { - pepper_bool_t crtc_used = PEPPER_FALSE; - drm_output_t *output; - - if (!(enc->possible_crtcs & (1 << j))) + if (!(possible_crtcs & (1 << j))) continue; - pepper_list_for_each(output, &drm->output_list, link) - { - if (res->crtcs[j] == output->crtc_id) - { - crtc_used = PEPPER_TRUE; - break; - } - } - - if (!crtc_used) - { - drmModeFreeEncoder(enc); + if (!(conn->drm->used_crtcs & (1 << j))) return j; - } } - - drmModeFreeEncoder(enc); } return -1; } static void -destroy_dumb_fb(drm_fb_t *fb) -{ - if (fb->map) - munmap(fb->map, fb->size); - - if (fb->id) - drmModeRmFB(fb->fd, fb->id); - - if (fb->handle) - { - struct drm_mode_destroy_dumb destroy_arg; - - memset(&destroy_arg, 0, sizeof(destroy_arg)); - destroy_arg.handle = fb->handle; - drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg); - } - - if (fb->target) - pepper_render_target_destroy(fb->target); - - free(fb); -} - -static drm_fb_t * -create_dumb_fb(drm_output_t *output) +fini_pixman_renderer(drm_output_t *output) { - drm_fb_t *fb; - - int drm_fd = output->drm->drm_fd; - uint32_t width = output->w; - uint32_t height = output->h; - - struct drm_mode_create_dumb create_arg; - struct drm_mode_map_dumb map_arg; - - fb = calloc(1, sizeof(drm_fb_t)); - if (!fb) - { - PEPPER_ERROR("Failed to allocate memory in %s\n", __FUNCTION__); - return NULL; - } - - fb->fd = drm_fd; - - memset(&create_arg, 0, sizeof create_arg); - create_arg.bpp = 32; - create_arg.width = width; - create_arg.height = height; - - if (drmIoctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg)) - { - PEPPER_ERROR("Failed to create dumb_fb fb with ioctl in %s\n", __FUNCTION__); - goto error; - } - - fb->handle = create_arg.handle; - fb->stride = create_arg.pitch; - fb->size = create_arg.size; - - if (drmModeAddFB(drm_fd, width, height, 24, 32, fb->stride, fb->handle, &fb->id)) - { - PEPPER_ERROR("Failed to add fb in %s\n", __FUNCTION__); - goto error; - } - - memset(&map_arg, 0, sizeof map_arg); - map_arg.handle = fb->handle; - - if (drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg)) - { - PEPPER_ERROR("Failed to map dumb_fb fb in %s\n", __FUNCTION__); - goto error; - } - - fb->map = mmap(0, fb->size, PROT_WRITE, MAP_SHARED, drm_fd, map_arg.offset); - if (fb->map == MAP_FAILED) - { - PEPPER_ERROR("Failed to map fb in %s\n", __FUNCTION__); - goto error; - } + int i; - fb->target = pepper_pixman_renderer_create_target(PEPPER_FORMAT_XRGB8888, fb->map, - fb->stride, width, height); - if (!fb->target) + for (i = 0; i < 2; i++) { - PEPPER_ERROR("Failed to create pixman render target.\n"); - goto error; + if (output->fb[i]) + { + drm_buffer_destroy(output->fb[i]); + output->fb[i] = NULL; + } } - return fb; - -error: - destroy_dumb_fb(fb); - return NULL; + pixman_region32_fini(&output->previous_damage); + output->renderer = NULL; + output->render_target = NULL; } static void -fini_pixman_renderer(drm_output_t *output) +init_pixman_renderer(drm_output_t *output) { - int i; + pepper_drm_t *drm = output->drm; + int i; + int w = output->mode->hdisplay; + int h = output->mode->vdisplay; - for (i = 0; i < DUMB_FB_COUNT; i++) + if (!drm->pixman_renderer) { - if (output->dumb_fb[i]) - destroy_dumb_fb(output->dumb_fb[i]); + drm->pixman_renderer = pepper_pixman_renderer_create(drm->compositor); + PEPPER_CHECK(drm->pixman_renderer, return, "pepper_pixman_renderer_create() failed.\n"); } -} -/* FIXME: copied from weston */ -static pepper_bool_t -init_pixman_renderer(drm_output_t *output) -{ - int i; + output->renderer = drm->pixman_renderer; - for (i = 0; i < DUMB_FB_COUNT; i++) + for (i = 0; i < 2; i++) { - output->dumb_fb[i] = create_dumb_fb(output); - if (!output->dumb_fb[i]) - { - PEPPER_ERROR("Failed to create dumb_fb[%d] in %s\n", i, __FUNCTION__); - return PEPPER_FALSE; - } + output->fb[i] = drm_buffer_create_dumb(drm, w, h); + PEPPER_CHECK(output->fb[i], goto error, "drm_buffer_create_dumb() failed.\n"); } - output->renderer = output->drm->pixman_renderer; - output->render_target = output->dumb_fb[output->back_fb_index]->target; - output->use_pixman = PEPPER_TRUE; + pixman_region32_init(&output->previous_damage); + return; - return PEPPER_TRUE; +error: + fini_pixman_renderer(output); } static void fini_gl_renderer(drm_output_t *output) { - if (output->gl_render_target) - pepper_render_target_destroy(output->gl_render_target); + if (output->render_target) + pepper_render_target_destroy(output->render_target); if (output->gbm_surface) gbm_surface_destroy(output->gbm_surface); - output->gl_render_target = NULL; + output->renderer = NULL; + output->render_target = NULL; output->gbm_surface = NULL; } -static pepper_bool_t +static void init_gl_renderer(drm_output_t *output) { - uint32_t native_visual_id; - - if (!output->drm->gl_renderer) - return PEPPER_FALSE; + pepper_drm_t *drm = output->drm; + int w = output->mode->hdisplay; + int h = output->mode->vdisplay; + uint32_t native_visual_id = GBM_FORMAT_XRGB8888; - output->gbm_surface = gbm_surface_create(output->drm->gbm_device, output->w, output->h, - GBM_FORMAT_XRGB8888/*FIXME*/, - GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING/*FIXME*/); - if (!output->gbm_surface) + if (!drm->gl_renderer) { - PEPPER_ERROR("Failed to create gbm surface in %s\n", __FUNCTION__); - goto error; - } + if (!drm->gbm_device) + { + drm->gbm_device = gbm_create_device(drm->fd); + PEPPER_CHECK(drm->gbm_device, return, "gbm_create_device() failed.\n"); + } - native_visual_id = GBM_FORMAT_XRGB8888; - output->gl_render_target = pepper_gl_renderer_create_target(output->drm->gl_renderer, - output->gbm_surface, - PEPPER_FORMAT_XRGB8888, - &native_visual_id); - if (!output->gl_render_target) - { - PEPPER_ERROR("Failed to create gl render target.\n"); - goto error; + drm->gl_renderer = pepper_gl_renderer_create(drm->compositor, drm->gbm_device, "gbm"); + PEPPER_CHECK(drm->gl_renderer, return, "pepper_gl_renderer_create() failed.\n"); } - output->renderer = output->drm->gl_renderer; - output->render_target = output->gl_render_target; + output->renderer = drm->gl_renderer; + + output->gbm_surface = gbm_surface_create(drm->gbm_device, w, h, GBM_FORMAT_XRGB8888, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + PEPPER_CHECK(output->gbm_surface, goto error, "gbm_surface_create() failed.\n"); - return PEPPER_TRUE; + output->render_target = pepper_gl_renderer_create_target(drm->gl_renderer, + output->gbm_surface, + PEPPER_FORMAT_XRGB8888, + &native_visual_id); + PEPPER_CHECK(output->render_target, goto error, "pepper_gl_renderer_create_target() failed.\n"); + return; error: fini_gl_renderer(output); - return PEPPER_FALSE; -} - -static pepper_bool_t -init_renderer(drm_output_t *output, const char *renderer) -{ - if (strcmp(renderer, "gl") == 0) - return init_gl_renderer(output); - - return init_pixman_renderer(output); } -static void -fini_renderer(drm_output_t *output) -{ - if (output->use_pixman) - fini_pixman_renderer(output); - else - fini_gl_renderer(output); -} - -static const char *connector_type_names[] = { - "None", - "VGA", - "DVI", - "DVI", - "DVI", - "Composite", - "TV", - "LVDS", - "CTV", - "DIN", - "DP", - "HDMI", - "HDMI", - "TV", - "eDP", -}; - -static drm_output_t * -drm_output_create(pepper_drm_t *drm, struct udev_device *device, - drmModeRes *res, drmModeConnector *conn) +drm_output_t * +drm_output_create(drm_connector_t *conn) { - int i; + pepper_drm_t *drm = conn->drm; drm_output_t *output; - const char *type_name; + drm_plane_t *plane, *tmp; + const char *render_env = getenv("PEPPER_DRM_RENDERER"); - output = (drm_output_t *)calloc(1, sizeof(drm_output_t)); - if (!output) - { - PEPPER_ERROR("Failed to allocate memory in %s\n", __FUNCTION__); - goto error; - } + PEPPER_CHECK(conn->output == NULL, return NULL, "The connector already has an output.\n"); - output->drm = drm; - output->subpixel = conn->subpixel; + output = calloc(1, sizeof(drm_output_t)); + PEPPER_CHECK(output, return NULL, "calloc() failed.\n"); - pepper_list_insert(&drm->output_list, &output->link); + output->drm = drm; + output->conn = conn; + output->crtc_index = find_crtc_for_connector(conn); + output->crtc_id = drm->resources->crtcs[output->crtc_index]; + output->saved_crtc = drmModeGetCrtc(drm->fd, output->crtc_id); + output->mode = &conn->connector->modes[0]; - /* find crtc + connector */ - output->crtc_index = find_crtc(drm, res, conn); - if (output->crtc_index < 0) - { - PEPPER_ERROR("Failed to find crtc in %s\n", __FUNCTION__); - goto error; - } - output->crtc_id = res->crtcs[output->crtc_index]; - output->conn_id = conn->connector_id; - output->saved_crtc = drmModeGetCrtc(drm->drm_fd, output->crtc_id); - - /* set modes */ - output->mode_count = conn->count_modes; - output->modes = (drmModeModeInfo *)calloc(conn->count_modes, - sizeof(drmModeModeInfo)); - if (!output->modes) - { - PEPPER_ERROR("Failed to allocate memory in %s\n", __FUNCTION__); - goto error; - } + output->base = pepper_compositor_add_output(drm->compositor, &drm_output_backend, + conn->name, output); + PEPPER_CHECK(output->base, goto error, "pepper_compositor_add_output() failed.\n"); - memcpy(output->modes, conn->modes, conn->count_modes * sizeof(drmModeModeInfo)); - for (i = 0; i < output->mode_count; i++) - { - drmModeModeInfo *m = &(output->modes[i]); - if (m->type & DRM_MODE_TYPE_PREFERRED) - { - output->current_mode = m; - output->w = m->hdisplay; - output->h = m->vdisplay; - } - } + if (render_env && strcmp(render_env, "gl") == 0) + init_gl_renderer(output); - if (!init_renderer(output, drm->renderer)) + if (!output->renderer) { - PEPPER_ERROR("Failed to initialize renderer in %s\n", __FUNCTION__); - goto error; + /* Pixman is default. */ + init_pixman_renderer(output); + PEPPER_CHECK(output->renderer, goto error, "Failed to initialize renderer.\n"); } - if (conn->connector_type < PEPPER_ARRAY_LENGTH(connector_type_names)) - type_name = connector_type_names[conn->connector_type]; - else - type_name = "UNKNOWN"; - - snprintf(&output->name[0], 32, "%s%d", type_name, conn->connector_type_id); - return output; - -error: - - if (output) - drm_output_destroy(output); - - return NULL; -} - -static pepper_bool_t -add_outputs(pepper_drm_t *drm, struct udev_device *device) -{ - int i; - drmModeRes *res; - drmModeConnector *conn; - drm_output_t *output; - - res = drmModeGetResources(drm->drm_fd); - if (!res) - { - PEPPER_ERROR("Failed to get drm resources in %s\n", __FUNCTION__); - return PEPPER_FALSE; - } + output->primary_plane = pepper_output_add_plane(output->base, NULL); + PEPPER_CHECK(output->primary_plane, goto error, "pepper_output_add_plane() failed.\n"); - drm->crtcs = calloc(res->count_crtcs, sizeof(uint32_t)); - if (!drm->crtcs) - { - PEPPER_ERROR("Failed to allocate memory in %s\n", __FUNCTION__); - return PEPPER_FALSE; - } - drm->count_crtcs = res->count_crtcs; - memcpy(drm->crtcs, res->crtcs, sizeof(uint32_t) * res->count_crtcs); + output->cursor_plane = pepper_output_add_plane(output->base, output->primary_plane); + PEPPER_CHECK(output->cursor_plane, goto error, "pepper_output_add_plane() failed.\n"); - drm->min_width = res->min_width; - drm->min_height = res->min_height; - drm->max_width = res->max_width; - drm->max_height = res->max_height; + output->fb_plane = pepper_output_add_plane(output->base, output->primary_plane); + PEPPER_CHECK(output->fb_plane, goto error, "pepper_output_add_plane() failed.\n"); - for (i = 0; i < res->count_connectors; i++) + pepper_list_for_each_safe(plane, tmp, &output->drm->plane_list, link) { - conn = drmModeGetConnector(drm->drm_fd, res->connectors[i]); - if (!conn) - continue; - - if (conn->connection != DRM_MODE_CONNECTED/* CHECKME */) - { - drmModeFreeConnector(conn); - continue; - } - - /* TODO: Get renderer string from somewhere else. i.e. config file. */ - output = drm_output_create(drm, device, res, conn); - if (!output) + if (plane->output == NULL && (plane->plane->possible_crtcs & (1 << output->crtc_index))) { - PEPPER_ERROR("Failed to create drm_output in %s\n", __FUNCTION__); - drmModeFreeConnector(conn); - continue; - } + plane->base = pepper_output_add_plane(output->base, output->primary_plane); - /* - * PEPPER_API pepper_output_t * - * pepper_compositor_add_output(pepper_compositor_t *compositor, - * const pepper_output_backend_t *backend, void *data) - */ - output->base = pepper_compositor_add_output(output->drm->compositor, - &drm_output_backend, output->name, output); - if (!output->base) - { - PEPPER_ERROR("Failed to add output to compositor in %s\n", __FUNCTION__); - drm_output_destroy(output); - drmModeFreeConnector(conn); - continue; + if (plane->base) + plane->output = output; } - - output->primary_plane = pepper_output_add_plane(output->base, NULL); - drmModeFreeConnector(conn); - } - - if (pepper_list_empty(&drm->output_list)) - { - PEPPER_ERROR("Failed to find active output in %s\n", __FUNCTION__); - drmModeFreeResources(res); - return PEPPER_FALSE; - } - - drmModeFreeResources(res); - - return PEPPER_TRUE; -} - -static void -remove_outputs(pepper_drm_t *drm) -{ - if (!pepper_list_empty(&drm->output_list)) - { - drm_output_t *output, *tmp; - - pepper_list_for_each_safe(output, tmp, &drm->output_list, link) - pepper_output_remove(output->base); } -} -static void -handle_vblank(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, - void *user_data) -{ - drm_plane_t *plane = (drm_plane_t *)user_data; - drm_output_t *output = plane->output; - - output->vblank_pending = PEPPER_FALSE; + drm->used_crtcs |= (1 << output->crtc_index); + return output; - if (plane->front_fb) +error: + if (output->saved_crtc) { - if (plane->front_fb->bo) - gbm_bo_destroy(plane->front_fb->bo); /* FIXME: destroy fb? */ + drmModeFreeCrtc(output->saved_crtc); + output->saved_crtc = NULL; } - plane->front_fb = plane->back_fb; - plane->back_fb = NULL; - plane->output = NULL; - - if (!output->page_flip_pending) - pepper_output_finish_frame(output->base, NULL); + drm_output_destroy(output); + return NULL; } -static void -handle_page_flip(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, - void *user_data) +void +drm_output_destroy(void *o) { - drm_output_t *output = (drm_output_t *)user_data; + drm_output_t *output = o; + drm_plane_t *plane; - if (output->use_pixman) - { - output->back_fb_index ^= 1; - output->render_target = output->dumb_fb[output->back_fb_index]->target; - } - else + if (output->saved_crtc) { - /* Assume GL renderer in this case. */ - if (output->front_fb && output->front_fb->bo) - gbm_surface_release_buffer(output->gbm_surface, output->front_fb->bo); + drmModeSetCrtc(output->conn->drm->fd, + output->saved_crtc->crtc_id, + output->saved_crtc->buffer_id, + output->saved_crtc->x, output->saved_crtc->y, + &output->conn->connector->connector_id, 1, &output->saved_crtc->mode); + drmModeFreeCrtc(output->saved_crtc); } - output->front_fb = output->back_fb; - output->back_fb = NULL; - output->page_flip_pending = PEPPER_FALSE; + if (output->fb_plane) + pepper_plane_destroy(output->fb_plane); - if (!output->vblank_pending) - pepper_output_finish_frame(output->base, NULL); -} - -static int -handle_drm_events(int fd, uint32_t mask, void *data) -{ - drmEventContext ctx; - - memset(&ctx, 0, sizeof(drmEventContext)); - ctx.version = DRM_EVENT_CONTEXT_VERSION; - ctx.vblank_handler = handle_vblank; - ctx.page_flip_handler = handle_page_flip; - drmHandleEvent(fd, &ctx); - - return 0; -} - -static pepper_bool_t -create_planes(pepper_drm_t *drm) -{ - uint32_t i; - drmModePlaneRes *res = drmModeGetPlaneResources(drm->drm_fd); - - if (!res) - { - PEPPER_ERROR("Failed to get plane resources\n"); - return PEPPER_FALSE; - } + if (output->primary_plane) + pepper_plane_destroy(output->primary_plane); - for (i = 0; i < res->count_planes; i++) + /* Release all planes. */ + pepper_list_for_each(plane, &output->drm->plane_list, link) { - drm_output_t *output = NULL, *o; - drmModePlane *pl = drmModeGetPlane(drm->drm_fd, res->planes[i]); - drm_plane_t *plane; - - if (!pl) - continue; - - pepper_list_for_each(o, &drm->output_list, link) - { - if (pl->possible_crtcs & (1 << o->crtc_index)) - { - output = o; - break; - } - } - - if (!output) - { - drmModeFreePlane(pl); - continue; - } - - plane = (drm_plane_t *)calloc(1, sizeof(drm_plane_t)); - if (!plane) - { - PEPPER_ERROR("Failed to allocate memory\n"); - drmModeFreePlane(pl); - continue; - } - - plane->drm = drm; - plane->possible_crtcs = pl->possible_crtcs; - plane->plane_id = pl->plane_id; - - /* TODO */ - - plane->base = pepper_output_add_plane(output->base, output->primary_plane); - if (!plane->base) + if (plane->output == output) { - PEPPER_ERROR("Failed to add plane\n"); - free(plane); + plane->output = NULL; + pepper_plane_destroy(plane->base); } - - pepper_list_insert(&drm->plane_list, &plane->link); - drmModeFreePlane(pl); } - drmModeFreePlaneResources(res); - return PEPPER_TRUE; + /* destroy renderer. */ + free(output); } -static void -destroy_planes(pepper_drm_t *drm) +void +drm_handle_vblank(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) { - drm_plane_t *plane, *tmp; + drm_plane_t *plane = data; + struct timespec ts; - pepper_list_for_each_safe(plane, tmp, &drm->plane_list, link) - { - pepper_list_remove(&plane->link); - pepper_plane_destroy(plane->base); - free(plane); - } -} + plane->output->vblank_pending--; -static void -update_outputs(pepper_drm_t *drm, struct udev_device *device) -{ - int i; - drmModeRes *res; + if (plane->front) + drm_buffer_release(plane->front); - res = drmModeGetResources(drm->drm_fd); - if (!res) - { - PEPPER_ERROR("Failed to get drm resources in %s\n", __FUNCTION__); - return; - } + plane->front = plane->back; + plane->back = NULL; - for (i = 0; i < res->count_connectors; i++) + if (plane->output->vblank_pending == 0 && !plane->output->page_flip_pending) { - drmModeConnector *conn = drmModeGetConnector(drm->drm_fd, res->connectors[i]); - drm_output_t *output = NULL, *o; - - if (!conn) - continue; - - pepper_list_for_each(o, &drm->output_list, link) - { - if (o->conn_id == conn->connector_id) - { - output = o; - break; - } - } - - if (output && conn->connection != DRM_MODE_CONNECTED) - { - pepper_output_remove(output->base); - } - else if (!output && conn->connection == DRM_MODE_CONNECTED) - { - /* TODO: Get renderer string from somewhere else. */ - output = drm_output_create(drm, device, res, conn); - if (!output) - { - PEPPER_ERROR("Failed to create drm_output in %s\n", __FUNCTION__); - drmModeFreeConnector(conn); - continue; - } - - output->base = pepper_compositor_add_output(output->drm->compositor, - &drm_output_backend, output->name, output); - if (!output->base) - { - PEPPER_ERROR("Failed to add output to compositor in %s\n", __FUNCTION__); - drm_output_destroy(output); - drmModeFreeConnector(conn); - continue; - } - - output->primary_plane = pepper_output_add_plane(output->base, NULL); - } - - drmModeFreeConnector(conn); + ts.tv_sec = sec; + ts.tv_nsec = usec * 1000; + pepper_output_finish_frame(plane->output->base, &ts); } - - drmModeFreeResources(res); } -static int -handle_udev_drm_events(int fd, uint32_t mask, void *data) -{ - pepper_drm_t *drm = (pepper_drm_t *)data; - struct udev_device *device; - - const char *sysnum; - const char *value; - - device = udev_monitor_receive_device(drm->udev_monitor); - - sysnum = udev_device_get_sysnum(device); - if (!sysnum || atoi(sysnum) != drm->drm_sysnum) - goto done; - - value = udev_device_get_property_value(device, "HOTPLUG"); - if (!value || strcmp(value, "1")) - goto done; - - update_outputs(drm, device); - - destroy_planes(drm); - create_planes(drm); - -done: - udev_device_unref(device); - return 0; -} - -pepper_bool_t -pepper_drm_output_create(pepper_drm_t *drm, const char *renderer) +void +drm_handle_page_flip(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) { - struct udev_device *drm_device; - const char *filepath; - const char *sysnum; + drm_output_t *output = data; + struct timespec ts; - struct wl_display *display; - struct wl_event_loop *loop; - - /* drm open */ - drm_device = find_primary_gpu(drm->udev); - if (!drm_device) - { - PEPPER_ERROR("Failed to find primary gpu in %s\n", __FUNCTION__); - goto error; - } - - sysnum = udev_device_get_sysnum(drm_device); - if (!sysnum) - { - PEPPER_ERROR("Failed to get sysnum in %s\n", __FUNCTION__); - goto error; - } - - drm->drm_sysnum = atoi(sysnum); - if (drm->drm_sysnum < 0) - { - PEPPER_ERROR("Failed to get sysnum in %s\n", __FUNCTION__); - goto error; - } - - filepath = udev_device_get_devnode(drm_device); - drm->drm_fd = drm_open(filepath, O_RDWR); - if (drm->drm_fd < 0) - { - PEPPER_ERROR("Failed to open drm[%s] in %s\n", filepath, __FUNCTION__); - goto error; - } - - if (renderer) - drm->renderer = strdup(renderer); - - /* create gl-renderer & pixman-renderer */ - if (strcmp(renderer, "gl") == 0) - { - drm->gbm_device = gbm_create_device(drm->drm_fd); - if (drm->gbm_device) - drm->gl_renderer = pepper_gl_renderer_create(drm->compositor, drm->gbm_device, "gbm"); - } - else if (strcmp(renderer, "pixman") == 0) - { - drm->pixman_renderer = pepper_pixman_renderer_create(drm->compositor); - if (!drm->pixman_renderer) - { - PEPPER_ERROR("Failed to create pixman-renderer\n"); - goto error; - } - } - else - { - PEPPER_ERROR("Unknown renderer: %s\n", renderer); - goto error; - } - - /* add outputs */ - if (add_outputs(drm, drm_device) == PEPPER_FALSE) - { - PEPPER_ERROR("Failed to add outputs in %s\n", __FUNCTION__); - goto error; - } - - if (create_planes(drm) == PEPPER_FALSE) - PEPPER_ERROR("Failed to create planes\n"); + output->page_flip_pending = PEPPER_FALSE; - /* add drm fd to main loop */ - display = pepper_compositor_get_display(drm->compositor); - loop = wl_display_get_event_loop(display); - drm->drm_event_source = wl_event_loop_add_fd(loop, drm->drm_fd, WL_EVENT_READABLE, - handle_drm_events, drm); - if (!drm->drm_event_source) - { - PEPPER_ERROR("Failed to add drm fd to main loop in %s\n", __FUNCTION__); - goto error; - } + if (output->front) + drm_buffer_release(output->front); - drm->udev_monitor = udev_monitor_new_from_netlink(drm->udev, "udev"); - if (!drm->udev_monitor) - { - PEPPER_ERROR("Failed to create udev_monitor in %s\n", __FUNCTION__); - goto error; - } - - udev_monitor_filter_add_match_subsystem_devtype(drm->udev_monitor, "drm", NULL); - drm->udev_monitor_source = wl_event_loop_add_fd(loop, - udev_monitor_get_fd(drm->udev_monitor), - WL_EVENT_READABLE, - handle_udev_drm_events, drm); - if (!drm->udev_monitor_source) - { - PEPPER_ERROR("Failed to add udev_monitor fd to main loop in %s\n", __FUNCTION__); - goto error; - } + output->front = output->back; + output->back = NULL; - if (udev_monitor_enable_receiving(drm->udev_monitor) < 0) + if (output->vblank_pending == 0) { - PEPPER_ERROR("Failed to enable udev_monitor in %s\n", __FUNCTION__); - goto error; + ts.tv_sec = sec; + ts.tv_nsec = usec * 1000; + pepper_output_finish_frame(output->base, &ts); } - - - udev_device_unref(drm_device); - - return PEPPER_TRUE; - -error: - - if (drm_device) - udev_device_unref(drm_device); - - return PEPPER_FALSE; -} - -void -pepper_drm_output_destroy(pepper_drm_t *drm) -{ - if (drm->renderer) - free(drm->renderer); - - if (drm->udev_monitor_source) - wl_event_source_remove(drm->udev_monitor_source); - - if (drm->udev_monitor) - udev_monitor_unref(drm->udev_monitor); - - if (drm->drm_event_source) - wl_event_source_remove(drm->drm_event_source); - - destroy_planes(drm); - remove_outputs(drm); - - if (drm->crtcs) - free(drm->crtcs); - - if (drm->gbm_device) - gbm_device_destroy(drm->gbm_device); - - if (drm->drm_fd) - close(drm->drm_fd); } diff --git a/src/lib/drm/drm-plane.c b/src/lib/drm/drm-plane.c new file mode 100644 index 0000000..c0ee549 --- /dev/null +++ b/src/lib/drm/drm-plane.c @@ -0,0 +1,35 @@ +#include "drm-internal.h" + +void +drm_init_planes(pepper_drm_t *drm) +{ + int i; + drmModePlaneRes *res = drmModeGetPlaneResources(drm->fd); + + PEPPER_CHECK(res, return, "drmModeGetPlaneResources() failed.\n"); + + for (i = 0; i < (int)res->count_planes; i++) + { + drm_plane_t *plane = calloc(1, sizeof(drm_plane_t)); + PEPPER_CHECK(plane, continue, "calloc() failed.\n"); + + plane->plane = drmModeGetPlane(drm->fd, res->planes[i]); + if (!plane->plane) + { + PEPPER_ERROR("drmModeGetPlane() failed.\n"); + free(plane); + continue; + } + + pepper_list_insert(drm->plane_list.prev, &plane->link); + } +} + +void +drm_plane_destroy(drm_plane_t *plane) +{ + if (plane->plane) + drmModeFreePlane(plane->plane); + + pepper_list_remove(&plane->link); +} diff --git a/src/lib/drm/pepper-drm.h b/src/lib/drm/pepper-drm.h index 1ad4681..3ca7572 100644 --- a/src/lib/drm/pepper-drm.h +++ b/src/lib/drm/pepper-drm.h @@ -8,11 +8,10 @@ extern "C" { #endif -typedef struct pepper_drm pepper_drm_t; +typedef struct pepper_drm pepper_drm_t; PEPPER_API pepper_drm_t * -pepper_drm_create(pepper_compositor_t *compositor, struct udev *udev, - const char *device, const char *renderer); +pepper_drm_create(pepper_compositor_t *compositor, struct udev *udev, const char *device); PEPPER_API void pepper_drm_destroy(pepper_drm_t *drm); diff --git a/src/samples/drm-backend.c b/src/samples/drm-backend.c index a33cb4e..6fef031 100644 --- a/src/samples/drm-backend.c +++ b/src/samples/drm-backend.c @@ -75,7 +75,7 @@ main(int argc, char **argv) if (!input) goto cleanup; - drm = pepper_drm_create(compositor, udev, ""/*device*/, "pixman"/*renderer*/); + drm = pepper_drm_create(compositor, udev, NULL); if (!drm) goto cleanup; -- 2.7.4