1
0
Fork 0

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.

(cherry picked from commit 0255c1f5c099bd0a761d5c42cfdbc74e4375882d)
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4027>
Signed-off-by: Mingi Sung <sungmg@saltyming.net>
This commit is contained in:
Gert-dev 2024-10-02 20:51:03 +02:00 committed by Mingi Sung
parent 3a202f58ce
commit e0b7afe8fa
Signed by: sungmg
GPG key ID: 41BAFD6FFD8036C5
5 changed files with 141 additions and 55 deletions

View file

@ -23,6 +23,7 @@
#include "backends/native/meta-drm-buffer-gbm.h"
#include <EGL/egl.h>
#include <drm_fourcc.h>
#include <errno.h>
#include <gio/gio.h>
@ -43,6 +44,14 @@ struct _MetaDrmBufferGbm
struct gbm_bo *bo;
};
typedef struct _MetaDrmBufferGbmBoUserData
{
EGLImageKHR egl_image;
MetaEgl *egl;
EGLDisplay egl_display;
} MetaDrmBufferGbmBoUserData;
static void
cogl_scanout_buffer_iface_init (CoglScanoutBufferInterface *iface);
@ -229,6 +238,120 @@ meta_drm_buffer_gbm_new_take (MetaDeviceFile *device_file,
return buffer_gbm;
}
static EGLImageKHR
meta_drm_buffer_gbm_create_native_blit_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
meta_drm_buffer_gbm_free_native_blit_image (struct gbm_bo *bo,
void *data)
{
MetaDrmBufferGbmBoUserData *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_prefix_error (&error, "Could not destroy EGLImage: ");
g_free (data);
}
EGLImageKHR
meta_drm_buffer_gbm_get_native_blit_image (MetaEgl *egl,
EGLDisplay egl_display,
struct gbm_bo *bo,
GError **error)
{
MetaDrmBufferGbmBoUserData *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 = meta_drm_buffer_gbm_create_native_blit_image (egl,
egl_display,
bo,
error);
if (!egl_image)
{
return EGL_NO_IMAGE;
}
bo_user_data = g_new0 (MetaDrmBufferGbmBoUserData, 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, meta_drm_buffer_gbm_free_native_blit_image);
}
return bo_user_data->egl_image;
}
static gboolean
meta_drm_buffer_gbm_blit_to_framebuffer (CoglScanout *scanout,
CoglFramebuffer *framebuffer,

View file

@ -21,6 +21,7 @@
#include <gbm.h>
#include "backends/meta-egl.h"
#include "backends/native/meta-backend-native-types.h"
#include "backends/native/meta-drm-buffer-private.h"
@ -42,3 +43,8 @@ MetaDrmBufferGbm * meta_drm_buffer_gbm_new_take (MetaDeviceFile *device_fil
GError **error);
struct gbm_bo * meta_drm_buffer_gbm_get_bo (MetaDrmBufferGbm *buffer_gbm);
EGLImageKHR meta_drm_buffer_gbm_get_native_blit_image (MetaEgl *egl,
EGLDisplay egl_display,
struct gbm_bo *shared_bo,
GError **error);

View file

@ -854,6 +854,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()");
@ -907,11 +908,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_drm_buffer_gbm_get_native_blit_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))
{

View file

@ -352,21 +352,12 @@ 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)
{
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;
GQuark context_data_quark;
ContextData *context_data;
gboolean can_blit;
@ -390,57 +381,14 @@ meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl,
gbm_bo_get_format (shared_bo),
gbm_bo_get_modifier (shared_bo));
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);
if (!egl_image)
return FALSE;
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;
}

View file

@ -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);