commit 2a4a013
shrub
·
2026-08-09 23:01:22 +0000 UTC
parent ac63183
make drm optional, add fb video on linux fbdev
27 files changed,
+690,
-42
+7,
-4
1@@ -1,7 +1,7 @@
2 neuswc
3 ------
4
5-neuswc is a fork of [swc](https://github.com/michaelforney/swc/) created by [wayland.fyi](https://wayland.fyi). it provides an easy C library interface to make a wayland compositor. it is much smaller than alternatives like wlroots, and easier to use. it is also portable to linux, freebsd, netbsd, and openbsd. if you want tohelp with that (or anything else) submit a patch to the [mailing list](https://lists.sr.ht/~shrub900/neuswc)
6+neuswc is a fork of [swc](https://github.com/michaelforney/swc/) created by [wayland.fyi](https://wayland.fyi). it provides an easy C library interface to make a wayland compositor. it is much smaller than alternatives like wlroots, and easier to use. it is also portable to linux, freebsd, netbsd, and openbsd. if you want to help with that (or anything else) submit a patch to the [mailing list](https://lists.sr.ht/~shrub900/neuswc)
7
8 you can view a list of some compositors made with neuswc at the [wayland.fyi website.](https://wayland.fyi)
9
10@@ -20,6 +20,7 @@ neu features
11 - screenshots
12 - layer shell support
13 - window decorations
14+- framebuffer support
15
16 neuswc is in active development, we plan to add many more features, and increase compatibility with new wayland protocols.
17
18@@ -32,7 +33,8 @@ you will need:
19 - pkg-config
20 - wayland-scanner, wayland-server, wayland-client
21 - wayland-server, wayland-client
22-- libdrm, pixman, xkbcommon
23+- libdrm (if building with DRM support)
24+- pixman, xkbcommon
25 - [neuwld](https://git.sr.ht/~shrub900/neuwld)
26 - libinput on Linux and wscons on BSD
27 - xcb, xcb-composite, xcb-ewmh and xcb-icccm if you want Xwayland support.
28@@ -52,5 +54,6 @@ an extremely large thank you to [michael forney](https://mforney.org) for creati
29
30 repositories
31 ------------
32-[srcdump](https://srcdump.net/shrub/neuswc)
33-[sourcehut](https://git.sr.ht/~shrub900/neuswc)
34+
35+- [srcdump](https://srcdump.net/shrub/neuswc)
36+- [sourcehut](https://git.sr.ht/~shrub900/neuswc)
+8,
-0
1@@ -50,3 +50,11 @@ device_is_drm(dev_t rdev)
2 {
3 return major(rdev) == DRM_MAJOR;
4 }
5+
6+#ifdef ENABLE_FBDEV
7+bool
8+device_is_fbdev(dev_t rdev)
9+{
10+ return major(rdev) == FB_MAJOR;
11+}
12+#endif
+4,
-0
1@@ -33,4 +33,8 @@ bool device_is_tty(dev_t);
2
3 bool device_is_drm(dev_t);
4
5+#ifdef ENABLE_FBDEV
6+bool device_is_fbdev(dev_t);
7+#endif
8+
9 #endif
+21,
-1
1@@ -34,6 +34,7 @@
2 #include <poll.h>
3 #include <signal.h>
4 #include <spawn.h>
5+#include <stdarg.h>
6 #include <stdbool.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9@@ -69,7 +70,9 @@
10 #include <dev/wscons/wsdisplay_usl_io.h>
11 #endif
12
13+#ifdef ENABLE_DRM
14 #include <xf86drm.h>
15+#endif
16
17 #define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array)[0])
18
19@@ -81,7 +84,9 @@ deactivate(void);
20 static bool nflag;
21 static int sigfd[2], sock[2];
22 static int input_fds[128], num_input_fds;
23+#ifdef ENABLE_DRM
24 static int drm_fds[16], num_drm_fds;
25+#endif
26 static int tty_fd;
27 static bool active;
28
29@@ -123,6 +128,7 @@ die(const char *format, ...)
30 static void
31 start_devices(void)
32 {
33+#ifdef ENABLE_DRM
34 int i;
35
36 for (i = 0; i < num_drm_fds; ++i) {
37@@ -130,6 +136,7 @@ start_devices(void)
38 die("failed to set DRM master");
39 }
40 }
41+#endif
42 }
43
44 static void
45@@ -137,11 +144,13 @@ stop_devices(bool fatal)
46 {
47 int i;
48
49+#ifdef ENABLE_DRM
50 for (i = 0; i < num_drm_fds; ++i) {
51 if (drmDropMaster(drm_fds[i]) < 0 && fatal) {
52 die("drmDropMaster:");
53 }
54 }
55+#endif
56 for (i = 0; i < num_input_fds; ++i) {
57 #ifdef EVIOCREVOKE
58 if (ioctl(input_fds[i], EVIOCREVOKE, 0) < 0 && errno != ENODEV &&
59@@ -278,13 +287,24 @@ handle_socket_data(int socket)
60 #endif
61 input_fds[num_input_fds++] = fd;
62 } else if (device_is_drm(st.st_rdev)) {
63+#ifdef ENABLE_DRM
64 if (num_drm_fds == ARRAY_LENGTH(drm_fds)) {
65 fprintf(stderr, "too many DRM devices opened\n");
66 goto fail;
67 }
68 drm_fds[num_drm_fds++] = fd;
69+#else
70+ fprintf(stderr, "DRM device requested by non-DRM backend\n");
71+ goto fail;
72+#endif
73+#ifdef ENABLE_FBDEV
74+ } else if (device_is_fbdev(st.st_rdev)) {
75+ if (!active) {
76+ goto fail;
77+ }
78+#endif
79 } else {
80- fprintf(stderr, "requested fd is not a DRM or input device\n");
81+ fprintf(stderr, "requested fd is not a video or input device\n");
82 goto fail;
83 }
84 break;
+1,
-1
1@@ -1,7 +1,7 @@
2 launch_protocol = files('protocol.c')
3 executable('swc-launch',
4 ['launch.c', launch_protocol, 'devmajor-@0@.c'.format(os)],
5- dependencies: requires_private[0], # libdrm
6+ dependencies: video_backend == 'drm' ? drm : [],
7 install: true,
8 install_mode: 'rwsr-xr-x',
9 )
+17,
-0
1@@ -0,0 +1,17 @@
2+#ifndef SWC_BACKEND_H
3+#define SWC_BACKEND_H
4+
5+#include <stdint.h>
6+
7+struct wld_context;
8+struct wld_renderer;
9+
10+/* rendering state shared by the drm and fb backends */
11+struct swc_backend {
12+ struct wld_context *context;
13+ struct wld_renderer *renderer;
14+ uint32_t cursor_width;
15+ uint32_t cursor_height;
16+};
17+
18+#endif
+26,
-15
1@@ -28,9 +28,12 @@
2 */
3
4 #include "compositor.h"
5+#include "backend.h"
6 #include "data_device_manager.h"
7 #include "decor.h"
8+#ifdef ENABLE_DRM
9 #include "drm.h"
10+#endif
11 #include "event.h"
12 #include "internal.h"
13 #include "launch.h"
14@@ -52,7 +55,9 @@
15 #include <limits.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18+#ifdef ENABLE_DRM
19 #include <wld/drm.h>
20+#endif
21 #include <wld/wld.h>
22 #include <xkbcommon/xkbcommon-keysyms.h>
23
24@@ -214,8 +219,14 @@ target_new(struct screen *screen)
25 }
26
27 target->surface =
28- wld_create_surface(swc.drm->context, geom->width, geom->height,
29- WLD_FORMAT_XRGB8888, WLD_DRM_FLAG_SCANOUT);
30+ wld_create_surface(swc.backend->context, geom->width, geom->height,
31+ WLD_FORMAT_XRGB8888,
32+#ifdef ENABLE_DRM
33+ WLD_DRM_FLAG_SCANOUT
34+#else
35+ WLD_FLAG_MAP
36+#endif
37+ );
38
39 if (!target->surface) {
40 goto error1;
41@@ -290,7 +301,7 @@ repaint_view(struct target *target, struct compositor_view *view,
42 pixman_region32_translate(&buffer_damage,
43 -geom->x + view->buffer_offset_x,
44 -geom->y + view->buffer_offset_y);
45- wld_copy_region(swc.drm->renderer, view->buffer, buf_x - target_geom->x,
46+ wld_copy_region(swc.backend->renderer, view->buffer, buf_x - target_geom->x,
47 buf_y - target_geom->y, &buffer_damage);
48 }
49
50@@ -321,12 +332,12 @@ repaint_view(struct target *target, struct compositor_view *view,
51 if (view->border.outwidth > 0 && pixman_region32_not_empty(&out_border)) {
52 pixman_region32_translate(&out_border, -target_geom->x,
53 -target_geom->y);
54- wld_fill_region(swc.drm->renderer, view->border.outcolor, &out_border);
55+ wld_fill_region(swc.backend->renderer, view->border.outcolor, &out_border);
56 }
57
58 if (view->border.inwidth > 0 && pixman_region32_not_empty(&in_border)) {
59 pixman_region32_translate(&in_border, -target_geom->x, -target_geom->y);
60- wld_fill_region(swc.drm->renderer, view->border.incolor, &in_border);
61+ wld_fill_region(swc.backend->renderer, view->border.incolor, &in_border);
62 }
63
64 pixman_region32_fini(&border_damage);
65@@ -336,7 +347,7 @@ repaint_view(struct target *target, struct compositor_view *view,
66
67 if ((view->decor.top || view->decor.right || view->decor.bottom ||
68 view->decor.left)) {
69- decor_repaint(swc.drm->renderer, target_geom, view, damage);
70+ decor_repaint(swc.backend->renderer, target_geom, view, damage);
71 }
72 }
73
74@@ -400,12 +411,12 @@ renderer_repaint(struct target *target, pixman_region32_t *damage,
75 target->view->geometry.x, target->view->geometry.y,
76 target->view->geometry.width, target->view->geometry.height);
77
78- wld_set_target_surface(swc.drm->renderer, target->surface);
79+ wld_set_target_surface(swc.backend->renderer, target->surface);
80
81 if (pixman_region32_not_empty(base_damage)) {
82 pixman_region32_translate(base_damage, -target->view->geometry.x,
83 -target->view->geometry.y);
84- wld_fill_region(swc.drm->renderer, DEFAULT_BG,
85+ wld_fill_region(swc.backend->renderer, DEFAULT_BG,
86 base_damage);
87 }
88
89@@ -416,9 +427,9 @@ renderer_repaint(struct target *target, pixman_region32_t *damage,
90 }
91 }
92
93- draw_overlays(swc.drm->renderer, target_geom);
94+ draw_overlays(swc.backend->renderer, target_geom);
95
96- wld_flush(swc.drm->renderer);
97+ wld_flush(swc.backend->renderer);
98 }
99
100 static int
101@@ -427,7 +438,7 @@ renderer_attach(struct compositor_view *view, struct wld_buffer *client_buffer)
102 struct wld_buffer *buffer;
103 bool was_proxy = view->buffer != view->base.buffer;
104 bool needs_proxy =
105- client_buffer && !(wld_capabilities(swc.drm->renderer, client_buffer) &
106+ client_buffer && !(wld_capabilities(swc.backend->renderer, client_buffer) &
107 WLD_CAPABILITY_READ);
108 bool resized = view->buffer && client_buffer &&
109 (view->buffer->width != client_buffer->width ||
110@@ -440,7 +451,7 @@ renderer_attach(struct compositor_view *view, struct wld_buffer *client_buffer)
111 if (!was_proxy || resized) {
112 DEBUG("Creating a proxy buffer\n");
113 buffer = wld_create_buffer(
114- swc.drm->context, client_buffer->width,
115+ swc.backend->context, client_buffer->width,
116 client_buffer->height, client_buffer->format, WLD_FLAG_MAP);
117
118 if (!buffer) {
119@@ -1656,9 +1667,9 @@ update_screen(struct screen *screen)
120
121 pixman_region32_t full;
122 pixman_region32_init_rect(&full, 0, 0, geom->width, geom->height);
123- wld_set_target_surface(swc.drm->renderer, target->surface);
124- wld_copy_region(swc.drm->renderer, zoomed, 0, 0, &full);
125- wld_flush(swc.drm->renderer);
126+ wld_set_target_surface(swc.backend->renderer, target->surface);
127+ wld_copy_region(swc.backend->renderer, zoomed, 0, 0, &full);
128+ wld_flush(swc.backend->renderer);
129 pixman_region32_fini(&full);
130
131 wld_buffer_unreference(zoomed);
+2,
-1
1@@ -1,4 +1,5 @@
2 #include "decor.h"
3+#include "backend.h"
4
5 #include "compositor.h"
6 #include "drm.h"
7@@ -210,7 +211,7 @@ copy_decor_part(struct decor_part_buffer *dst, const struct swc_decor_part *src)
8 dst->height = src->height;
9 dst->stride = src->stride;
10 /* DRM renderers only allow read support for their native buffers not pixman/shmbuffers */
11- dst->buffer = wld_create_buffer(swc.drm->context, src->width, src->height,
12+ dst->buffer = wld_create_buffer(swc.backend->context, src->width, src->height,
13 WLD_FORMAT_ARGB8888, WLD_FLAG_MAP);
14 if (!dst->buffer) {
15 free(dst->data);
+5,
-0
1@@ -290,6 +290,9 @@ drm_initialize(void)
2 val = 64;
3 }
4 swc.drm->cursor_h = val;
5+ swc.backend = &swc.drm->backend;
6+ swc.backend->cursor_width = swc.drm->cursor_w;
7+ swc.backend->cursor_height = swc.drm->cursor_h;
8
9 drm.path = drmGetRenderDeviceNameFromFd(swc.drm->fd);
10 if (!drm.path) {
11@@ -306,6 +309,8 @@ drm_initialize(void)
12 ERROR("Could not create WLD DRM renderer\n");
13 goto error2;
14 }
15+ swc.backend->context = swc.drm->context;
16+ swc.backend->renderer = swc.drm->renderer;
17
18 drm.event_source = wl_event_loop_add_fd(
19 swc.event_loop, swc.drm->fd, WL_EVENT_READABLE, &handle_data, NULL);
+3,
-0
1@@ -1,6 +1,8 @@
2 #ifndef SWC_DRM_H
3 #define SWC_DRM_H
4
5+#include "backend.h"
6+
7 #include <stdbool.h>
8 #include <stdint.h>
9
10@@ -12,6 +14,7 @@ struct drm_handler {
11 };
12
13 struct swc_drm {
14+ struct swc_backend backend;
15 int fd;
16 uint32_t cursor_w, cursor_h;
17 struct wld_context *context;
+142,
-0
1@@ -0,0 +1,142 @@
2+#include "fb.h"
3+#include "internal.h"
4+#include "output.h"
5+#include "pointer.h"
6+#include "screen.h"
7+#include "seat.h"
8+#include "util.h"
9+
10+#include <stdlib.h>
11+#include <string.h>
12+#include <wayland-server.h>
13+#include <wld/pixman.h>
14+#include <wld/wld.h>
15+
16+struct swc_fb swc_fb;
17+
18+/* for the cursor */
19+static uint32_t
20+blend(uint32_t background, uint32_t foreground)
21+{
22+ uint32_t alpha = foreground >> 24;
23+ uint32_t inverse = 255 - alpha;
24+ uint32_t red = ((foreground >> 16) & 0xff) +
25+ (((background >> 16) & 0xff) * inverse + 127) / 255;
26+ uint32_t green = ((foreground >> 8) & 0xff) +
27+ (((background >> 8) & 0xff) * inverse + 127) / 255;
28+ uint32_t blue = (foreground & 0xff) +
29+ ((background & 0xff) * inverse + 127) / 255;
30+ return (MIN(red, 255) << 16) | (MIN(green, 255) << 8) | MIN(blue, 255);
31+}
32+
33+bool
34+fb_initialize(void)
35+{
36+ if (!fbdev_initialize(&swc_fb)) {
37+ return false;
38+ }
39+ swc_fb.pitch = (size_t)swc_fb.width * sizeof(*swc_fb.pixels);
40+ swc_fb.pixels = calloc(swc_fb.height, swc_fb.pitch);
41+ if (!swc_fb.pixels) {
42+ goto error0;
43+ }
44+ swc_fb.backend.context = wld_pixman_create_context();
45+ if (!swc_fb.backend.context) {
46+ goto error1;
47+ }
48+ swc_fb.backend.renderer = wld_create_renderer(swc_fb.backend.context);
49+ if (!swc_fb.backend.renderer) {
50+ goto error2;
51+ }
52+ swc_fb.backend.cursor_width = 64;
53+ swc_fb.backend.cursor_height = 64;
54+ swc.backend = &swc_fb.backend;
55+ return true;
56+
57+error2:
58+ wld_destroy_context(swc_fb.backend.context);
59+error1:
60+ free(swc_fb.pixels);
61+error0:
62+ fbdev_finalize(&swc_fb);
63+ return false;
64+}
65+
66+void
67+fb_finalize(void)
68+{
69+ wld_destroy_renderer(swc_fb.backend.renderer);
70+ wld_destroy_context(swc_fb.backend.context);
71+ free(swc_fb.pixels);
72+ fbdev_finalize(&swc_fb);
73+}
74+
75+bool
76+fb_create_screens(struct wl_list *screens)
77+{
78+ struct output *output;
79+ struct screen *screen;
80+
81+ output = output_new_fb(swc_fb.width, swc_fb.height, "fbdev-0");
82+ if (!output) {
83+ return false;
84+ }
85+ screen = screen_new(output);
86+ if (!screen) {
87+ output_destroy(output);
88+ return false;
89+ }
90+ screen->id = 0;
91+ output->screen = screen;
92+ wl_list_insert(screens, &screen->link);
93+ return true;
94+}
95+
96+bool
97+fb_present(struct wld_buffer *buffer, int32_t origin_x, int32_t origin_y)
98+{
99+ struct pointer *pointer = swc.seat ? swc.seat->pointer : NULL;
100+ struct wld_buffer *cursor = NULL;
101+ int32_t cursor_x = 0, cursor_y = 0;
102+ uint32_t width, height, x, y;
103+ bool cursor_mapped = false;
104+
105+ if (!buffer || !wld_map(buffer)) {
106+ return false;
107+ }
108+ if (pointer && pointer->cursor.view.buffer) {
109+ cursor = pointer->cursor.buffer;
110+ cursor_x = pointer->cursor.view.geometry.x - origin_x;
111+ cursor_y = pointer->cursor.view.geometry.y - origin_y;
112+ cursor_mapped = wld_map(cursor);
113+ }
114+
115+ width = buffer->width < swc_fb.width ? buffer->width : swc_fb.width;
116+ height = buffer->height < swc_fb.height ? buffer->height : swc_fb.height;
117+ if (width != swc_fb.width || height != swc_fb.height) {
118+ memset(swc_fb.pixels, 0, swc_fb.height * swc_fb.pitch);
119+ }
120+ for (y = 0; y < height; ++y) {
121+ uint32_t *source = (uint32_t *)((uint8_t *)buffer->map +
122+ (size_t)y * buffer->pitch);
123+ uint32_t *destination = (uint32_t *)((uint8_t *)swc_fb.pixels +
124+ (size_t)y * swc_fb.pitch);
125+ for (x = 0; x < width; ++x) {
126+ uint32_t pixel = source[x];
127+ int32_t cx = (int32_t)x - cursor_x;
128+ int32_t cy = (int32_t)y - cursor_y;
129+ if (cursor_mapped && cx >= 0 && cy >= 0 &&
130+ (uint32_t)cx < cursor->width && (uint32_t)cy < cursor->height) {
131+ uint32_t foreground = *(uint32_t *)((uint8_t *)cursor->map +
132+ (size_t)cy * cursor->pitch + (size_t)cx * 4);
133+ pixel = blend(pixel, foreground);
134+ }
135+ destination[x] = pixel;
136+ }
137+ }
138+ if (cursor_mapped) {
139+ wld_unmap(cursor);
140+ }
141+ wld_unmap(buffer);
142+ return fbdev_present(&swc_fb);
143+}
+32,
-0
1@@ -0,0 +1,32 @@
2+#ifndef SWC_FB_H
3+#define SWC_FB_H
4+
5+#include "backend.h"
6+
7+#include <stdbool.h>
8+#include <stddef.h>
9+#include <stdint.h>
10+
11+struct wl_list;
12+struct wld_buffer;
13+
14+struct swc_fb {
15+ struct swc_backend backend;
16+ uint32_t width;
17+ uint32_t height;
18+ uint32_t *pixels;
19+ size_t pitch;
20+};
21+
22+extern struct swc_fb swc_fb;
23+
24+bool fb_initialize(void);
25+void fb_finalize(void);
26+bool fb_create_screens(struct wl_list *screens);
27+bool fb_present(struct wld_buffer *buffer, int32_t x, int32_t y);
28+
29+bool fbdev_initialize(struct swc_fb *fb);
30+void fbdev_finalize(struct swc_fb *fb);
31+bool fbdev_present(struct swc_fb *fb);
32+
33+#endif
+185,
-0
1@@ -0,0 +1,185 @@
2+#include "fb.h"
3+#include "launch.h"
4+#include "util.h"
5+
6+#include <fcntl.h>
7+#include <linux/fb.h>
8+#include <stdint.h>
9+#include <string.h>
10+#include <sys/ioctl.h>
11+#include <sys/mman.h>
12+#include <unistd.h>
13+
14+struct fb_channel {
15+ uint8_t offset;
16+ uint8_t length;
17+};
18+
19+static struct {
20+ int fd;
21+ void *memory;
22+ size_t memory_length;
23+ size_t memory_offset;
24+ uint32_t pitch;
25+ uint8_t bits_per_pixel;
26+ struct fb_channel red;
27+ struct fb_channel green;
28+ struct fb_channel blue;
29+} fbdev;
30+
31+static struct fb_channel
32+channel_from_fbdev(struct fb_bitfield field)
33+{
34+ return (struct fb_channel) {
35+ .offset = field.offset,
36+ .length = field.length,
37+ };
38+}
39+
40+bool
41+fbdev_initialize(struct swc_fb *fb)
42+{
43+ struct fb_fix_screeninfo fixed;
44+ struct fb_var_screeninfo variable;
45+ size_t visible_offset;
46+
47+ memset(&fbdev, 0, sizeof(fbdev));
48+ fbdev.fd = launch_open_device(FBDEV_DEVICE, O_RDWR | O_CLOEXEC);
49+ if (fbdev.fd < 0) {
50+ ERROR("Could not open framebuffer device %s\n", FBDEV_DEVICE);
51+ return false;
52+ }
53+ if (ioctl(fbdev.fd, FBIOGET_FSCREENINFO, &fixed) < 0 ||
54+ ioctl(fbdev.fd, FBIOGET_VSCREENINFO, &variable) < 0) {
55+ ERROR("Could not query framebuffer device %s\n", FBDEV_DEVICE);
56+ goto error;
57+ }
58+ if (variable.bits_per_pixel != 16 && variable.bits_per_pixel != 24 &&
59+ variable.bits_per_pixel != 32) {
60+ ERROR("Unsupported fbdev depth: %u bits per pixel\n",
61+ variable.bits_per_pixel);
62+ goto error;
63+ }
64+ if (fixed.type != FB_TYPE_PACKED_PIXELS ||
65+ (fixed.visual != FB_VISUAL_TRUECOLOR &&
66+ fixed.visual != FB_VISUAL_DIRECTCOLOR)) {
67+ ERROR("Unsupported fbdev framebuffer type or visual\n");
68+ goto error;
69+ }
70+
71+ if (!variable.xres || !variable.yres || variable.xres > UINT16_MAX ||
72+ variable.yres > UINT16_MAX ||
73+ variable.red.msb_right || variable.green.msb_right ||
74+ variable.blue.msb_right ||
75+ variable.red.length > 16 || variable.green.length > 16 ||
76+ variable.blue.length > 16 ||
77+ variable.red.offset + variable.red.length > variable.bits_per_pixel ||
78+ variable.green.offset + variable.green.length > variable.bits_per_pixel ||
79+ variable.blue.offset + variable.blue.length > variable.bits_per_pixel) {
80+ ERROR("Unsupported fbdev geometry or channel layout\n");
81+ goto error;
82+ }
83+ fbdev.memory_length = fixed.smem_len;
84+ fbdev.memory = mmap(NULL, fbdev.memory_length, PROT_READ | PROT_WRITE,
85+ MAP_SHARED, fbdev.fd, 0);
86+ if (fbdev.memory == MAP_FAILED) {
87+ fbdev.memory = NULL;
88+ ERROR("Could not map framebuffer device %s\n", FBDEV_DEVICE);
89+ goto error;
90+ }
91+
92+ fb->width = variable.xres;
93+ fb->height = variable.yres;
94+ fbdev.pitch = fixed.line_length;
95+ fbdev.bits_per_pixel = variable.bits_per_pixel;
96+ fbdev.red = channel_from_fbdev(variable.red);
97+ fbdev.green = channel_from_fbdev(variable.green);
98+ fbdev.blue = channel_from_fbdev(variable.blue);
99+ visible_offset = (size_t)variable.yoffset * fbdev.pitch +
100+ (size_t)variable.xoffset * variable.bits_per_pixel / 8;
101+ if (fixed.line_length < (size_t)variable.xres * variable.bits_per_pixel / 8 ||
102+ visible_offset >= fbdev.memory_length ||
103+ (size_t)(variable.yres - 1) * fixed.line_length >
104+ fbdev.memory_length - visible_offset ||
105+ (size_t)variable.xres * variable.bits_per_pixel / 8 >
106+ fbdev.memory_length - visible_offset -
107+ (size_t)(variable.yres - 1) * fixed.line_length) {
108+ ERROR("fbdev visible buffer lies outside its mapping\n");
109+ goto error;
110+ }
111+ fbdev.memory_offset = visible_offset;
112+ return true;
113+
114+error:
115+ if (fbdev.memory) {
116+ munmap(fbdev.memory, fbdev.memory_length);
117+ }
118+ close(fbdev.fd);
119+ fbdev.fd = -1;
120+ return false;
121+}
122+
123+void
124+fbdev_finalize(struct swc_fb *fb)
125+{
126+ (void)fb;
127+ munmap(fbdev.memory, fbdev.memory_length);
128+ close(fbdev.fd);
129+}
130+
131+static uint32_t
132+channel(uint8_t value, struct fb_channel field)
133+{
134+ uint32_t maximum;
135+
136+ if (!field.length) {
137+ return 0;
138+ }
139+ maximum = field.length >= 32 ? UINT32_MAX : (1u << field.length) - 1;
140+ return (((uint32_t)value * maximum + 127) / 255) << field.offset;
141+}
142+
143+static uint32_t
144+native_pixel(uint32_t pixel)
145+{
146+ return channel(pixel >> 16, fbdev.red) |
147+ channel(pixel >> 8, fbdev.green) |
148+ channel(pixel, fbdev.blue);
149+}
150+
151+static void
152+store_pixel(uint8_t *destination, uint32_t pixel)
153+{
154+ uint32_t native = native_pixel(pixel);
155+
156+ if (fbdev.bits_per_pixel == 24) {
157+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
158+ destination[0] = native >> 16;
159+ destination[1] = native >> 8;
160+ destination[2] = native;
161+#else
162+ destination[0] = native;
163+ destination[1] = native >> 8;
164+ destination[2] = native >> 16;
165+#endif
166+ } else {
167+ memcpy(destination, &native, fbdev.bits_per_pixel / 8);
168+ }
169+}
170+
171+bool
172+fbdev_present(struct swc_fb *fb)
173+{
174+ uint32_t bytes = fbdev.bits_per_pixel / 8;
175+ uint32_t x, y;
176+
177+ for (y = 0; y < fb->height; ++y) {
178+ uint32_t *source = (uint32_t *)((uint8_t *)fb->pixels + y * fb->pitch);
179+ uint8_t *destination = (uint8_t *)fbdev.memory + fbdev.memory_offset +
180+ (size_t)y * fbdev.pitch;
181+ for (x = 0; x < fb->width; ++x) {
182+ store_pixel(destination + (size_t)x * bytes, source[x]);
183+ }
184+ }
185+ return true;
186+}
+3,
-0
1@@ -44,7 +44,10 @@ struct swc {
2 struct wl_list screens;
3 struct swc_compositor *const compositor;
4 struct swc_shm *shm;
5+#ifdef ENABLE_DRM
6 struct swc_drm *const drm;
7+#endif
8+ struct swc_backend *backend;
9 struct wl_global *data_device_manager;
10 struct wl_global *kde_decoration_manager;
11 struct wl_global *layer_shell;
+3,
-3
1@@ -7,8 +7,6 @@ libswc_src = files(
2 'data_device.c',
3 'data_device_manager.c',
4 'decor.c',
5- 'dmabuf.c',
6- 'drm.c',
7 'input.c',
8 'kde_decoration.c',
9 'keyboard.c',
10@@ -18,7 +16,6 @@ libswc_src = files(
11 'output.c',
12 'panel.c',
13 'panel_manager.c',
14- 'plane.c',
15 'pointer.c',
16 'primary_plane.c',
17 'region.c',
18@@ -44,6 +41,9 @@ libswc_src = files(
19 input_backend == 'wscons' ? 'seat-ws.c' : [],
20
21 xwayland.found() ? ['xserver.c', 'xwm.c'] : [],
22+
23+ video_backend == 'drm' ? ['dmabuf.c', 'drm.c', 'plane.c'] : [],
24+ video_backend == 'fb' ? ['fb.c', 'fb_fbdev.c'] : [],
25 )
26 libswc_src += [cursor, launch_protocol]
27
+12,
-0
1@@ -23,6 +23,7 @@
2
3 #include "mode.h"
4
5+#ifdef ENABLE_DRM
6 bool
7 mode_initialize(struct mode *mode, drmModeModeInfo *mode_info)
8 {
9@@ -33,6 +34,17 @@ mode_initialize(struct mode *mode, drmModeModeInfo *mode_info)
10 mode->info = *mode_info;
11 return true;
12 }
13+#endif
14+
15+void
16+mode_initialize_simple(struct mode *mode, uint16_t width, uint16_t height,
17+ uint32_t refresh)
18+{
19+ mode->width = width;
20+ mode->height = height;
21+ mode->refresh = refresh;
22+ mode->preferred = true;
23+}
24
25 bool
26 mode_equal(const struct mode *mode1, const struct mode *mode2)
+9,
-0
1@@ -27,7 +27,9 @@
2 #include <stdbool.h>
3 #include <stddef.h>
4 #include <stdint.h>
5+#ifdef ENABLE_DRM
6 #include <xf86drmMode.h>
7+#endif
8
9 struct mode {
10 uint16_t width, height;
11@@ -35,11 +37,18 @@ struct mode {
12
13 bool preferred;
14
15+#ifdef ENABLE_DRM
16 drmModeModeInfo info;
17+#endif
18 };
19
20+#ifdef ENABLE_DRM
21 bool
22 mode_initialize(struct mode *mode, drmModeModeInfo *mode_info);
23+#endif
24+void
25+mode_initialize_simple(struct mode *mode, uint16_t width, uint16_t height,
26+ uint32_t refresh);
27 bool
28 mode_equal(const struct mode *mode1, const struct mode *mode2);
29
+38,
-1
1@@ -1,15 +1,19 @@
2 #include "output.h"
3+#ifdef ENABLE_DRM
4 #include "drm.h"
5+#endif
6 #include "internal.h"
7 #include "mode.h"
8 #include "screen.h"
9 #include "util.h"
10
11+#ifdef ENABLE_DRM
12 #include <drm.h>
13+#include <xf86drm.h>
14+#endif
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18-#include <xf86drm.h>
19
20 static const struct wl_output_interface output_impl = {
21 .release = destroy_resource,
22@@ -65,6 +69,7 @@ bind_output(struct wl_client *client, void *data, uint32_t version, uint32_t id)
23 }
24 }
25
26+#ifdef ENABLE_DRM
27 struct output *
28 output_new(drmModeConnectorPtr connector)
29 {
30@@ -132,6 +137,38 @@ error1:
31 error0:
32 return NULL;
33 }
34+#endif
35+
36+struct output *
37+output_new_fb(uint32_t width, uint32_t height, const char *name)
38+{
39+ struct output *output;
40+ struct mode *mode;
41+
42+ output = calloc(1, sizeof(*output));
43+ if (!output) {
44+ return NULL;
45+ }
46+ output->global = wl_global_create(swc.display, &wl_output_interface, 4,
47+ output, &bind_output);
48+ if (!output->global) {
49+ free(output);
50+ return NULL;
51+ }
52+ wl_list_init(&output->resources);
53+ wl_array_init(&output->modes);
54+ pixman_region32_init(&output->current_damage);
55+ pixman_region32_init(&output->previous_damage);
56+ mode = wl_array_add(&output->modes, sizeof(*mode));
57+ if (!mode) {
58+ output_destroy(output);
59+ return NULL;
60+ }
61+ mode_initialize_simple(mode, width, height, 60000);
62+ output->preferred_mode = mode;
63+ snprintf(output->name, sizeof(output->name), "%s", name);
64+ return output;
65+}
66
67 void
68 output_destroy(struct output *output)
+8,
-0
1@@ -4,7 +4,9 @@
2 #include <pixman.h>
3 #include <stdint.h>
4 #include <wayland-util.h>
5+#ifdef ENABLE_DRM
6 #include <xf86drmMode.h>
7+#endif
8
9 struct wl_display;
10
11@@ -21,16 +23,22 @@ struct output {
12
13 pixman_region32_t current_damage, previous_damage;
14
15+#ifdef ENABLE_DRM
16 /* The DRM connector corresponding to this output */
17 uint32_t connector;
18+#endif
19
20 struct wl_global *global;
21 struct wl_list resources;
22 struct wl_list link;
23 };
24
25+#ifdef ENABLE_DRM
26 struct output *
27 output_new(drmModeConnector *connector);
28+#endif
29+struct output *
30+output_new_fb(uint32_t width, uint32_t height, const char *name);
31 void
32 output_destroy(struct output *output);
33
+23,
-6
1@@ -22,11 +22,14 @@
2 */
3
4 #include "pointer.h"
5+#include "backend.h"
6 #include "compositor.h"
7 #include "cursor/cursor_data.h"
8 #include "event.h"
9 #include "internal.h"
10+#ifdef ENABLE_DRM
11 #include "plane.h"
12+#endif
13 #include "screen.h"
14 #include "seat.h"
15 #include "shm.h"
16@@ -175,7 +178,9 @@ attach(struct view *view, struct wld_buffer *buffer)
17 {
18 struct pointer *pointer = wl_container_of(view, pointer, cursor.view);
19 struct surface *surface = pointer->cursor.surface;
20+#ifdef ENABLE_DRM
21 struct screen *screen;
22+#endif
23
24 if (surface && !pixman_region32_not_empty(&surface->state.damage)) {
25 return 0;
26@@ -203,12 +208,15 @@ attach(struct view *view, struct wld_buffer *buffer)
27 view_update_screens(view);
28 }
29
30- wl_list_for_each(screen, &swc.screens, link)
31- {
32+#ifdef ENABLE_DRM
33+ wl_list_for_each(screen, &swc.screens, link) {
34 view_attach(&screen->planes.cursor->view,
35 buffer ? pointer->cursor.buffer : NULL);
36 view_update(&screen->planes.cursor->view);
37 }
38+#else
39+ compositor_damage_all();
40+#endif
41
42 return 0;
43 }
44@@ -216,18 +224,23 @@ attach(struct view *view, struct wld_buffer *buffer)
45 static bool
46 move(struct view *view, int32_t x, int32_t y)
47 {
48+#ifdef ENABLE_DRM
49 struct screen *screen;
50+#endif
51
52 if (view_set_position(view, x, y)) {
53 view_update_screens(view);
54 }
55
56- wl_list_for_each(screen, &swc.screens, link)
57- {
58+#ifdef ENABLE_DRM
59+ wl_list_for_each(screen, &swc.screens, link) {
60 view_move(&screen->planes.cursor->view, view->geometry.x,
61 view->geometry.y);
62 view_update(&screen->planes.cursor->view);
63 }
64+#else
65+ compositor_damage_all();
66+#endif
67
68 return true;
69 }
70@@ -509,7 +522,8 @@ pointer_initialize(struct pointer *pointer)
71 pointer->cursor.surface = NULL;
72 pointer->cursor.destroy_listener.notify = &handle_cursor_surface_destroy;
73 pointer->cursor.buffer = wld_create_buffer(
74- swc.drm->context, swc.drm->cursor_w, swc.drm->cursor_h,
75+ swc.backend->context, swc.backend->cursor_width,
76+ swc.backend->cursor_height,
77 WLD_FORMAT_ARGB8888, WLD_FLAG_MAP | WLD_FLAG_CURSOR);
78 pointer->cursor.internal_buffer = NULL;
79
80@@ -519,8 +533,11 @@ pointer_initialize(struct pointer *pointer)
81
82 pointer_set_cursor(pointer, cursor_left_ptr);
83
84+#ifdef ENABLE_DRM
85 wl_list_for_each(screen, &swc.screens, link)
86- view_attach(&screen->planes.cursor->view, pointer->cursor.buffer);
87+ if (screen->planes.cursor)
88+ view_attach(&screen->planes.cursor->view, pointer->cursor.buffer);
89+#endif
90
91 input_focus_initialize(&pointer->focus, &pointer->focus_handler);
92 pixman_region32_init(&pointer->region);
+42,
-2
1@@ -22,17 +22,24 @@
2 */
3
4 #include "primary_plane.h"
5-#include "drm.h"
6 #include "event.h"
7+#ifdef ENABLE_DRM
8+#include "drm.h"
9+#else
10+#include "compositor.h"
11+#include "fb.h"
12+#endif
13 #include "internal.h"
14 #include "launch.h"
15 #include "util.h"
16
17+#ifdef ENABLE_DRM
18 #include <errno.h>
19 #include <wld/drm.h>
20-#include <wld/wld.h>
21 #include <xf86drm.h>
22 #include <xf86drmMode.h>
23+#endif
24+#include <wld/wld.h>
25
26 static bool
27 update(struct view *view)
28@@ -52,6 +59,7 @@ static int
29 attach(struct view *view, struct wld_buffer *buffer)
30 {
31 struct primary_plane *plane = wl_container_of(view, plane, view);
32+#ifdef ENABLE_DRM
33 uint32_t fb;
34 int ret;
35
36@@ -80,6 +88,13 @@ attach(struct view *view, struct wld_buffer *buffer)
37 }
38
39 return 0;
40+#else
41+ if (!fb_present(buffer, view->geometry.x, view->geometry.y)) {
42+ return -1;
43+ }
44+ wl_event_loop_add_idle(swc.event_loop, &send_frame, plane);
45+ return 0;
46+#endif
47 }
48
49 static bool
50@@ -95,12 +110,14 @@ static const struct view_impl view_impl = {
51 .move = move,
52 };
53
54+#ifdef ENABLE_DRM
55 static void
56 handle_page_flip(struct drm_handler *handler, uint32_t time)
57 {
58 struct primary_plane *plane = wl_container_of(handler, plane, drm_handler);
59 view_frame(&plane->view, time);
60 }
61+#endif
62
63 static void
64 handle_swc_event(struct wl_listener *listener, void *data)
65@@ -111,16 +128,25 @@ handle_swc_event(struct wl_listener *listener, void *data)
66
67 switch (event->type) {
68 case SWC_EVENT_ACTIVATED:
69+#ifdef ENABLE_DRM
70 plane->need_modeset = true;
71+#else
72+ compositor_damage_all();
73+#endif
74 break;
75 }
76 }
77
78 bool
79+#ifdef ENABLE_DRM
80 primary_plane_initialize(struct primary_plane *plane, uint32_t crtc,
81 struct mode *mode, uint32_t *connectors,
82 uint32_t num_connectors)
83+#else
84+primary_plane_initialize(struct primary_plane *plane, struct mode *mode)
85+#endif
86 {
87+#ifdef ENABLE_DRM
88 uint32_t *plane_connectors;
89
90 if (!(plane->original_crtc_state = drmModeGetCrtc(swc.drm->fd, crtc))) {
91@@ -148,22 +174,36 @@ primary_plane_initialize(struct primary_plane *plane, uint32_t crtc,
92 plane->drm_handler.page_flip = &handle_page_flip;
93 plane->swc_listener.notify = &handle_swc_event;
94 plane->mode = *mode;
95+#else
96+ view_initialize(&plane->view, &view_impl);
97+ plane->view.geometry.width = mode->width;
98+ plane->view.geometry.height = mode->height;
99+ plane->mode = *mode;
100+#endif
101+ plane->swc_listener.notify = &handle_swc_event;
102 wl_signal_add(&swc.event_signal, &plane->swc_listener);
103
104 return true;
105
106+#ifdef ENABLE_DRM
107 error1:
108 drmModeFreeCrtc(plane->original_crtc_state);
109 error0:
110 return false;
111+#endif
112 }
113
114 void
115 primary_plane_finalize(struct primary_plane *plane)
116 {
117+ wl_list_remove(&plane->swc_listener.link);
118+#ifdef ENABLE_DRM
119 wl_array_release(&plane->connectors);
120 drmModeCrtcPtr crtc = plane->original_crtc_state;
121 drmModeSetCrtc(swc.drm->fd, crtc->crtc_id, crtc->buffer_id, crtc->x,
122 crtc->y, NULL, 0, &crtc->mode);
123 drmModeFreeCrtc(crtc);
124+#else
125+ (void)plane;
126+#endif
127 }
+12,
-1
1@@ -24,29 +24,40 @@
2 #ifndef SWC_PRIMARY_PLANE_H
3 #define SWC_PRIMARY_PLANE_H
4
5-#include "drm.h"
6 #include "mode.h"
7 #include "view.h"
8+#ifdef ENABLE_DRM
9+#include "drm.h"
10+#endif
11
12 #include <stdbool.h>
13 #include <stdint.h>
14 #include <wayland-server.h>
15
16 struct primary_plane {
17+#ifdef ENABLE_DRM
18 uint32_t crtc;
19 drmModeCrtcPtr original_crtc_state;
20+#endif
21 struct mode mode;
22 struct view view;
23+#ifdef ENABLE_DRM
24 struct wl_array connectors;
25 bool need_modeset;
26 struct drm_handler drm_handler;
27+#endif
28 struct wl_listener swc_listener;
29 };
30
31+#ifdef ENABLE_DRM
32 bool
33 primary_plane_initialize(struct primary_plane *plane, uint32_t crtc,
34 struct mode *mode, uint32_t *connectors,
35 uint32_t num_connectors);
36+#else
37+bool
38+primary_plane_initialize(struct primary_plane *plane, struct mode *mode);
39+#endif
40 void
41 primary_plane_finalize(struct primary_plane *plane);
42
+31,
-3
1@@ -22,12 +22,18 @@
2 */
3
4 #include "screen.h"
5+#ifdef ENABLE_DRM
6 #include "drm.h"
7+#else
8+#include "fb.h"
9+#endif
10 #include "event.h"
11 #include "internal.h"
12 #include "mode.h"
13 #include "output.h"
14+#ifdef ENABLE_DRM
15 #include "plane.h"
16+#endif
17 #include "pointer.h"
18 #include "util.h"
19
20@@ -65,7 +71,13 @@ screens_initialize(void)
21 {
22 wl_list_init(&swc.screens);
23
24- if (!drm_create_screens(&swc.screens)) {
25+ if (!
26+#ifdef ENABLE_DRM
27+ drm_create_screens(&swc.screens)
28+#else
29+ fb_create_screens(&swc.screens)
30+#endif
31+ ) {
32 return false;
33 }
34
35@@ -103,7 +115,11 @@ bind_screen(struct wl_client *client, void *data, uint32_t version, uint32_t id)
36 }
37
38 struct screen *
39+#ifdef ENABLE_DRM
40 screen_new(uint32_t crtc, struct output *output, struct plane *cursor_plane)
41+#else
42+screen_new(struct output *output)
43+#endif
44 {
45 struct screen *screen;
46 int32_t x = 0;
47@@ -124,8 +140,8 @@ screen_new(uint32_t crtc, struct output *output, struct plane *cursor_plane)
48 goto error1;
49 }
50
51+#ifdef ENABLE_DRM
52 screen->crtc = crtc;
53-
54 if (!primary_plane_initialize(&screen->planes.primary,
55 crtc,
56 output->preferred_mode,
57@@ -137,6 +153,14 @@ screen_new(uint32_t crtc, struct output *output, struct plane *cursor_plane)
58
59 cursor_plane->screen = screen;
60 screen->planes.cursor = cursor_plane;
61+#else
62+ if (!primary_plane_initialize(&screen->planes.primary,
63+ output->preferred_mode)) {
64+ ERROR("Failed to initialize primary plane\n");
65+ goto error2;
66+ }
67+ screen->planes.cursor = NULL;
68+#endif
69
70 screen->handler = &null_handler;
71 wl_signal_init(&screen->destroy_signal);
72@@ -176,7 +200,11 @@ screen_destroy(struct screen *screen)
73 wl_list_for_each_safe(output, next, &screen->outputs, link)
74 output_destroy(output);
75 primary_plane_finalize(&screen->planes.primary);
76- plane_destroy(screen->planes.cursor);
77+#ifdef ENABLE_DRM
78+ if (screen->planes.cursor) {
79+ plane_destroy(screen->planes.cursor);
80+ }
81+#endif
82 free(screen);
83 }
84
+7,
-0
1@@ -51,7 +51,9 @@ struct screen {
2
3 struct wl_signal destroy_signal;
4 uint8_t id;
5+#ifdef ENABLE_DRM
6 uint32_t crtc;
7+#endif
8
9 struct {
10 struct primary_plane primary;
11@@ -71,8 +73,13 @@ screens_initialize(void);
12 void
13 screens_finalize(void);
14
15+#ifdef ENABLE_DRM
16 struct screen *
17 screen_new(uint32_t crtc, struct output *output, struct plane *cursor_plane);
18+#else
19+struct screen *
20+screen_new(struct output *output);
21+#endif
22 void
23 screen_destroy(struct screen *screen);
24
+24,
-2
1@@ -25,7 +25,11 @@
2 #include "bindings.h"
3 #include "compositor.h"
4 #include "data_device_manager.h"
5+#ifdef ENABLE_DRM
6 #include "drm.h"
7+#else
8+#include "fb.h"
9+#endif
10 #include "event.h"
11 #include "internal.h"
12 #include "kde_decoration.h"
13@@ -53,7 +57,9 @@
14 extern struct swc_launch swc_launch;
15 extern const struct swc_bindings swc_bindings;
16 extern struct swc_compositor swc_compositor;
17+#ifdef ENABLE_DRM
18 extern struct swc_drm swc_drm;
19+#endif
20 #ifdef ENABLE_XWAYLAND
21 extern struct swc_xserver swc_xserver;
22 #endif
23@@ -63,7 +69,9 @@ extern struct pointer_handler screens_pointer_handler;
24 struct swc swc = {
25 .bindings = &swc_bindings,
26 .compositor = &swc_compositor,
27+#ifdef ENABLE_DRM
28 .drm = &swc_drm,
29+#endif
30 #ifdef ENABLE_XWAYLAND
31 .xserver = &swc_xserver,
32 #endif
33@@ -160,8 +168,14 @@ swc_initialize(struct wl_display *display, struct wl_event_loop *event_loop,
34 goto error0;
35 }
36
37- if (!drm_initialize()) {
38- ERROR("Could not initialize DRM\n");
39+ if (!
40+#ifdef ENABLE_DRM
41+ drm_initialize()
42+#else
43+ fb_initialize()
44+#endif
45+ ) {
46+ ERROR("Could not initialize video backend\n");
47 goto error1;
48 }
49
50@@ -302,7 +316,11 @@ error4:
51 error3:
52 shm_destroy(swc.shm);
53 error2:
54+#ifdef ENABLE_DRM
55 drm_finalize();
56+#else
57+ fb_finalize();
58+#endif
59 error1:
60 launch_finalize();
61 error0:
62@@ -329,6 +347,10 @@ swc_finalize(void)
63 screens_finalize();
64 bindings_finalize();
65 shm_destroy(swc.shm);
66+#ifdef ENABLE_DRM
67 drm_finalize();
68+#else
69+ fb_finalize();
70+#endif
71 launch_finalize();
72 }
+23,
-2
1@@ -31,14 +31,34 @@ requires = [
2 dependency('wayland-server', version: '>=1.6.0'),
3 ]
4 requires_private = [
5- dependency('libdrm'),
6 dependency('pixman-1'),
7 dependency('wayland-protocols'),
8 dependency('wld'),
9 dependency('xkbcommon'),
10 ]
11
12-xwayland = dependency('xwayland', required: get_option('xwayland'))
13+video_backend = get_option('video')
14+drm = disabler()
15+if video_backend == 'drm'
16+ drm = dependency('libdrm')
17+ requires_private += drm
18+ add_project_arguments('-DENABLE_DRM=1', language: 'c')
19+elif video_backend == 'fb'
20+ if os != 'linux'
21+ error('The fb video backend is currently supported only on Linux')
22+ endif
23+ add_project_arguments([
24+ '-DENABLE_FBDEV=1',
25+ '-DFBDEV_DEVICE="@0@"'.format(get_option('fbdev-device')),
26+ ], language: 'c')
27+endif
28+
29+if video_backend != 'drm' and get_option('xwayland').enabled()
30+ error('Xwayland requires the DRM video backend')
31+endif
32+xwayland = video_backend == 'drm' \
33+ ? dependency('xwayland', required: get_option('xwayland')) \
34+ : disabler()
35 xwayland_deps = [
36 'xcb',
37 'xcb-composite',
38@@ -93,4 +113,5 @@ endif
39 summary({
40 'Xwayland support': xwayland.found(),
41 'Input backend': input_backend,
42+ 'Video backend': video_backend,
43 }, bool_yn: true)
+2,
-0
1@@ -1,5 +1,7 @@
2 option('xwayland', type: 'feature', value: 'auto', description: 'Automatic Xwayland handling')
3 option('input', type: 'combo', value: 'auto', choices: ['auto', 'libinput', 'wscons'], description: 'Input backend to use')
4+option('video', type: 'combo', value: 'drm', choices: ['drm', 'fb'], description: 'Video backend to use')
5+option('fbdev-device', type: 'string', value: '/dev/fb0', description: 'Linux framebuffer device')
6 option('udev', type: 'feature', value: 'auto', description: 'libinput libudev support')
7 option('extra', type: 'boolean', value: true, description: 'Build swc utility applications')
8 option('example', type: 'boolean', value: false, description: 'Build swc example compositor')