[Mesa-dev] [PATCH 09/11] Wayland/egl: Add GPU offloading support
Axel Davy
axel.davy at ens.fr
Wed Jun 18 20:27:38 PDT 2014
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.davy at 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
More information about the mesa-dev
mailing list