backends/native: Assume zero rendering time for direct scanout buffers

The previous logic didn't work correctly at least when priority-based
preeption wasn't supported by the DRM driver, such as in the case
of amdgpu. The call to glGetQueryObjecti64v would block on client
work which is already in progress (most likely for the next frame)
and delay notifying the ClutterFrameClock about presentation.

Conveniently, the Wayland transactions mechanism guarantees that all
fences of a dma-buf buffer are signalled before the buffer is
included in a frame, which means that dma-buf buffers are ready for
presentation when being directly scanned-out.

Direct scanout is only supported for dma-buf buffers too, which means
that all buffers going through direct scanout are effectively ready
and require no GPU rendering before presentation.

Assuming zero rendering time for dma-buf buffers going through direct
scanout simplifies the code and removes the need for
glGetQueryObjecti64v, thus avoiding the aforementioned issue where it
could block for longer than expected.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2766
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3080>
This commit is contained in:
Dor Askayo 2023-06-19 01:53:36 +03:00 committed by Marge Bot
parent e30eb78891
commit 56580ea7c9
5 changed files with 1 additions and 181 deletions

View File

@ -231,127 +231,6 @@ meta_drm_buffer_gbm_new_take (MetaDeviceFile *device_file,
return buffer_gbm;
}
static gboolean
meta_drm_buffer_gbm_fill_timings (MetaDrmBuffer *buffer,
CoglFrameInfo *info,
GError **error)
{
MetaDrmBufferGbm *buffer_gbm = META_DRM_BUFFER_GBM (buffer);
MetaDeviceFile *device_file = meta_drm_buffer_get_device_file (buffer);
MetaDevicePool *device_pool = meta_device_file_get_pool (device_file);
MetaBackend *backend = meta_device_pool_get_backend (device_pool);
MetaEgl *egl = meta_backend_get_egl (backend);
ClutterBackend *clutter_backend =
meta_backend_get_clutter_backend (backend);
CoglContext *cogl_context =
clutter_backend_get_cogl_context (clutter_backend);
CoglDisplay *cogl_display = cogl_context->display;
CoglRenderer *cogl_renderer = cogl_display->renderer;
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
EGLDisplay egl_display = cogl_renderer_egl->edpy;
EGLImageKHR egl_image;
CoglPixelFormat cogl_format;
CoglEglImageFlags flags;
g_autoptr (CoglOffscreen) cogl_fbo = NULL;
CoglTexture2D *cogl_tex;
uint32_t n_planes;
uint64_t *modifiers;
uint32_t *strides;
uint32_t *offsets;
uint32_t width;
uint32_t height;
uint32_t drm_format;
int *fds;
gboolean result;
int dmabuf_fd = -1;
uint32_t i;
dmabuf_fd = gbm_bo_get_fd (buffer_gbm->bo);
if (dmabuf_fd == -1)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to export buffer's DMA fd: %s",
g_strerror (errno));
return FALSE;
}
drm_format = gbm_bo_get_format (buffer_gbm->bo);
result = meta_cogl_pixel_format_from_drm_format (drm_format,
&cogl_format,
NULL);
g_assert (result);
width = gbm_bo_get_width (buffer_gbm->bo);
height = gbm_bo_get_height (buffer_gbm->bo);
n_planes = gbm_bo_get_plane_count (buffer_gbm->bo);
fds = g_alloca (sizeof (int) * n_planes);
strides = g_alloca (sizeof (uint32_t) * n_planes);
offsets = g_alloca (sizeof (uint32_t) * n_planes);
modifiers = g_alloca (sizeof (uint64_t) * n_planes);
for (i = 0; i < n_planes; i++)
{
fds[i] = dmabuf_fd;
strides[i] = gbm_bo_get_stride_for_plane (buffer_gbm->bo, i);
offsets[i] = gbm_bo_get_offset (buffer_gbm->bo, i);
modifiers[i] = gbm_bo_get_modifier (buffer_gbm->bo);
}
egl_image = meta_egl_create_dmabuf_image (egl,
egl_display,
width,
height,
drm_format,
n_planes,
fds,
strides,
offsets,
modifiers,
error);
if (egl_image == EGL_NO_IMAGE_KHR)
goto out;
flags = COGL_EGL_IMAGE_FLAG_NO_GET_DATA;
cogl_tex = cogl_egl_texture_2d_new_from_image (cogl_context,
width,
height,
cogl_format,
egl_image,
flags,
error);
meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
if (!cogl_tex)
goto out;
cogl_fbo = cogl_offscreen_new_with_texture (COGL_TEXTURE (cogl_tex));
cogl_object_unref (cogl_tex);
if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (cogl_fbo), error))
goto out;
if (cogl_has_feature (cogl_context, COGL_FEATURE_ID_TIMESTAMP_QUERY))
{
info->gpu_time_before_buffer_swap_ns =
cogl_context_get_gpu_time_ns (cogl_context);
}
info->cpu_time_before_buffer_swap_us = g_get_monotonic_time ();
/* Set up a timestamp query for when all rendering will be finished. */
if (cogl_has_feature (cogl_context, COGL_FEATURE_ID_TIMESTAMP_QUERY))
{
info->timestamp_query =
cogl_framebuffer_create_timestamp_query (COGL_FRAMEBUFFER (cogl_fbo));
}
out:
close (dmabuf_fd);
return TRUE;
}
static gboolean
meta_drm_buffer_gbm_blit_to_framebuffer (CoglScanout *scanout,
CoglFramebuffer *framebuffer,
@ -522,5 +401,4 @@ meta_drm_buffer_gbm_class_init (MetaDrmBufferGbmClass *klass)
buffer_class->get_format = meta_drm_buffer_gbm_get_format;
buffer_class->get_offset = meta_drm_buffer_gbm_get_offset;
buffer_class->get_modifier = meta_drm_buffer_gbm_get_modifier;
buffer_class->fill_timings = meta_drm_buffer_gbm_fill_timings;
}

View File

@ -54,10 +54,6 @@ struct _MetaDrmBufferClass
int (* get_offset) (MetaDrmBuffer *buffer,
int plane);
uint64_t (* get_modifier) (MetaDrmBuffer *buffer);
gboolean (* fill_timings) (MetaDrmBuffer *buffer,
CoglFrameInfo *info,
GError **error);
};
MetaDeviceFile * meta_drm_buffer_get_device_file (MetaDrmBuffer *buffer);

View File

@ -241,27 +241,6 @@ meta_drm_buffer_get_modifier (MetaDrmBuffer *buffer)
return META_DRM_BUFFER_GET_CLASS (buffer)->get_modifier (buffer);
}
gboolean
meta_drm_buffer_supports_fill_timings (MetaDrmBuffer *buffer)
{
return META_DRM_BUFFER_GET_CLASS (buffer)->fill_timings != NULL;
}
gboolean
meta_drm_buffer_fill_timings (MetaDrmBuffer *buffer,
CoglFrameInfo *info,
GError **error)
{
if (!meta_drm_buffer_supports_fill_timings (buffer))
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
"Buffer doesn't support filling timing info");
return FALSE;
}
return META_DRM_BUFFER_GET_CLASS (buffer)->fill_timings (buffer, info, error);
}
static void
meta_drm_buffer_get_property (GObject *object,
guint prop_id,

View File

@ -68,10 +68,4 @@ int meta_drm_buffer_get_offset (MetaDrmBuffer *buffer,
uint64_t meta_drm_buffer_get_modifier (MetaDrmBuffer *buffer);
gboolean meta_drm_buffer_supports_fill_timings (MetaDrmBuffer *buffer);
gboolean meta_drm_buffer_fill_timings (MetaDrmBuffer *buffer,
CoglFrameInfo *info,
GError **error);
#endif /* META_DRM_BUFFER_H */

View File

@ -1349,8 +1349,6 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
MetaPowerSave power_save_mode;
ClutterFrame *frame = user_data;
MetaFrameNative *frame_native = meta_frame_native_from_frame (frame);
MetaDrmBuffer *scanout_buffer;
GError *fill_timings_error = NULL;
MetaKmsCrtc *kms_crtc;
MetaKmsDevice *kms_device;
MetaKmsUpdate *kms_update;
@ -1383,32 +1381,7 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
g_set_object (&onscreen_native->gbm.next_fb, META_DRM_BUFFER (scanout));
/* Try to get a measurement of GPU rendering time on the scanout buffer.
*
* The successful operation here adds ~0.4 ms to a ~0.1 ms total frame clock
* dispatch duration when displaying an unredirected client, thus
* unfortunately bringing it more in line with duration of the regular
* non-unredirected frame clock dispatch. However, measuring GPU rendering
* time is important for computing accurate max render time without
* underestimating. Also this operation should be optimizable by caching
* EGLImage for each buffer instead of re-creating it every time it's needed.
* This should also help all other cases which convert the buffer to a
* EGLImage.
*/
if (META_IS_DRM_BUFFER (scanout))
{
scanout_buffer = META_DRM_BUFFER (scanout);
if (meta_drm_buffer_supports_fill_timings (scanout_buffer))
{
if (!meta_drm_buffer_fill_timings (scanout_buffer, frame_info,
&fill_timings_error))
{
g_warning ("Failed to fill timings for a scanout buffer: %s",
fill_timings_error->message);
g_error_free (fill_timings_error);
}
}
}
frame_info->cpu_time_before_buffer_swap_us = g_get_monotonic_time ();
kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (onscreen_native->crtc));
kms_device = meta_kms_crtc_get_device (kms_crtc);