This is easier than GLX DRI3 GPU offloading support, because applications are not allowed to read the front buffer.
We just need to send to the server buffers it can read, and for that we use for every back buffer an intermediate buffer with no tiling to which we copy before sending the buffer to the compositor. Signed-off-by: Axel Davy <axel.d...@ens.fr> --- src/egl/drivers/dri2/egl_dri2.h | 5 +- src/egl/drivers/dri2/platform_wayland.c | 171 ++++++++++++++++++++++++++------ 2 files changed, 142 insertions(+), 34 deletions(-) diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h index 0dd9d69..4b70c48 100644 --- a/src/egl/drivers/dri2/egl_dri2.h +++ b/src/egl/drivers/dri2/egl_dri2.h @@ -195,6 +195,8 @@ struct dri2_egl_display int authenticated; int formats; uint32_t capabilities; + int is_different_gpu; + int blit_front; #endif }; @@ -247,7 +249,8 @@ struct dri2_egl_surface struct { #ifdef HAVE_WAYLAND_PLATFORM struct wl_buffer *wl_buffer; - __DRIimage *dri_image; + __DRIimage *rendering_image; + __DRIimage *shared_image; #endif #ifdef HAVE_DRM_PLATFORM struct gbm_bo *bo; diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index 537d26e..0dd4640 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -238,8 +238,10 @@ dri2_wl_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { if (dri2_surf->color_buffers[i].wl_buffer) wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); - if (dri2_surf->color_buffers[i].dri_image) - dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); + if (dri2_surf->color_buffers[i].rendering_image) { + dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].rendering_image); + dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].shared_image); + } } for (i = 0; i < __DRI_BUFFER_COUNT; i++) @@ -272,11 +274,14 @@ dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf) if (dri2_surf->color_buffers[i].wl_buffer && !dri2_surf->color_buffers[i].locked) wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); - if (dri2_surf->color_buffers[i].dri_image) - dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); + if (dri2_surf->color_buffers[i].rendering_image) { + dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].rendering_image); + dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].shared_image); + } dri2_surf->color_buffers[i].wl_buffer = NULL; - dri2_surf->color_buffers[i].dri_image = NULL; + dri2_surf->color_buffers[i].rendering_image = NULL; + dri2_surf->color_buffers[i].shared_image = NULL; dri2_surf->color_buffers[i].locked = 0; } @@ -292,6 +297,7 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); + unsigned int use_flags; int i; /* We always want to throttle to some event (either a frame callback or @@ -311,24 +317,45 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) continue; if (dri2_surf->back == NULL) dri2_surf->back = &dri2_surf->color_buffers[i]; - else if (dri2_surf->back->dri_image == NULL) + else if (dri2_surf->back->rendering_image == NULL) dri2_surf->back = &dri2_surf->color_buffers[i]; } } if (dri2_surf->back == NULL) return -1; - if (dri2_surf->back->dri_image == NULL) { - dri2_surf->back->dri_image = + + if (dri2_surf->back->rendering_image == NULL) { + use_flags = __DRI_IMAGE_USE_SHARE; + + if (dri2_dpy->is_different_gpu) + use_flags |= __DRI_IMAGE_USE_LINEAR; + + dri2_surf->back->shared_image = dri2_dpy->image->createImage(dri2_dpy->dri_screen, dri2_surf->base.Width, dri2_surf->base.Height, __DRI_IMAGE_FORMAT_ARGB8888, - __DRI_IMAGE_USE_SHARE, + use_flags, NULL); + if (dri2_surf->back->shared_image == NULL) + return -1; + + if (dri2_dpy->blit_front) + dri2_surf->back->rendering_image = + dri2_dpy->image->createImage(dri2_dpy->dri_screen, + dri2_surf->base.Width, + dri2_surf->base.Height, + __DRI_IMAGE_FORMAT_ARGB8888, + 0, + NULL); + else + dri2_surf->back->rendering_image = + dri2_dpy->image->dupImage(dri2_surf->back->shared_image, NULL); + dri2_surf->back->age = 0; } - if (dri2_surf->back->dri_image == NULL) + if (dri2_surf->back->rendering_image == NULL) return -1; dri2_surf->back->locked = 1; @@ -345,7 +372,7 @@ back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer) __DRIimage *image; int name, pitch; - image = dri2_surf->back->dri_image; + image = dri2_surf->back->rendering_image; dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name); dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch); @@ -411,9 +438,11 @@ update_buffers(struct dri2_egl_surface *dri2_surf) if (!dri2_surf->color_buffers[i].locked && dri2_surf->color_buffers[i].wl_buffer) { wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); - dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); + dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].rendering_image); + dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].shared_image); dri2_surf->color_buffers[i].wl_buffer = NULL; - dri2_surf->color_buffers[i].dri_image = NULL; + dri2_surf->color_buffers[i].rendering_image = NULL; + dri2_surf->color_buffers[i].shared_image = NULL; } } @@ -504,7 +533,7 @@ image_get_buffers(__DRIdrawable *driDrawable, return 0; buffers->image_mask = __DRI_IMAGE_BUFFER_BACK; - buffers->back = dri2_surf->back->dri_image; + buffers->back = dri2_surf->back->rendering_image; return 1; } @@ -549,9 +578,9 @@ create_wl_buffer(struct dri2_egl_surface *dri2_surf) return; if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) { - dri2_dpy->image->queryImage(dri2_surf->current->dri_image, + dri2_dpy->image->queryImage(dri2_surf->current->shared_image, __DRI_IMAGE_ATTRIB_FD, &fd); - dri2_dpy->image->queryImage(dri2_surf->current->dri_image, + dri2_dpy->image->queryImage(dri2_surf->current->shared_image, __DRI_IMAGE_ATTRIB_STRIDE, &stride); dri2_surf->current->wl_buffer = @@ -565,9 +594,9 @@ create_wl_buffer(struct dri2_egl_surface *dri2_surf) 0, 0); close(fd); } else { - dri2_dpy->image->queryImage(dri2_surf->current->dri_image, + dri2_dpy->image->queryImage(dri2_surf->current->shared_image, __DRI_IMAGE_ATTRIB_NAME, &name); - dri2_dpy->image->queryImage(dri2_surf->current->dri_image, + dri2_dpy->image->queryImage(dri2_surf->current->shared_image, __DRI_IMAGE_ATTRIB_STRIDE, &stride); dri2_surf->current->wl_buffer = @@ -650,6 +679,11 @@ dri2_wl_swap_buffers_with_damage(_EGLDriver *drv, } } + if (dri2_dpy->flush->base.version >= 4 || dri2_dpy->blit_front) { + ctx = _eglGetCurrentContext(); + dri2_ctx = dri2_egl_context(ctx); + } + if (dri2_dpy->flush->base.version >= 4) { ctx = _eglGetCurrentContext(); dri2_ctx = dri2_egl_context(ctx); @@ -661,6 +695,15 @@ dri2_wl_swap_buffers_with_damage(_EGLDriver *drv, (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); } + if (dri2_dpy->blit_front) + dri2_dpy->image->blitImage(dri2_ctx->dri_context, + dri2_surf->current->shared_image, + dri2_surf->current->rendering_image, + 0, 0, dri2_surf->base.Width, + dri2_surf->base.Height, + 0, 0, dri2_surf->base.Width, + dri2_surf->base.Height, 1); + (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable); wl_surface_commit(dri2_surf->wl_win->surface); @@ -714,6 +757,14 @@ dri2_wl_create_wayland_buffer_from_image(_EGLDriver *drv, int width, height, format, pitch; enum wl_drm_format wl_format; + /* The buffer to import likely has tiling. This tiling mode is likely + * incompatible with the server gpu. We can't check for it, so assume + * we cannot import.*/ + if (dri2_dpy->is_different_gpu) { + _eglError(EGL_BAD_MATCH, "dri2_create_wayland_buffer_from_image_wl"); + return NULL; + } + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format); switch (format) { @@ -777,6 +828,22 @@ bad_format: return NULL; } +static char +is_fd_render_node(int fd) +{ + struct stat render; + + if (fstat(fd, &render)) + return 0; + + if (!S_ISCHR(render.st_mode)) + return 0; + + if (render.st_rdev & 0x80) + return 1; + return 0; +} + static int dri2_wl_authenticate(_EGLDisplay *disp, uint32_t id) { @@ -804,28 +871,27 @@ drm_handle_device(void *data, struct wl_drm *drm, const char *device) struct dri2_egl_display *dri2_dpy = data; drm_magic_t magic; - dri2_dpy->device_name = strdup(device); - if (!dri2_dpy->device_name) - return; - #ifdef O_CLOEXEC - dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC); + dri2_dpy->fd = open(device, O_RDWR | O_CLOEXEC); if (dri2_dpy->fd == -1 && errno == EINVAL) #endif { - dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR); + dri2_dpy->fd = open(device, O_RDWR); if (dri2_dpy->fd != -1) fcntl(dri2_dpy->fd, F_SETFD, fcntl(dri2_dpy->fd, F_GETFD) | FD_CLOEXEC); } if (dri2_dpy->fd == -1) { _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)", - dri2_dpy->device_name, strerror(errno)); + device, strerror(errno)); return; } - drmGetMagic(dri2_dpy->fd, &magic); - wl_drm_authenticate(dri2_dpy->wl_drm, magic); + if (!is_fd_render_node(dri2_dpy->fd)) { + drmGetMagic(dri2_dpy->fd, &magic); + wl_drm_authenticate(dri2_dpy->wl_drm, magic); + } else + dri2_dpy->authenticated = 1; } static void @@ -967,6 +1033,23 @@ static struct dri2_egl_display_vtbl dri2_wl_display_vtbl = { .get_sync_values = dri2_fallback_get_sync_values, }; +static EGLBoolean +is_render_node_capable(struct dri2_egl_display *dri2_dpy) +{ + const __DRIextension **extensions; + int i; + + if (!(dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME)) + return EGL_FALSE; + + extensions = dri2_dpy->driver_extensions; + for (i = 0; extensions[i]; i++) { + if (strcmp(extensions[i]->name, __DRI_IMAGE_DRIVER) == 0) + return EGL_TRUE; + } + return EGL_FALSE; +} + EGLBoolean dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) { @@ -1014,10 +1097,19 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated) goto cleanup_fd; + dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu); + dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd); + + if (dri2_dpy->device_name == NULL) { + _eglError(EGL_BAD_ALLOC, "DRI2: failed to get device name"); + goto cleanup_fd; + } + dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd, 0); + if (dri2_dpy->driver_name == NULL) { _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name"); - goto cleanup_fd; + goto cleanup_device_name; } if (!dri2_load_driver(disp)) @@ -1043,15 +1135,25 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) dri2_wl_setup_swap_interval(dri2_dpy); - /* The server shouldn't advertise WL_DRM_CAPABILITY_PRIME if the driver - * doesn't have createImageFromFds, since we're using the same driver on - * both sides. We don't want crash if that happens anyway, so fall back to - * gem names if we don't have prime support. */ + /* To use Prime, we must have _DRI_IMAGE v7 at least. + * createImageFromFds support indicates that Prime export/import + * is supported by the driver. Fall back to + * gem names if we don't have Prime support. */ if (dri2_dpy->image->base.version < 7 || dri2_dpy->image->createImageFromFds == NULL) dri2_dpy->capabilities &= ~WL_DRM_CAPABILITY_PRIME; + if (is_fd_render_node(dri2_dpy->fd) && !is_render_node_capable(dri2_dpy)) { + _eglLog(_EGL_WARNING, "wayland-egl: display is not render-node capable"); + goto cleanup_screen; + } + + if (dri2_dpy->is_different_gpu && dri2_dpy->image->base.version >= 9) { + dri2_dpy->blit_front = 1; + _eglLog(_EGL_DEBUG, "wayland-egl: blit mode activated"); + } + types = EGL_WINDOW_BIT; for (i = 0; dri2_dpy->driver_configs[i]; i++) { config = dri2_dpy->driver_configs[i]; @@ -1080,14 +1182,17 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) return EGL_TRUE; + cleanup_screen: + dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); cleanup_driver: dlclose(dri2_dpy->driver); cleanup_driver_name: free(dri2_dpy->driver_name); + cleanup_device_name: + free(dri2_dpy->device_name); cleanup_fd: close(dri2_dpy->fd); cleanup_drm: - free(dri2_dpy->device_name); wl_drm_destroy(dri2_dpy->wl_drm); cleanup_dpy: free(dri2_dpy); -- 1.9.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev