mirror of
https://github.com/brl/mutter.git
synced 2024-12-25 12:32:05 +00:00
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:
parent
e30eb78891
commit
56580ea7c9
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user