diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 9290e28f..0fc978e9 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -2,6 +2,7 @@ #include #include #include +#include #include @@ -16,7 +17,10 @@ #include #include "backend/wayland.h" +#include "render/drm_format_set.h" +#include "render/gbm_allocator.h" #include "util/signal.h" + #include "linux-dmabuf-unstable-v1-client-protocol.h" #include "pointer-gestures-unstable-v1-client-protocol.h" #include "presentation-time-client-protocol.h" @@ -277,7 +281,8 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, } wl_registry_add_listener(wl->registry, ®istry_listener, wl); - wl_display_roundtrip(wl->remote_display); + wl_display_roundtrip(wl->remote_display); // get globals + wl_display_roundtrip(wl->remote_display); // get linux-dmabuf formats if (!wl->compositor) { wlr_log(WLR_ERROR, @@ -317,12 +322,42 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, wl->renderer = create_renderer_func(&wl->egl, EGL_PLATFORM_WAYLAND_EXT, wl->remote_display, config_attribs, 0); - if (!wl->renderer) { wlr_log(WLR_ERROR, "Could not create renderer"); goto error_event; } + // TODO: get FD from linux-dmabuf hints instead + int drm_fd = wlr_renderer_get_drm_fd(wl->renderer); + if (drm_fd < 0) { + wlr_log(WLR_ERROR, "Failed to get DRM device FD from renderer"); + goto error_event; + } + + drm_fd = dup(drm_fd); + if (drm_fd < 0) { + wlr_log_errno(WLR_ERROR, "dup failed"); + goto error_event; + } + + struct wlr_gbm_allocator *alloc = wlr_gbm_allocator_create(drm_fd); + if (alloc == NULL) { + wlr_log(WLR_ERROR, "Failed to create GBM allocator"); + goto error_event; + } + wl->allocator = &alloc->base; + + 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 ARGB8888 " + "via linux-dmabuf-unstable-v1"); + goto error_event; + } + // TODO: intersect with render formats + wl->format = wlr_drm_format_dup(remote_format); + wl->local_display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &wl->local_display_destroy); diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 77412056..540cc1f7 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -15,7 +15,10 @@ #include #include "backend/wayland.h" +#include "render/swapchain.h" +#include "render/wlr_renderer.h" #include "util/signal.h" + #include "linux-dmabuf-unstable-v1-client-protocol.h" #include "presentation-time-client-protocol.h" #include "xdg-decoration-unstable-v1-client-protocol.h" @@ -94,17 +97,40 @@ static const struct wp_presentation_feedback_listener static bool output_set_custom_mode(struct wlr_output *wlr_output, int32_t width, int32_t height, int32_t refresh) { struct wlr_wl_output *output = get_wl_output_from_output(wlr_output); - wl_egl_window_resize(output->egl_window, width, height, 0, 0); + + if (wlr_output->width != width || wlr_output->height != height) { + struct wlr_swapchain *swapchain = wlr_swapchain_create( + output->backend->allocator, width, height, output->backend->format); + if (swapchain == NULL) { + return false; + } + wlr_swapchain_destroy(output->swapchain); + output->swapchain = swapchain; + } + wlr_output_update_custom_mode(&output->wlr_output, width, height, 0); return true; } static bool output_attach_render(struct wlr_output *wlr_output, int *buffer_age) { - struct wlr_wl_output *output = - get_wl_output_from_output(wlr_output); - return wlr_egl_make_current(&output->backend->egl, output->egl_surface, - buffer_age); + struct wlr_wl_output *output = get_wl_output_from_output(wlr_output); + + wlr_buffer_unlock(output->back_buffer); + output->back_buffer = wlr_swapchain_acquire(output->swapchain, buffer_age); + if (!output->back_buffer) { + return false; + } + + if (!wlr_egl_make_current(&output->backend->egl, EGL_NO_SURFACE, NULL)) { + return false; + } + if (!wlr_renderer_bind_buffer(output->backend->renderer, + output->back_buffer)) { + return false; + } + + return true; } static void destroy_wl_buffer(struct wlr_wl_buffer *buffer) { @@ -246,39 +272,49 @@ static bool output_commit(struct wlr_output *wlr_output) { output->frame_callback = wl_surface_frame(output->surface); wl_callback_add_listener(output->frame_callback, &frame_listener, output); + struct wlr_buffer *wlr_buffer = NULL; switch (wlr_output->pending.buffer_type) { case WLR_OUTPUT_STATE_BUFFER_RENDER: - if (!wlr_egl_swap_buffers(&output->backend->egl, - output->egl_surface, damage)) { - return false; - } + assert(output->back_buffer != NULL); + wlr_buffer = output->back_buffer; + + wlr_renderer_bind_buffer(output->backend->renderer, NULL); + wlr_egl_unset_current(&output->backend->egl); break; case WLR_OUTPUT_STATE_BUFFER_SCANOUT:; - struct wlr_wl_buffer *buffer = - create_wl_buffer(output->backend, wlr_output->pending.buffer); - if (buffer == NULL) { - return false; - } + wlr_buffer = wlr_output->pending.buffer; + break; + } + + struct wlr_wl_buffer *buffer = + create_wl_buffer(output->backend, wlr_buffer); + if (buffer == NULL) { + return false; + } + + wl_surface_attach(output->surface, buffer->wl_buffer, 0, 0); - wl_surface_attach(output->surface, buffer->wl_buffer, 0, 0); - - if (damage == NULL) { - wl_surface_damage_buffer(output->surface, - 0, 0, INT32_MAX, INT32_MAX); - } else { - int rects_len; - pixman_box32_t *rects = - pixman_region32_rectangles(damage, &rects_len); - for (int i = 0; i < rects_len; i++) { - pixman_box32_t *r = &rects[i]; - wl_surface_damage_buffer(output->surface, r->x1, r->y1, - r->x2 - r->x1, r->y2 - r->y1); - } + if (damage == NULL) { + wl_surface_damage_buffer(output->surface, + 0, 0, INT32_MAX, INT32_MAX); + } else { + int rects_len; + pixman_box32_t *rects = + pixman_region32_rectangles(damage, &rects_len); + for (int i = 0; i < rects_len; i++) { + pixman_box32_t *r = &rects[i]; + wl_surface_damage_buffer(output->surface, r->x1, r->y1, + r->x2 - r->x1, r->y2 - r->y1); } - wl_surface_commit(output->surface); - break; } + wl_surface_commit(output->surface); + + wlr_buffer_unlock(output->back_buffer); + output->back_buffer = NULL; + + wlr_swapchain_set_buffer_submitted(output->swapchain, wlr_buffer); + if (wp_feedback != NULL) { struct wlr_wl_presentation_feedback *feedback = calloc(1, sizeof(*feedback)); @@ -302,8 +338,8 @@ static bool output_commit(struct wlr_output *wlr_output) { } static void output_rollback_render(struct wlr_output *wlr_output) { - struct wlr_wl_output *output = - get_wl_output_from_output(wlr_output); + struct wlr_wl_output *output = get_wl_output_from_output(wlr_output); + wlr_renderer_bind_buffer(output->backend->renderer, NULL); wlr_egl_unset_current(&output->backend->egl); } @@ -407,8 +443,8 @@ static void output_destroy(struct wlr_output *wlr_output) { presentation_feedback_destroy(feedback); } - wlr_egl_destroy_surface(&output->backend->egl, output->egl_surface); - wl_egl_window_destroy(output->egl_window); + wlr_buffer_unlock(output->back_buffer); + wlr_swapchain_destroy(output->swapchain); if (output->zxdg_toplevel_decoration_v1) { zxdg_toplevel_decoration_v1_destroy(output->zxdg_toplevel_decoration_v1); } @@ -558,10 +594,11 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) { &xdg_toplevel_listener, output); wl_surface_commit(output->surface); - output->egl_window = wl_egl_window_create(output->surface, - wlr_output->width, wlr_output->height); - output->egl_surface = wlr_egl_create_surface(&backend->egl, - output->egl_window); + output->swapchain = wlr_swapchain_create(output->backend->allocator, + wlr_output->width, wlr_output->height, output->backend->format); + if (output->swapchain == NULL) { + goto error; + } wl_display_roundtrip(output->backend->remote_display); diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 9596b72c..8189c463 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -25,6 +25,8 @@ struct wlr_wl_backend { struct wl_list outputs; struct wlr_egl egl; struct wlr_renderer *renderer; + struct wlr_drm_format *format; + struct wlr_allocator *allocator; size_t requested_outputs; size_t last_output_num; struct wl_listener local_display_destroy; @@ -67,10 +69,11 @@ struct wlr_wl_output { struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1; - struct wl_egl_window *egl_window; - EGLSurface egl_surface; struct wl_list presentation_feedbacks; + struct wlr_swapchain *swapchain; + struct wlr_buffer *back_buffer; + uint32_t enter_serial; struct {