diff --git a/backend/drm/backend.c b/backend/drm/backend.c index e046cea6..95c86bb1 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -33,7 +33,7 @@ static void wlr_drm_backend_destroy(struct wlr_backend *_backend) { wlr_output_destroy(&output->output); } - wlr_drm_renderer_free(&backend->renderer); + wlr_drm_renderer_finish(&backend->renderer); wlr_drm_resources_free(backend); wlr_session_close_file(backend->session, backend->fd); wl_event_source_remove(backend->drm_event); diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 40a6f37b..05a050e6 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -173,121 +173,9 @@ void wlr_drm_resources_free(struct wlr_drm_backend *backend) { free(backend->planes); } -bool wlr_drm_renderer_init(struct wlr_drm_renderer *renderer, int fd) { - renderer->gbm = gbm_create_device(fd); - if (!renderer->gbm) { - wlr_log(L_ERROR, "Failed to create GBM device: %s", strerror(errno)); - return false; - } - - if (!wlr_egl_init(&renderer->egl, EGL_PLATFORM_GBM_MESA, - GBM_FORMAT_ARGB8888, renderer->gbm)) { - gbm_device_destroy(renderer->gbm); - return false; - } - - renderer->fd = fd; - return true; -} - -void wlr_drm_renderer_free(struct wlr_drm_renderer *renderer) { - if (!renderer) { - return; - } - - wlr_egl_free(&renderer->egl); - gbm_device_destroy(renderer->gbm); -} - -static bool wlr_drm_plane_renderer_init(struct wlr_drm_renderer *renderer, - struct wlr_drm_plane *plane, uint32_t width, uint32_t height, uint32_t format, uint32_t flags) { - if (plane->width == width && plane->height == height) { - return true; - } - - plane->width = width; - plane->height = height; - - plane->gbm = gbm_surface_create(renderer->gbm, width, height, - format, GBM_BO_USE_RENDERING | flags); - if (!plane->gbm) { - wlr_log_errno(L_ERROR, "Failed to create GBM surface for plane"); - return false; - } - - plane->egl = wlr_egl_create_surface(&renderer->egl, plane->gbm); - if (plane->egl == EGL_NO_SURFACE) { - wlr_log(L_ERROR, "Failed to create EGL surface for plane"); - return false; - } - - return true; -} - -static void wlr_drm_plane_renderer_free(struct wlr_drm_renderer *renderer, - struct wlr_drm_plane *plane) { - if (!renderer || !plane) { - return; - } - - eglMakeCurrent(renderer->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - - if (plane->front) { - gbm_surface_release_buffer(plane->gbm, plane->front); - } - if (plane->back) { - gbm_surface_release_buffer(plane->gbm, plane->back); - } - - if (plane->egl) { - eglDestroySurface(renderer->egl.display, plane->egl); - } - if (plane->gbm) { - gbm_surface_destroy(plane->gbm); - } - - if (plane->wlr_tex) { - wlr_texture_destroy(plane->wlr_tex); - } - if (plane->wlr_rend) { - wlr_renderer_destroy(plane->wlr_rend); - } - if (plane->cursor_bo) { - gbm_bo_destroy(plane->cursor_bo); - } - - plane->width = 0; - plane->height = 0; - plane->egl = EGL_NO_SURFACE; - plane->gbm = NULL; - plane->front = NULL; - plane->back = NULL; - plane->wlr_rend = NULL; - plane->wlr_tex = NULL; - plane->cursor_bo = NULL; -} - -static void wlr_drm_plane_make_current(struct wlr_drm_renderer *renderer, - struct wlr_drm_plane *plane) { - eglMakeCurrent(renderer->egl.display, plane->egl, plane->egl, - renderer->egl.context); -} - -static void wlr_drm_plane_swap_buffers(struct wlr_drm_renderer *renderer, - struct wlr_drm_plane *plane) { - if (plane->front) { - gbm_surface_release_buffer(plane->gbm, plane->front); - } - - eglSwapBuffers(renderer->egl.display, plane->egl); - - plane->front = plane->back; - plane->back = gbm_surface_lock_front_buffer(plane->gbm); -} - static void wlr_drm_output_make_current(struct wlr_output *_output) { struct wlr_drm_output *output = (struct wlr_drm_output *)_output; - wlr_drm_plane_make_current(output->renderer, output->crtc->primary); + wlr_drm_surface_make_current(output->renderer, &output->crtc->primary->surf); } static void wlr_drm_output_swap_buffers(struct wlr_output *_output) { @@ -298,9 +186,8 @@ static void wlr_drm_output_swap_buffers(struct wlr_output *_output) { struct wlr_drm_crtc *crtc = output->crtc; struct wlr_drm_plane *plane = crtc->primary; - wlr_drm_plane_swap_buffers(renderer, plane); - - uint32_t fb_id = get_fb_for_bo(plane->back); + struct gbm_bo *bo = wlr_drm_surface_swap_buffers(renderer, &plane->surf); + uint32_t fb_id = get_fb_for_bo(bo); if (backend->iface->crtc_pageflip(backend, output, crtc, fb_id, NULL)) { output->pageflip_pending = true; @@ -338,17 +225,7 @@ void wlr_drm_output_start_renderer(struct wlr_drm_output *output) { struct wlr_drm_crtc *crtc = output->crtc; struct wlr_drm_plane *plane = crtc->primary; - struct gbm_bo *bo = plane->front; - if (!bo) { - // Render a black frame to start the rendering loop - wlr_drm_plane_make_current(renderer, plane); - glViewport(0, 0, plane->width, plane->height); - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); - wlr_drm_plane_swap_buffers(renderer, plane); - - bo = plane->back; - } + struct gbm_bo *bo = wlr_drm_surface_get_front(renderer, &plane->surf); struct wlr_drm_output_mode *_mode = (struct wlr_drm_output_mode *)output->output.current_mode; @@ -415,8 +292,10 @@ static void realloc_planes(struct wlr_drm_backend *backend, const uint32_t *crtc struct wlr_drm_plane *new = &backend->type_planes[type][crtc_res[i]]; if (*old != new) { - wlr_drm_plane_renderer_free(&backend->renderer, *old); - wlr_drm_plane_renderer_free(&backend->renderer, new); + if (*old) { + wlr_drm_surface_finish(&backend->renderer, &(*old)->surf); + } + wlr_drm_surface_finish(&backend->renderer, &new->surf); *old = new; } } @@ -547,7 +426,7 @@ static bool wlr_drm_output_set_mode(struct wlr_output *_output, continue; } - if (!wlr_drm_plane_renderer_init(&backend->renderer, crtc->primary, + if (!wlr_drm_surface_init(&backend->renderer, &crtc->primary->surf, mode->width, mode->height, GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT)) { wlr_log(L_ERROR, "Failed to initalise renderer for plane"); @@ -598,7 +477,7 @@ static bool wlr_drm_output_set_cursor(struct wlr_output *_output, crtc->cursor = plane; } - if (!plane->gbm) { + if (!plane->surf.gbm) { int ret; uint64_t w, h; ret = drmGetCap(backend->fd, DRM_CAP_CURSOR_WIDTH, &w); @@ -611,7 +490,7 @@ static bool wlr_drm_output_set_cursor(struct wlr_output *_output, return false; } - if (!wlr_drm_plane_renderer_init(renderer, plane, w, h, GBM_FORMAT_ARGB8888, 0)) { + if (!wlr_drm_surface_init(renderer, &plane->surf, w, h, GBM_FORMAT_ARGB8888, 0)) { wlr_log(L_ERROR, "Cannot allocate cursor resources"); return false; } @@ -625,7 +504,7 @@ static bool wlr_drm_output_set_cursor(struct wlr_output *_output, // OpenGL will read the pixels out upside down, // so we need to flip the image vertically - wlr_matrix_texture(plane->matrix, plane->width, plane->height, + wlr_matrix_texture(plane->matrix, plane->surf.width, plane->surf.height, output->output.transform ^ WL_OUTPUT_TRANSFORM_FLIPPED_180); // TODO the image needs to be rotated depending on the output rotation @@ -653,12 +532,12 @@ static bool wlr_drm_output_set_cursor(struct wlr_output *_output, return false; } - wlr_drm_plane_make_current(renderer, plane); + wlr_drm_surface_make_current(renderer, &plane->surf); wlr_texture_upload_pixels(plane->wlr_tex, WL_SHM_FORMAT_ARGB8888, stride, width, height, buf); - glViewport(0, 0, plane->width, plane->height); + glViewport(0, 0, plane->surf.width, plane->surf.height); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); @@ -668,10 +547,10 @@ static bool wlr_drm_output_set_cursor(struct wlr_output *_output, glFinish(); glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, bo_stride); - glReadPixels(0, 0, plane->width, plane->height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, bo_data); + glReadPixels(0, 0, plane->surf.width, plane->surf.height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, bo_data); glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0); - wlr_drm_plane_swap_buffers(renderer, plane); + wlr_drm_surface_swap_buffers(renderer, &plane->surf); gbm_bo_unmap(bo, bo_data); @@ -914,9 +793,9 @@ static void page_flip_handler(int fd, unsigned seq, } struct wlr_drm_plane *plane = output->crtc->primary; - if (plane->front) { - gbm_surface_release_buffer(plane->gbm, plane->front); - plane->front = NULL; + if (plane->surf.front) { + gbm_surface_release_buffer(plane->surf.gbm, plane->surf.front); + plane->surf.front = NULL; } if (backend->session->active) { @@ -987,7 +866,7 @@ void wlr_drm_output_cleanup(struct wlr_drm_output *output) { case WLR_DRM_OUTPUT_CLEANUP:; struct wlr_drm_crtc *crtc = output->crtc; for (int i = 0; i < 3; ++i) { - wlr_drm_plane_renderer_free(renderer, crtc->planes[i]); + wlr_drm_surface_finish(renderer, &crtc->planes[i]->surf); if (crtc->planes[i] && crtc->planes[i]->id == 0) { free(crtc->planes[i]); crtc->planes[i] = NULL; diff --git a/backend/drm/iface_atomic.c b/backend/drm/iface_atomic.c index 75a3c33a..ce5de091 100644 --- a/backend/drm/iface_atomic.c +++ b/backend/drm/iface_atomic.c @@ -84,10 +84,10 @@ static void set_plane_props(struct atomic *atom, struct wlr_drm_plane *plane, // The src_* properties are in 16.16 fixed point atomic_add(atom, id, props->src_x, 0); atomic_add(atom, id, props->src_y, 0); - atomic_add(atom, id, props->src_w, plane->width << 16); - atomic_add(atom, id, props->src_h, plane->height << 16); - atomic_add(atom, id, props->crtc_w, plane->width); - atomic_add(atom, id, props->crtc_h, plane->height); + atomic_add(atom, id, props->src_w, plane->surf.width << 16); + atomic_add(atom, id, props->src_h, plane->surf.height << 16); + atomic_add(atom, id, props->crtc_w, plane->surf.width); + atomic_add(atom, id, props->crtc_h, plane->surf.height); atomic_add(atom, id, props->fb_id, fb_id); atomic_add(atom, id, props->crtc_id, crtc_id); if (set_crtc_xy) { diff --git a/backend/drm/iface_legacy.c b/backend/drm/iface_legacy.c index 110b38b5..e320af93 100644 --- a/backend/drm/iface_legacy.c +++ b/backend/drm/iface_legacy.c @@ -45,7 +45,7 @@ bool legacy_crtc_set_cursor(struct wlr_drm_backend *backend, struct wlr_drm_plane *plane = crtc->cursor; if (drmModeSetCursor(backend->fd, crtc->id, gbm_bo_get_handle(bo).u32, - plane->width, plane->height)) { + plane->surf.width, plane->surf.height)) { wlr_log_errno(L_ERROR, "Failed to set hardware cursor"); return false; } diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c new file mode 100644 index 00000000..8afc6dca --- /dev/null +++ b/backend/drm/renderer.c @@ -0,0 +1,126 @@ +#include + +#include +#include +#include +#include + +#include +#include +#include "backend/drm/drm.h" + +bool wlr_drm_renderer_init(struct wlr_drm_renderer *renderer, int fd) { + renderer->gbm = gbm_create_device(fd); + if (!renderer->gbm) { + wlr_log(L_ERROR, "Failed to create GBM device"); + return false; + } + + if (!wlr_egl_init(&renderer->egl, EGL_PLATFORM_GBM_MESA, + GBM_FORMAT_ARGB8888, renderer->gbm)) { + gbm_device_destroy(renderer->gbm); + return false; + } + + renderer->fd = fd; + return true; +} + +void wlr_drm_renderer_finish(struct wlr_drm_renderer *renderer) { + if (!renderer) { + return; + } + + wlr_egl_free(&renderer->egl); + gbm_device_destroy(renderer->gbm); +} + +bool wlr_drm_surface_init(struct wlr_drm_renderer *renderer, + struct wlr_drm_surface *surf, uint32_t width, uint32_t height, + uint32_t format, uint32_t flags) { + if (surf->width == width && surf->height == height) { + return true; + } + + surf->width = width; + surf->height = height; + + surf->gbm = gbm_surface_create(renderer->gbm, width, height, + format, GBM_BO_USE_RENDERING | flags); + if (!surf->gbm) { + wlr_log_errno(L_ERROR, "Failed to create GBM surface"); + goto error_zero; + } + + surf->egl = wlr_egl_create_surface(&renderer->egl, surf->gbm); + if (surf->egl == EGL_NO_SURFACE) { + wlr_log(L_ERROR, "Failed to create EGL surface"); + goto error_gbm; + } + + return true; + +error_gbm: + gbm_surface_destroy(surf->gbm); +error_zero: + memset(surf, 0, sizeof(*surf)); + return false; +} + +void wlr_drm_surface_finish(struct wlr_drm_renderer *renderer, + struct wlr_drm_surface *surf) { + if (!renderer || !surf || !surf->gbm) { + return; + } + + eglMakeCurrent(renderer->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + + if (surf->front) { + gbm_surface_release_buffer(surf->gbm, surf->front); + } + if (surf->back) { + gbm_surface_release_buffer(surf->gbm, surf->back); + } + + if (surf->egl) { + eglDestroySurface(renderer->egl.display, surf->egl); + } + if (surf->gbm) { + gbm_surface_destroy(surf->gbm); + } + + memset(surf, 0, sizeof(*surf)); +} + +void wlr_drm_surface_make_current(struct wlr_drm_renderer *renderer, + struct wlr_drm_surface *surf) { + eglMakeCurrent(renderer->egl.display, surf->egl, surf->egl, + renderer->egl.context); +} + +struct gbm_bo *wlr_drm_surface_swap_buffers(struct wlr_drm_renderer *renderer, + struct wlr_drm_surface *surf) { + if (surf->front) { + gbm_surface_release_buffer(surf->gbm, surf->front); + } + + eglSwapBuffers(renderer->egl.display, surf->egl); + + surf->front = surf->back; + surf->back = gbm_surface_lock_front_buffer(surf->gbm); + return surf->back; +} + +struct gbm_bo *wlr_drm_surface_get_front(struct wlr_drm_renderer *renderer, + struct wlr_drm_surface *surf) { + if (surf->front) { + return surf->front; + } + + wlr_drm_surface_make_current(renderer, surf); + glViewport(0, 0, surf->width, surf->height); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + return wlr_drm_surface_swap_buffers(renderer, surf); +} diff --git a/backend/meson.build b/backend/meson.build index 630bc284..caf2c8b0 100644 --- a/backend/meson.build +++ b/backend/meson.build @@ -8,6 +8,7 @@ backend_files = files( 'drm/iface_atomic.c', 'drm/iface_legacy.c', 'drm/properties.c', + 'drm/renderer.c', 'drm/util.c', 'libinput/backend.c', 'libinput/events.c', diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index c57493f3..b13cb5e7 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -17,6 +17,7 @@ #include "iface.h" #include "properties.h" +#include "renderer.h" struct wlr_drm_plane { uint32_t type; @@ -24,13 +25,7 @@ struct wlr_drm_plane { uint32_t possible_crtcs; - uint32_t width, height; - - struct gbm_surface *gbm; - EGLSurface egl; - - struct gbm_bo *front; - struct gbm_bo *back; + struct wlr_drm_surface surf; // Only used by cursor float matrix[16]; @@ -70,17 +65,6 @@ struct wlr_drm_connector { struct wl_list link; }; -struct wlr_drm_renderer { - int fd; - struct gbm_device *gbm; - struct wlr_egl egl; -}; - -bool wlr_drm_renderer_init(struct wlr_drm_renderer *renderer, int fd); -void wlr_drm_renderer_free(struct wlr_drm_renderer *renderer); - -struct wlr_drm_interface; - struct wlr_drm_backend { struct wlr_backend backend; diff --git a/include/backend/drm/renderer.h b/include/backend/drm/renderer.h new file mode 100644 index 00000000..bbcf4f0c --- /dev/null +++ b/include/backend/drm/renderer.h @@ -0,0 +1,47 @@ +#ifndef BACKEND_DRM_RENDERER_H +#define BACKEND_DRM_RENDERER_H + +#include +#include + +#include +#include + +struct wlr_drm_renderer { + int fd; + struct gbm_device *gbm; + struct wlr_egl egl; +}; + +struct wlr_drm_surface { + uint32_t width; + uint32_t height; + + struct gbm_surface *gbm; + EGLSurface egl; + + struct gbm_bo *front; + struct gbm_bo *back; +}; + +bool wlr_drm_renderer_init(struct wlr_drm_renderer *renderer, int fd); + +void wlr_drm_renderer_finish(struct wlr_drm_renderer *renderer); + +bool wlr_drm_surface_init(struct wlr_drm_renderer *renderer, + struct wlr_drm_surface *surf, uint32_t width, uint32_t height, + uint32_t format, uint32_t flags); + +void wlr_drm_surface_finish(struct wlr_drm_renderer *renderer, + struct wlr_drm_surface *surf); + +void wlr_drm_surface_make_current(struct wlr_drm_renderer *renderer, + struct wlr_drm_surface *surf); + +struct gbm_bo *wlr_drm_surface_swap_buffers(struct wlr_drm_renderer *renderer, + struct wlr_drm_surface *surf); + +struct gbm_bo *wlr_drm_surface_get_front(struct wlr_drm_renderer *renderer, + struct wlr_drm_surface *surf); + +#endif