diff --git a/src/backends/native/meta-egl-gbm.c b/src/backends/native/meta-egl-gbm.c new file mode 100644 index 000000000..c50d9556a --- /dev/null +++ b/src/backends/native/meta-egl-gbm.c @@ -0,0 +1,150 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2016, 2017 Red Hat Inc. + * Copyright (C) 2018, 2019 DisplayLink (UK) Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Written by: + * Jonas Ådahl + */ + +#include "config.h" + +#include +#include + +#include "backends/native/meta-egl-gbm.h" + +typedef struct _GbmBoUserData +{ + EGLImageKHR egl_image; + + MetaEgl *egl; + EGLDisplay egl_display; +} GbmBoUserData; + +static EGLImageKHR +create_gbm_bo_egl_image (MetaEgl *egl, + EGLDisplay egl_display, + struct gbm_bo *shared_bo, + GError **error) +{ + int shared_bo_fd; + unsigned int width; + unsigned int height; + uint32_t i, n_planes; + uint32_t strides[4] = { 0 }; + uint32_t offsets[4] = { 0 }; + uint64_t modifiers[4] = { 0 }; + int fds[4] = { -1, -1, -1, -1 }; + uint32_t format; + EGLImageKHR egl_image; + gboolean use_modifiers; + + shared_bo_fd = gbm_bo_get_fd (shared_bo); + if (shared_bo_fd < 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to export gbm_bo: %s", strerror (errno)); + return FALSE; + } + + width = gbm_bo_get_width (shared_bo); + height = gbm_bo_get_height (shared_bo); + format = gbm_bo_get_format (shared_bo); + + n_planes = gbm_bo_get_plane_count (shared_bo); + for (i = 0; i < n_planes; i++) + { + strides[i] = gbm_bo_get_stride_for_plane (shared_bo, i); + offsets[i] = gbm_bo_get_offset (shared_bo, i); + modifiers[i] = gbm_bo_get_modifier (shared_bo); + fds[i] = shared_bo_fd; + } + + /* Workaround for https://gitlab.gnome.org/GNOME/mutter/issues/18 */ + if (modifiers[0] == DRM_FORMAT_MOD_LINEAR || + modifiers[0] == DRM_FORMAT_MOD_INVALID) + use_modifiers = FALSE; + else + use_modifiers = TRUE; + + egl_image = meta_egl_create_dmabuf_image (egl, + egl_display, + width, + height, + format, + n_planes, + fds, + strides, + offsets, + use_modifiers ? modifiers : NULL, + error); + close (shared_bo_fd); + + return egl_image; +} + +static void +free_gbm_bo_egl_image (struct gbm_bo *bo, + void *data) +{ + GbmBoUserData *user_data = data; + g_autoptr (GError) error = NULL; + + if (!meta_egl_destroy_image (user_data->egl, + user_data->egl_display, + user_data->egl_image, + &error)) + { + g_warning ("Could not destroy EGLImage attached to GBM BO: %s", error->message); + } + + g_free (data); +} + +EGLImageKHR +meta_egl_ensure_gbm_bo_egl_image (MetaEgl *egl, + EGLDisplay egl_display, + struct gbm_bo *bo, + GError **error) +{ + GbmBoUserData *bo_user_data = NULL; + + bo_user_data = gbm_bo_get_user_data (bo); + + if (!bo_user_data) + { + EGLImageKHR egl_image = EGL_NO_IMAGE; + + egl_image = create_gbm_bo_egl_image (egl, + egl_display, + bo, + error); + + if (!egl_image) + return EGL_NO_IMAGE; + + bo_user_data = g_new0 (GbmBoUserData, 1); + bo_user_data->egl = egl; + bo_user_data->egl_display = egl_display; + bo_user_data->egl_image = egl_image; + + gbm_bo_set_user_data (bo, bo_user_data, free_gbm_bo_egl_image); + } + + return bo_user_data->egl_image; +} diff --git a/src/backends/native/meta-egl-gbm.h b/src/backends/native/meta-egl-gbm.h new file mode 100644 index 000000000..6685db7f9 --- /dev/null +++ b/src/backends/native/meta-egl-gbm.h @@ -0,0 +1,34 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2016 Red Hat Inc. + * Copyright (C) 2019 DisplayLink (UK) Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Written by: + * Jonas Ådahl + */ + +#pragma once + +#include +#include + +#include "backends/meta-egl.h" + +EGLImageKHR meta_egl_ensure_gbm_bo_egl_image (MetaEgl *egl, + EGLDisplay egl_display, + struct gbm_bo *shared_bo, + GError **error); diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c index a7a632abc..8006b9f52 100644 --- a/src/backends/native/meta-onscreen-native.c +++ b/src/backends/native/meta-onscreen-native.c @@ -50,6 +50,7 @@ #include "backends/native/meta-render-device.h" #include "backends/native/meta-renderer-native-gles3.h" #include "backends/native/meta-renderer-native-private.h" +#include "backends/native/meta-egl-gbm.h" #include "cogl/cogl.h" #include "common/meta-cogl-drm-formats.h" #include "common/meta-drm-format-helpers.h" @@ -847,6 +848,7 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, struct gbm_bo *bo; EGLSync egl_sync = EGL_NO_SYNC; g_autofd int sync_fd = -1; + EGLImageKHR egl_image; COGL_TRACE_BEGIN_SCOPED (CopySharedFramebufferSecondaryGpu, "copy_shared_framebuffer_gpu()"); @@ -900,11 +902,19 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, buffer_gbm = META_DRM_BUFFER_GBM (primary_gpu_fb); bo = meta_drm_buffer_gbm_get_bo (buffer_gbm); + egl_image = meta_egl_ensure_gbm_bo_egl_image (egl, egl_display, bo, error); + + if (!egl_image) + { + g_prefix_error (error, "Failed to create EGL image from buffer object for secondary GPU: "); + goto done; + } + if (!meta_renderer_native_gles3_blit_shared_bo (egl, gles3, egl_display, renderer_gpu_data->secondary.egl_context, - secondary_gpu_state->egl_surface, + egl_image, bo, error)) { diff --git a/src/backends/native/meta-renderer-native-gles3.c b/src/backends/native/meta-renderer-native-gles3.c index b23e04f47..51a449a96 100644 --- a/src/backends/native/meta-renderer-native-gles3.c +++ b/src/backends/native/meta-renderer-native-gles3.c @@ -347,74 +347,12 @@ paint_egl_image (ContextData *context_data, GLBAS (gles3, glDeleteTextures, (1, &texture)); } -static EGLImageKHR -meta_create_gbm_bo_egl_image (MetaEgl *egl, - EGLDisplay egl_display, - struct gbm_bo *shared_bo, - GError **error) -{ - int shared_bo_fd; - unsigned int width; - unsigned int height; - uint32_t i, n_planes; - uint32_t strides[4] = { 0 }; - uint32_t offsets[4] = { 0 }; - uint64_t modifiers[4] = { 0 }; - int fds[4] = { -1, -1, -1, -1 }; - uint32_t format; - EGLImageKHR egl_image; - gboolean use_modifiers; - - shared_bo_fd = gbm_bo_get_fd (shared_bo); - if (shared_bo_fd < 0) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Failed to export gbm_bo: %s", strerror (errno)); - return FALSE; - } - - width = gbm_bo_get_width (shared_bo); - height = gbm_bo_get_height (shared_bo); - format = gbm_bo_get_format (shared_bo); - - n_planes = gbm_bo_get_plane_count (shared_bo); - for (i = 0; i < n_planes; i++) - { - strides[i] = gbm_bo_get_stride_for_plane (shared_bo, i); - offsets[i] = gbm_bo_get_offset (shared_bo, i); - modifiers[i] = gbm_bo_get_modifier (shared_bo); - fds[i] = shared_bo_fd; - } - - /* Workaround for https://gitlab.gnome.org/GNOME/mutter/issues/18 */ - if (modifiers[0] == DRM_FORMAT_MOD_LINEAR || - modifiers[0] == DRM_FORMAT_MOD_INVALID) - use_modifiers = FALSE; - else - use_modifiers = TRUE; - - egl_image = meta_egl_create_dmabuf_image (egl, - egl_display, - width, - height, - format, - n_planes, - fds, - strides, - offsets, - use_modifiers ? modifiers : NULL, - error); - close (shared_bo_fd); - - return egl_image; -} - gboolean meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl, MetaGles3 *gles3, EGLDisplay egl_display, EGLContext egl_context, - EGLSurface egl_surface, + EGLImageKHR egl_image, struct gbm_bo *shared_bo, GError **error) { @@ -423,7 +361,6 @@ meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl, GQuark context_data_quark; ContextData *context_data; gboolean can_blit; - EGLImageKHR egl_image = EGL_NO_IMAGE; context_data_quark = get_quark_for_egl_context (egl_context); context_data = g_object_get_qdata (G_OBJECT (gles3), context_data_quark); @@ -447,18 +384,11 @@ meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl, width = gbm_bo_get_width (shared_bo); height = gbm_bo_get_height (shared_bo); - egl_image = meta_create_gbm_bo_egl_image (egl, - egl_display, - shared_bo, - error); - if (can_blit) blit_egl_image (gles3, egl_image, width, height); else paint_egl_image (context_data, gles3, egl_image, width, height); - meta_egl_destroy_image (egl, egl_display, egl_image, NULL); - return TRUE; } diff --git a/src/backends/native/meta-renderer-native-gles3.h b/src/backends/native/meta-renderer-native-gles3.h index f5791a171..6a935c7e6 100644 --- a/src/backends/native/meta-renderer-native-gles3.h +++ b/src/backends/native/meta-renderer-native-gles3.h @@ -30,7 +30,7 @@ gboolean meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl, MetaGles3 *gles3, EGLDisplay egl_display, EGLContext egl_context, - EGLSurface egl_surface, + EGLImageKHR egl_image, struct gbm_bo *shared_bo, GError **error); diff --git a/src/meson.build b/src/meson.build index 12362093c..84640debe 100644 --- a/src/meson.build +++ b/src/meson.build @@ -791,6 +791,8 @@ if have_native_backend 'backends/native/meta-drm-buffer-private.h', 'backends/native/meta-drm-buffer.c', 'backends/native/meta-drm-buffer.h', + 'backends/native/meta-egl-gbm.c', + 'backends/native/meta-egl-gbm.h', 'backends/native/meta-gpu-kms.c', 'backends/native/meta-gpu-kms.h', 'backends/native/meta-frame-native.c',