mirror of
https://gitlab.freedesktop.org/wayland/weston.git
synced 2026-05-18 08:08:11 +02:00
compostor-drm: Use gbm surface
Instead of using the hacks of gbm_bos, EGLImage, FBOs and surfaceless we switch to using the new gbm surface API. This gives us an EGL native window type for gbm and lets us use a real EGL surface.
This commit is contained in:
parent
0a38611e7d
commit
cbcd04794c
1 changed files with 127 additions and 150 deletions
|
|
@ -77,14 +77,14 @@ struct drm_output {
|
|||
uint32_t crtc_id;
|
||||
uint32_t connector_id;
|
||||
drmModeCrtcPtr original_crtc;
|
||||
GLuint rbo[2];
|
||||
uint32_t fb_id[2];
|
||||
EGLImageKHR image[2];
|
||||
struct gbm_bo *bo[2];
|
||||
uint32_t current;
|
||||
|
||||
uint32_t fs_surf_fb_id;
|
||||
uint32_t pending_fs_surf_fb_id;
|
||||
struct gbm_surface *surface;
|
||||
EGLSurface egl_surface;
|
||||
uint32_t current_fb_id;
|
||||
uint32_t next_fb_id;
|
||||
struct gbm_bo *current_bo;
|
||||
struct gbm_bo *next_bo;
|
||||
|
||||
struct wl_buffer *scanout_buffer;
|
||||
struct wl_listener scanout_buffer_destroy_listener;
|
||||
struct wl_buffer *pending_scanout_buffer;
|
||||
|
|
@ -158,10 +158,6 @@ drm_output_prepare_scanout_surface(struct drm_output *output)
|
|||
struct drm_compositor *c =
|
||||
(struct drm_compositor *) output->base.compositor;
|
||||
struct weston_surface *es;
|
||||
EGLint handle, stride;
|
||||
int ret;
|
||||
uint32_t fb_id = 0;
|
||||
struct gbm_bo *bo;
|
||||
|
||||
es = container_of(c->base.surface_list.next,
|
||||
struct weston_surface, link);
|
||||
|
|
@ -178,29 +174,12 @@ drm_output_prepare_scanout_surface(struct drm_output *output)
|
|||
es->image == EGL_NO_IMAGE_KHR)
|
||||
return -1;
|
||||
|
||||
bo = gbm_bo_create_from_egl_image(c->gbm,
|
||||
c->base.display, es->image,
|
||||
es->geometry.width,
|
||||
es->geometry.height,
|
||||
GBM_BO_USE_SCANOUT);
|
||||
|
||||
handle = gbm_bo_get_handle(bo).s32;
|
||||
stride = gbm_bo_get_pitch(bo);
|
||||
|
||||
gbm_bo_destroy(bo);
|
||||
|
||||
if (handle == 0)
|
||||
return -1;
|
||||
|
||||
ret = drmModeAddFB(c->drm.fd,
|
||||
output->base.current->width,
|
||||
output->base.current->height,
|
||||
24, 32, stride, handle, &fb_id);
|
||||
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
output->pending_fs_surf_fb_id = fb_id;
|
||||
output->next_bo =
|
||||
gbm_bo_create_from_egl_image(c->gbm,
|
||||
c->base.display, es->image,
|
||||
es->geometry.width,
|
||||
es->geometry.height,
|
||||
GBM_BO_USE_SCANOUT);
|
||||
|
||||
/* assert output->pending_scanout_buffer == NULL */
|
||||
output->pending_scanout_buffer = es->buffer;
|
||||
|
|
@ -215,6 +194,30 @@ drm_output_prepare_scanout_surface(struct drm_output *output)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
drm_output_render(struct drm_output *output, pixman_region32_t *damage)
|
||||
{
|
||||
struct drm_compositor *compositor =
|
||||
(struct drm_compositor *) output->base.compositor;
|
||||
struct weston_surface *surface;
|
||||
|
||||
if (!eglMakeCurrent(compositor->base.display, output->egl_surface,
|
||||
output->egl_surface, compositor->base.context)) {
|
||||
fprintf(stderr, "failed to make current\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wl_list_for_each_reverse(surface, &compositor->base.surface_list, link)
|
||||
weston_surface_draw(surface, &output->base, damage);
|
||||
|
||||
eglSwapBuffers(compositor->base.display, output->egl_surface);
|
||||
output->next_bo = gbm_surface_lock_front_buffer(output->surface);
|
||||
if (!output->next_bo) {
|
||||
fprintf(stderr, "failed to lock front buffer: %m\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drm_output_repaint(struct weston_output *output_base,
|
||||
pixman_region32_t *damage)
|
||||
|
|
@ -222,36 +225,51 @@ drm_output_repaint(struct weston_output *output_base,
|
|||
struct drm_output *output = (struct drm_output *) output_base;
|
||||
struct drm_compositor *compositor =
|
||||
(struct drm_compositor *) output->base.compositor;
|
||||
struct weston_surface *surface;
|
||||
struct drm_sprite *s;
|
||||
uint32_t fb_id = 0;
|
||||
struct drm_mode *mode;
|
||||
uint32_t stride, handle;
|
||||
int ret = 0;
|
||||
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER,
|
||||
output->rbo[output->current]);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
return;
|
||||
|
||||
drm_output_prepare_scanout_surface(output);
|
||||
if (!output->next_bo)
|
||||
drm_output_render(output, damage);
|
||||
|
||||
wl_list_for_each_reverse(surface, &compositor->base.surface_list, link)
|
||||
weston_surface_draw(surface, &output->base, damage);
|
||||
stride = gbm_bo_get_pitch(output->next_bo);
|
||||
handle = gbm_bo_get_handle(output->next_bo).u32;
|
||||
|
||||
glFlush();
|
||||
/* Destroy and set to NULL now so we don't try to
|
||||
* gbm_surface_release_buffer() a client buffer in the
|
||||
* page_flip_handler. */
|
||||
if (output->pending_scanout_buffer) {
|
||||
gbm_bo_destroy(output->next_bo);
|
||||
output->next_bo = NULL;
|
||||
}
|
||||
|
||||
output->current ^= 1;
|
||||
ret = drmModeAddFB(compositor->drm.fd,
|
||||
output->base.current->width,
|
||||
output->base.current->height,
|
||||
24, 32, stride, handle, &output->next_fb_id);
|
||||
if (ret) {
|
||||
fprintf(stderr, "failed to create kms fb: %m\n");
|
||||
gbm_surface_release_buffer(output->surface, output->next_bo);
|
||||
output->next_bo = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (output->pending_fs_surf_fb_id != 0) {
|
||||
fb_id = output->pending_fs_surf_fb_id;
|
||||
} else {
|
||||
fb_id = output->fb_id[output->current ^ 1];
|
||||
mode = container_of(output->base.current, struct drm_mode, base);
|
||||
if (output->current_fb_id == 0) {
|
||||
ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
|
||||
output->next_fb_id, 0, 0,
|
||||
&output->connector_id, 1,
|
||||
&mode->mode_info);
|
||||
if (ret) {
|
||||
fprintf(stderr, "set mode failed: %m\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
|
||||
fb_id,
|
||||
output->next_fb_id,
|
||||
DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
|
||||
fprintf(stderr, "queueing pageflip failed: %m\n");
|
||||
return;
|
||||
|
|
@ -330,24 +348,30 @@ page_flip_handler(int fd, unsigned int frame,
|
|||
(struct drm_compositor *) output->base.compositor;
|
||||
uint32_t msecs;
|
||||
|
||||
if (output->current_fb_id)
|
||||
drmModeRmFB(c->drm.fd, output->current_fb_id);
|
||||
output->current_fb_id = output->next_fb_id;
|
||||
output->next_fb_id = 0;
|
||||
|
||||
if (output->scanout_buffer) {
|
||||
weston_buffer_post_release(output->scanout_buffer);
|
||||
wl_list_remove(&output->scanout_buffer_destroy_listener.link);
|
||||
output->scanout_buffer = NULL;
|
||||
drmModeRmFB(c->drm.fd, output->fs_surf_fb_id);
|
||||
output->fs_surf_fb_id = 0;
|
||||
} else if (output->current_bo) {
|
||||
gbm_surface_release_buffer(output->surface,
|
||||
output->current_bo);
|
||||
}
|
||||
|
||||
output->current_bo = output->next_bo;
|
||||
output->next_bo = NULL;
|
||||
|
||||
if (output->pending_scanout_buffer) {
|
||||
output->scanout_buffer = output->pending_scanout_buffer;
|
||||
wl_list_remove(&output->pending_scanout_buffer_destroy_listener.link);
|
||||
wl_list_insert(output->scanout_buffer->resource.destroy_listener_list.prev,
|
||||
&output->scanout_buffer_destroy_listener.link);
|
||||
output->pending_scanout_buffer = NULL;
|
||||
output->fs_surf_fb_id = output->pending_fs_surf_fb_id;
|
||||
output->pending_fs_surf_fb_id = 0;
|
||||
}
|
||||
|
||||
msecs = sec * 1000 + usec / 1000;
|
||||
weston_output_finish_frame(&output->base, msecs);
|
||||
}
|
||||
|
|
@ -703,7 +727,6 @@ drm_output_destroy(struct weston_output *output_base)
|
|||
struct drm_compositor *c =
|
||||
(struct drm_compositor *) output->base.compositor;
|
||||
drmModeCrtcPtr origcrtc = output->original_crtc;
|
||||
int i;
|
||||
|
||||
if (output->backlight)
|
||||
backlight_destroy(output->backlight);
|
||||
|
|
@ -717,24 +740,12 @@ drm_output_destroy(struct weston_output *output_base)
|
|||
&output->connector_id, 1, &origcrtc->mode);
|
||||
drmModeFreeCrtc(origcrtc);
|
||||
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER,
|
||||
0);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
glDeleteRenderbuffers(2, output->rbo);
|
||||
|
||||
/* Destroy output buffers */
|
||||
for (i = 0; i < 2; i++) {
|
||||
drmModeRmFB(c->drm.fd, output->fb_id[i]);
|
||||
c->base.destroy_image(c->base.display, output->image[i]);
|
||||
gbm_bo_destroy(output->bo[i]);
|
||||
}
|
||||
|
||||
c->crtc_allocator &= ~(1 << output->crtc_id);
|
||||
c->connector_allocator &= ~(1 << output->connector_id);
|
||||
|
||||
eglDestroySurface(c->base.display, output->egl_surface);
|
||||
gbm_surface_destroy(output->surface);
|
||||
|
||||
weston_output_destroy(&output->base);
|
||||
wl_list_remove(&output->base.link);
|
||||
|
||||
|
|
@ -758,7 +769,7 @@ on_drm_input(int fd, uint32_t mask, void *data)
|
|||
static int
|
||||
init_egl(struct drm_compositor *ec, struct udev_device *device)
|
||||
{
|
||||
EGLint major, minor;
|
||||
EGLint major, minor, n;
|
||||
const char *extensions, *filename, *sysnum;
|
||||
int fd;
|
||||
static const EGLint context_attribs[] = {
|
||||
|
|
@ -774,6 +785,16 @@ init_egl(struct drm_compositor *ec, struct udev_device *device)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static const EGLint config_attribs[] = {
|
||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||
EGL_RED_SIZE, 1,
|
||||
EGL_GREEN_SIZE, 1,
|
||||
EGL_BLUE_SIZE, 1,
|
||||
EGL_ALPHA_SIZE, 0,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
filename = udev_device_get_devnode(device);
|
||||
fd = open(filename, O_RDWR | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
|
|
@ -807,7 +828,13 @@ init_egl(struct drm_compositor *ec, struct udev_device *device)
|
|||
return -1;
|
||||
}
|
||||
|
||||
ec->base.context = eglCreateContext(ec->base.display, NULL,
|
||||
if (!eglChooseConfig(ec->base.display, config_attribs,
|
||||
&ec->base.config, 1, &n) || n != 1) {
|
||||
fprintf(stderr, "failed to choose config: %d\n", n);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ec->base.context = eglCreateContext(ec->base.display, ec->base.config,
|
||||
EGL_NO_CONTEXT, context_attribs);
|
||||
if (ec->base.context == NULL) {
|
||||
fprintf(stderr, "failed to create context\n");
|
||||
|
|
@ -1017,7 +1044,6 @@ create_output_for_connector(struct drm_compositor *ec,
|
|||
struct drm_mode *drm_mode, *next;
|
||||
drmModeEncoder *encoder;
|
||||
int i, ret;
|
||||
unsigned handle, stride;
|
||||
|
||||
encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[0]);
|
||||
if (encoder == NULL) {
|
||||
|
|
@ -1041,8 +1067,6 @@ create_output_for_connector(struct drm_compositor *ec,
|
|||
drmModeFreeEncoder(encoder);
|
||||
return -1;
|
||||
}
|
||||
output->fb_id[0] = -1;
|
||||
output->fb_id[1] = -1;
|
||||
|
||||
memset(output, 0, sizeof *output);
|
||||
output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
|
||||
|
|
@ -1076,54 +1100,23 @@ create_output_for_connector(struct drm_compositor *ec,
|
|||
drm_mode->base.flags =
|
||||
WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
|
||||
|
||||
glGenRenderbuffers(2, output->rbo);
|
||||
for (i = 0; i < 2; i++) {
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
|
||||
|
||||
output->bo[i] =
|
||||
gbm_bo_create(ec->gbm,
|
||||
output->base.current->width,
|
||||
output->base.current->height,
|
||||
GBM_BO_FORMAT_XRGB8888,
|
||||
GBM_BO_USE_SCANOUT |
|
||||
GBM_BO_USE_RENDERING);
|
||||
if (!output->bo[i])
|
||||
goto err_bufs;
|
||||
|
||||
output->image[i] = ec->base.create_image(ec->base.display,
|
||||
NULL,
|
||||
EGL_NATIVE_PIXMAP_KHR,
|
||||
output->bo[i], NULL);
|
||||
if (!output->image[i])
|
||||
goto err_bufs;
|
||||
|
||||
ec->base.image_target_renderbuffer_storage(GL_RENDERBUFFER,
|
||||
output->image[i]);
|
||||
stride = gbm_bo_get_pitch(output->bo[i]);
|
||||
handle = gbm_bo_get_handle(output->bo[i]).u32;
|
||||
|
||||
ret = drmModeAddFB(ec->drm.fd,
|
||||
output->base.current->width,
|
||||
output->base.current->height,
|
||||
24, 32, stride, handle, &output->fb_id[i]);
|
||||
if (ret) {
|
||||
fprintf(stderr, "failed to add fb %d: %m\n", i);
|
||||
goto err_bufs;
|
||||
}
|
||||
output->surface = gbm_surface_create(ec->gbm,
|
||||
output->base.current->width,
|
||||
output->base.current->height,
|
||||
GBM_FORMAT_XRGB8888,
|
||||
GBM_BO_USE_SCANOUT |
|
||||
GBM_BO_USE_RENDERING);
|
||||
if (!output->surface) {
|
||||
fprintf(stderr, "failed to create gbm surface\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
output->current = 0;
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER,
|
||||
output->rbo[output->current]);
|
||||
ret = drmModeSetCrtc(ec->drm.fd, output->crtc_id,
|
||||
output->fb_id[output->current ^ 1], 0, 0,
|
||||
&output->connector_id, 1,
|
||||
&drm_mode->mode_info);
|
||||
if (ret) {
|
||||
fprintf(stderr, "failed to set mode: %m\n");
|
||||
goto err_fb;
|
||||
output->egl_surface =
|
||||
eglCreateWindowSurface(ec->base.display, ec->base.config,
|
||||
output->surface, NULL);
|
||||
if (output->egl_surface == EGL_NO_SURFACE) {
|
||||
fprintf(stderr, "failed to create egl surface\n");
|
||||
goto err_surface;
|
||||
}
|
||||
|
||||
output->backlight = backlight_init(drm_device,
|
||||
|
|
@ -1134,7 +1127,8 @@ create_output_for_connector(struct drm_compositor *ec,
|
|||
}
|
||||
|
||||
weston_output_init(&output->base, &ec->base, x, y,
|
||||
connector->mmWidth, connector->mmHeight, 0);
|
||||
connector->mmWidth, connector->mmHeight,
|
||||
WL_OUTPUT_FLIPPED);
|
||||
|
||||
wl_list_insert(ec->base.output_list.prev, &output->base.link);
|
||||
|
||||
|
|
@ -1143,7 +1137,7 @@ create_output_for_connector(struct drm_compositor *ec,
|
|||
output->pending_scanout_buffer_destroy_listener.func =
|
||||
output_handle_pending_scanout_buffer_destroy;
|
||||
|
||||
output->pending_fs_surf_fb_id = 0;
|
||||
output->next_fb_id = 0;
|
||||
output->base.repaint = drm_output_repaint;
|
||||
output->base.destroy = drm_output_destroy;
|
||||
output->base.assign_planes = drm_assign_planes;
|
||||
|
|
@ -1151,23 +1145,9 @@ create_output_for_connector(struct drm_compositor *ec,
|
|||
|
||||
return 0;
|
||||
|
||||
err_fb:
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER,
|
||||
0);
|
||||
err_bufs:
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (output->fb_id[i] != -1)
|
||||
drmModeRmFB(ec->drm.fd, output->fb_id[i]);
|
||||
if (output->image[i])
|
||||
ec->base.destroy_image(ec->base.display,
|
||||
output->image[i]);
|
||||
if (output->bo[i])
|
||||
gbm_bo_destroy(output->bo[i]);
|
||||
}
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
glDeleteRenderbuffers(2, output->rbo);
|
||||
eglDestroySurface(ec->base.display, output->egl_surface);
|
||||
err_surface:
|
||||
gbm_surface_destroy(output->surface);
|
||||
err_free:
|
||||
wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
|
||||
base.link) {
|
||||
|
|
@ -1178,8 +1158,8 @@ err_free:
|
|||
drmModeFreeCrtc(output->original_crtc);
|
||||
ec->crtc_allocator &= ~(1 << output->crtc_id);
|
||||
ec->connector_allocator &= ~(1 << output->connector_id);
|
||||
|
||||
free(output);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -1453,12 +1433,12 @@ drm_compositor_set_modes(struct drm_compositor *compositor)
|
|||
wl_list_for_each(output, &compositor->base.output_list, base.link) {
|
||||
drm_mode = (struct drm_mode *) output->base.current;
|
||||
ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
|
||||
output->fb_id[output->current ^ 1], 0, 0,
|
||||
output->current_fb_id, 0, 0,
|
||||
&output->connector_id, 1,
|
||||
&drm_mode->mode_info);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr,
|
||||
"failed to set mode %dx%d for output at %d,%d: %m",
|
||||
"failed to set mode %dx%d for output at %d,%d: %m\n",
|
||||
drm_mode->base.width, drm_mode->base.height,
|
||||
output->base.x, output->base.y);
|
||||
}
|
||||
|
|
@ -1592,9 +1572,6 @@ drm_compositor_create(struct wl_display *display,
|
|||
|
||||
ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
|
||||
|
||||
glGenFramebuffers(1, &ec->base.fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, ec->base.fbo);
|
||||
|
||||
/* Can't init base class until we have a current egl context */
|
||||
if (weston_compositor_init(&ec->base, display) < 0)
|
||||
return NULL;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue