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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4027>
This commit is contained in:
parent
110bdf0e9f
commit
507409f5d0
150
src/backends/native/meta-egl-gbm.c
Normal file
150
src/backends/native/meta-egl-gbm.c
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Written by:
|
||||
* Jonas Ådahl <jadahl@gmail.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
#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;
|
||||
}
|
34
src/backends/native/meta-egl-gbm.h
Normal file
34
src/backends/native/meta-egl-gbm.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Written by:
|
||||
* Jonas Ådahl <jadahl@gmail.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gbm.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#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);
|
@ -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))
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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',
|
||||
|
Loading…
x
Reference in New Issue
Block a user