mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2024-11-23 07:32:20 +00:00
95b22619e0
The deleted includes are redundant, because other headers will include the necessary files. Additionally, they cause build failures, because including EGL/egl.h or EGL/eglext.h directly, instead of through wlr/render/egl.h or wlr/render/interface.h, will mean that MESA_EGL_NO_X11_HEADERS will not have been defined, and so the EGL headers will attempt to pull in unnecessary X11 headers that may not exist on the system. For the headers produced by glgen.sh, the includes couldn't simply be deleted, because no other header would include the EGL headers. Neither wlr/render/egl.h or wlr/render/interface.h felt appropriate to include, so I opted instead to copy the MESA_EGL_NO_X11_HEADERS definition before the EGL includes.
259 lines
6.4 KiB
C
259 lines
6.4 KiB
C
#include <assert.h>
|
|
#include <gbm.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <wayland-util.h>
|
|
#include <wlr/render/egl.h>
|
|
#include <wlr/render/gles2.h>
|
|
#include <wlr/render/wlr_renderer.h>
|
|
#include <wlr/types/wlr_matrix.h>
|
|
#include <wlr/util/log.h>
|
|
#include "backend/drm/drm.h"
|
|
#include "glapi.h"
|
|
|
|
bool init_drm_renderer(struct wlr_drm_backend *drm,
|
|
struct wlr_drm_renderer *renderer, wlr_renderer_create_func_t create_renderer_func) {
|
|
renderer->gbm = gbm_create_device(drm->fd);
|
|
if (!renderer->gbm) {
|
|
wlr_log(WLR_ERROR, "Failed to create GBM device");
|
|
return false;
|
|
}
|
|
|
|
if (!create_renderer_func) {
|
|
create_renderer_func = wlr_renderer_autocreate;
|
|
}
|
|
|
|
static EGLint config_attribs[] = {
|
|
EGL_RED_SIZE, 1,
|
|
EGL_GREEN_SIZE, 1,
|
|
EGL_BLUE_SIZE, 1,
|
|
EGL_ALPHA_SIZE, 1,
|
|
EGL_NONE,
|
|
};
|
|
|
|
renderer->gbm_format = GBM_FORMAT_ARGB8888;
|
|
renderer->wlr_rend = create_renderer_func(&renderer->egl,
|
|
EGL_PLATFORM_GBM_MESA, renderer->gbm,
|
|
config_attribs, renderer->gbm_format);
|
|
if (!renderer->wlr_rend) {
|
|
wlr_log(WLR_ERROR, "Failed to create EGL/WLR renderer");
|
|
goto error_gbm;
|
|
}
|
|
|
|
renderer->fd = drm->fd;
|
|
return true;
|
|
|
|
error_gbm:
|
|
gbm_device_destroy(renderer->gbm);
|
|
return false;
|
|
}
|
|
|
|
void finish_drm_renderer(struct wlr_drm_renderer *renderer) {
|
|
if (!renderer) {
|
|
return;
|
|
}
|
|
|
|
wlr_renderer_destroy(renderer->wlr_rend);
|
|
wlr_egl_finish(&renderer->egl);
|
|
gbm_device_destroy(renderer->gbm);
|
|
}
|
|
|
|
bool init_drm_surface(struct wlr_drm_surface *surf,
|
|
struct wlr_drm_renderer *renderer, uint32_t width, uint32_t height,
|
|
uint32_t format, uint32_t flags) {
|
|
if (surf->width == width && surf->height == height) {
|
|
return true;
|
|
}
|
|
|
|
surf->renderer = renderer;
|
|
surf->width = width;
|
|
surf->height = height;
|
|
|
|
if (surf->gbm) {
|
|
if (surf->front) {
|
|
gbm_surface_release_buffer(surf->gbm, surf->front);
|
|
surf->front = NULL;
|
|
}
|
|
if (surf->back) {
|
|
gbm_surface_release_buffer(surf->gbm, surf->back);
|
|
surf->back = NULL;
|
|
}
|
|
gbm_surface_destroy(surf->gbm);
|
|
}
|
|
wlr_egl_destroy_surface(&surf->renderer->egl, surf->egl);
|
|
|
|
surf->gbm = gbm_surface_create(renderer->gbm, width, height,
|
|
format, GBM_BO_USE_RENDERING | flags);
|
|
if (!surf->gbm) {
|
|
wlr_log_errno(WLR_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(WLR_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 finish_drm_surface(struct wlr_drm_surface *surf) {
|
|
if (!surf || !surf->renderer) {
|
|
return;
|
|
}
|
|
|
|
if (surf->front) {
|
|
gbm_surface_release_buffer(surf->gbm, surf->front);
|
|
}
|
|
if (surf->back) {
|
|
gbm_surface_release_buffer(surf->gbm, surf->back);
|
|
}
|
|
|
|
wlr_egl_destroy_surface(&surf->renderer->egl, surf->egl);
|
|
if (surf->gbm) {
|
|
gbm_surface_destroy(surf->gbm);
|
|
}
|
|
|
|
memset(surf, 0, sizeof(*surf));
|
|
}
|
|
|
|
bool make_drm_surface_current(struct wlr_drm_surface *surf,
|
|
int *buffer_damage) {
|
|
return wlr_egl_make_current(&surf->renderer->egl, surf->egl, buffer_damage);
|
|
}
|
|
|
|
struct gbm_bo *swap_drm_surface_buffers(struct wlr_drm_surface *surf,
|
|
pixman_region32_t *damage) {
|
|
if (surf->front) {
|
|
gbm_surface_release_buffer(surf->gbm, surf->front);
|
|
}
|
|
|
|
wlr_egl_swap_buffers(&surf->renderer->egl, surf->egl, damage);
|
|
|
|
surf->front = surf->back;
|
|
surf->back = gbm_surface_lock_front_buffer(surf->gbm);
|
|
return surf->back;
|
|
}
|
|
|
|
struct gbm_bo *get_drm_surface_front(struct wlr_drm_surface *surf) {
|
|
if (surf->front) {
|
|
return surf->front;
|
|
}
|
|
|
|
make_drm_surface_current(surf, NULL);
|
|
struct wlr_renderer *renderer = surf->renderer->wlr_rend;
|
|
wlr_renderer_begin(renderer, surf->width, surf->height);
|
|
wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 1.0 });
|
|
wlr_renderer_end(renderer);
|
|
return swap_drm_surface_buffers(surf, NULL);
|
|
}
|
|
|
|
void post_drm_surface(struct wlr_drm_surface *surf) {
|
|
if (surf->front) {
|
|
gbm_surface_release_buffer(surf->gbm, surf->front);
|
|
surf->front = NULL;
|
|
}
|
|
}
|
|
|
|
bool export_drm_bo(struct gbm_bo *bo, struct wlr_dmabuf_attributes *attribs) {
|
|
memset(attribs, 0, sizeof(struct wlr_dmabuf_attributes));
|
|
|
|
attribs->n_planes = gbm_bo_get_plane_count(bo);
|
|
if (attribs->n_planes > WLR_DMABUF_MAX_PLANES) {
|
|
return false;
|
|
}
|
|
|
|
attribs->width = gbm_bo_get_width(bo);
|
|
attribs->height = gbm_bo_get_height(bo);
|
|
attribs->format = gbm_bo_get_format(bo);
|
|
attribs->modifier = gbm_bo_get_modifier(bo);
|
|
|
|
for (int i = 0; i < attribs->n_planes; ++i) {
|
|
attribs->offset[i] = gbm_bo_get_offset(bo, i);
|
|
attribs->stride[i] = gbm_bo_get_stride_for_plane(bo, i);
|
|
attribs->fd[i] = gbm_bo_get_fd(bo);
|
|
if (attribs->fd[i] < 0) {
|
|
for (int j = 0; j < i; ++j) {
|
|
close(attribs->fd[j]);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void free_tex(struct gbm_bo *bo, void *data) {
|
|
struct wlr_texture *tex = data;
|
|
wlr_texture_destroy(tex);
|
|
}
|
|
|
|
static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer,
|
|
struct gbm_bo *bo) {
|
|
struct wlr_texture *tex = gbm_bo_get_user_data(bo);
|
|
if (tex) {
|
|
return tex;
|
|
}
|
|
|
|
struct wlr_dmabuf_attributes attribs;
|
|
if (!export_drm_bo(bo, &attribs)) {
|
|
return NULL;
|
|
}
|
|
|
|
tex = wlr_texture_from_dmabuf(renderer->wlr_rend, &attribs);
|
|
if (tex) {
|
|
gbm_bo_set_user_data(bo, tex, free_tex);
|
|
}
|
|
|
|
return tex;
|
|
}
|
|
|
|
struct gbm_bo *copy_drm_surface_mgpu(struct wlr_drm_surface *dest,
|
|
struct gbm_bo *src) {
|
|
make_drm_surface_current(dest, NULL);
|
|
|
|
struct wlr_texture *tex = get_tex_for_bo(dest->renderer, src);
|
|
assert(tex);
|
|
|
|
float mat[9];
|
|
wlr_matrix_projection(mat, 1, 1, WL_OUTPUT_TRANSFORM_NORMAL);
|
|
|
|
struct wlr_renderer *renderer = dest->renderer->wlr_rend;
|
|
wlr_renderer_begin(renderer, dest->width, dest->height);
|
|
wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 0.0 });
|
|
wlr_render_texture_with_matrix(renderer, tex, mat, 1.0f);
|
|
wlr_renderer_end(renderer);
|
|
|
|
return swap_drm_surface_buffers(dest, NULL);
|
|
}
|
|
|
|
bool init_drm_plane_surfaces(struct wlr_drm_plane *plane,
|
|
struct wlr_drm_backend *drm, int32_t width, uint32_t height,
|
|
uint32_t format) {
|
|
if (!drm->parent) {
|
|
return init_drm_surface(&plane->surf, &drm->renderer, width, height,
|
|
format, GBM_BO_USE_SCANOUT);
|
|
}
|
|
|
|
if (!init_drm_surface(&plane->surf, &drm->parent->renderer,
|
|
width, height, format, GBM_BO_USE_LINEAR)) {
|
|
return false;
|
|
}
|
|
|
|
if (!init_drm_surface(&plane->mgpu_surf, &drm->renderer,
|
|
width, height, format, GBM_BO_USE_SCANOUT)) {
|
|
finish_drm_surface(&plane->surf);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|