From 507409f5d0a7bced42656276e806da6f516ca321 Mon Sep 17 00:00:00 2001 From: Gert-dev Date: Wed, 18 Dec 2024 16:13:16 +0100 Subject: [PATCH] onscreen/native: Cache created secondary GPU EGLImages in copy path Creating an EGLImage is rather expensive and is taking the bulk of the time the secondary GPU copy path is using for each frame. By caching these per GBM BO we avoid this expensive recreation, which seems to significantly improve FPS throughput in these scenarios, e.g. an AMD or Intel iGPU with an NVIDIA dGPU. Part-of: --- src/backends/native/meta-egl-gbm.c | 150 ++++++++++++++++++ src/backends/native/meta-egl-gbm.h | 34 ++++ src/backends/native/meta-onscreen-native.c | 12 +- .../native/meta-renderer-native-gles3.c | 72 +-------- .../native/meta-renderer-native-gles3.h | 2 +- src/meson.build | 2 + 6 files changed, 199 insertions(+), 73 deletions(-) create mode 100644 src/backends/native/meta-egl-gbm.c create mode 100644 src/backends/native/meta-egl-gbm.h 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',