From e446a5300b742dd8a7f403bf96d1137e91ba1b11 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Tue, 2 May 2017 18:13:17 +1200 Subject: [PATCH] Added example. --- CMake/FindGBM.cmake | 39 ++++++++++++ CMakeLists.txt | 5 +- backend/CMakeLists.txt | 7 +++ backend/drm/backend.c | 17 +++++- backend/drm/drm.c | 10 +++- backend/drm/session.c | 2 +- backend/drm/udev.c | 8 ++- example/CMakeLists.txt | 8 +++ example/example-drm.c | 109 ++++++++++++++++++++++++++++++++++ include/backend/drm/backend.h | 5 +- include/backend/drm/drm.h | 3 +- include/wlr/backend/drm.h | 20 +++++++ 12 files changed, 220 insertions(+), 13 deletions(-) create mode 100644 CMake/FindGBM.cmake create mode 100644 example/example-drm.c create mode 100644 include/wlr/backend/drm.h diff --git a/CMake/FindGBM.cmake b/CMake/FindGBM.cmake new file mode 100644 index 000000000..85df1f7c3 --- /dev/null +++ b/CMake/FindGBM.cmake @@ -0,0 +1,39 @@ +#.rst: +# FindGBM +# ------- +# +# Find GBM library +# +# Try to find GBM library on UNIX systems. The following values are defined +# +# :: +# +# GBM_FOUND - True if gbm is available +# GBM_INCLUDE_DIRS - Include directories for gbm +# GBM_LIBRARIES - List of libraries for gbm +# GBM_DEFINITIONS - List of definitions for gbm +# +#============================================================================= +# Copyright (c) 2015 Jari Vetoniemi +# +# Distributed under the OSI-approved BSD License (the "License"); +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= + +set_package_properties(GBM PROPERTIES + URL "http://www.mesa3d.org/" + DESCRIPTION "Generic buffer manager") + +find_package(PkgConfig) +pkg_check_modules(PC_GBM QUIET gbm) +find_library(GBM_LIBRARIES NAMES gbm HINTS ${PC_GBM_LIBRARY_DIRS}) +find_path(GBM_INCLUDE_DIRS gbm.h HINTS ${PC_GBM_INCLUDE_DIRS}) + +set(GBM_DEFINITIONS ${PC_GBM_CFLAGS_OTHER}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GBM DEFAULT_MSG GBM_INCLUDE_DIRS GBM_LIBRARIES) +mark_as_advanced(GBM_INCLUDE_DIRS GBM_LIBRARIES GBM_DEFINITIONS) diff --git a/CMakeLists.txt b/CMakeLists.txt index 30a2c37d5..192eb4448 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,10 +48,11 @@ find_package(WaylandProtocols REQUIRED) find_package(EGL REQUIRED) find_package(GLESv2 REQUIRED) find_package(DRM REQUIRED) +find_package(GBM REQUIRED) find_package(LibInput REQUIRED) -find_package(Udev) +find_package(Udev REQUIRED) find_package(Dbus) -find_package(Systemd) +find_package(Systemd REQUIRED) include(Wayland) include(Manpage) diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt index 344dd3cc0..184854fe1 100644 --- a/backend/CMakeLists.txt +++ b/backend/CMakeLists.txt @@ -19,4 +19,11 @@ target_link_libraries(wlr-backend wlr-common wlr-wayland ${WAYLAND_LIBRARIES} + ${DRM_LIBRARIES} + ${GBM_LIBRARIES} + ${GLESv2_LIBRARIES} + ${EGL_LIBRARIES} + ${SYSTEMD_LIBRARIES} + ${UDEV_LIBRARIES} + ${GBM_LIBRARIES} ) diff --git a/backend/drm/backend.c b/backend/drm/backend.c index 73e57bfa0..7db6e9a10 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -12,7 +12,9 @@ #include "backend/drm/udev.h" #include "common/log.h" -struct wlr_drm_backend *wlr_drm_backend_init(void) +struct wlr_drm_backend *wlr_drm_backend_init(struct wl_listener *add, + struct wl_listener *rem, + struct wl_listener *render) { struct wlr_drm_backend *backend = calloc(1, sizeof *backend); if (!backend) { @@ -57,6 +59,13 @@ struct wlr_drm_backend *wlr_drm_backend_init(void) wl_signal_init(&backend->signals.display_rem); wl_signal_init(&backend->signals.display_render); + if (add) + wl_signal_add(&backend->signals.display_add, add); + if (rem) + wl_signal_add(&backend->signals.display_rem, rem); + if (render) + wl_signal_add(&backend->signals.display_render, render); + wlr_drm_scan_connectors(backend); return backend; @@ -80,6 +89,7 @@ static void free_display(void *item) { struct wlr_drm_display *disp = item; wlr_drm_display_free(disp, true); + free(disp); } void wlr_drm_backend_free(struct wlr_drm_backend *backend) @@ -95,9 +105,14 @@ void wlr_drm_backend_free(struct wlr_drm_backend *backend) wlr_session_end(&backend->session); wl_event_source_remove(backend->event_src.drm); + wl_event_source_remove(backend->event_src.udev); wl_event_loop_destroy(backend->event_loop); list_free(backend->displays); free(backend); } +struct wl_event_loop *wlr_drm_backend_get_event_loop(struct wlr_drm_backend *backend) +{ + return backend->event_loop; +} diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 226c79fbf..470a76bbe 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -281,6 +281,7 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *backend) continue; } + disp->renderer = &backend->renderer; disp->state = DRM_DISP_DISCONNECTED; disp->connector = res->connectors[i]; snprintf(disp->name, sizeof disp->name, "%s-%"PRIu32, @@ -288,6 +289,7 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *backend) conn->connector_type_id); list_add(backend->displays, disp); + wlr_log(L_INFO, "Found display '%s'", disp->name); } else { disp = backend->displays->items[index]; } @@ -295,12 +297,14 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *backend) if (disp->state == DRM_DISP_DISCONNECTED && conn->connection == DRM_MODE_CONNECTED) { disp->state = DRM_DISP_NEEDS_MODESET; + wlr_log(L_INFO, "Sending modesetting signal for '%s'", disp->name); wl_signal_emit(&backend->signals.display_add, disp); } else if (disp->state == DRM_DISP_CONNECTED && conn->connection != DRM_MODE_CONNECTED) { disp->state = DRM_DISP_DISCONNECTED; wlr_drm_display_free(disp, false); + wlr_log(L_INFO, "Sending destruction signal for '%s'", disp->name); wl_signal_emit(&backend->signals.display_rem, disp); } @@ -430,9 +434,9 @@ static drmModeModeInfo *select_mode(size_t num_modes, return NULL; } -bool wlr_drm_display_modeset(struct wlr_drm_backend *backend, - struct wlr_drm_display *disp, const char *str) +bool wlr_drm_display_modeset(struct wlr_drm_display *disp, const char *str) { + struct wlr_drm_backend *backend = disp->renderer->backend; wlr_log(L_INFO, "Modesetting %s with '%s'", disp->name, str); drmModeConnector *conn = drmModeGetConnector(backend->fd, disp->connector); @@ -519,7 +523,7 @@ bool wlr_drm_display_modeset(struct wlr_drm_backend *backend, drmModeFreeConnector(conn); - wlr_log(L_INFO, "Configuring %s with mode %"PRIu16"x%"PRIu16"@%"PRIu32"\n", + wlr_log(L_INFO, "Configuring %s with mode %"PRIu16"x%"PRIu16"@%"PRIu32"", disp->name, disp->active_mode->hdisplay, disp->active_mode->vdisplay, disp->active_mode->vrefresh); diff --git a/backend/drm/session.c b/backend/drm/session.c index 49223334c..073f822b7 100644 --- a/backend/drm/session.c +++ b/backend/drm/session.c @@ -194,7 +194,7 @@ bool wlr_session_start(struct wlr_session *session) sprintf(session->path, fmt, session->id); - ret = sd_bus_open_system(&session->bus); + ret = sd_bus_default_system(&session->bus); if (ret < 0) { wlr_log(L_ERROR, "Failed to open DBus connection: %s", strerror(-ret)); goto error; diff --git a/backend/drm/udev.c b/backend/drm/udev.c index 6c4aa0740..ae99bcfc1 100644 --- a/backend/drm/udev.c +++ b/backend/drm/udev.c @@ -94,9 +94,10 @@ int wlr_udev_find_gpu(struct wlr_udev *udev, struct wlr_session *session) const char *id = udev_device_get_sysattr_value(pci, "boot_vga"); if (id && strcmp(id, "1") == 0) is_boot_vga = true; - udev_device_unref(pci); + //udev_device_unref(pci); } + // We already have a valid GPU if (!is_boot_vga && fd >= 0) { udev_device_unref(dev); continue; @@ -107,9 +108,10 @@ int wlr_udev_find_gpu(struct wlr_udev *udev, struct wlr_session *session) continue; } - if (is_boot_vga) { + udev_device_unref(dev); + + if (is_boot_vga) break; - } } udev_enumerate_unref(en); diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 737683936..dfb069b4b 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -5,3 +5,11 @@ add_executable(example target_link_libraries(example wlr-backend ) + +add_executable(example-drm + example-drm.c +) + +target_link_libraries(example-drm + wlr-backend +) diff --git a/example/example-drm.c b/example/example-drm.c new file mode 100644 index 000000000..4c9442266 --- /dev/null +++ b/example/example-drm.c @@ -0,0 +1,109 @@ +#define _POSIX_C_SOURCE 199309L +#include +#include +#include +#include +#include + +#include + +struct state { + float color[3]; + int dec; + + struct timespec last_frame; + + struct wl_listener add; + struct wl_listener rem; + struct wl_listener render; +}; + +void display_add(struct wl_listener *listener, void *data) +{ + struct wlr_drm_display *disp = data; + + fprintf(stderr, "Display added\n"); + wlr_drm_display_modeset(disp, "preferred"); +} + +void display_rem(struct wl_listener *listener, void *data) +{ + fprintf(stderr, "Display removed\n"); +} + +void display_render(struct wl_listener *listener, void *data) +{ + struct wlr_drm_display *disp = data; + struct state *s = wl_container_of(listener, s, render); + + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + long ms = (now.tv_sec - s->last_frame.tv_sec) * 1000 + + (now.tv_nsec - s->last_frame.tv_nsec) / 1000000; + int inc = (s->dec + 1) % 3; + + s->color[inc] += ms / 2000.0f; + s->color[s->dec] -= ms / 2000.0f; + + if (s->color[s->dec] < 0.0f) { + s->color[inc] = 1.0f; + s->color[s->dec] = 0.0f; + + s->dec = inc; + } + + s->last_frame = now; + + wlr_drm_display_begin(disp); + + glClearColor(s->color[0], s->color[1], s->color[2], 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + wlr_drm_display_end(disp); +} + +int timer_done(void *data) +{ + *(bool *)data = true; + return 1; +} + +int main() +{ + if (getenv("DISPLAY")) { + fprintf(stderr, "Detected that X is running. Run this in its own virtual terminal.\n"); + return 1; + } else if (getenv("WAYLAND_DISPLAY")) { + fprintf(stderr, "Detected that Wayland is running. Run this in its own virtual terminal.\n"); + return 1; + } + + struct state state = { + .color = { 1.0, 0.0, 0.0 }, + .dec = 0, + .add = { .notify = display_add }, + .rem = { .notify = display_rem }, + .render = { .notify = display_render }, + }; + + wl_list_init(&state.add.link); + wl_list_init(&state.rem.link); + wl_list_init(&state.render.link); + clock_gettime(CLOCK_MONOTONIC, &state.last_frame); + + struct wlr_drm_backend *wlr = wlr_drm_backend_init(&state.add, &state.rem, &state.render); + + bool done = false; + struct wl_event_loop *event_loop = wlr_drm_backend_get_event_loop(wlr); + struct wl_event_source *timer = wl_event_loop_add_timer(event_loop, + timer_done, &done); + + wl_event_source_timer_update(timer, 10000); + + while (!done) + wl_event_loop_dispatch(event_loop, 0); + + wl_event_source_remove(timer); + wlr_drm_backend_free(wlr); +} diff --git a/include/backend/drm/backend.h b/include/backend/drm/backend.h index 87471fbbc..1ad8e479b 100644 --- a/include/backend/drm/backend.h +++ b/include/backend/drm/backend.h @@ -9,6 +9,7 @@ #include #include +#include #include "session.h" #include "udev.h" @@ -41,7 +42,9 @@ struct wlr_drm_backend { struct wlr_udev udev; }; -struct wlr_drm_backend *wlr_drm_backend_init(void); +struct wlr_drm_backend *wlr_drm_backend_init(struct wl_listener *add, + struct wl_listener *rem, + struct wl_listener *render); void wlr_drm_backend_free(struct wlr_drm_backend *backend); #endif diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 1fe4b7b05..17d4aa908 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -57,8 +57,7 @@ struct wlr_drm_display { bool cleanup; }; -bool wlr_drm_display_modeset(struct wlr_drm_backend *backend, - struct wlr_drm_display *disp, const char *str); +bool wlr_drm_display_modeset(struct wlr_drm_display *disp, const char *str); void wlr_drm_display_free(struct wlr_drm_display *disp, bool restore); void wlr_drm_display_begin(struct wlr_drm_display *disp); diff --git a/include/wlr/backend/drm.h b/include/wlr/backend/drm.h new file mode 100644 index 000000000..5179db4bf --- /dev/null +++ b/include/wlr/backend/drm.h @@ -0,0 +1,20 @@ +#ifndef WLR_BACKEND_DRM_H +#define WLR_BACKEND_DRM_H + +#include + +struct wlr_drm_backend; +struct wlr_drm_display; + +struct wlr_drm_backend *wlr_drm_backend_init(struct wl_listener *add, + struct wl_listener *rem, + struct wl_listener *render); +void wlr_drm_backend_free(struct wlr_drm_backend *backend); + +struct wl_event_loop *wlr_drm_backend_get_event_loop(struct wlr_drm_backend *backend); + +bool wlr_drm_display_modeset(struct wlr_drm_display *disp, const char *str); +void wlr_drm_display_begin(struct wlr_drm_display *disp); +void wlr_drm_display_end(struct wlr_drm_display *disp); + +#endif