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:
parent
3a202f58ce
commit
e0b7afe8fa
5 changed files with 141 additions and 55 deletions
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue