Skip to content
This repository has been archived by the owner on Nov 1, 2021. It is now read-only.

Pixman renderer #2661

Merged
merged 7 commits into from Apr 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
98 changes: 66 additions & 32 deletions backend/wayland/backend.c
Expand Up @@ -20,6 +20,8 @@
#include "backend/wayland.h"
#include "render/drm_format_set.h"
#include "render/gbm_allocator.h"
#include "render/pixel_format.h"
#include "render/shm_allocator.h"
#include "render/wlr_renderer.h"
#include "util/signal.h"

Expand Down Expand Up @@ -190,6 +192,17 @@ static const struct wl_drm_listener legacy_drm_listener = {
.capabilities = legacy_drm_handle_capabilities,
};

static void shm_handle_format(void *data, struct wl_shm *shm,
uint32_t shm_format) {
struct wlr_wl_backend *wl = data;
uint32_t drm_format = convert_wl_shm_format_to_drm(shm_format);
wlr_drm_format_set_add(&wl->shm_formats, drm_format, DRM_FORMAT_MOD_INVALID);
}

static const struct wl_shm_listener shm_listener = {
.format = shm_handle_format,
};

static void registry_global(void *data, struct wl_registry *registry,
uint32_t name, const char *iface, uint32_t version) {
struct wlr_wl_backend *wl = data;
Expand Down Expand Up @@ -233,6 +246,9 @@ static void registry_global(void *data, struct wl_registry *registry,
} else if (strcmp(iface, wl_drm_interface.name) == 0) {
wl->legacy_drm = wl_registry_bind(registry, name, &wl_drm_interface, 1);
wl_drm_add_listener(wl->legacy_drm, &legacy_drm_listener, wl);
} else if (strcmp(iface, wl_shm_interface.name) == 0) {
wl->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
wl_shm_add_listener(wl->shm, &shm_listener, wl);
}
}

Expand Down Expand Up @@ -302,6 +318,7 @@ static void backend_destroy(struct wlr_backend *backend) {
wlr_allocator_destroy(wl->allocator);
close(wl->drm_fd);

wlr_drm_format_set_finish(&wl->shm_formats);
wlr_drm_format_set_finish(&wl->linux_dmabuf_v1_formats);

struct wlr_wl_buffer *buffer, *tmp_buffer;
Expand All @@ -322,6 +339,9 @@ static void backend_destroy(struct wlr_backend *backend) {
if (wl->zwp_linux_dmabuf_v1) {
zwp_linux_dmabuf_v1_destroy(wl->zwp_linux_dmabuf_v1);
}
if (wl->shm) {
wl_shm_destroy(wl->shm);
}
if (wl->zwp_relative_pointer_manager_v1) {
zwp_relative_pointer_manager_v1_destroy(wl->zwp_relative_pointer_manager_v1);
}
Expand Down Expand Up @@ -405,11 +425,6 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
"Remote Wayland compositor does not support xdg-shell");
goto error_registry;
}
if (!wl->drm_render_name) {
wlr_log(WLR_ERROR, "Failed to get DRM render node from remote Wayland "
"compositor wl_drm interface");
goto error_registry;
}

struct wl_event_loop *loop = wl_display_get_event_loop(wl->local_display);
int fd = wl_display_get_fd(wl->remote_display);
Expand All @@ -421,49 +436,68 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
}
wl_event_source_check(wl->remote_display_src);

wlr_log(WLR_DEBUG, "Opening DRM render node %s", wl->drm_render_name);
wl->drm_fd = open(wl->drm_render_name, O_RDWR | O_NONBLOCK | O_CLOEXEC);
if (wl->drm_fd < 0) {
wlr_log_errno(WLR_ERROR, "Failed to open DRM render node %s",
wl->drm_render_name);
goto error_remote_display_src;
}
wl->drm_fd = -1;
if (wl->drm_render_name != NULL) {
wlr_log(WLR_DEBUG, "Opening DRM render node %s", wl->drm_render_name);
wl->drm_fd = open(wl->drm_render_name, O_RDWR | O_NONBLOCK | O_CLOEXEC);
if (wl->drm_fd < 0) {
wlr_log_errno(WLR_ERROR, "Failed to open DRM render node %s",
wl->drm_render_name);
goto error_remote_display_src;
}

int drm_fd = fcntl(wl->drm_fd, F_DUPFD_CLOEXEC, 0);
if (drm_fd < 0) {
wlr_log(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed");
goto error_drm_fd;
}
int drm_fd = fcntl(wl->drm_fd, F_DUPFD_CLOEXEC, 0);
if (drm_fd < 0) {
wlr_log(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed");
goto error_drm_fd;
}

struct wlr_gbm_allocator *gbm_alloc = wlr_gbm_allocator_create(drm_fd);
if (gbm_alloc == NULL) {
wlr_log(WLR_ERROR, "Failed to create GBM allocator");
close(drm_fd);
goto error_drm_fd;
struct wlr_gbm_allocator *gbm_alloc = wlr_gbm_allocator_create(drm_fd);
if (gbm_alloc == NULL) {
wlr_log(WLR_ERROR, "Failed to create GBM allocator");
close(drm_fd);
goto error_drm_fd;
}
wl->allocator = &gbm_alloc->base;
} else {
wlr_log(WLR_DEBUG, "No render node found, falling back to shared memory");
struct wlr_shm_allocator *shm_alloc = wlr_shm_allocator_create();
if (shm_alloc == NULL) {
wlr_log(WLR_ERROR, "Failed to create shared memory allocator");
goto error_remote_display_src;
}
wl->allocator = &shm_alloc->base;
}
wl->allocator = &gbm_alloc->base;

wl->renderer = wlr_renderer_autocreate(&wl->backend);
if (wl->renderer == NULL) {
wlr_log(WLR_ERROR, "Failed to create renderer");
goto error_allocator;
}

uint32_t fmt = DRM_FORMAT_ARGB8888;
const struct wlr_drm_format *remote_format =
wlr_drm_format_set_get(&wl->linux_dmabuf_v1_formats, fmt);
if (remote_format == NULL) {
wlr_log(WLR_ERROR, "Remote compositor doesn't support format "
"0x%"PRIX32" via linux-dmabuf-unstable-v1", fmt);
goto error_renderer;
const struct wlr_drm_format_set *remote_formats;
if (wl->drm_fd >= 0) {
remote_formats = &wl->linux_dmabuf_v1_formats;
} else {
remote_formats = &wl->shm_formats;
}

const struct wlr_drm_format_set *render_formats =
wlr_renderer_get_render_formats(wl->renderer);
if (render_formats == NULL) {
wlr_log(WLR_ERROR, "Failed to get available DMA-BUF formats from renderer");
wlr_log(WLR_ERROR, "Failed to get available render-capable formats");
goto error_renderer;
}

uint32_t fmt = DRM_FORMAT_ARGB8888;

const struct wlr_drm_format *remote_format =
wlr_drm_format_set_get(remote_formats, fmt);
if (remote_format == NULL) {
wlr_log(WLR_ERROR, "Remote compositor doesn't support DRM format "
"0x%"PRIX32, fmt);
goto error_renderer;
}

const struct wlr_drm_format *render_format =
wlr_drm_format_set_get(render_formats, fmt);
if (render_format == NULL) {
Expand Down
87 changes: 58 additions & 29 deletions backend/wayland/output.c
Expand Up @@ -7,6 +7,7 @@
#include <sys/types.h>
#include <unistd.h>

#include <drm_fourcc.h>
#include <wayland-client.h>

#include <wlr/interfaces/wlr_output.h>
Expand All @@ -15,6 +16,7 @@
#include <wlr/util/log.h>

#include "backend/wayland.h"
#include "render/pixel_format.h"
#include "render/swapchain.h"
#include "render/wlr_renderer.h"
#include "util/signal.h"
Expand Down Expand Up @@ -161,52 +163,79 @@ static void buffer_handle_buffer_destroy(struct wl_listener *listener,

static bool test_buffer(struct wlr_wl_backend *wl,
struct wlr_buffer *wlr_buffer) {
struct wlr_dmabuf_attributes attribs;
if (!wlr_buffer_get_dmabuf(wlr_buffer, &attribs)) {
return false;
}

if (!wlr_drm_format_set_has(&wl->linux_dmabuf_v1_formats,
attribs.format, attribs.modifier)) {
struct wlr_dmabuf_attributes dmabuf;
struct wlr_shm_attributes shm;
if (wlr_buffer_get_dmabuf(wlr_buffer, &dmabuf)) {
return wlr_drm_format_set_has(&wl->linux_dmabuf_v1_formats,
dmabuf.format, dmabuf.modifier);
} else if (wlr_buffer_get_shm(wlr_buffer, &shm)) {
return wlr_drm_format_set_has(&wl->shm_formats, shm.format,
DRM_FORMAT_MOD_INVALID);
} else {
return false;
}

return true;
}

static struct wlr_wl_buffer *create_wl_buffer(struct wlr_wl_backend *wl,
struct wlr_buffer *wlr_buffer) {
if (!test_buffer(wl, wlr_buffer)) {
return NULL;
}

struct wlr_dmabuf_attributes attribs;
if (!wlr_buffer_get_dmabuf(wlr_buffer, &attribs)) {
return NULL;
}

uint32_t modifier_hi = attribs.modifier >> 32;
uint32_t modifier_lo = (uint32_t)attribs.modifier;
static struct wl_buffer *import_dmabuf(struct wlr_wl_backend *wl,
struct wlr_dmabuf_attributes *dmabuf) {
uint32_t modifier_hi = dmabuf->modifier >> 32;
uint32_t modifier_lo = (uint32_t)dmabuf->modifier;
struct zwp_linux_buffer_params_v1 *params =
zwp_linux_dmabuf_v1_create_params(wl->zwp_linux_dmabuf_v1);
for (int i = 0; i < attribs.n_planes; i++) {
zwp_linux_buffer_params_v1_add(params, attribs.fd[i], i,
attribs.offset[i], attribs.stride[i], modifier_hi, modifier_lo);
for (int i = 0; i < dmabuf->n_planes; i++) {
zwp_linux_buffer_params_v1_add(params, dmabuf->fd[i], i,
dmabuf->offset[i], dmabuf->stride[i], modifier_hi, modifier_lo);
}

uint32_t flags = 0;
if (attribs.flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT) {
if (dmabuf->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT) {
flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT;
}
if (attribs.flags & WLR_DMABUF_ATTRIBUTES_FLAGS_INTERLACED) {
if (dmabuf->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_INTERLACED) {
flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_INTERLACED;
}
if (attribs.flags & WLR_DMABUF_ATTRIBUTES_FLAGS_BOTTOM_FIRST) {
if (dmabuf->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_BOTTOM_FIRST) {
flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_BOTTOM_FIRST;
}
struct wl_buffer *wl_buffer = zwp_linux_buffer_params_v1_create_immed(
params, attribs.width, attribs.height, attribs.format, flags);
params, dmabuf->width, dmabuf->height, dmabuf->format, flags);
// TODO: handle create() errors
return wl_buffer;
}

static struct wl_buffer *import_shm(struct wlr_wl_backend *wl,
struct wlr_shm_attributes *shm) {
enum wl_shm_format wl_shm_format = convert_drm_format_to_wl_shm(shm->format);
uint32_t size = shm->stride * shm->height;
struct wl_shm_pool *pool = wl_shm_create_pool(wl->shm, shm->fd, size);
if (pool == NULL) {
return NULL;
}
struct wl_buffer *wl_buffer = wl_shm_pool_create_buffer(pool, shm->offset,
shm->width, shm->height, shm->stride, wl_shm_format);
wl_shm_pool_destroy(pool);
return wl_buffer;
}

static struct wlr_wl_buffer *create_wl_buffer(struct wlr_wl_backend *wl,
struct wlr_buffer *wlr_buffer) {
if (!test_buffer(wl, wlr_buffer)) {
return NULL;
}

struct wlr_dmabuf_attributes dmabuf;
struct wlr_shm_attributes shm;
struct wl_buffer *wl_buffer;
if (wlr_buffer_get_dmabuf(wlr_buffer, &dmabuf)) {
wl_buffer = import_dmabuf(wl, &dmabuf);
} else if (wlr_buffer_get_shm(wlr_buffer, &shm)) {
wl_buffer = import_shm(wl, &shm);
} else {
return NULL;
}
if (wl_buffer == NULL) {
return NULL;
}

struct wlr_wl_buffer *buffer = calloc(1, sizeof(struct wlr_wl_buffer));
if (buffer == NULL) {
Expand Down
2 changes: 2 additions & 0 deletions include/backend/wayland.h
Expand Up @@ -38,10 +38,12 @@ struct wlr_wl_backend {
struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1;
struct zwp_pointer_gestures_v1 *zwp_pointer_gestures_v1;
struct wp_presentation *presentation;
struct wl_shm *shm;
struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1;
struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1;
struct wl_list seats; // wlr_wl_seat.link
struct zwp_tablet_manager_v2 *tablet_manager;
struct wlr_drm_format_set shm_formats;
struct wlr_drm_format_set linux_dmabuf_v1_formats;
struct wl_drm *legacy_drm;
char *drm_render_name;
Expand Down
49 changes: 49 additions & 0 deletions include/render/pixman.h
@@ -0,0 +1,49 @@
#ifndef RENDER_PIXMAN_H
#define RENDER_PIXMAN_H

#include <wlr/render/pixman.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/render/drm_format_set.h>
#include "render/pixel_format.h"

struct wlr_pixman_pixel_format {
uint32_t drm_format;
pixman_format_code_t pixman_format;
};

struct wlr_pixman_buffer;

struct wlr_pixman_renderer {
struct wlr_renderer wlr_renderer;

struct wl_list buffers; // wlr_pixman_buffer.link

struct wlr_pixman_buffer *current_buffer;
int32_t width, height;

struct wlr_drm_format_set drm_formats;
};

struct wlr_pixman_buffer {
struct wlr_buffer *buffer;
struct wlr_pixman_renderer *renderer;

pixman_image_t *image;

struct wl_listener buffer_destroy;
struct wl_list link; // wlr_pixman_renderer.buffers
};

struct wlr_pixman_texture {
struct wlr_texture wlr_texture;
struct wlr_pixman_renderer *renderer;

void *data;
pixman_image_t *image;
const struct wlr_pixel_format_info *format;
};

pixman_format_code_t get_pixman_format_from_drm(uint32_t fmt);
const uint32_t *get_pixman_drm_formats(size_t *len);

#endif
23 changes: 23 additions & 0 deletions include/render/shm_allocator.h
@@ -0,0 +1,23 @@
#ifndef RENDER_SHM_ALLOCATOR_H
#define RENDER_SHM_ALLOCATOR_H

#include <wlr/types/wlr_buffer.h>
#include "render/allocator.h"

struct wlr_shm_buffer {
struct wlr_buffer base;
struct wlr_shm_attributes shm;
void *data;
size_t size;
};

struct wlr_shm_allocator {
struct wlr_allocator base;
};

/**
* Creates a new shared memory allocator.
*/
struct wlr_shm_allocator *wlr_shm_allocator_create(void);

#endif
15 changes: 15 additions & 0 deletions include/types/wlr_buffer.h
@@ -0,0 +1,15 @@
#ifndef TYPES_WLR_BUFFER
#define TYPES_WLR_BUFFER

#include <wlr/types/wlr_buffer.h>
/**
* Access a pointer to the allocated data from the underlying implementation,
* and its stride.
*
* The returned pointer should be pointing to a valid memory location for read
* and write operations.
*/
bool buffer_get_data_ptr(struct wlr_buffer *buffer, void **data,
size_t *stride);

#endif