2016-05-07 11:07:46 -04:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
|
|
|
|
/*
|
2016-05-09 07:51:29 -04:00
|
|
|
* Copyright (C) 2011 Intel Corporation.
|
2016-05-07 11:07:46 -04:00
|
|
|
* Copyright (C) 2016 Red Hat
|
2018-11-29 06:34:40 -05:00
|
|
|
* Copyright (c) 2018,2019 DisplayLink (UK) Ltd.
|
2016-05-07 11:07:46 -04:00
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person
|
|
|
|
* obtaining a copy of this software and associated documentation
|
|
|
|
* files (the "Software"), to deal in the Software without
|
|
|
|
* restriction, including without limitation the rights to use, copy,
|
|
|
|
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
|
|
* of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be
|
|
|
|
* included in all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
* SOFTWARE.
|
|
|
|
*
|
2016-05-09 07:51:29 -04:00
|
|
|
* Authors:
|
|
|
|
* Rob Bradford <rob@linux.intel.com> (from cogl-winsys-egl-kms.c)
|
|
|
|
* Kristian Høgsberg (from eglkms.c)
|
|
|
|
* Benjamin Franzke (from eglkms.c)
|
|
|
|
* Robert Bragg <robert@linux.intel.com> (from cogl-winsys-egl-kms.c)
|
|
|
|
* Neil Roberts <neil@linux.intel.com> (from cogl-winsys-egl-kms.c)
|
|
|
|
* Jonas Ådahl <jadahl@redhat.com>
|
|
|
|
*
|
2016-05-07 11:07:46 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2018-07-10 04:36:24 -04:00
|
|
|
#include <drm_fourcc.h>
|
2016-05-09 07:51:29 -04:00
|
|
|
#include <errno.h>
|
|
|
|
#include <gbm.h>
|
2016-05-09 09:22:01 -04:00
|
|
|
#include <gio/gio.h>
|
|
|
|
#include <glib-object.h>
|
2016-05-09 07:51:29 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
2016-05-07 11:07:46 -04:00
|
|
|
|
2018-07-10 04:36:24 -04:00
|
|
|
#include "backends/meta-gles3.h"
|
2016-12-12 21:37:11 -05:00
|
|
|
#include "backends/meta-logical-monitor.h"
|
2021-04-12 10:05:34 -04:00
|
|
|
#include "backends/native/meta-backend-native-private.h"
|
2020-08-28 20:58:18 -04:00
|
|
|
#include "backends/native/meta-cogl-utils.h"
|
2017-08-03 10:42:50 -04:00
|
|
|
#include "backends/native/meta-crtc-kms.h"
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 10:49:28 -05:00
|
|
|
#include "backends/native/meta-crtc-virtual.h"
|
2021-04-12 10:05:34 -04:00
|
|
|
#include "backends/native/meta-device-pool.h"
|
2020-11-14 04:41:23 -05:00
|
|
|
#include "backends/native/meta-kms-device.h"
|
backend/native: Add and use transactional KMS API
This commit introduces, and makes use of, a transactional API used for
setting up KMS state, later to be applied, potentially atomically. From
an API point of view, so is always the case, but in the current
implementation, it still uses legacy drmMode* API to apply the state
non-atomically.
The API consists of various buliding blocks:
* MetaKmsUpdate - a set of configuration changes, the higher level
handle for handing over configuration to the impl backend. It's used to
set mode, assign framebuffers to planes, queue page flips and set
connector properties.
* MetaKmsPlaneAssignment - the assignment of a framebuffer to a plane.
Currently used to map a framebuffer to the primary plane of a CRTC. In
the legacy KMS implementation, the plane assignment is used to derive
the framebuffer used for mode setting and page flipping.
This also means various high level changes:
State, excluding configuring the cursor plane and creating/destroying
DRM framebuffer handles, are applied in the end of a clutter frame, in
one go. From an API point of view, this is done atomically, but as
mentioned, only the non-atomic implementation exists so far.
From MetaRendererNative's point of view, a page flip now initially
always succeeds; the handling of EBUSY errors are done asynchronously in
the MetaKmsImpl backend (still by retrying at refresh rate, but
postponing flip callbacks instead of manipulating the frame clock).
Handling of falling back to mode setting instead of page flipping is
notified after the fact by a more precise page flip feedback API.
EGLStream based page flipping relies on the impl backend not being
atomic, as the page flipping is done in the EGLStream backend (e.g.
nvidia driver). It uses a 'custom' page flip queueing method, keeping
the EGLStream logic inside meta-renderer-native.c.
Page flip handling is moved to meta-kms-impl-device.c from
meta-gpu-kms.c. It goes via an extra idle callback before reaching
meta-renderer-native.c to make sure callbacks are invoked outside of the
impl context.
While dummy power save page flipping is kept in meta-renderer-native.c, the
EBUSY handling is moved to meta-kms-impl-simple.c. Instead of freezing the
frame clock, actual page flip callbacks are postponed until all EBUSY retries
have either succeeded or failed due to some other error than EBUSY. This
effectively inhibits new frames to be drawn, meaning we won't stall waiting on
the file descriptor for pending page flips.
https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-04-04 16:36:41 -04:00
|
|
|
#include "backends/native/meta-kms.h"
|
2020-10-17 17:08:28 -04:00
|
|
|
#include "backends/native/meta-onscreen-native.h"
|
2021-05-05 09:53:59 -04:00
|
|
|
#include "backends/native/meta-render-device-gbm.h"
|
|
|
|
#include "backends/native/meta-render-device-surfaceless.h"
|
2020-10-17 17:08:28 -04:00
|
|
|
#include "backends/native/meta-renderer-native-private.h"
|
2016-05-07 11:09:59 -04:00
|
|
|
#include "cogl/cogl.h"
|
2016-06-08 05:05:31 -04:00
|
|
|
#include "core/boxes-private.h"
|
2016-05-07 11:09:59 -04:00
|
|
|
|
2021-05-05 09:53:59 -04:00
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
#include "backends/native/meta-render-device-egl-stream.h"
|
|
|
|
#endif
|
|
|
|
|
2016-08-17 23:28:59 -04:00
|
|
|
#ifndef EGL_DRM_MASTER_FD_EXT
|
|
|
|
#define EGL_DRM_MASTER_FD_EXT 0x333C
|
|
|
|
#endif
|
|
|
|
|
2018-11-21 08:25:07 -05:00
|
|
|
/* added in libdrm 2.4.95 */
|
|
|
|
#ifndef DRM_FORMAT_INVALID
|
|
|
|
#define DRM_FORMAT_INVALID 0
|
|
|
|
#endif
|
|
|
|
|
2016-05-07 11:07:46 -04:00
|
|
|
struct _MetaRendererNative
|
|
|
|
{
|
|
|
|
MetaRenderer parent;
|
2016-05-07 11:09:59 -04:00
|
|
|
|
2018-12-10 07:19:25 -05:00
|
|
|
MetaGpuKms *primary_gpu_kms;
|
2019-01-11 09:35:42 -05:00
|
|
|
|
2017-07-24 22:21:04 -04:00
|
|
|
MetaGles3 *gles3;
|
2016-08-17 22:37:16 -04:00
|
|
|
|
2018-04-11 08:39:15 -04:00
|
|
|
gboolean use_modifiers;
|
|
|
|
|
2017-07-10 06:19:32 -04:00
|
|
|
GHashTable *gpu_datas;
|
2016-08-17 23:28:59 -04:00
|
|
|
|
2020-10-09 17:17:06 -04:00
|
|
|
GList *pending_mode_set_views;
|
|
|
|
gboolean pending_mode_set;
|
2019-03-25 05:24:46 -04:00
|
|
|
|
2020-10-23 04:21:54 -04:00
|
|
|
GList *kept_alive_onscreens;
|
|
|
|
|
backend/native: Add and use transactional KMS API
This commit introduces, and makes use of, a transactional API used for
setting up KMS state, later to be applied, potentially atomically. From
an API point of view, so is always the case, but in the current
implementation, it still uses legacy drmMode* API to apply the state
non-atomically.
The API consists of various buliding blocks:
* MetaKmsUpdate - a set of configuration changes, the higher level
handle for handing over configuration to the impl backend. It's used to
set mode, assign framebuffers to planes, queue page flips and set
connector properties.
* MetaKmsPlaneAssignment - the assignment of a framebuffer to a plane.
Currently used to map a framebuffer to the primary plane of a CRTC. In
the legacy KMS implementation, the plane assignment is used to derive
the framebuffer used for mode setting and page flipping.
This also means various high level changes:
State, excluding configuring the cursor plane and creating/destroying
DRM framebuffer handles, are applied in the end of a clutter frame, in
one go. From an API point of view, this is done atomically, but as
mentioned, only the non-atomic implementation exists so far.
From MetaRendererNative's point of view, a page flip now initially
always succeeds; the handling of EBUSY errors are done asynchronously in
the MetaKmsImpl backend (still by retrying at refresh rate, but
postponing flip callbacks instead of manipulating the frame clock).
Handling of falling back to mode setting instead of page flipping is
notified after the fact by a more precise page flip feedback API.
EGLStream based page flipping relies on the impl backend not being
atomic, as the page flipping is done in the EGLStream backend (e.g.
nvidia driver). It uses a 'custom' page flip queueing method, keeping
the EGLStream logic inside meta-renderer-native.c.
Page flip handling is moved to meta-kms-impl-device.c from
meta-gpu-kms.c. It goes via an extra idle callback before reaching
meta-renderer-native.c to make sure callbacks are invoked outside of the
impl context.
While dummy power save page flipping is kept in meta-renderer-native.c, the
EBUSY handling is moved to meta-kms-impl-simple.c. Instead of freezing the
frame clock, actual page flip callbacks are postponed until all EBUSY retries
have either succeeded or failed due to some other error than EBUSY. This
effectively inhibits new frames to be drawn, meaning we won't stall waiting on
the file descriptor for pending page flips.
https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-04-04 16:36:41 -04:00
|
|
|
GList *power_save_page_flip_onscreens;
|
2019-03-25 05:24:46 -04:00
|
|
|
guint power_save_page_flip_source_id;
|
2016-05-07 11:07:46 -04:00
|
|
|
};
|
|
|
|
|
2016-05-09 09:22:01 -04:00
|
|
|
static void
|
|
|
|
initable_iface_init (GInitableIface *initable_iface);
|
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (MetaRendererNative,
|
|
|
|
meta_renderer_native,
|
|
|
|
META_TYPE_RENDERER,
|
|
|
|
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
|
|
|
|
initable_iface_init))
|
2016-05-07 11:07:46 -04:00
|
|
|
|
2016-05-09 07:51:29 -04:00
|
|
|
static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable;
|
|
|
|
static const CoglWinsysVtable *parent_vtable;
|
|
|
|
|
2021-04-12 10:25:53 -04:00
|
|
|
static gboolean
|
|
|
|
meta_renderer_native_ensure_gpu_data (MetaRendererNative *renderer_native,
|
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
GError **error);
|
|
|
|
|
2019-06-19 14:57:14 -04:00
|
|
|
static void
|
|
|
|
meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native);
|
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
const CoglWinsysVtable *
|
|
|
|
meta_get_renderer_native_parent_vtable (void)
|
|
|
|
{
|
|
|
|
return parent_vtable;
|
|
|
|
}
|
|
|
|
|
2017-07-10 06:19:32 -04:00
|
|
|
static void
|
|
|
|
meta_renderer_native_gpu_data_free (MetaRendererNativeGpuData *renderer_gpu_data)
|
|
|
|
{
|
2021-04-13 09:46:05 -04:00
|
|
|
if (renderer_gpu_data->secondary.egl_context != EGL_NO_CONTEXT)
|
|
|
|
{
|
2021-05-05 09:53:59 -04:00
|
|
|
MetaRenderDevice *render_device = renderer_gpu_data->render_device;
|
|
|
|
EGLDisplay egl_display =
|
|
|
|
meta_render_device_get_egl_display (render_device);
|
|
|
|
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
|
|
|
|
MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
|
|
|
|
|
2021-04-13 09:46:05 -04:00
|
|
|
meta_egl_destroy_context (egl,
|
2021-05-05 09:53:59 -04:00
|
|
|
egl_display,
|
2021-04-13 09:46:05 -04:00
|
|
|
renderer_gpu_data->secondary.egl_context,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2021-05-05 09:53:59 -04:00
|
|
|
g_clear_pointer (&renderer_gpu_data->render_device, g_object_unref);
|
2017-07-10 06:19:32 -04:00
|
|
|
g_free (renderer_gpu_data);
|
|
|
|
}
|
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
MetaRendererNativeGpuData *
|
2017-07-10 06:19:32 -04:00
|
|
|
meta_renderer_native_get_gpu_data (MetaRendererNative *renderer_native,
|
|
|
|
MetaGpuKms *gpu_kms)
|
|
|
|
{
|
|
|
|
return g_hash_table_lookup (renderer_native->gpu_datas, gpu_kms);
|
|
|
|
}
|
|
|
|
|
|
|
|
static MetaRendererNative *
|
|
|
|
meta_renderer_native_from_gpu (MetaGpuKms *gpu_kms)
|
|
|
|
{
|
2019-01-11 09:35:42 -05:00
|
|
|
MetaBackend *backend = meta_gpu_get_backend (META_GPU (gpu_kms));
|
2017-07-10 06:19:32 -04:00
|
|
|
|
|
|
|
return META_RENDERER_NATIVE (meta_backend_get_renderer (backend));
|
|
|
|
}
|
|
|
|
|
|
|
|
struct gbm_device *
|
|
|
|
meta_gbm_device_from_gpu (MetaGpuKms *gpu_kms)
|
|
|
|
{
|
2017-07-24 22:21:04 -04:00
|
|
|
MetaRendererNative *renderer_native = meta_renderer_native_from_gpu (gpu_kms);
|
2017-07-10 06:19:32 -04:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
2021-05-05 09:53:59 -04:00
|
|
|
MetaRenderDevice *render_device;
|
|
|
|
MetaRenderDeviceGbm *render_device_gbm;
|
2017-07-10 06:19:32 -04:00
|
|
|
|
|
|
|
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
|
|
|
gpu_kms);
|
2021-05-05 09:53:59 -04:00
|
|
|
render_device = renderer_gpu_data->render_device;
|
|
|
|
|
|
|
|
if (!META_IS_RENDER_DEVICE_GBM (render_device))
|
|
|
|
return NULL;
|
2017-07-10 06:19:32 -04:00
|
|
|
|
2021-05-05 09:53:59 -04:00
|
|
|
render_device_gbm = META_RENDER_DEVICE_GBM (render_device);
|
|
|
|
return meta_render_device_gbm_get_gbm_device (render_device_gbm);
|
2017-07-10 06:19:32 -04:00
|
|
|
}
|
|
|
|
|
2019-09-12 05:50:34 -04:00
|
|
|
MetaGpuKms *
|
|
|
|
meta_renderer_native_get_primary_gpu (MetaRendererNative *renderer_native)
|
|
|
|
{
|
|
|
|
return renderer_native->primary_gpu_kms;
|
|
|
|
}
|
|
|
|
|
2021-04-12 10:13:29 -04:00
|
|
|
MetaDeviceFile *
|
|
|
|
meta_renderer_native_get_primary_device_file (MetaRendererNative *renderer_native)
|
|
|
|
{
|
|
|
|
MetaGpuKms *gpu_kms = renderer_native->primary_gpu_kms;
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
2021-05-05 09:53:59 -04:00
|
|
|
MetaRenderDevice *render_device;
|
2021-04-12 10:13:29 -04:00
|
|
|
|
|
|
|
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
|
|
|
gpu_kms);
|
2021-05-05 09:53:59 -04:00
|
|
|
render_device = renderer_gpu_data->render_device;
|
|
|
|
return meta_render_device_get_device_file (render_device);
|
2021-04-12 10:13:29 -04:00
|
|
|
}
|
|
|
|
|
2017-07-10 06:19:32 -04:00
|
|
|
static MetaRendererNativeGpuData *
|
2021-04-13 09:51:36 -04:00
|
|
|
meta_create_renderer_native_gpu_data (void)
|
2017-07-10 06:19:32 -04:00
|
|
|
{
|
2021-05-05 09:53:59 -04:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
|
|
|
|
renderer_gpu_data = g_new0 (MetaRendererNativeGpuData, 1);
|
|
|
|
renderer_gpu_data->secondary.egl_context = EGL_NO_CONTEXT;
|
|
|
|
|
|
|
|
return renderer_gpu_data;
|
2017-07-10 06:19:32 -04:00
|
|
|
}
|
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
MetaEgl *
|
2017-07-24 03:54:29 -04:00
|
|
|
meta_renderer_native_get_egl (MetaRendererNative *renderer_native)
|
|
|
|
{
|
2019-10-01 05:51:53 -04:00
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
|
|
|
|
|
|
|
return meta_backend_get_egl (meta_renderer_get_backend (renderer));
|
2017-07-24 03:54:29 -04:00
|
|
|
}
|
|
|
|
|
2020-09-14 14:36:17 -04:00
|
|
|
gboolean
|
|
|
|
meta_renderer_native_use_modifiers (MetaRendererNative *renderer_native)
|
|
|
|
{
|
|
|
|
return renderer_native->use_modifiers;
|
|
|
|
}
|
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
MetaGles3 *
|
|
|
|
meta_renderer_native_get_gles3 (MetaRendererNative *renderer_native)
|
2018-11-21 08:25:07 -05:00
|
|
|
{
|
2020-10-17 17:08:28 -04:00
|
|
|
return renderer_native->gles3;
|
2018-11-21 08:25:07 -05:00
|
|
|
}
|
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
gboolean
|
|
|
|
meta_renderer_native_has_pending_mode_sets (MetaRendererNative *renderer_native)
|
2017-07-24 22:21:04 -04:00
|
|
|
{
|
2020-10-17 17:08:28 -04:00
|
|
|
return !!renderer_native->pending_mode_set_views;
|
2017-07-24 22:21:04 -04:00
|
|
|
}
|
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
gboolean
|
|
|
|
meta_renderer_native_has_pending_mode_set (MetaRendererNative *renderer_native)
|
2017-07-24 22:21:04 -04:00
|
|
|
{
|
2020-10-17 17:08:28 -04:00
|
|
|
return renderer_native->pending_mode_set;
|
2017-07-24 22:21:04 -04:00
|
|
|
}
|
|
|
|
|
2021-10-14 12:36:43 -04:00
|
|
|
MetaRendererNativeMode
|
|
|
|
meta_renderer_native_get_mode (MetaRendererNative *renderer_native)
|
|
|
|
{
|
|
|
|
MetaGpuKms *primary_gpu = renderer_native->primary_gpu_kms;
|
|
|
|
MetaRendererNativeGpuData *primary_gpu_data;
|
|
|
|
|
|
|
|
primary_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
|
|
|
primary_gpu);
|
|
|
|
return primary_gpu_data->mode;
|
|
|
|
}
|
|
|
|
|
2016-05-09 07:51:29 -04:00
|
|
|
static void
|
2016-06-01 05:53:07 -04:00
|
|
|
meta_renderer_native_disconnect (CoglRenderer *cogl_renderer)
|
2016-05-09 07:51:29 -04:00
|
|
|
{
|
2017-07-14 03:20:41 -04:00
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
2016-05-09 07:51:29 -04:00
|
|
|
|
2020-10-19 13:57:57 -04:00
|
|
|
g_free (cogl_renderer_egl);
|
2016-05-09 07:51:29 -04:00
|
|
|
}
|
|
|
|
|
2016-08-17 22:21:12 -04:00
|
|
|
static gboolean
|
2016-05-27 03:13:09 -04:00
|
|
|
meta_renderer_native_connect (CoglRenderer *cogl_renderer,
|
2016-08-17 22:21:12 -04:00
|
|
|
GError **error)
|
2016-05-09 07:51:29 -04:00
|
|
|
{
|
2017-07-14 03:20:41 -04:00
|
|
|
CoglRendererEGL *cogl_renderer_egl;
|
2021-02-09 08:32:55 -05:00
|
|
|
MetaRendererNative *renderer_native = cogl_renderer->custom_winsys_user_data;
|
|
|
|
MetaGpuKms *gpu_kms;
|
2017-07-24 22:21:04 -04:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
2021-05-05 09:53:59 -04:00
|
|
|
MetaRenderDevice *render_device;
|
2016-05-09 07:51:29 -04:00
|
|
|
|
2020-10-19 13:57:57 -04:00
|
|
|
cogl_renderer->winsys = g_new0 (CoglRendererEGL, 1);
|
2017-07-14 03:20:41 -04:00
|
|
|
cogl_renderer_egl = cogl_renderer->winsys;
|
2016-05-09 07:51:29 -04:00
|
|
|
|
2021-02-09 08:32:55 -05:00
|
|
|
gpu_kms = meta_renderer_native_get_primary_gpu (renderer_native);
|
2017-07-24 22:21:04 -04:00
|
|
|
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
|
|
|
gpu_kms);
|
2021-05-05 09:53:59 -04:00
|
|
|
render_device = renderer_gpu_data->render_device;
|
2017-07-24 22:21:04 -04:00
|
|
|
|
2017-07-14 03:20:41 -04:00
|
|
|
cogl_renderer_egl->platform_vtable = &_cogl_winsys_egl_vtable;
|
2017-07-24 22:21:04 -04:00
|
|
|
cogl_renderer_egl->platform = renderer_gpu_data;
|
2021-05-05 09:53:59 -04:00
|
|
|
cogl_renderer_egl->edpy = meta_render_device_get_egl_display (render_device);
|
2016-05-09 07:51:29 -04:00
|
|
|
|
|
|
|
if (!_cogl_winsys_egl_renderer_connect_common (cogl_renderer, error))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
fail:
|
2016-05-27 03:13:09 -04:00
|
|
|
meta_renderer_native_disconnect (cogl_renderer);
|
2016-05-09 07:51:29 -04:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2016-09-26 03:54:27 -04:00
|
|
|
static int
|
2020-10-12 17:31:38 -04:00
|
|
|
meta_renderer_native_add_egl_config_attributes (CoglDisplay *cogl_display,
|
|
|
|
const CoglFramebufferConfig *config,
|
|
|
|
EGLint *attributes)
|
2016-09-26 03:54:27 -04:00
|
|
|
{
|
2017-07-14 03:20:41 -04:00
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_display->renderer->winsys;
|
2017-07-24 22:21:04 -04:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
2016-09-26 03:54:27 -04:00
|
|
|
int i = 0;
|
|
|
|
|
2017-07-24 22:21:04 -04:00
|
|
|
switch (renderer_gpu_data->mode)
|
2016-08-17 23:28:59 -04:00
|
|
|
{
|
|
|
|
case META_RENDERER_NATIVE_MODE_GBM:
|
|
|
|
attributes[i++] = EGL_SURFACE_TYPE;
|
|
|
|
attributes[i++] = EGL_WINDOW_BIT;
|
|
|
|
break;
|
2021-02-09 08:32:55 -05:00
|
|
|
case META_RENDERER_NATIVE_MODE_SURFACELESS:
|
|
|
|
attributes[i++] = EGL_SURFACE_TYPE;
|
|
|
|
attributes[i++] = EGL_PBUFFER_BIT;
|
|
|
|
break;
|
2016-08-17 23:28:59 -04:00
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
|
|
|
attributes[i++] = EGL_SURFACE_TYPE;
|
|
|
|
attributes[i++] = EGL_STREAM_BIT_KHR;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
2016-09-26 03:54:27 -04:00
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2018-02-23 09:14:07 -05:00
|
|
|
static gboolean
|
|
|
|
choose_egl_config_from_gbm_format (MetaEgl *egl,
|
|
|
|
EGLDisplay egl_display,
|
|
|
|
const EGLint *attributes,
|
|
|
|
uint32_t gbm_format,
|
|
|
|
EGLConfig *out_config,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
EGLConfig *egl_configs;
|
|
|
|
EGLint n_configs;
|
|
|
|
EGLint i;
|
|
|
|
|
|
|
|
egl_configs = meta_egl_choose_all_configs (egl, egl_display,
|
|
|
|
attributes,
|
|
|
|
&n_configs,
|
|
|
|
error);
|
|
|
|
if (!egl_configs)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
for (i = 0; i < n_configs; i++)
|
|
|
|
{
|
|
|
|
EGLint visual_id;
|
|
|
|
|
|
|
|
if (!meta_egl_get_config_attrib (egl, egl_display,
|
|
|
|
egl_configs[i],
|
|
|
|
EGL_NATIVE_VISUAL_ID,
|
|
|
|
&visual_id,
|
|
|
|
error))
|
|
|
|
{
|
|
|
|
g_free (egl_configs);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((uint32_t) visual_id == gbm_format)
|
|
|
|
{
|
|
|
|
*out_config = egl_configs[i];
|
|
|
|
g_free (egl_configs);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (egl_configs);
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"No EGL config matching supported GBM format found");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_renderer_native_choose_egl_config (CoglDisplay *cogl_display,
|
|
|
|
EGLint *attributes,
|
|
|
|
EGLConfig *out_config,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
CoglRenderer *cogl_renderer = cogl_display->renderer;
|
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
|
|
|
MetaBackend *backend = meta_get_backend ();
|
|
|
|
MetaEgl *egl = meta_backend_get_egl (backend);
|
2018-06-07 19:29:44 -04:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
2018-02-23 09:14:07 -05:00
|
|
|
EGLDisplay egl_display = cogl_renderer_egl->edpy;
|
|
|
|
|
2018-06-07 19:29:44 -04:00
|
|
|
switch (renderer_gpu_data->mode)
|
|
|
|
{
|
|
|
|
case META_RENDERER_NATIVE_MODE_GBM:
|
|
|
|
return choose_egl_config_from_gbm_format (egl,
|
|
|
|
egl_display,
|
|
|
|
attributes,
|
|
|
|
GBM_FORMAT_XRGB8888,
|
|
|
|
out_config,
|
|
|
|
error);
|
2021-02-09 08:32:55 -05:00
|
|
|
case META_RENDERER_NATIVE_MODE_SURFACELESS:
|
|
|
|
*out_config = EGL_NO_CONFIG_KHR;
|
|
|
|
return TRUE;
|
2018-06-07 19:29:44 -04:00
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
|
|
|
return meta_egl_choose_first_config (egl,
|
|
|
|
egl_display,
|
|
|
|
attributes,
|
|
|
|
out_config,
|
|
|
|
error);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
2018-02-23 09:14:07 -05:00
|
|
|
}
|
|
|
|
|
2016-08-17 22:21:12 -04:00
|
|
|
static gboolean
|
2016-06-01 05:53:07 -04:00
|
|
|
meta_renderer_native_setup_egl_display (CoglDisplay *cogl_display,
|
2016-08-17 22:21:12 -04:00
|
|
|
GError **error)
|
2016-05-09 07:51:29 -04:00
|
|
|
{
|
2017-07-14 03:20:41 -04:00
|
|
|
CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
|
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_display->renderer->winsys;
|
2017-07-24 22:21:04 -04:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
|
|
|
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
|
2016-05-09 07:51:29 -04:00
|
|
|
|
2017-07-14 03:20:41 -04:00
|
|
|
cogl_display_egl->platform = renderer_native;
|
2016-05-09 07:51:29 -04:00
|
|
|
|
|
|
|
/* Force a full modeset / drmModeSetCrtc on
|
|
|
|
* the first swap buffers call.
|
|
|
|
*/
|
2016-06-08 05:05:31 -04:00
|
|
|
meta_renderer_native_queue_modes_reset (renderer_native);
|
2016-05-09 07:51:29 -04:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-06-01 05:53:07 -04:00
|
|
|
meta_renderer_native_destroy_egl_display (CoglDisplay *cogl_display)
|
2016-05-09 07:51:29 -04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-08-30 23:25:45 -04:00
|
|
|
static EGLSurface
|
|
|
|
create_dummy_pbuffer_surface (EGLDisplay egl_display,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaBackend *backend = meta_get_backend ();
|
|
|
|
MetaEgl *egl = meta_backend_get_egl (backend);
|
|
|
|
EGLConfig pbuffer_config;
|
|
|
|
static const EGLint pbuffer_config_attribs[] = {
|
|
|
|
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
|
|
|
|
EGL_RED_SIZE, 1,
|
|
|
|
EGL_GREEN_SIZE, 1,
|
|
|
|
EGL_BLUE_SIZE, 1,
|
|
|
|
EGL_ALPHA_SIZE, 0,
|
|
|
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
|
|
|
EGL_NONE
|
|
|
|
};
|
|
|
|
static const EGLint pbuffer_attribs[] = {
|
|
|
|
EGL_WIDTH, 16,
|
|
|
|
EGL_HEIGHT, 16,
|
|
|
|
EGL_NONE
|
|
|
|
};
|
|
|
|
|
2018-02-23 09:13:11 -05:00
|
|
|
if (!meta_egl_choose_first_config (egl, egl_display, pbuffer_config_attribs,
|
|
|
|
&pbuffer_config, error))
|
2016-08-30 23:25:45 -04:00
|
|
|
return EGL_NO_SURFACE;
|
|
|
|
|
|
|
|
return meta_egl_create_pbuffer_surface (egl, egl_display,
|
|
|
|
pbuffer_config, pbuffer_attribs,
|
|
|
|
error);
|
|
|
|
}
|
|
|
|
|
2016-08-17 22:21:12 -04:00
|
|
|
static gboolean
|
2016-06-01 05:53:07 -04:00
|
|
|
meta_renderer_native_egl_context_created (CoglDisplay *cogl_display,
|
2016-08-17 22:21:12 -04:00
|
|
|
GError **error)
|
2016-05-09 07:51:29 -04:00
|
|
|
{
|
2017-07-14 03:20:41 -04:00
|
|
|
CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
|
2016-06-01 05:53:07 -04:00
|
|
|
CoglRenderer *cogl_renderer = cogl_display->renderer;
|
2017-07-14 03:20:41 -04:00
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
2016-05-09 07:51:29 -04:00
|
|
|
|
2017-07-14 03:20:41 -04:00
|
|
|
if ((cogl_renderer_egl->private_features &
|
2016-05-09 07:51:29 -04:00
|
|
|
COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT) == 0)
|
|
|
|
{
|
2017-07-14 03:20:41 -04:00
|
|
|
cogl_display_egl->dummy_surface =
|
|
|
|
create_dummy_pbuffer_surface (cogl_renderer_egl->edpy, error);
|
|
|
|
if (cogl_display_egl->dummy_surface == EGL_NO_SURFACE)
|
2016-08-30 23:25:45 -04:00
|
|
|
return FALSE;
|
2016-05-09 07:51:29 -04:00
|
|
|
}
|
|
|
|
|
2016-06-01 05:53:07 -04:00
|
|
|
if (!_cogl_winsys_egl_make_current (cogl_display,
|
2017-07-14 03:20:41 -04:00
|
|
|
cogl_display_egl->dummy_surface,
|
|
|
|
cogl_display_egl->dummy_surface,
|
|
|
|
cogl_display_egl->egl_context))
|
2016-05-09 07:51:29 -04:00
|
|
|
{
|
2019-06-17 12:18:12 -04:00
|
|
|
g_set_error (error, COGL_WINSYS_ERROR,
|
2016-05-09 07:51:29 -04:00
|
|
|
COGL_WINSYS_ERROR_CREATE_CONTEXT,
|
|
|
|
"Failed to make context current");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-06-01 05:53:07 -04:00
|
|
|
meta_renderer_native_egl_cleanup_context (CoglDisplay *cogl_display)
|
2016-05-09 07:51:29 -04:00
|
|
|
{
|
2017-07-14 03:20:41 -04:00
|
|
|
CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
|
2016-06-01 05:53:07 -04:00
|
|
|
CoglRenderer *cogl_renderer = cogl_display->renderer;
|
2017-07-14 03:20:41 -04:00
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
2017-07-24 22:21:04 -04:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
|
|
|
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
|
2017-07-24 04:19:55 -04:00
|
|
|
MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
|
2016-05-09 07:51:29 -04:00
|
|
|
|
2017-07-14 03:20:41 -04:00
|
|
|
if (cogl_display_egl->dummy_surface != EGL_NO_SURFACE)
|
2016-05-09 07:51:29 -04:00
|
|
|
{
|
2017-07-24 04:19:55 -04:00
|
|
|
meta_egl_destroy_surface (egl,
|
|
|
|
cogl_renderer_egl->edpy,
|
|
|
|
cogl_display_egl->dummy_surface,
|
|
|
|
NULL);
|
2017-07-14 03:20:41 -04:00
|
|
|
cogl_display_egl->dummy_surface = EGL_NO_SURFACE;
|
2016-05-09 07:51:29 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
static CoglContext *
|
|
|
|
cogl_context_from_renderer_native (MetaRendererNative *renderer_native)
|
2017-07-24 22:21:04 -04:00
|
|
|
{
|
2020-10-17 17:08:28 -04:00
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
|
|
|
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
Explicitly create the clutter context and backend
This changes the setup phase of clutter to not be result of calling an
init function that sets up a few global singletons, via global singleton
setup vfuncs.
The way it worked was that mutter first did some initial setup
(connecting to the X11 server), then set a "custom backend" setup vfunc
global, before calling clutter_init().
During the clutter_init() call, the context and backend was setup by
calling the global singleton getters, which implicitly created the
backend and context on-demand.
This has now changed to mutter explicitly creating a `ClutterContext`
(which is actually a `ClutterMainContext`, but with the name shortened to
be consistent with `CoglContext` and `MetaContext`), calling it with a
backend constructor vfunc and user data pointer.
This function now explicitly creates the backend, without having to go
via the previously set global vfunc.
This changes the behavior of some "get_default()" like functions, which
will now fail if called after mutter has shut down, as when it does so,
it now destroys the backends and contexts, not only its own, but the
clutter ones too.
The "ownership" of the clutter backend is also moved to
`ClutterContext`, and MetaBackend is changed to fetch it via the clutter
context.
This also removed the unused option parsing that existed in clutter.
In some places, NULL checks for fetching the clutter context, or
backend, and fetching the cogl context from the clutter backend, had to
be added.
The reason for this is that some code that handles EGL contexts attempts
to restore the cogl EGL context tracking so that the right EGL context
is used by cogl the next time. This makes no sense to do before Cogl and
Clutter are even initialized, which was the case. It wasn't noticed
because the relevant singletons were initialized on demand via their
"getters".
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2002>
2021-09-16 05:38:49 -04:00
|
|
|
ClutterBackend *clutter_backend;
|
|
|
|
|
|
|
|
clutter_backend = meta_backend_get_clutter_backend (backend);
|
|
|
|
if (!clutter_backend)
|
|
|
|
return NULL;
|
2020-10-17 17:08:28 -04:00
|
|
|
|
|
|
|
return clutter_backend_get_cogl_context (clutter_backend);
|
2017-07-24 22:21:04 -04:00
|
|
|
}
|
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
CoglFramebuffer *
|
|
|
|
meta_renderer_native_create_dma_buf_framebuffer (MetaRendererNative *renderer_native,
|
|
|
|
int dmabuf_fd,
|
|
|
|
uint32_t width,
|
|
|
|
uint32_t height,
|
|
|
|
uint32_t stride,
|
|
|
|
uint32_t offset,
|
|
|
|
uint64_t modifier,
|
|
|
|
uint32_t drm_format,
|
|
|
|
GError **error)
|
2016-05-12 02:55:06 -04:00
|
|
|
{
|
2020-10-17 17:08:28 -04:00
|
|
|
CoglContext *cogl_context =
|
|
|
|
cogl_context_from_renderer_native (renderer_native);
|
|
|
|
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;
|
|
|
|
MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
|
|
|
|
EGLImageKHR egl_image;
|
|
|
|
uint32_t strides[1];
|
|
|
|
uint32_t offsets[1];
|
|
|
|
uint64_t modifiers[1];
|
|
|
|
CoglPixelFormat cogl_format;
|
|
|
|
CoglEglImageFlags flags;
|
|
|
|
CoglTexture2D *cogl_tex;
|
|
|
|
CoglOffscreen *cogl_fbo;
|
|
|
|
int ret;
|
2020-10-09 19:22:54 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
ret = meta_cogl_pixel_format_from_drm_format (drm_format,
|
|
|
|
&cogl_format,
|
|
|
|
NULL);
|
|
|
|
g_assert (ret);
|
2016-05-12 02:55:06 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
strides[0] = stride;
|
|
|
|
offsets[0] = offset;
|
|
|
|
modifiers[0] = modifier;
|
|
|
|
egl_image = meta_egl_create_dmabuf_image (egl,
|
|
|
|
egl_display,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
drm_format,
|
|
|
|
1 /* n_planes */,
|
|
|
|
&dmabuf_fd,
|
|
|
|
strides,
|
|
|
|
offsets,
|
|
|
|
modifiers,
|
|
|
|
error);
|
|
|
|
if (egl_image == EGL_NO_IMAGE_KHR)
|
|
|
|
return NULL;
|
2017-07-24 22:21:04 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
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);
|
2016-05-12 02:55:06 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
|
2020-02-26 18:08:58 -05:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
if (!cogl_tex)
|
|
|
|
return NULL;
|
2020-02-26 18:08:58 -05:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
cogl_fbo = cogl_offscreen_new_with_texture (COGL_TEXTURE (cogl_tex));
|
|
|
|
cogl_object_unref (cogl_tex);
|
2020-02-26 18:08:58 -05:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (cogl_fbo), error))
|
2016-06-08 05:05:31 -04:00
|
|
|
{
|
2020-10-17 17:08:28 -04:00
|
|
|
g_object_unref (cogl_fbo);
|
|
|
|
return NULL;
|
2016-06-08 05:05:31 -04:00
|
|
|
}
|
backend/native: Add and use transactional KMS API
This commit introduces, and makes use of, a transactional API used for
setting up KMS state, later to be applied, potentially atomically. From
an API point of view, so is always the case, but in the current
implementation, it still uses legacy drmMode* API to apply the state
non-atomically.
The API consists of various buliding blocks:
* MetaKmsUpdate - a set of configuration changes, the higher level
handle for handing over configuration to the impl backend. It's used to
set mode, assign framebuffers to planes, queue page flips and set
connector properties.
* MetaKmsPlaneAssignment - the assignment of a framebuffer to a plane.
Currently used to map a framebuffer to the primary plane of a CRTC. In
the legacy KMS implementation, the plane assignment is used to derive
the framebuffer used for mode setting and page flipping.
This also means various high level changes:
State, excluding configuring the cursor plane and creating/destroying
DRM framebuffer handles, are applied in the end of a clutter frame, in
one go. From an API point of view, this is done atomically, but as
mentioned, only the non-atomic implementation exists so far.
From MetaRendererNative's point of view, a page flip now initially
always succeeds; the handling of EBUSY errors are done asynchronously in
the MetaKmsImpl backend (still by retrying at refresh rate, but
postponing flip callbacks instead of manipulating the frame clock).
Handling of falling back to mode setting instead of page flipping is
notified after the fact by a more precise page flip feedback API.
EGLStream based page flipping relies on the impl backend not being
atomic, as the page flipping is done in the EGLStream backend (e.g.
nvidia driver). It uses a 'custom' page flip queueing method, keeping
the EGLStream logic inside meta-renderer-native.c.
Page flip handling is moved to meta-kms-impl-device.c from
meta-gpu-kms.c. It goes via an extra idle callback before reaching
meta-renderer-native.c to make sure callbacks are invoked outside of the
impl context.
While dummy power save page flipping is kept in meta-renderer-native.c, the
EBUSY handling is moved to meta-kms-impl-simple.c. Instead of freezing the
frame clock, actual page flip callbacks are postponed until all EBUSY retries
have either succeeded or failed due to some other error than EBUSY. This
effectively inhibits new frames to be drawn, meaning we won't stall waiting on
the file descriptor for pending page flips.
https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-04-04 16:36:41 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
return COGL_FRAMEBUFFER (cogl_fbo);
|
backend/native: Add and use transactional KMS API
This commit introduces, and makes use of, a transactional API used for
setting up KMS state, later to be applied, potentially atomically. From
an API point of view, so is always the case, but in the current
implementation, it still uses legacy drmMode* API to apply the state
non-atomically.
The API consists of various buliding blocks:
* MetaKmsUpdate - a set of configuration changes, the higher level
handle for handing over configuration to the impl backend. It's used to
set mode, assign framebuffers to planes, queue page flips and set
connector properties.
* MetaKmsPlaneAssignment - the assignment of a framebuffer to a plane.
Currently used to map a framebuffer to the primary plane of a CRTC. In
the legacy KMS implementation, the plane assignment is used to derive
the framebuffer used for mode setting and page flipping.
This also means various high level changes:
State, excluding configuring the cursor plane and creating/destroying
DRM framebuffer handles, are applied in the end of a clutter frame, in
one go. From an API point of view, this is done atomically, but as
mentioned, only the non-atomic implementation exists so far.
From MetaRendererNative's point of view, a page flip now initially
always succeeds; the handling of EBUSY errors are done asynchronously in
the MetaKmsImpl backend (still by retrying at refresh rate, but
postponing flip callbacks instead of manipulating the frame clock).
Handling of falling back to mode setting instead of page flipping is
notified after the fact by a more precise page flip feedback API.
EGLStream based page flipping relies on the impl backend not being
atomic, as the page flipping is done in the EGLStream backend (e.g.
nvidia driver). It uses a 'custom' page flip queueing method, keeping
the EGLStream logic inside meta-renderer-native.c.
Page flip handling is moved to meta-kms-impl-device.c from
meta-gpu-kms.c. It goes via an extra idle callback before reaching
meta-renderer-native.c to make sure callbacks are invoked outside of the
impl context.
While dummy power save page flipping is kept in meta-renderer-native.c, the
EBUSY handling is moved to meta-kms-impl-simple.c. Instead of freezing the
frame clock, actual page flip callbacks are postponed until all EBUSY retries
have either succeeded or failed due to some other error than EBUSY. This
effectively inhibits new frames to be drawn, meaning we won't stall waiting on
the file descriptor for pending page flips.
https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-04-04 16:36:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-04-10 15:35:04 -04:00
|
|
|
configure_disabled_crtcs (MetaKmsDevice *kms_device)
|
2016-08-17 23:28:59 -04:00
|
|
|
{
|
2021-04-10 15:35:04 -04:00
|
|
|
MetaKms *kms = meta_kms_device_get_kms (kms_device);
|
2020-10-17 17:08:28 -04:00
|
|
|
GList *l;
|
backend/native: Add and use transactional KMS API
This commit introduces, and makes use of, a transactional API used for
setting up KMS state, later to be applied, potentially atomically. From
an API point of view, so is always the case, but in the current
implementation, it still uses legacy drmMode* API to apply the state
non-atomically.
The API consists of various buliding blocks:
* MetaKmsUpdate - a set of configuration changes, the higher level
handle for handing over configuration to the impl backend. It's used to
set mode, assign framebuffers to planes, queue page flips and set
connector properties.
* MetaKmsPlaneAssignment - the assignment of a framebuffer to a plane.
Currently used to map a framebuffer to the primary plane of a CRTC. In
the legacy KMS implementation, the plane assignment is used to derive
the framebuffer used for mode setting and page flipping.
This also means various high level changes:
State, excluding configuring the cursor plane and creating/destroying
DRM framebuffer handles, are applied in the end of a clutter frame, in
one go. From an API point of view, this is done atomically, but as
mentioned, only the non-atomic implementation exists so far.
From MetaRendererNative's point of view, a page flip now initially
always succeeds; the handling of EBUSY errors are done asynchronously in
the MetaKmsImpl backend (still by retrying at refresh rate, but
postponing flip callbacks instead of manipulating the frame clock).
Handling of falling back to mode setting instead of page flipping is
notified after the fact by a more precise page flip feedback API.
EGLStream based page flipping relies on the impl backend not being
atomic, as the page flipping is done in the EGLStream backend (e.g.
nvidia driver). It uses a 'custom' page flip queueing method, keeping
the EGLStream logic inside meta-renderer-native.c.
Page flip handling is moved to meta-kms-impl-device.c from
meta-gpu-kms.c. It goes via an extra idle callback before reaching
meta-renderer-native.c to make sure callbacks are invoked outside of the
impl context.
While dummy power save page flipping is kept in meta-renderer-native.c, the
EBUSY handling is moved to meta-kms-impl-simple.c. Instead of freezing the
frame clock, actual page flip callbacks are postponed until all EBUSY retries
have either succeeded or failed due to some other error than EBUSY. This
effectively inhibits new frames to be drawn, meaning we won't stall waiting on
the file descriptor for pending page flips.
https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-04-04 16:36:41 -04:00
|
|
|
|
2021-04-10 15:35:04 -04:00
|
|
|
for (l = meta_kms_device_get_crtcs (kms_device); l; l = l->next)
|
2016-08-17 23:28:59 -04:00
|
|
|
{
|
2021-04-10 15:35:04 -04:00
|
|
|
MetaKmsCrtc *kms_crtc = l->data;
|
|
|
|
MetaCrtcKms *crtc_kms = meta_crtc_kms_from_kms_crtc (kms_crtc);
|
|
|
|
MetaKmsUpdate *kms_update;
|
2016-08-17 23:28:59 -04:00
|
|
|
|
2021-04-10 15:35:04 -04:00
|
|
|
if (meta_crtc_get_config (META_CRTC (crtc_kms)))
|
2020-10-17 17:08:28 -04:00
|
|
|
continue;
|
2020-10-21 13:40:08 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
if (!meta_kms_crtc_is_active (kms_crtc))
|
|
|
|
continue;
|
2020-10-21 13:40:08 -04:00
|
|
|
|
2021-04-10 15:35:04 -04:00
|
|
|
kms_update = meta_kms_ensure_pending_update (kms, kms_device);
|
2020-10-17 17:08:28 -04:00
|
|
|
meta_kms_update_mode_set (kms_update, kms_crtc, NULL, NULL);
|
|
|
|
}
|
2019-02-12 13:10:59 -05:00
|
|
|
}
|
|
|
|
|
2019-03-25 05:24:46 -04:00
|
|
|
static gboolean
|
|
|
|
dummy_power_save_page_flip_cb (gpointer user_data)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = user_data;
|
|
|
|
|
backend/native: Add and use transactional KMS API
This commit introduces, and makes use of, a transactional API used for
setting up KMS state, later to be applied, potentially atomically. From
an API point of view, so is always the case, but in the current
implementation, it still uses legacy drmMode* API to apply the state
non-atomically.
The API consists of various buliding blocks:
* MetaKmsUpdate - a set of configuration changes, the higher level
handle for handing over configuration to the impl backend. It's used to
set mode, assign framebuffers to planes, queue page flips and set
connector properties.
* MetaKmsPlaneAssignment - the assignment of a framebuffer to a plane.
Currently used to map a framebuffer to the primary plane of a CRTC. In
the legacy KMS implementation, the plane assignment is used to derive
the framebuffer used for mode setting and page flipping.
This also means various high level changes:
State, excluding configuring the cursor plane and creating/destroying
DRM framebuffer handles, are applied in the end of a clutter frame, in
one go. From an API point of view, this is done atomically, but as
mentioned, only the non-atomic implementation exists so far.
From MetaRendererNative's point of view, a page flip now initially
always succeeds; the handling of EBUSY errors are done asynchronously in
the MetaKmsImpl backend (still by retrying at refresh rate, but
postponing flip callbacks instead of manipulating the frame clock).
Handling of falling back to mode setting instead of page flipping is
notified after the fact by a more precise page flip feedback API.
EGLStream based page flipping relies on the impl backend not being
atomic, as the page flipping is done in the EGLStream backend (e.g.
nvidia driver). It uses a 'custom' page flip queueing method, keeping
the EGLStream logic inside meta-renderer-native.c.
Page flip handling is moved to meta-kms-impl-device.c from
meta-gpu-kms.c. It goes via an extra idle callback before reaching
meta-renderer-native.c to make sure callbacks are invoked outside of the
impl context.
While dummy power save page flipping is kept in meta-renderer-native.c, the
EBUSY handling is moved to meta-kms-impl-simple.c. Instead of freezing the
frame clock, actual page flip callbacks are postponed until all EBUSY retries
have either succeeded or failed due to some other error than EBUSY. This
effectively inhibits new frames to be drawn, meaning we won't stall waiting on
the file descriptor for pending page flips.
https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-04-04 16:36:41 -04:00
|
|
|
g_list_foreach (renderer_native->power_save_page_flip_onscreens,
|
2020-10-17 17:08:28 -04:00
|
|
|
(GFunc) meta_onscreen_native_dummy_power_save_page_flip,
|
|
|
|
NULL);
|
2021-04-09 18:49:51 -04:00
|
|
|
g_clear_list (&renderer_native->power_save_page_flip_onscreens,
|
|
|
|
g_object_unref);
|
2019-03-25 05:24:46 -04:00
|
|
|
renderer_native->power_save_page_flip_source_id = 0;
|
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
void
|
|
|
|
meta_renderer_native_queue_power_save_page_flip (MetaRendererNative *renderer_native,
|
|
|
|
CoglOnscreen *onscreen)
|
2019-03-25 05:24:46 -04:00
|
|
|
{
|
|
|
|
const unsigned int timeout_ms = 100;
|
|
|
|
|
|
|
|
if (!renderer_native->power_save_page_flip_source_id)
|
|
|
|
{
|
|
|
|
renderer_native->power_save_page_flip_source_id =
|
|
|
|
g_timeout_add (timeout_ms,
|
|
|
|
dummy_power_save_page_flip_cb,
|
|
|
|
renderer_native);
|
|
|
|
}
|
|
|
|
|
backend/native: Add and use transactional KMS API
This commit introduces, and makes use of, a transactional API used for
setting up KMS state, later to be applied, potentially atomically. From
an API point of view, so is always the case, but in the current
implementation, it still uses legacy drmMode* API to apply the state
non-atomically.
The API consists of various buliding blocks:
* MetaKmsUpdate - a set of configuration changes, the higher level
handle for handing over configuration to the impl backend. It's used to
set mode, assign framebuffers to planes, queue page flips and set
connector properties.
* MetaKmsPlaneAssignment - the assignment of a framebuffer to a plane.
Currently used to map a framebuffer to the primary plane of a CRTC. In
the legacy KMS implementation, the plane assignment is used to derive
the framebuffer used for mode setting and page flipping.
This also means various high level changes:
State, excluding configuring the cursor plane and creating/destroying
DRM framebuffer handles, are applied in the end of a clutter frame, in
one go. From an API point of view, this is done atomically, but as
mentioned, only the non-atomic implementation exists so far.
From MetaRendererNative's point of view, a page flip now initially
always succeeds; the handling of EBUSY errors are done asynchronously in
the MetaKmsImpl backend (still by retrying at refresh rate, but
postponing flip callbacks instead of manipulating the frame clock).
Handling of falling back to mode setting instead of page flipping is
notified after the fact by a more precise page flip feedback API.
EGLStream based page flipping relies on the impl backend not being
atomic, as the page flipping is done in the EGLStream backend (e.g.
nvidia driver). It uses a 'custom' page flip queueing method, keeping
the EGLStream logic inside meta-renderer-native.c.
Page flip handling is moved to meta-kms-impl-device.c from
meta-gpu-kms.c. It goes via an extra idle callback before reaching
meta-renderer-native.c to make sure callbacks are invoked outside of the
impl context.
While dummy power save page flipping is kept in meta-renderer-native.c, the
EBUSY handling is moved to meta-kms-impl-simple.c. Instead of freezing the
frame clock, actual page flip callbacks are postponed until all EBUSY retries
have either succeeded or failed due to some other error than EBUSY. This
effectively inhibits new frames to be drawn, meaning we won't stall waiting on
the file descriptor for pending page flips.
https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-04-04 16:36:41 -04:00
|
|
|
renderer_native->power_save_page_flip_onscreens =
|
|
|
|
g_list_prepend (renderer_native->power_save_page_flip_onscreens,
|
2020-10-13 05:35:47 -04:00
|
|
|
g_object_ref (onscreen));
|
2019-02-12 13:10:59 -05:00
|
|
|
}
|
|
|
|
|
2016-06-08 05:05:31 -04:00
|
|
|
static void
|
2020-10-17 17:08:28 -04:00
|
|
|
clear_kept_alive_onscreens (MetaRendererNative *renderer_native)
|
2018-11-29 06:54:31 -05:00
|
|
|
{
|
2021-04-09 18:49:51 -04:00
|
|
|
g_clear_list (&renderer_native->kept_alive_onscreens,
|
|
|
|
g_object_unref);
|
2018-11-29 06:54:31 -05:00
|
|
|
}
|
|
|
|
|
2021-04-12 10:25:53 -04:00
|
|
|
static gboolean
|
|
|
|
is_gpu_unused (gpointer key,
|
|
|
|
gpointer value,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
GHashTable *used_gpus = user_data;
|
|
|
|
|
|
|
|
return !g_hash_table_contains (used_gpus, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_unused_gpu_datas (MetaRendererNative *renderer_native)
|
|
|
|
{
|
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
|
|
|
g_autoptr (GHashTable) used_gpus = NULL;
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
used_gpus = g_hash_table_new (NULL, NULL);
|
|
|
|
g_hash_table_add (used_gpus, renderer_native->primary_gpu_kms);
|
|
|
|
|
|
|
|
for (l = meta_renderer_get_views (renderer); l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaRendererView *view = l->data;
|
|
|
|
MetaCrtc *crtc = meta_renderer_view_get_crtc (view);
|
|
|
|
MetaGpu *gpu;
|
|
|
|
|
|
|
|
gpu = meta_crtc_get_gpu (crtc);
|
|
|
|
if (!gpu)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
g_hash_table_add (used_gpus, gpu);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_hash_table_foreach_remove (renderer_native->gpu_datas,
|
|
|
|
is_gpu_unused,
|
|
|
|
used_gpus);
|
|
|
|
}
|
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
void
|
|
|
|
meta_renderer_native_post_mode_set_updates (MetaRendererNative *renderer_native)
|
2018-11-29 06:34:40 -05:00
|
|
|
{
|
2019-12-09 08:04:56 -05:00
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
|
|
|
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
2020-10-17 17:08:28 -04:00
|
|
|
MetaKms *kms = meta_backend_native_get_kms (META_BACKEND_NATIVE (backend));
|
|
|
|
GList *l;
|
2018-11-29 06:34:40 -05:00
|
|
|
|
2021-04-10 15:35:04 -04:00
|
|
|
for (l = meta_kms_get_devices (kms); l; l = l->next)
|
2018-11-29 06:34:40 -05:00
|
|
|
{
|
2021-04-10 15:35:04 -04:00
|
|
|
MetaKmsDevice *kms_device = l->data;
|
2020-10-17 17:08:28 -04:00
|
|
|
MetaKmsUpdate *kms_update;
|
|
|
|
MetaKmsUpdateFlag flags;
|
|
|
|
g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
|
|
|
|
const GError *feedback_error;
|
2020-10-09 17:17:06 -04:00
|
|
|
|
2021-04-10 15:35:04 -04:00
|
|
|
configure_disabled_crtcs (kms_device);
|
2020-10-09 17:17:06 -04:00
|
|
|
|
|
|
|
kms_update = meta_kms_get_pending_update (kms, kms_device);
|
|
|
|
if (!kms_update)
|
2020-10-17 17:08:28 -04:00
|
|
|
continue;
|
2016-05-09 07:51:29 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
flags = META_KMS_UPDATE_FLAG_NONE;
|
|
|
|
kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags);
|
2016-05-09 07:51:29 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
switch (meta_kms_feedback_get_result (kms_feedback))
|
|
|
|
{
|
|
|
|
case META_KMS_FEEDBACK_PASSED:
|
|
|
|
break;
|
|
|
|
case META_KMS_FEEDBACK_FAILED:
|
|
|
|
feedback_error = meta_kms_feedback_get_error (kms_feedback);
|
|
|
|
if (!g_error_matches (feedback_error,
|
|
|
|
G_IO_ERROR,
|
|
|
|
G_IO_ERROR_PERMISSION_DENIED))
|
|
|
|
g_warning ("Failed to post KMS update: %s", feedback_error->message);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-09-29 10:46:34 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
clear_kept_alive_onscreens (renderer_native);
|
2021-04-12 10:25:53 -04:00
|
|
|
|
|
|
|
meta_kms_notify_modes_set (kms);
|
|
|
|
|
|
|
|
free_unused_gpu_datas (renderer_native);
|
2016-09-29 10:46:34 -04:00
|
|
|
}
|
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
static void
|
|
|
|
unset_disabled_crtcs (MetaBackend *backend,
|
|
|
|
MetaKms *kms)
|
2016-09-29 10:46:34 -04:00
|
|
|
{
|
2020-10-17 17:08:28 -04:00
|
|
|
GList *l;
|
2016-09-29 10:46:34 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
meta_topic (META_DEBUG_KMS, "Disabling all disabled CRTCs");
|
|
|
|
|
|
|
|
for (l = meta_backend_get_gpus (backend); l; l = l->next)
|
2016-08-17 23:28:59 -04:00
|
|
|
{
|
2020-10-17 17:08:28 -04:00
|
|
|
MetaGpu *gpu = l->data;
|
|
|
|
MetaKmsDevice *kms_device =
|
|
|
|
meta_gpu_kms_get_kms_device (META_GPU_KMS (gpu));
|
|
|
|
GList *k;
|
|
|
|
gboolean did_mode_set = FALSE;
|
|
|
|
MetaKmsUpdateFlag flags;
|
|
|
|
g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
|
2016-08-17 23:11:30 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
for (k = meta_gpu_get_crtcs (gpu); k; k = k->next)
|
|
|
|
{
|
|
|
|
MetaCrtc *crtc = k->data;
|
|
|
|
MetaKmsUpdate *kms_update;
|
2016-08-17 23:28:59 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
if (meta_crtc_get_config (crtc))
|
|
|
|
continue;
|
2016-08-17 23:28:59 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
kms_update = meta_kms_ensure_pending_update (kms, kms_device);
|
|
|
|
meta_crtc_kms_set_mode (META_CRTC_KMS (crtc), kms_update);
|
2016-08-17 23:11:30 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
did_mode_set = TRUE;
|
|
|
|
}
|
2016-05-09 07:51:29 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
if (!did_mode_set)
|
|
|
|
continue;
|
2019-06-17 13:16:12 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
flags = META_KMS_UPDATE_FLAG_NONE;
|
|
|
|
kms_feedback = meta_kms_post_pending_update_sync (kms,
|
|
|
|
kms_device,
|
|
|
|
flags);
|
|
|
|
if (meta_kms_feedback_get_result (kms_feedback) !=
|
|
|
|
META_KMS_FEEDBACK_PASSED)
|
|
|
|
{
|
|
|
|
const GError *error = meta_kms_feedback_get_error (kms_feedback);
|
2019-06-17 13:16:12 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
if (!g_error_matches (error, G_IO_ERROR,
|
|
|
|
G_IO_ERROR_PERMISSION_DENIED))
|
|
|
|
g_warning ("Failed to post KMS update: %s", error->message);
|
|
|
|
}
|
2019-06-17 13:16:12 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
static CoglDmaBufHandle *
|
|
|
|
meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer,
|
|
|
|
int width,
|
|
|
|
int height,
|
|
|
|
GError **error)
|
2016-05-09 07:51:29 -04:00
|
|
|
{
|
2020-10-17 17:08:28 -04:00
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
|
|
|
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
|
2019-06-17 12:18:42 -04:00
|
|
|
|
2017-07-10 06:19:32 -04:00
|
|
|
switch (renderer_gpu_data->mode)
|
2016-05-09 07:51:29 -04:00
|
|
|
{
|
2016-08-17 23:28:59 -04:00
|
|
|
case META_RENDERER_NATIVE_MODE_GBM:
|
2020-10-17 17:08:28 -04:00
|
|
|
{
|
2021-05-05 09:53:59 -04:00
|
|
|
MetaRenderDevice *render_device;
|
|
|
|
MetaDrmBufferFlags flags;
|
|
|
|
g_autoptr (MetaDrmBuffer) buffer = NULL;
|
|
|
|
int dmabuf_fd;
|
|
|
|
uint32_t stride;
|
|
|
|
uint32_t offset;
|
|
|
|
uint32_t bpp;
|
|
|
|
uint32_t modifier;
|
|
|
|
uint32_t format;
|
2020-10-17 17:08:28 -04:00
|
|
|
CoglFramebuffer *dmabuf_fb;
|
|
|
|
CoglDmaBufHandle *dmabuf_handle;
|
2016-08-17 23:28:59 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
|
2021-05-05 09:53:59 -04:00
|
|
|
render_device = renderer_gpu_data->render_device;
|
|
|
|
flags = META_DRM_BUFFER_FLAG_NONE;
|
|
|
|
buffer = meta_render_device_allocate_dma_buf (render_device,
|
|
|
|
width, height,
|
|
|
|
DRM_FORMAT_XRGB8888,
|
|
|
|
flags,
|
|
|
|
error);
|
|
|
|
if (!buffer)
|
|
|
|
return NULL;
|
2019-06-17 13:16:12 -04:00
|
|
|
|
2021-05-05 09:53:59 -04:00
|
|
|
dmabuf_fd = meta_drm_buffer_export_fd (buffer, error);
|
2020-10-17 17:08:28 -04:00
|
|
|
if (dmabuf_fd == -1)
|
2021-05-05 09:53:59 -04:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
stride = meta_drm_buffer_get_stride (buffer);
|
|
|
|
offset = meta_drm_buffer_get_offset (buffer, 0);
|
|
|
|
bpp = meta_drm_buffer_get_bpp (buffer);
|
|
|
|
modifier = meta_drm_buffer_get_modifier (buffer);
|
|
|
|
format = meta_drm_buffer_get_format (buffer);
|
2020-10-17 17:08:28 -04:00
|
|
|
|
|
|
|
dmabuf_fb =
|
|
|
|
meta_renderer_native_create_dma_buf_framebuffer (renderer_native,
|
|
|
|
dmabuf_fd,
|
|
|
|
width, height,
|
|
|
|
stride,
|
|
|
|
offset,
|
2021-05-05 09:53:59 -04:00
|
|
|
modifier,
|
|
|
|
format,
|
2020-10-17 17:08:28 -04:00
|
|
|
error);
|
|
|
|
|
|
|
|
if (!dmabuf_fb)
|
2021-05-05 09:53:59 -04:00
|
|
|
{
|
|
|
|
close (dmabuf_fd);
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-10-17 17:08:28 -04:00
|
|
|
|
|
|
|
dmabuf_handle =
|
|
|
|
cogl_dma_buf_handle_new (dmabuf_fb, dmabuf_fd,
|
|
|
|
width, height, stride, offset, bpp,
|
2021-05-05 09:53:59 -04:00
|
|
|
g_steal_pointer (&buffer),
|
|
|
|
g_object_unref);
|
2020-10-17 17:08:28 -04:00
|
|
|
g_object_unref (dmabuf_fb);
|
|
|
|
return dmabuf_handle;
|
|
|
|
}
|
2016-08-17 23:28:59 -04:00
|
|
|
break;
|
2021-02-09 08:32:55 -05:00
|
|
|
case META_RENDERER_NATIVE_MODE_SURFACELESS:
|
2016-08-17 23:28:59 -04:00
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
2020-10-17 17:08:28 -04:00
|
|
|
#endif
|
2021-02-09 08:32:55 -05:00
|
|
|
break;
|
2016-05-09 07:51:29 -04:00
|
|
|
}
|
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN,
|
|
|
|
"Current mode does not support exporting DMA buffers");
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_renderer_native_init_egl_context (CoglContext *cogl_context,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
CoglRenderer *cogl_renderer = cogl_context->display->renderer;
|
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
COGL_FLAGS_SET (cogl_context->winsys_features,
|
|
|
|
COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT,
|
|
|
|
TRUE);
|
|
|
|
COGL_FLAGS_SET (cogl_context->winsys_features,
|
|
|
|
COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT,
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
if (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_EGL_DEVICE)
|
|
|
|
COGL_FLAGS_SET (cogl_context->features,
|
|
|
|
COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL, TRUE);
|
|
|
|
#endif
|
2017-07-24 22:21:04 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
return TRUE;
|
2016-05-09 07:51:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static const CoglWinsysEGLVtable
|
|
|
|
_cogl_winsys_egl_vtable = {
|
2016-09-26 03:54:27 -04:00
|
|
|
.add_config_attributes = meta_renderer_native_add_egl_config_attributes,
|
2018-02-23 09:14:07 -05:00
|
|
|
.choose_config = meta_renderer_native_choose_egl_config,
|
2016-05-27 03:13:09 -04:00
|
|
|
.display_setup = meta_renderer_native_setup_egl_display,
|
|
|
|
.display_destroy = meta_renderer_native_destroy_egl_display,
|
|
|
|
.context_created = meta_renderer_native_egl_context_created,
|
|
|
|
.cleanup_context = meta_renderer_native_egl_cleanup_context,
|
|
|
|
.context_init = meta_renderer_native_init_egl_context
|
2016-05-09 07:51:29 -04:00
|
|
|
};
|
|
|
|
|
2019-06-19 14:57:14 -04:00
|
|
|
static void
|
2016-05-09 07:51:29 -04:00
|
|
|
meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native)
|
|
|
|
{
|
2016-06-08 05:05:31 -04:00
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
2021-06-09 12:28:46 -04:00
|
|
|
GList *l;
|
2016-06-08 05:05:31 -04:00
|
|
|
|
2021-06-12 15:09:55 -04:00
|
|
|
g_clear_list (&renderer_native->pending_mode_set_views, NULL);
|
2021-06-09 12:28:46 -04:00
|
|
|
for (l = meta_renderer_get_views (renderer); l; l = l->next)
|
|
|
|
{
|
|
|
|
ClutterStageView *stage_view = l->data;
|
|
|
|
CoglFramebuffer *framebuffer =
|
|
|
|
clutter_stage_view_get_onscreen (stage_view);
|
|
|
|
|
|
|
|
if (COGL_IS_ONSCREEN (framebuffer))
|
|
|
|
{
|
|
|
|
renderer_native->pending_mode_set_views =
|
|
|
|
g_list_prepend (renderer_native->pending_mode_set_views,
|
|
|
|
stage_view);
|
|
|
|
}
|
|
|
|
}
|
2020-10-09 17:17:06 -04:00
|
|
|
renderer_native->pending_mode_set = TRUE;
|
2016-06-08 05:05:31 -04:00
|
|
|
|
2020-10-02 12:37:18 -04:00
|
|
|
meta_topic (META_DEBUG_KMS, "Queue mode set");
|
2016-05-09 07:51:29 -04:00
|
|
|
}
|
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
void
|
|
|
|
meta_renderer_native_notify_mode_sets_reset (MetaRendererNative *renderer_native)
|
2016-07-31 21:47:11 -04:00
|
|
|
{
|
2020-10-17 17:08:28 -04:00
|
|
|
renderer_native->pending_mode_set = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_renderer_native_pop_pending_mode_set (MetaRendererNative *renderer_native,
|
|
|
|
MetaRendererView *view)
|
|
|
|
{
|
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
|
|
|
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
meta_backend_get_monitor_manager (backend);
|
|
|
|
MetaPowerSave power_save_mode;
|
|
|
|
GList *link;
|
2016-07-31 21:47:11 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
g_assert (META_IS_RENDERER_VIEW (view));
|
2018-07-10 05:46:02 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
|
|
|
|
if (power_save_mode != META_POWER_SAVE_ON)
|
|
|
|
return FALSE;
|
2016-07-31 21:47:11 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
link = g_list_find (renderer_native->pending_mode_set_views, view);
|
|
|
|
if (!link)
|
|
|
|
return FALSE;
|
2017-07-10 06:19:32 -04:00
|
|
|
|
2020-10-17 17:08:28 -04:00
|
|
|
renderer_native->pending_mode_set_views =
|
|
|
|
g_list_delete_link (renderer_native->pending_mode_set_views, link);
|
|
|
|
return TRUE;
|
2016-07-31 21:47:11 -04:00
|
|
|
}
|
|
|
|
|
2016-07-31 21:48:30 -04:00
|
|
|
static CoglOffscreen *
|
|
|
|
meta_renderer_native_create_offscreen (MetaRendererNative *renderer,
|
|
|
|
CoglContext *context,
|
|
|
|
gint view_width,
|
2017-07-24 05:35:55 -04:00
|
|
|
gint view_height,
|
|
|
|
GError **error)
|
2016-07-31 21:48:30 -04:00
|
|
|
{
|
|
|
|
CoglOffscreen *fb;
|
|
|
|
CoglTexture2D *tex;
|
|
|
|
|
|
|
|
tex = cogl_texture_2d_new_with_size (context, view_width, view_height);
|
|
|
|
cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (tex), FALSE);
|
|
|
|
|
2017-07-24 05:35:55 -04:00
|
|
|
if (!cogl_texture_allocate (COGL_TEXTURE (tex), error))
|
2016-07-31 21:48:30 -04:00
|
|
|
{
|
|
|
|
cogl_object_unref (tex);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
fb = cogl_offscreen_new_with_texture (COGL_TEXTURE (tex));
|
|
|
|
cogl_object_unref (tex);
|
2017-07-24 05:35:55 -04:00
|
|
|
if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (fb), error))
|
2016-07-31 21:48:30 -04:00
|
|
|
{
|
2020-10-13 05:35:47 -04:00
|
|
|
g_object_unref (fb);
|
2016-07-31 21:48:30 -04:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fb;
|
|
|
|
}
|
|
|
|
|
2016-05-09 07:51:29 -04:00
|
|
|
static const CoglWinsysVtable *
|
2016-09-22 23:49:10 -04:00
|
|
|
get_native_cogl_winsys_vtable (CoglRenderer *cogl_renderer)
|
2016-05-09 07:51:29 -04:00
|
|
|
{
|
2016-08-17 22:21:12 -04:00
|
|
|
static gboolean vtable_inited = FALSE;
|
2016-05-09 07:51:29 -04:00
|
|
|
static CoglWinsysVtable vtable;
|
|
|
|
|
|
|
|
if (!vtable_inited)
|
|
|
|
{
|
|
|
|
/* The this winsys is a subclass of the EGL winsys so we
|
|
|
|
start by copying its vtable */
|
|
|
|
|
|
|
|
parent_vtable = _cogl_winsys_egl_get_vtable ();
|
|
|
|
vtable = *parent_vtable;
|
|
|
|
|
|
|
|
vtable.id = COGL_WINSYS_ID_CUSTOM;
|
|
|
|
vtable.name = "EGL_KMS";
|
|
|
|
|
2016-05-27 03:13:09 -04:00
|
|
|
vtable.renderer_connect = meta_renderer_native_connect;
|
|
|
|
vtable.renderer_disconnect = meta_renderer_native_disconnect;
|
2019-12-09 08:05:37 -05:00
|
|
|
vtable.renderer_create_dma_buf = meta_renderer_native_create_dma_buf;
|
2016-05-09 07:51:29 -04:00
|
|
|
|
|
|
|
vtable_inited = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &vtable;
|
|
|
|
}
|
|
|
|
|
2016-05-08 21:59:54 -04:00
|
|
|
static CoglRenderer *
|
2021-02-09 08:32:55 -05:00
|
|
|
meta_renderer_native_create_cogl_renderer (MetaRenderer *renderer)
|
2016-05-08 21:59:54 -04:00
|
|
|
{
|
|
|
|
CoglRenderer *cogl_renderer;
|
|
|
|
|
|
|
|
cogl_renderer = cogl_renderer_new ();
|
|
|
|
cogl_renderer_set_custom_winsys (cogl_renderer,
|
2017-07-24 04:03:02 -04:00
|
|
|
get_native_cogl_winsys_vtable,
|
2021-02-09 08:32:55 -05:00
|
|
|
renderer);
|
2016-05-08 21:59:54 -04:00
|
|
|
return cogl_renderer;
|
|
|
|
}
|
|
|
|
|
2017-03-08 03:05:00 -05:00
|
|
|
static MetaMonitorTransform
|
|
|
|
calculate_view_transform (MetaMonitorManager *monitor_manager,
|
2020-01-17 15:08:02 -05:00
|
|
|
MetaLogicalMonitor *logical_monitor,
|
|
|
|
MetaOutput *output,
|
|
|
|
MetaCrtc *crtc)
|
2017-03-08 03:05:00 -05:00
|
|
|
{
|
2018-07-23 15:36:57 -04:00
|
|
|
MetaMonitorTransform crtc_transform;
|
|
|
|
|
2020-01-17 15:08:02 -05:00
|
|
|
crtc = meta_output_get_assigned_crtc (output);
|
2018-07-23 15:36:57 -04:00
|
|
|
crtc_transform =
|
2020-01-17 15:08:02 -05:00
|
|
|
meta_output_logical_to_crtc_transform (output, logical_monitor->transform);
|
2017-03-08 03:05:00 -05:00
|
|
|
|
|
|
|
if (meta_monitor_manager_is_transform_handled (monitor_manager,
|
2017-11-03 06:25:30 -04:00
|
|
|
crtc,
|
2018-07-23 15:36:57 -04:00
|
|
|
crtc_transform))
|
2017-03-08 03:05:00 -05:00
|
|
|
return META_MONITOR_TRANSFORM_NORMAL;
|
|
|
|
else
|
2018-07-23 15:36:57 -04:00
|
|
|
return crtc_transform;
|
2017-03-08 03:05:00 -05:00
|
|
|
}
|
|
|
|
|
2018-10-09 09:55:23 -04:00
|
|
|
static gboolean
|
|
|
|
should_force_shadow_fb (MetaRendererNative *renderer_native,
|
|
|
|
MetaGpuKms *primary_gpu)
|
|
|
|
{
|
2019-10-01 05:54:32 -04:00
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
2020-05-05 11:06:35 -04:00
|
|
|
CoglContext *cogl_context =
|
|
|
|
cogl_context_from_renderer_native (renderer_native);
|
2021-03-29 05:48:59 -04:00
|
|
|
MetaKmsDevice *kms_device = meta_gpu_kms_get_kms_device (primary_gpu);
|
2018-10-09 09:55:23 -04:00
|
|
|
|
2019-10-01 05:54:32 -04:00
|
|
|
if (meta_renderer_is_hardware_accelerated (renderer))
|
|
|
|
return FALSE;
|
2018-10-09 09:55:23 -04:00
|
|
|
|
2020-05-05 11:06:35 -04:00
|
|
|
if (!cogl_has_feature (cogl_context, COGL_FEATURE_ID_BLIT_FRAMEBUFFER))
|
|
|
|
return FALSE;
|
|
|
|
|
2021-03-29 05:48:59 -04:00
|
|
|
return meta_kms_device_prefers_shadow_buffer (kms_device);
|
2018-10-09 09:55:23 -04:00
|
|
|
}
|
|
|
|
|
2021-04-10 15:29:22 -04:00
|
|
|
static CoglFramebuffer *
|
|
|
|
create_fallback_offscreen (MetaRendererNative *renderer_native,
|
|
|
|
CoglContext *cogl_context,
|
|
|
|
int width,
|
|
|
|
int height)
|
|
|
|
{
|
|
|
|
CoglOffscreen *fallback_offscreen;
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
fallback_offscreen = meta_renderer_native_create_offscreen (renderer_native,
|
|
|
|
cogl_context,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
&error);
|
|
|
|
if (!fallback_offscreen)
|
|
|
|
{
|
|
|
|
g_error ("Failed to create fallback offscreen framebuffer: %s",
|
|
|
|
error->message);
|
|
|
|
}
|
|
|
|
|
|
|
|
return COGL_FRAMEBUFFER (fallback_offscreen);
|
|
|
|
}
|
|
|
|
|
2016-06-08 05:05:31 -04:00
|
|
|
static MetaRendererView *
|
2016-11-25 01:31:38 -05:00
|
|
|
meta_renderer_native_create_view (MetaRenderer *renderer,
|
2020-01-17 15:08:02 -05:00
|
|
|
MetaLogicalMonitor *logical_monitor,
|
|
|
|
MetaOutput *output,
|
|
|
|
MetaCrtc *crtc)
|
2016-06-08 05:05:31 -04:00
|
|
|
{
|
2017-07-06 04:00:56 -04:00
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
|
2019-10-01 05:51:53 -04:00
|
|
|
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
2017-03-08 03:05:00 -05:00
|
|
|
MetaMonitorManager *monitor_manager =
|
2019-01-11 09:35:42 -05:00
|
|
|
meta_backend_get_monitor_manager (backend);
|
2017-07-10 06:19:32 -04:00
|
|
|
CoglContext *cogl_context =
|
2018-10-09 09:55:23 -04:00
|
|
|
cogl_context_from_renderer_native (renderer_native);
|
2016-07-31 21:48:30 -04:00
|
|
|
CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
|
2020-02-26 04:37:53 -05:00
|
|
|
const MetaCrtcConfig *crtc_config;
|
2020-02-26 18:08:58 -05:00
|
|
|
const MetaCrtcModeInfo *crtc_mode_info;
|
2017-03-08 03:05:00 -05:00
|
|
|
MetaMonitorTransform view_transform;
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 10:49:28 -05:00
|
|
|
g_autoptr (CoglFramebuffer) framebuffer = NULL;
|
|
|
|
g_autoptr (CoglOffscreen) offscreen = NULL;
|
2020-04-30 11:53:30 -04:00
|
|
|
gboolean use_shadowfb;
|
2017-05-25 04:12:51 -04:00
|
|
|
float scale;
|
2020-01-17 15:08:02 -05:00
|
|
|
int onscreen_width;
|
|
|
|
int onscreen_height;
|
2020-04-14 04:44:16 -04:00
|
|
|
MetaRectangle view_layout;
|
2016-06-08 05:05:31 -04:00
|
|
|
MetaRendererView *view;
|
2020-10-17 03:55:01 -04:00
|
|
|
EGLSurface egl_surface;
|
2016-09-29 10:46:34 -04:00
|
|
|
GError *error = NULL;
|
2016-06-08 05:05:31 -04:00
|
|
|
|
2020-02-26 04:37:53 -05:00
|
|
|
crtc_config = meta_crtc_get_config (crtc);
|
2020-02-26 18:08:58 -05:00
|
|
|
crtc_mode_info = meta_crtc_mode_get_info (crtc_config->mode);
|
|
|
|
onscreen_width = crtc_mode_info->width;
|
|
|
|
onscreen_height = crtc_mode_info->height;
|
2017-02-24 05:10:52 -05:00
|
|
|
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 10:49:28 -05:00
|
|
|
if (META_IS_CRTC_KMS (crtc))
|
|
|
|
{
|
2021-04-10 15:29:22 -04:00
|
|
|
MetaGpuKms *gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 10:49:28 -05:00
|
|
|
MetaOnscreenNative *onscreen_native;
|
|
|
|
|
2021-04-12 10:25:53 -04:00
|
|
|
if (!meta_renderer_native_ensure_gpu_data (renderer_native,
|
|
|
|
gpu_kms,
|
|
|
|
&error))
|
2021-04-10 15:29:22 -04:00
|
|
|
{
|
2021-07-14 10:47:32 -04:00
|
|
|
g_warning ("Failed to create secondary GPU data for %s: %s",
|
|
|
|
meta_gpu_kms_get_file_path (gpu_kms),
|
|
|
|
error->message);
|
2021-04-12 10:25:53 -04:00
|
|
|
use_shadowfb = FALSE;
|
2021-04-10 15:29:22 -04:00
|
|
|
framebuffer = create_fallback_offscreen (renderer_native,
|
|
|
|
cogl_context,
|
|
|
|
onscreen_width,
|
|
|
|
onscreen_height);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-04-12 10:25:53 -04:00
|
|
|
MetaGpuKms *primary_gpu_kms = renderer_native->primary_gpu_kms;
|
|
|
|
|
|
|
|
onscreen_native = meta_onscreen_native_new (renderer_native,
|
|
|
|
primary_gpu_kms,
|
|
|
|
output,
|
|
|
|
crtc,
|
|
|
|
cogl_context,
|
|
|
|
onscreen_width,
|
|
|
|
onscreen_height);
|
|
|
|
|
|
|
|
if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (onscreen_native), &error))
|
|
|
|
{
|
2021-07-14 10:47:32 -04:00
|
|
|
g_warning ("Failed to allocate onscreen framebuffer for %s: %s",
|
|
|
|
meta_gpu_kms_get_file_path (gpu_kms),
|
|
|
|
error->message);
|
2021-04-12 10:25:53 -04:00
|
|
|
use_shadowfb = FALSE;
|
|
|
|
framebuffer = create_fallback_offscreen (renderer_native,
|
|
|
|
cogl_context,
|
|
|
|
onscreen_width,
|
|
|
|
onscreen_height);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
use_shadowfb = should_force_shadow_fb (renderer_native,
|
|
|
|
primary_gpu_kms);
|
|
|
|
framebuffer = COGL_FRAMEBUFFER (onscreen_native);
|
|
|
|
}
|
2021-04-10 15:29:22 -04:00
|
|
|
}
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 10:49:28 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CoglOffscreen *virtual_onscreen;
|
2020-10-17 19:39:21 -04:00
|
|
|
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 10:49:28 -05:00
|
|
|
g_assert (META_IS_CRTC_VIRTUAL (crtc));
|
|
|
|
|
|
|
|
virtual_onscreen = meta_renderer_native_create_offscreen (renderer_native,
|
|
|
|
cogl_context,
|
|
|
|
onscreen_width,
|
|
|
|
onscreen_height,
|
|
|
|
&error);
|
|
|
|
if (!virtual_onscreen)
|
|
|
|
g_error ("Failed to allocate back buffer texture: %s", error->message);
|
|
|
|
use_shadowfb = FALSE;
|
|
|
|
framebuffer = COGL_FRAMEBUFFER (virtual_onscreen);
|
|
|
|
}
|
2016-06-08 05:05:31 -04:00
|
|
|
|
2020-01-17 15:08:02 -05:00
|
|
|
view_transform = calculate_view_transform (monitor_manager,
|
|
|
|
logical_monitor,
|
|
|
|
output,
|
|
|
|
crtc);
|
2020-01-17 13:35:19 -05:00
|
|
|
if (view_transform != META_MONITOR_TRANSFORM_NORMAL)
|
2016-07-31 21:48:30 -04:00
|
|
|
{
|
2020-01-17 15:08:02 -05:00
|
|
|
int offscreen_width;
|
|
|
|
int offscreen_height;
|
|
|
|
|
|
|
|
if (meta_monitor_transform_is_rotated (view_transform))
|
|
|
|
{
|
|
|
|
offscreen_width = onscreen_height;
|
|
|
|
offscreen_height = onscreen_width;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
offscreen_width = onscreen_width;
|
|
|
|
offscreen_height = onscreen_height;
|
|
|
|
}
|
|
|
|
|
2017-07-10 06:19:32 -04:00
|
|
|
offscreen = meta_renderer_native_create_offscreen (renderer_native,
|
2016-07-31 21:48:30 -04:00
|
|
|
cogl_context,
|
2020-01-17 15:08:02 -05:00
|
|
|
offscreen_width,
|
|
|
|
offscreen_height,
|
2017-07-24 05:35:55 -04:00
|
|
|
&error);
|
2016-07-31 21:48:30 -04:00
|
|
|
if (!offscreen)
|
2017-07-24 05:35:55 -04:00
|
|
|
g_error ("Failed to allocate back buffer texture: %s", error->message);
|
2019-10-22 11:05:46 -04:00
|
|
|
}
|
|
|
|
|
2020-01-17 15:08:02 -05:00
|
|
|
if (meta_is_stage_views_scaled ())
|
|
|
|
scale = meta_logical_monitor_get_scale (logical_monitor);
|
|
|
|
else
|
|
|
|
scale = 1.0;
|
|
|
|
|
2020-02-26 04:37:53 -05:00
|
|
|
meta_rectangle_from_graphene_rect (&crtc_config->layout,
|
2020-04-14 04:44:16 -04:00
|
|
|
META_ROUNDING_STRATEGY_ROUND,
|
|
|
|
&view_layout);
|
2016-06-08 05:05:31 -04:00
|
|
|
view = g_object_new (META_TYPE_RENDERER_VIEW,
|
2020-04-30 04:42:30 -04:00
|
|
|
"name", meta_output_get_name (output),
|
2020-03-30 11:34:43 -04:00
|
|
|
"stage", meta_backend_get_stage (backend),
|
2020-04-14 04:44:16 -04:00
|
|
|
"layout", &view_layout,
|
2020-04-01 05:13:22 -04:00
|
|
|
"crtc", crtc,
|
2017-05-25 04:12:51 -04:00
|
|
|
"scale", scale,
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 10:49:28 -05:00
|
|
|
"framebuffer", framebuffer,
|
2016-07-31 21:48:30 -04:00
|
|
|
"offscreen", offscreen,
|
2020-04-30 11:53:30 -04:00
|
|
|
"use-shadowfb", use_shadowfb,
|
2017-03-08 03:05:00 -05:00
|
|
|
"transform", view_transform,
|
2020-04-17 03:18:37 -04:00
|
|
|
"refresh-rate", crtc_mode_info->refresh_rate,
|
2021-01-06 07:18:26 -05:00
|
|
|
"vblank-duration-us", crtc_mode_info->vblank_duration_us,
|
2016-06-08 05:05:31 -04:00
|
|
|
NULL);
|
2016-09-29 10:46:34 -04:00
|
|
|
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 10:49:28 -05:00
|
|
|
if (META_IS_ONSCREEN_NATIVE (framebuffer))
|
|
|
|
{
|
|
|
|
CoglDisplayEGL *cogl_display_egl;
|
|
|
|
CoglOnscreenEgl *onscreen_egl;
|
|
|
|
|
|
|
|
meta_onscreen_native_set_view (COGL_ONSCREEN (framebuffer), view);
|
|
|
|
|
|
|
|
/* Ensure we don't point to stale surfaces when creating the offscreen */
|
|
|
|
cogl_display_egl = cogl_display->winsys;
|
|
|
|
onscreen_egl = COGL_ONSCREEN_EGL (framebuffer);
|
|
|
|
egl_surface = cogl_onscreen_egl_get_egl_surface (onscreen_egl);
|
|
|
|
_cogl_winsys_egl_make_current (cogl_display,
|
|
|
|
egl_surface,
|
|
|
|
egl_surface,
|
|
|
|
cogl_display_egl->egl_context);
|
|
|
|
}
|
2016-09-29 10:46:34 -04:00
|
|
|
|
2016-06-08 05:05:31 -04:00
|
|
|
return view;
|
|
|
|
}
|
|
|
|
|
2020-10-23 04:21:54 -04:00
|
|
|
static void
|
|
|
|
keep_current_onscreens_alive (MetaRenderer *renderer)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
|
|
|
|
GList *views;
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
views = meta_renderer_get_views (renderer);
|
|
|
|
for (l = views; l; l = l->next)
|
|
|
|
{
|
|
|
|
ClutterStageView *stage_view = l->data;
|
|
|
|
CoglFramebuffer *onscreen = clutter_stage_view_get_onscreen (stage_view);
|
|
|
|
|
|
|
|
renderer_native->kept_alive_onscreens =
|
|
|
|
g_list_prepend (renderer_native->kept_alive_onscreens,
|
|
|
|
g_object_ref (onscreen));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-19 14:57:14 -04:00
|
|
|
static void
|
|
|
|
meta_renderer_native_rebuild_views (MetaRenderer *renderer)
|
|
|
|
{
|
2019-10-01 05:51:53 -04:00
|
|
|
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
|
|
|
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
|
2019-06-19 15:14:05 -04:00
|
|
|
MetaKms *kms = meta_backend_native_get_kms (backend_native);
|
2019-06-19 14:57:14 -04:00
|
|
|
MetaRendererClass *parent_renderer_class =
|
|
|
|
META_RENDERER_CLASS (meta_renderer_native_parent_class);
|
|
|
|
|
2019-06-19 15:14:05 -04:00
|
|
|
meta_kms_discard_pending_page_flips (kms);
|
|
|
|
|
2020-10-23 04:21:54 -04:00
|
|
|
keep_current_onscreens_alive (renderer);
|
|
|
|
|
2019-06-19 14:57:14 -04:00
|
|
|
parent_renderer_class->rebuild_views (renderer);
|
|
|
|
|
|
|
|
meta_renderer_native_queue_modes_reset (META_RENDERER_NATIVE (renderer));
|
|
|
|
}
|
|
|
|
|
2020-10-10 05:47:58 -04:00
|
|
|
void
|
|
|
|
meta_renderer_native_prepare_frame (MetaRendererNative *renderer_native,
|
|
|
|
MetaRendererView *view,
|
|
|
|
ClutterFrame *frame)
|
|
|
|
{
|
2021-04-21 04:44:13 -04:00
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
|
|
|
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
meta_backend_get_monitor_manager (backend);
|
2020-10-10 05:47:58 -04:00
|
|
|
MetaCrtc *crtc = meta_renderer_view_get_crtc (view);
|
2021-04-21 04:44:13 -04:00
|
|
|
MetaPowerSave power_save_mode;
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 10:49:28 -05:00
|
|
|
MetaCrtcKms *crtc_kms;
|
|
|
|
MetaKmsCrtc *kms_crtc;
|
|
|
|
MetaKmsDevice *kms_device;
|
|
|
|
|
|
|
|
if (!META_IS_CRTC_KMS (crtc))
|
|
|
|
return;
|
|
|
|
|
2021-04-21 04:44:13 -04:00
|
|
|
power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
|
|
|
|
if (power_save_mode != META_POWER_SAVE_ON)
|
|
|
|
return;
|
|
|
|
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 10:49:28 -05:00
|
|
|
crtc_kms = META_CRTC_KMS (crtc);
|
|
|
|
kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc));
|
|
|
|
kms_device = meta_kms_crtc_get_device (kms_crtc);
|
2020-10-10 05:47:58 -04:00
|
|
|
|
|
|
|
meta_crtc_kms_maybe_set_gamma (crtc_kms, kms_device);
|
|
|
|
}
|
|
|
|
|
2016-06-08 05:05:31 -04:00
|
|
|
void
|
2020-10-09 19:02:28 -04:00
|
|
|
meta_renderer_native_finish_frame (MetaRendererNative *renderer_native,
|
|
|
|
MetaRendererView *view,
|
|
|
|
ClutterFrame *frame)
|
2016-06-08 05:05:31 -04:00
|
|
|
{
|
2020-10-09 19:02:28 -04:00
|
|
|
if (!clutter_frame_has_result (frame))
|
|
|
|
{
|
2020-10-17 17:08:28 -04:00
|
|
|
CoglFramebuffer *framebuffer =
|
|
|
|
clutter_stage_view_get_onscreen (CLUTTER_STAGE_VIEW (view));
|
2020-10-09 19:02:28 -04:00
|
|
|
|
Introduce virtual monitors
Virtual monitors are monitors that isn't backed by any monitor like
hardware. It would typically be backed by e.g. a remote desktop service,
or a network display.
It is currently only supported by the native backend, and whether the
X11 backend will ever see virtual monitors is an open question. This
rest of this commit message describes how it works under the native
backend.
Each virutal monitor consists of virtualized mode setting components:
* A virtual CRTC mode (MetaCrtcModeVirtual)
* A virtual CRTC (MetaCrtcVirtual)
* A virtual connector (MetaOutputVirtual)
In difference to the corresponding mode setting objects that represents
KMS objects, the virtual ones isn't directly tied to a MetaGpu, other
than the CoglFramebuffer being part of the GPU context of the primary
GPU, which is the case for all monitors no matter what GPU they are
connected to. Part of the reason for this is that a MetaGpu in practice
represents a mode setting device, and its CRTCs and outputs, are all
backed by real mode setting objects, while a virtual monitor is only
backed by a framebuffer that is tied to the primary GPU. Maybe this will
be reevaluated in the future, but since a virtual monitor is not tied to
any GPU currently, so is the case for the virtual mode setting objects.
The native rendering backend, including the cursor renderer, is adapted
to handle the situation where a CRTC does not have a GPU associated with
it; this in practice means that it e.g. will not try to upload HW cursor
buffers when the cursor is only on a virtual monitor. The same applies
to the native renderer, which is made to avoid creating
MetaOnscreenNative for views that are backed by virtual CRTCs, as well
as to avoid trying to mode set on such views.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>
2021-01-26 10:49:28 -05:00
|
|
|
if (COGL_IS_ONSCREEN (framebuffer))
|
|
|
|
{
|
|
|
|
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
|
|
|
|
|
|
|
|
meta_onscreen_native_finish_frame (onscreen, frame);
|
|
|
|
}
|
2020-10-09 19:02:28 -04:00
|
|
|
}
|
2016-06-08 05:05:31 -04:00
|
|
|
}
|
|
|
|
|
2017-07-24 22:21:04 -04:00
|
|
|
static gboolean
|
2018-06-07 19:29:44 -04:00
|
|
|
create_secondary_egl_config (MetaEgl *egl,
|
|
|
|
MetaRendererNativeMode mode,
|
|
|
|
EGLDisplay egl_display,
|
|
|
|
EGLConfig *egl_config,
|
|
|
|
GError **error)
|
2017-07-24 22:21:04 -04:00
|
|
|
{
|
|
|
|
EGLint attributes[] = {
|
|
|
|
EGL_RED_SIZE, 1,
|
|
|
|
EGL_GREEN_SIZE, 1,
|
|
|
|
EGL_BLUE_SIZE, 1,
|
|
|
|
EGL_ALPHA_SIZE, EGL_DONT_CARE,
|
|
|
|
EGL_BUFFER_SIZE, EGL_DONT_CARE,
|
|
|
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
|
|
|
|
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
|
|
|
EGL_NONE
|
|
|
|
};
|
|
|
|
|
2018-06-07 19:29:44 -04:00
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case META_RENDERER_NATIVE_MODE_GBM:
|
2021-02-09 08:32:55 -05:00
|
|
|
case META_RENDERER_NATIVE_MODE_SURFACELESS:
|
2018-06-07 19:29:44 -04:00
|
|
|
return choose_egl_config_from_gbm_format (egl,
|
|
|
|
egl_display,
|
|
|
|
attributes,
|
|
|
|
GBM_FORMAT_XRGB8888,
|
|
|
|
egl_config,
|
|
|
|
error);
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
|
|
|
return meta_egl_choose_first_config (egl,
|
|
|
|
egl_display,
|
|
|
|
attributes,
|
|
|
|
egl_config,
|
|
|
|
error);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
2017-07-24 22:21:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static EGLContext
|
|
|
|
create_secondary_egl_context (MetaEgl *egl,
|
|
|
|
EGLDisplay egl_display,
|
|
|
|
EGLConfig egl_config,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
EGLint attributes[] = {
|
|
|
|
EGL_CONTEXT_CLIENT_VERSION, 3,
|
|
|
|
EGL_NONE
|
|
|
|
};
|
|
|
|
|
|
|
|
return meta_egl_create_context (egl,
|
|
|
|
egl_display,
|
|
|
|
egl_config,
|
|
|
|
EGL_NO_CONTEXT,
|
|
|
|
attributes,
|
|
|
|
error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_renderer_native_ensure_gles3 (MetaRendererNative *renderer_native)
|
|
|
|
{
|
|
|
|
MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
|
|
|
|
|
|
|
|
if (renderer_native->gles3)
|
|
|
|
return;
|
|
|
|
|
|
|
|
renderer_native->gles3 = meta_gles3_new (egl);
|
|
|
|
}
|
|
|
|
|
2021-04-12 10:25:53 -04:00
|
|
|
static void
|
|
|
|
maybe_restore_cogl_egl_api (MetaRendererNative *renderer_native)
|
|
|
|
{
|
|
|
|
CoglContext *cogl_context;
|
|
|
|
CoglDisplay *cogl_display;
|
|
|
|
CoglRenderer *cogl_renderer;
|
|
|
|
|
|
|
|
cogl_context = cogl_context_from_renderer_native (renderer_native);
|
|
|
|
if (!cogl_context)
|
|
|
|
return;
|
|
|
|
|
|
|
|
cogl_display = cogl_context_get_display (cogl_context);
|
|
|
|
cogl_renderer = cogl_display_get_renderer (cogl_display);
|
|
|
|
cogl_renderer_bind_api (cogl_renderer);
|
|
|
|
}
|
|
|
|
|
2017-07-24 22:21:04 -04:00
|
|
|
static gboolean
|
|
|
|
init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
|
2021-05-05 09:53:59 -04:00
|
|
|
MetaRenderDevice *render_device = renderer_gpu_data->render_device;
|
2017-07-24 22:21:04 -04:00
|
|
|
MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
|
2021-05-05 09:53:59 -04:00
|
|
|
EGLDisplay egl_display;
|
2017-07-24 22:21:04 -04:00
|
|
|
EGLConfig egl_config;
|
|
|
|
EGLContext egl_context;
|
2019-01-20 05:46:46 -05:00
|
|
|
const char **missing_gl_extensions;
|
2021-05-05 09:53:59 -04:00
|
|
|
|
|
|
|
egl_display = meta_render_device_get_egl_display (render_device);
|
|
|
|
if (egl_display == EGL_NO_DISPLAY)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"No EGL display");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!meta_render_device_is_hardware_accelerated (render_device))
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Not hardware accelerated");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2017-07-24 22:21:04 -04:00
|
|
|
|
2021-04-12 10:25:53 -04:00
|
|
|
meta_egl_bind_api (egl, EGL_OPENGL_ES_API, NULL);
|
|
|
|
|
2018-06-07 19:29:44 -04:00
|
|
|
if (!create_secondary_egl_config (egl, renderer_gpu_data->mode, egl_display,
|
|
|
|
&egl_config, error))
|
2021-04-12 10:25:53 -04:00
|
|
|
goto err;
|
2017-07-24 22:21:04 -04:00
|
|
|
|
2021-05-05 09:53:59 -04:00
|
|
|
egl_context = create_secondary_egl_context (egl, egl_display, egl_config,
|
|
|
|
error);
|
2017-07-24 22:21:04 -04:00
|
|
|
if (egl_context == EGL_NO_CONTEXT)
|
2021-04-12 10:25:53 -04:00
|
|
|
goto err;
|
2017-07-24 22:21:04 -04:00
|
|
|
|
|
|
|
meta_renderer_native_ensure_gles3 (renderer_native);
|
|
|
|
|
|
|
|
if (!meta_egl_make_current (egl,
|
|
|
|
egl_display,
|
|
|
|
EGL_NO_SURFACE,
|
|
|
|
EGL_NO_SURFACE,
|
|
|
|
egl_context,
|
|
|
|
error))
|
|
|
|
{
|
|
|
|
meta_egl_destroy_context (egl, egl_display, egl_context, NULL);
|
2021-04-12 10:25:53 -04:00
|
|
|
goto err;
|
2017-07-24 22:21:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!meta_gles3_has_extensions (renderer_native->gles3,
|
|
|
|
&missing_gl_extensions,
|
|
|
|
"GL_OES_EGL_image_external",
|
|
|
|
NULL))
|
|
|
|
{
|
|
|
|
char *missing_gl_extensions_str;
|
|
|
|
|
2019-01-20 05:46:46 -05:00
|
|
|
missing_gl_extensions_str = g_strjoinv (", ",
|
|
|
|
(char **) missing_gl_extensions);
|
2017-07-24 22:21:04 -04:00
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Missing OpenGL ES extensions: %s",
|
|
|
|
missing_gl_extensions_str);
|
|
|
|
g_free (missing_gl_extensions_str);
|
|
|
|
g_free (missing_gl_extensions);
|
2019-01-28 06:02:07 -05:00
|
|
|
|
2021-05-05 09:53:59 -04:00
|
|
|
goto err_fail_make_current;
|
2017-07-24 22:21:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
renderer_gpu_data->secondary.egl_config = egl_config;
|
2018-11-29 06:34:40 -05:00
|
|
|
renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU;
|
|
|
|
|
|
|
|
renderer_gpu_data->secondary.has_EGL_EXT_image_dma_buf_import_modifiers =
|
|
|
|
meta_egl_has_extensions (egl, egl_display, NULL,
|
|
|
|
"EGL_EXT_image_dma_buf_import_modifiers",
|
|
|
|
NULL);
|
2017-07-24 22:21:04 -04:00
|
|
|
|
2021-04-12 10:25:53 -04:00
|
|
|
maybe_restore_cogl_egl_api (renderer_native);
|
|
|
|
|
2017-07-24 22:21:04 -04:00
|
|
|
return TRUE;
|
2019-01-28 06:02:07 -05:00
|
|
|
|
2021-05-05 09:53:59 -04:00
|
|
|
err_fail_make_current:
|
2019-01-28 06:02:07 -05:00
|
|
|
meta_egl_make_current (egl,
|
|
|
|
egl_display,
|
|
|
|
EGL_NO_SURFACE,
|
|
|
|
EGL_NO_SURFACE,
|
|
|
|
EGL_NO_CONTEXT,
|
|
|
|
NULL);
|
|
|
|
|
2021-04-12 10:25:53 -04:00
|
|
|
err:
|
|
|
|
maybe_restore_cogl_egl_api (renderer_native);
|
|
|
|
|
2019-01-28 06:02:07 -05:00
|
|
|
return FALSE;
|
2017-07-24 22:21:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
init_secondary_gpu_data_cpu (MetaRendererNativeGpuData *renderer_gpu_data)
|
|
|
|
{
|
2019-05-24 10:07:14 -04:00
|
|
|
/* First try ZERO, it automatically falls back to PRIMARY as needed */
|
|
|
|
renderer_gpu_data->secondary.copy_mode =
|
|
|
|
META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO;
|
2017-07-24 22:21:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
init_secondary_gpu_data (MetaRendererNativeGpuData *renderer_gpu_data)
|
|
|
|
{
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
if (init_secondary_gpu_data_gpu (renderer_gpu_data, &error))
|
|
|
|
return;
|
|
|
|
|
2021-01-25 15:12:51 -05:00
|
|
|
g_message ("Failed to initialize accelerated iGPU/dGPU framebuffer sharing: %s",
|
2017-07-24 22:21:04 -04:00
|
|
|
error->message);
|
|
|
|
g_error_free (error);
|
|
|
|
|
|
|
|
init_secondary_gpu_data_cpu (renderer_gpu_data);
|
|
|
|
}
|
|
|
|
|
renderer/native: Prefer hardware rendering for primary GPU
Mutter prefers platform devices over anything else as the primary GPU.
This will not work too well, when a platform device does not actually
have a rendering GPU but is a display-only device. An example of this
are DisplayLink devices with the proprietary driver stack, which exposes
a DRM KMS platform device but without any rendering driver.
Mutter cannot rely on EGL init failing on such devices either, because
nowadays Mesa supports software renderers on GBM, so the initialization
may well succeed.
The hardware rendering capability is recognized by matching the GL
renderer string to the known Mesa software renderers. At this time,
there is no better alternative to detecting this.
The secondary GPU data is abused for the GL renderer, as the Cogl
context may not have been created yet. Also, the Cogl context would
only be created on the primary GPU, but at this point the primary GPU
has not been chosen yet. Hence, GPU copy path GL context is used as a
proxy and predictor of what the Cogl context might be if it was created.
Mind, that even the GL flavour are not the same between Cogl and
secondary contexts, so this is stretch but it should be just enough.
The logic to choose the primary GPU is changed to always prefer hardware
rendering devices while also maintaining the old order of preferring
platform over boot_vga devices.
Co-authored by: Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
https://gitlab.gnome.org/GNOME/mutter/merge_requests/271
2018-12-10 09:49:58 -05:00
|
|
|
static gboolean
|
|
|
|
gpu_kms_is_hardware_rendering (MetaRendererNative *renderer_native,
|
|
|
|
MetaGpuKms *gpu_kms)
|
|
|
|
{
|
|
|
|
MetaRendererNativeGpuData *data;
|
|
|
|
|
|
|
|
data = meta_renderer_native_get_gpu_data (renderer_native, gpu_kms);
|
2021-05-05 09:53:59 -04:00
|
|
|
return meta_render_device_is_hardware_accelerated (data->render_device);
|
2019-04-03 06:11:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static MetaRendererNativeGpuData *
|
|
|
|
create_renderer_gpu_data_gbm (MetaRendererNative *renderer_native,
|
2021-04-12 10:05:34 -04:00
|
|
|
MetaDeviceFile *device_file,
|
2021-05-05 09:53:59 -04:00
|
|
|
MetaGpuKms *gpu_kms,
|
2019-04-03 06:11:45 -04:00
|
|
|
GError **error)
|
|
|
|
{
|
2021-05-05 09:53:59 -04:00
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
|
|
|
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
|
|
|
MetaRenderDeviceGbm *render_device_gbm;
|
2019-04-03 06:11:45 -04:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
|
2021-05-05 09:53:59 -04:00
|
|
|
render_device_gbm = meta_render_device_gbm_new (backend, device_file, error);
|
|
|
|
if (!render_device_gbm)
|
|
|
|
return NULL;
|
2016-05-09 09:22:01 -04:00
|
|
|
|
2021-04-13 09:51:36 -04:00
|
|
|
renderer_gpu_data = meta_create_renderer_native_gpu_data ();
|
2017-07-10 06:19:32 -04:00
|
|
|
renderer_gpu_data->renderer_native = renderer_native;
|
|
|
|
renderer_gpu_data->mode = META_RENDERER_NATIVE_MODE_GBM;
|
2021-05-05 09:53:59 -04:00
|
|
|
renderer_gpu_data->render_device = META_RENDER_DEVICE (render_device_gbm);
|
2019-04-03 06:11:45 -04:00
|
|
|
|
|
|
|
init_secondary_gpu_data (renderer_gpu_data);
|
2017-07-10 06:19:32 -04:00
|
|
|
return renderer_gpu_data;
|
2016-05-09 09:22:01 -04:00
|
|
|
}
|
|
|
|
|
2021-02-09 08:32:55 -05:00
|
|
|
static MetaRendererNativeGpuData *
|
|
|
|
create_renderer_gpu_data_surfaceless (MetaRendererNative *renderer_native,
|
|
|
|
GError **error)
|
|
|
|
{
|
2021-05-05 09:53:59 -04:00
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
|
|
|
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
|
|
|
MetaRenderDeviceSurfaceless *render_device_surfaceless;
|
2021-02-09 08:32:55 -05:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
|
2021-05-05 09:53:59 -04:00
|
|
|
render_device_surfaceless = meta_render_device_surfaceless_new (backend,
|
|
|
|
error);
|
|
|
|
if (!render_device_surfaceless)
|
2021-02-09 08:32:55 -05:00
|
|
|
return NULL;
|
|
|
|
|
2021-04-13 09:51:36 -04:00
|
|
|
renderer_gpu_data = meta_create_renderer_native_gpu_data ();
|
2021-02-09 08:32:55 -05:00
|
|
|
renderer_gpu_data->renderer_native = renderer_native;
|
|
|
|
renderer_gpu_data->mode = META_RENDERER_NATIVE_MODE_SURFACELESS;
|
2021-05-05 09:53:59 -04:00
|
|
|
renderer_gpu_data->render_device =
|
|
|
|
META_RENDER_DEVICE (render_device_surfaceless);
|
2021-02-09 08:32:55 -05:00
|
|
|
|
|
|
|
return renderer_gpu_data;
|
|
|
|
}
|
|
|
|
|
2016-08-17 23:28:59 -04:00
|
|
|
#ifdef HAVE_EGL_DEVICE
|
2017-07-10 06:19:32 -04:00
|
|
|
static MetaRendererNativeGpuData *
|
|
|
|
create_renderer_gpu_data_egl_device (MetaRendererNative *renderer_native,
|
2021-04-12 10:05:34 -04:00
|
|
|
MetaDeviceFile *device_file,
|
2021-05-05 09:53:59 -04:00
|
|
|
MetaGpuKms *gpu_kms,
|
2017-07-10 06:19:32 -04:00
|
|
|
GError **error)
|
2016-08-17 23:28:59 -04:00
|
|
|
{
|
2021-05-05 09:53:59 -04:00
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
|
|
|
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
|
|
|
MetaRenderDeviceEglStream *render_device_egl_stream;
|
2017-07-10 06:19:32 -04:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
2016-08-17 23:28:59 -04:00
|
|
|
|
2021-05-05 09:53:59 -04:00
|
|
|
render_device_egl_stream = meta_render_device_egl_stream_new (backend,
|
|
|
|
device_file,
|
|
|
|
error);
|
|
|
|
if (!render_device_egl_stream)
|
2017-07-10 06:19:32 -04:00
|
|
|
return NULL;
|
2016-08-17 23:28:59 -04:00
|
|
|
|
2021-04-13 09:51:36 -04:00
|
|
|
renderer_gpu_data = meta_create_renderer_native_gpu_data ();
|
2017-07-10 06:19:32 -04:00
|
|
|
renderer_gpu_data->renderer_native = renderer_native;
|
|
|
|
renderer_gpu_data->mode = META_RENDERER_NATIVE_MODE_EGL_DEVICE;
|
2021-05-05 09:53:59 -04:00
|
|
|
renderer_gpu_data->render_device =
|
|
|
|
META_RENDER_DEVICE (render_device_egl_stream);
|
2016-08-17 23:28:59 -04:00
|
|
|
|
2017-07-10 06:19:32 -04:00
|
|
|
return renderer_gpu_data;
|
2016-08-17 23:28:59 -04:00
|
|
|
}
|
|
|
|
#endif /* HAVE_EGL_DEVICE */
|
|
|
|
|
2017-07-10 06:19:32 -04:00
|
|
|
static MetaRendererNativeGpuData *
|
|
|
|
meta_renderer_native_create_renderer_gpu_data (MetaRendererNative *renderer_native,
|
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
GError **error)
|
2016-08-17 23:14:03 -04:00
|
|
|
{
|
2021-04-12 10:05:34 -04:00
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
|
|
|
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
|
|
|
MetaDevicePool *device_pool =
|
|
|
|
meta_backend_native_get_device_pool (META_BACKEND_NATIVE (backend));
|
2021-10-11 04:39:43 -04:00
|
|
|
MetaRendererNativeGpuData *gbm_renderer_gpu_data;
|
2021-04-12 10:05:34 -04:00
|
|
|
MetaDeviceFileFlags device_file_flags = META_DEVICE_FILE_FLAG_NONE;
|
|
|
|
g_autoptr (MetaDeviceFile) device_file = NULL;
|
2016-08-17 23:28:59 -04:00
|
|
|
GError *gbm_error = NULL;
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
2021-10-11 04:39:43 -04:00
|
|
|
MetaRendererNativeGpuData *egl_stream_renderer_gpu_data;
|
2016-08-17 23:28:59 -04:00
|
|
|
GError *egl_device_error = NULL;
|
|
|
|
#endif
|
|
|
|
|
2021-02-09 08:32:55 -05:00
|
|
|
if (!gpu_kms)
|
|
|
|
return create_renderer_gpu_data_surfaceless (renderer_native, error);
|
|
|
|
|
2021-04-12 10:05:34 -04:00
|
|
|
if (!(meta_kms_device_get_flags (meta_gpu_kms_get_kms_device (gpu_kms)) &
|
|
|
|
META_KMS_DEVICE_FLAG_NO_MODE_SETTING))
|
|
|
|
device_file_flags = META_DEVICE_FILE_FLAG_TAKE_CONTROL;
|
|
|
|
|
|
|
|
device_file = meta_device_pool_open (device_pool,
|
|
|
|
meta_gpu_kms_get_file_path (gpu_kms),
|
|
|
|
device_file_flags,
|
|
|
|
error);
|
|
|
|
if (!device_file)
|
|
|
|
return NULL;
|
|
|
|
|
2021-10-11 04:39:43 -04:00
|
|
|
gbm_renderer_gpu_data = create_renderer_gpu_data_gbm (renderer_native,
|
|
|
|
device_file,
|
|
|
|
gpu_kms,
|
|
|
|
&gbm_error);
|
|
|
|
if (gbm_renderer_gpu_data)
|
2016-08-17 23:28:59 -04:00
|
|
|
{
|
2021-10-11 04:39:43 -04:00
|
|
|
MetaRenderDevice *render_device = gbm_renderer_gpu_data->render_device;
|
|
|
|
|
|
|
|
if (meta_render_device_is_hardware_accelerated (render_device))
|
|
|
|
return gbm_renderer_gpu_data;
|
|
|
|
}
|
|
|
|
|
2017-07-07 05:59:20 -04:00
|
|
|
#ifdef HAVE_EGL_DEVICE
|
2021-10-11 04:39:43 -04:00
|
|
|
egl_stream_renderer_gpu_data =
|
|
|
|
create_renderer_gpu_data_egl_device (renderer_native,
|
|
|
|
device_file,
|
|
|
|
gpu_kms,
|
|
|
|
&egl_device_error);
|
|
|
|
if (egl_stream_renderer_gpu_data)
|
|
|
|
{
|
|
|
|
g_clear_pointer (&gbm_renderer_gpu_data,
|
|
|
|
meta_renderer_native_gpu_data_free);
|
|
|
|
return egl_stream_renderer_gpu_data;
|
2016-08-17 23:28:59 -04:00
|
|
|
}
|
2021-10-11 04:39:43 -04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (gbm_renderer_gpu_data)
|
|
|
|
return gbm_renderer_gpu_data;
|
2016-08-17 23:28:59 -04:00
|
|
|
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
G_IO_ERROR_FAILED,
|
|
|
|
"Failed to initialize renderer: "
|
|
|
|
"%s"
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
", %s"
|
|
|
|
#endif
|
|
|
|
, gbm_error->message
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
, egl_device_error->message
|
|
|
|
#endif
|
|
|
|
);
|
|
|
|
|
|
|
|
g_error_free (gbm_error);
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
g_error_free (egl_device_error);
|
|
|
|
#endif
|
|
|
|
|
2017-07-10 06:19:32 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-10-11 04:52:43 -04:00
|
|
|
static const char *
|
|
|
|
renderer_data_mode_to_string (MetaRendererNativeMode mode)
|
|
|
|
{
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case META_RENDERER_NATIVE_MODE_GBM:
|
|
|
|
return "gbm";
|
|
|
|
case META_RENDERER_NATIVE_MODE_SURFACELESS:
|
|
|
|
return "surfaceless";
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
|
|
|
return "egldevice";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
}
|
|
|
|
|
2018-09-17 07:03:18 -04:00
|
|
|
static gboolean
|
|
|
|
create_renderer_gpu_data (MetaRendererNative *renderer_native,
|
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
|
|
|
|
renderer_gpu_data =
|
|
|
|
meta_renderer_native_create_renderer_gpu_data (renderer_native,
|
|
|
|
gpu_kms,
|
|
|
|
error);
|
|
|
|
if (!renderer_gpu_data)
|
|
|
|
return FALSE;
|
|
|
|
|
2021-10-11 04:52:43 -04:00
|
|
|
if (gpu_kms)
|
|
|
|
{
|
|
|
|
g_message ("Created %s renderer for '%s'",
|
|
|
|
renderer_data_mode_to_string (renderer_gpu_data->mode),
|
|
|
|
meta_gpu_kms_get_file_path (gpu_kms));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_message ("Created %s renderer without GPU",
|
|
|
|
renderer_data_mode_to_string (renderer_gpu_data->mode));
|
|
|
|
}
|
|
|
|
|
2018-09-17 07:03:18 -04:00
|
|
|
g_hash_table_insert (renderer_native->gpu_datas,
|
|
|
|
gpu_kms,
|
|
|
|
renderer_gpu_data);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2021-04-12 10:25:53 -04:00
|
|
|
static gboolean
|
|
|
|
meta_renderer_native_ensure_gpu_data (MetaRendererNative *renderer_native,
|
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
|
|
|
|
renderer_gpu_data = g_hash_table_lookup (renderer_native->gpu_datas, gpu_kms);
|
|
|
|
if (renderer_gpu_data)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
return create_renderer_gpu_data (renderer_native, gpu_kms, error);
|
|
|
|
}
|
|
|
|
|
2018-09-17 07:03:18 -04:00
|
|
|
static void
|
2019-01-11 09:35:42 -05:00
|
|
|
on_gpu_added (MetaBackendNative *backend_native,
|
2018-09-17 07:03:18 -04:00
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
MetaRendererNative *renderer_native)
|
|
|
|
{
|
2019-01-11 09:35:42 -05:00
|
|
|
MetaBackend *backend = META_BACKEND (backend_native);
|
2018-09-17 07:03:18 -04:00
|
|
|
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
|
|
|
|
CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
|
|
|
|
CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
if (!create_renderer_gpu_data (renderer_native, gpu_kms, &error))
|
|
|
|
{
|
|
|
|
g_warning ("on_gpu_added: could not create gpu_data for gpu %s: %s",
|
|
|
|
meta_gpu_kms_get_file_path (gpu_kms), error->message);
|
|
|
|
g_clear_error (&error);
|
|
|
|
}
|
|
|
|
|
|
|
|
_cogl_winsys_egl_ensure_current (cogl_display);
|
|
|
|
}
|
|
|
|
|
backend/native: Add and use transactional KMS API
This commit introduces, and makes use of, a transactional API used for
setting up KMS state, later to be applied, potentially atomically. From
an API point of view, so is always the case, but in the current
implementation, it still uses legacy drmMode* API to apply the state
non-atomically.
The API consists of various buliding blocks:
* MetaKmsUpdate - a set of configuration changes, the higher level
handle for handing over configuration to the impl backend. It's used to
set mode, assign framebuffers to planes, queue page flips and set
connector properties.
* MetaKmsPlaneAssignment - the assignment of a framebuffer to a plane.
Currently used to map a framebuffer to the primary plane of a CRTC. In
the legacy KMS implementation, the plane assignment is used to derive
the framebuffer used for mode setting and page flipping.
This also means various high level changes:
State, excluding configuring the cursor plane and creating/destroying
DRM framebuffer handles, are applied in the end of a clutter frame, in
one go. From an API point of view, this is done atomically, but as
mentioned, only the non-atomic implementation exists so far.
From MetaRendererNative's point of view, a page flip now initially
always succeeds; the handling of EBUSY errors are done asynchronously in
the MetaKmsImpl backend (still by retrying at refresh rate, but
postponing flip callbacks instead of manipulating the frame clock).
Handling of falling back to mode setting instead of page flipping is
notified after the fact by a more precise page flip feedback API.
EGLStream based page flipping relies on the impl backend not being
atomic, as the page flipping is done in the EGLStream backend (e.g.
nvidia driver). It uses a 'custom' page flip queueing method, keeping
the EGLStream logic inside meta-renderer-native.c.
Page flip handling is moved to meta-kms-impl-device.c from
meta-gpu-kms.c. It goes via an extra idle callback before reaching
meta-renderer-native.c to make sure callbacks are invoked outside of the
impl context.
While dummy power save page flipping is kept in meta-renderer-native.c, the
EBUSY handling is moved to meta-kms-impl-simple.c. Instead of freezing the
frame clock, actual page flip callbacks are postponed until all EBUSY retries
have either succeeded or failed due to some other error than EBUSY. This
effectively inhibits new frames to be drawn, meaning we won't stall waiting on
the file descriptor for pending page flips.
https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-04-04 16:36:41 -04:00
|
|
|
static void
|
|
|
|
on_power_save_mode_changed (MetaMonitorManager *monitor_manager,
|
|
|
|
MetaRendererNative *renderer_native)
|
|
|
|
{
|
2019-10-01 05:51:53 -04:00
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
|
|
|
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
|
|
|
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
|
backend/native: Add and use transactional KMS API
This commit introduces, and makes use of, a transactional API used for
setting up KMS state, later to be applied, potentially atomically. From
an API point of view, so is always the case, but in the current
implementation, it still uses legacy drmMode* API to apply the state
non-atomically.
The API consists of various buliding blocks:
* MetaKmsUpdate - a set of configuration changes, the higher level
handle for handing over configuration to the impl backend. It's used to
set mode, assign framebuffers to planes, queue page flips and set
connector properties.
* MetaKmsPlaneAssignment - the assignment of a framebuffer to a plane.
Currently used to map a framebuffer to the primary plane of a CRTC. In
the legacy KMS implementation, the plane assignment is used to derive
the framebuffer used for mode setting and page flipping.
This also means various high level changes:
State, excluding configuring the cursor plane and creating/destroying
DRM framebuffer handles, are applied in the end of a clutter frame, in
one go. From an API point of view, this is done atomically, but as
mentioned, only the non-atomic implementation exists so far.
From MetaRendererNative's point of view, a page flip now initially
always succeeds; the handling of EBUSY errors are done asynchronously in
the MetaKmsImpl backend (still by retrying at refresh rate, but
postponing flip callbacks instead of manipulating the frame clock).
Handling of falling back to mode setting instead of page flipping is
notified after the fact by a more precise page flip feedback API.
EGLStream based page flipping relies on the impl backend not being
atomic, as the page flipping is done in the EGLStream backend (e.g.
nvidia driver). It uses a 'custom' page flip queueing method, keeping
the EGLStream logic inside meta-renderer-native.c.
Page flip handling is moved to meta-kms-impl-device.c from
meta-gpu-kms.c. It goes via an extra idle callback before reaching
meta-renderer-native.c to make sure callbacks are invoked outside of the
impl context.
While dummy power save page flipping is kept in meta-renderer-native.c, the
EBUSY handling is moved to meta-kms-impl-simple.c. Instead of freezing the
frame clock, actual page flip callbacks are postponed until all EBUSY retries
have either succeeded or failed due to some other error than EBUSY. This
effectively inhibits new frames to be drawn, meaning we won't stall waiting on
the file descriptor for pending page flips.
https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-04-04 16:36:41 -04:00
|
|
|
MetaKms *kms = meta_backend_native_get_kms (backend_native);
|
|
|
|
MetaPowerSave power_save_mode;
|
|
|
|
|
|
|
|
power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
|
|
|
|
if (power_save_mode == META_POWER_SAVE_ON)
|
|
|
|
meta_renderer_native_queue_modes_reset (renderer_native);
|
|
|
|
else
|
|
|
|
meta_kms_discard_pending_page_flips (kms);
|
|
|
|
}
|
|
|
|
|
2020-12-21 01:59:32 -05:00
|
|
|
void
|
|
|
|
meta_renderer_native_reset_modes (MetaRendererNative *renderer_native)
|
|
|
|
{
|
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
|
|
|
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
|
|
|
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
|
|
|
|
MetaKms *kms = meta_backend_native_get_kms (backend_native);
|
|
|
|
|
2020-10-02 04:38:57 -04:00
|
|
|
unset_disabled_crtcs (backend, kms);
|
2020-12-21 01:59:32 -05:00
|
|
|
}
|
|
|
|
|
2018-12-10 07:19:25 -05:00
|
|
|
static MetaGpuKms *
|
2019-01-11 09:35:42 -05:00
|
|
|
choose_primary_gpu_unchecked (MetaBackend *backend,
|
2019-04-03 06:34:09 -04:00
|
|
|
MetaRendererNative *renderer_native)
|
2018-12-10 07:19:25 -05:00
|
|
|
{
|
2019-01-11 09:35:42 -05:00
|
|
|
GList *gpus = meta_backend_get_gpus (backend);
|
2018-12-10 07:19:25 -05:00
|
|
|
GList *l;
|
renderer/native: Prefer hardware rendering for primary GPU
Mutter prefers platform devices over anything else as the primary GPU.
This will not work too well, when a platform device does not actually
have a rendering GPU but is a display-only device. An example of this
are DisplayLink devices with the proprietary driver stack, which exposes
a DRM KMS platform device but without any rendering driver.
Mutter cannot rely on EGL init failing on such devices either, because
nowadays Mesa supports software renderers on GBM, so the initialization
may well succeed.
The hardware rendering capability is recognized by matching the GL
renderer string to the known Mesa software renderers. At this time,
there is no better alternative to detecting this.
The secondary GPU data is abused for the GL renderer, as the Cogl
context may not have been created yet. Also, the Cogl context would
only be created on the primary GPU, but at this point the primary GPU
has not been chosen yet. Hence, GPU copy path GL context is used as a
proxy and predictor of what the Cogl context might be if it was created.
Mind, that even the GL flavour are not the same between Cogl and
secondary contexts, so this is stretch but it should be just enough.
The logic to choose the primary GPU is changed to always prefer hardware
rendering devices while also maintaining the old order of preferring
platform over boot_vga devices.
Co-authored by: Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
https://gitlab.gnome.org/GNOME/mutter/merge_requests/271
2018-12-10 09:49:58 -05:00
|
|
|
int allow_sw;
|
2018-12-10 07:19:25 -05:00
|
|
|
|
renderer/native: Prefer hardware rendering for primary GPU
Mutter prefers platform devices over anything else as the primary GPU.
This will not work too well, when a platform device does not actually
have a rendering GPU but is a display-only device. An example of this
are DisplayLink devices with the proprietary driver stack, which exposes
a DRM KMS platform device but without any rendering driver.
Mutter cannot rely on EGL init failing on such devices either, because
nowadays Mesa supports software renderers on GBM, so the initialization
may well succeed.
The hardware rendering capability is recognized by matching the GL
renderer string to the known Mesa software renderers. At this time,
there is no better alternative to detecting this.
The secondary GPU data is abused for the GL renderer, as the Cogl
context may not have been created yet. Also, the Cogl context would
only be created on the primary GPU, but at this point the primary GPU
has not been chosen yet. Hence, GPU copy path GL context is used as a
proxy and predictor of what the Cogl context might be if it was created.
Mind, that even the GL flavour are not the same between Cogl and
secondary contexts, so this is stretch but it should be just enough.
The logic to choose the primary GPU is changed to always prefer hardware
rendering devices while also maintaining the old order of preferring
platform over boot_vga devices.
Co-authored by: Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
https://gitlab.gnome.org/GNOME/mutter/merge_requests/271
2018-12-10 09:49:58 -05:00
|
|
|
/*
|
|
|
|
* Check first hardware rendering devices, and if none found,
|
|
|
|
* then software rendering devices.
|
|
|
|
*/
|
|
|
|
for (allow_sw = 0; allow_sw < 2; allow_sw++)
|
|
|
|
{
|
2020-11-14 04:41:23 -05:00
|
|
|
/* First check if one was explicitly configured. */
|
|
|
|
for (l = gpus; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaGpuKms *gpu_kms = META_GPU_KMS (l->data);
|
|
|
|
MetaKmsDevice *kms_device = meta_gpu_kms_get_kms_device (gpu_kms);
|
|
|
|
|
|
|
|
if (meta_kms_device_get_flags (kms_device) &
|
|
|
|
META_KMS_DEVICE_FLAG_PREFERRED_PRIMARY)
|
|
|
|
{
|
|
|
|
g_message ("GPU %s selected primary given udev rule",
|
|
|
|
meta_gpu_kms_get_file_path (gpu_kms));
|
|
|
|
return gpu_kms;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
renderer/native: Prefer hardware rendering for primary GPU
Mutter prefers platform devices over anything else as the primary GPU.
This will not work too well, when a platform device does not actually
have a rendering GPU but is a display-only device. An example of this
are DisplayLink devices with the proprietary driver stack, which exposes
a DRM KMS platform device but without any rendering driver.
Mutter cannot rely on EGL init failing on such devices either, because
nowadays Mesa supports software renderers on GBM, so the initialization
may well succeed.
The hardware rendering capability is recognized by matching the GL
renderer string to the known Mesa software renderers. At this time,
there is no better alternative to detecting this.
The secondary GPU data is abused for the GL renderer, as the Cogl
context may not have been created yet. Also, the Cogl context would
only be created on the primary GPU, but at this point the primary GPU
has not been chosen yet. Hence, GPU copy path GL context is used as a
proxy and predictor of what the Cogl context might be if it was created.
Mind, that even the GL flavour are not the same between Cogl and
secondary contexts, so this is stretch but it should be just enough.
The logic to choose the primary GPU is changed to always prefer hardware
rendering devices while also maintaining the old order of preferring
platform over boot_vga devices.
Co-authored by: Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
https://gitlab.gnome.org/GNOME/mutter/merge_requests/271
2018-12-10 09:49:58 -05:00
|
|
|
/* Prefer a platform device */
|
|
|
|
for (l = gpus; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaGpuKms *gpu_kms = META_GPU_KMS (l->data);
|
|
|
|
|
|
|
|
if (meta_gpu_kms_is_platform_device (gpu_kms) &&
|
|
|
|
(allow_sw == 1 ||
|
|
|
|
gpu_kms_is_hardware_rendering (renderer_native, gpu_kms)))
|
2020-11-14 04:41:23 -05:00
|
|
|
{
|
|
|
|
g_message ("Integrated GPU %s selected as primary",
|
|
|
|
meta_gpu_kms_get_file_path (gpu_kms));
|
|
|
|
return gpu_kms;
|
|
|
|
}
|
renderer/native: Prefer hardware rendering for primary GPU
Mutter prefers platform devices over anything else as the primary GPU.
This will not work too well, when a platform device does not actually
have a rendering GPU but is a display-only device. An example of this
are DisplayLink devices with the proprietary driver stack, which exposes
a DRM KMS platform device but without any rendering driver.
Mutter cannot rely on EGL init failing on such devices either, because
nowadays Mesa supports software renderers on GBM, so the initialization
may well succeed.
The hardware rendering capability is recognized by matching the GL
renderer string to the known Mesa software renderers. At this time,
there is no better alternative to detecting this.
The secondary GPU data is abused for the GL renderer, as the Cogl
context may not have been created yet. Also, the Cogl context would
only be created on the primary GPU, but at this point the primary GPU
has not been chosen yet. Hence, GPU copy path GL context is used as a
proxy and predictor of what the Cogl context might be if it was created.
Mind, that even the GL flavour are not the same between Cogl and
secondary contexts, so this is stretch but it should be just enough.
The logic to choose the primary GPU is changed to always prefer hardware
rendering devices while also maintaining the old order of preferring
platform over boot_vga devices.
Co-authored by: Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
https://gitlab.gnome.org/GNOME/mutter/merge_requests/271
2018-12-10 09:49:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Otherwise a device we booted with */
|
|
|
|
for (l = gpus; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaGpuKms *gpu_kms = META_GPU_KMS (l->data);
|
|
|
|
|
|
|
|
if (meta_gpu_kms_is_boot_vga (gpu_kms) &&
|
|
|
|
(allow_sw == 1 ||
|
|
|
|
gpu_kms_is_hardware_rendering (renderer_native, gpu_kms)))
|
2020-11-14 04:41:23 -05:00
|
|
|
{
|
|
|
|
g_message ("Boot VGA GPU %s selected as primary",
|
|
|
|
meta_gpu_kms_get_file_path (gpu_kms));
|
|
|
|
return gpu_kms;
|
|
|
|
}
|
renderer/native: Prefer hardware rendering for primary GPU
Mutter prefers platform devices over anything else as the primary GPU.
This will not work too well, when a platform device does not actually
have a rendering GPU but is a display-only device. An example of this
are DisplayLink devices with the proprietary driver stack, which exposes
a DRM KMS platform device but without any rendering driver.
Mutter cannot rely on EGL init failing on such devices either, because
nowadays Mesa supports software renderers on GBM, so the initialization
may well succeed.
The hardware rendering capability is recognized by matching the GL
renderer string to the known Mesa software renderers. At this time,
there is no better alternative to detecting this.
The secondary GPU data is abused for the GL renderer, as the Cogl
context may not have been created yet. Also, the Cogl context would
only be created on the primary GPU, but at this point the primary GPU
has not been chosen yet. Hence, GPU copy path GL context is used as a
proxy and predictor of what the Cogl context might be if it was created.
Mind, that even the GL flavour are not the same between Cogl and
secondary contexts, so this is stretch but it should be just enough.
The logic to choose the primary GPU is changed to always prefer hardware
rendering devices while also maintaining the old order of preferring
platform over boot_vga devices.
Co-authored by: Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
https://gitlab.gnome.org/GNOME/mutter/merge_requests/271
2018-12-10 09:49:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Fall back to any device */
|
|
|
|
for (l = gpus; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaGpuKms *gpu_kms = META_GPU_KMS (l->data);
|
|
|
|
|
|
|
|
if (allow_sw == 1 ||
|
|
|
|
gpu_kms_is_hardware_rendering (renderer_native, gpu_kms))
|
2020-11-14 04:41:23 -05:00
|
|
|
{
|
|
|
|
g_message ("GPU %s selected as primary",
|
|
|
|
meta_gpu_kms_get_file_path (gpu_kms));
|
|
|
|
return gpu_kms;
|
|
|
|
}
|
renderer/native: Prefer hardware rendering for primary GPU
Mutter prefers platform devices over anything else as the primary GPU.
This will not work too well, when a platform device does not actually
have a rendering GPU but is a display-only device. An example of this
are DisplayLink devices with the proprietary driver stack, which exposes
a DRM KMS platform device but without any rendering driver.
Mutter cannot rely on EGL init failing on such devices either, because
nowadays Mesa supports software renderers on GBM, so the initialization
may well succeed.
The hardware rendering capability is recognized by matching the GL
renderer string to the known Mesa software renderers. At this time,
there is no better alternative to detecting this.
The secondary GPU data is abused for the GL renderer, as the Cogl
context may not have been created yet. Also, the Cogl context would
only be created on the primary GPU, but at this point the primary GPU
has not been chosen yet. Hence, GPU copy path GL context is used as a
proxy and predictor of what the Cogl context might be if it was created.
Mind, that even the GL flavour are not the same between Cogl and
secondary contexts, so this is stretch but it should be just enough.
The logic to choose the primary GPU is changed to always prefer hardware
rendering devices while also maintaining the old order of preferring
platform over boot_vga devices.
Co-authored by: Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
https://gitlab.gnome.org/GNOME/mutter/merge_requests/271
2018-12-10 09:49:58 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
return NULL;
|
2018-12-10 07:19:25 -05:00
|
|
|
}
|
|
|
|
|
2019-04-03 06:34:09 -04:00
|
|
|
static MetaGpuKms *
|
2019-01-11 09:35:42 -05:00
|
|
|
choose_primary_gpu (MetaBackend *backend,
|
2019-04-03 06:34:09 -04:00
|
|
|
MetaRendererNative *renderer_native,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaGpuKms *gpu_kms;
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
2021-05-05 09:53:59 -04:00
|
|
|
MetaRenderDevice *render_device;
|
2019-04-03 06:34:09 -04:00
|
|
|
|
2019-01-11 09:35:42 -05:00
|
|
|
gpu_kms = choose_primary_gpu_unchecked (backend, renderer_native);
|
2019-04-03 06:34:09 -04:00
|
|
|
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
|
|
|
gpu_kms);
|
2021-05-05 09:53:59 -04:00
|
|
|
render_device = renderer_gpu_data->render_device;
|
|
|
|
if (meta_render_device_get_egl_display (render_device) == EGL_NO_DISPLAY)
|
2019-04-03 06:34:09 -04:00
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"The GPU %s chosen as primary is not supported by EGL.",
|
|
|
|
meta_gpu_kms_get_file_path (gpu_kms));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return gpu_kms;
|
|
|
|
}
|
|
|
|
|
2017-07-10 06:19:32 -04:00
|
|
|
static gboolean
|
|
|
|
meta_renderer_native_initable_init (GInitable *initable,
|
|
|
|
GCancellable *cancellable,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (initable);
|
2019-10-01 05:51:53 -04:00
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
|
|
|
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
2017-07-10 06:19:32 -04:00
|
|
|
GList *gpus;
|
2017-07-24 22:21:04 -04:00
|
|
|
GList *l;
|
2017-07-10 06:19:32 -04:00
|
|
|
|
2019-01-11 09:35:42 -05:00
|
|
|
gpus = meta_backend_get_gpus (backend);
|
2021-02-09 08:32:55 -05:00
|
|
|
if (gpus)
|
2017-07-10 06:19:32 -04:00
|
|
|
{
|
2021-03-19 07:08:21 -04:00
|
|
|
const char *use_kms_modifiers_debug_env;
|
|
|
|
|
2021-02-09 08:32:55 -05:00
|
|
|
for (l = gpus; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaGpuKms *gpu_kms = META_GPU_KMS (l->data);
|
2017-07-10 06:19:32 -04:00
|
|
|
|
2021-02-09 08:32:55 -05:00
|
|
|
if (!create_renderer_gpu_data (renderer_native, gpu_kms, error))
|
|
|
|
return FALSE;
|
|
|
|
}
|
2017-07-10 06:19:32 -04:00
|
|
|
|
2021-02-09 08:32:55 -05:00
|
|
|
renderer_native->primary_gpu_kms = choose_primary_gpu (backend,
|
|
|
|
renderer_native,
|
|
|
|
error);
|
|
|
|
if (!renderer_native->primary_gpu_kms)
|
|
|
|
return FALSE;
|
2018-10-12 08:19:24 -04:00
|
|
|
|
2021-03-19 07:08:21 -04:00
|
|
|
use_kms_modifiers_debug_env = g_getenv ("MUTTER_DEBUG_USE_KMS_MODIFIERS");
|
|
|
|
if (use_kms_modifiers_debug_env)
|
|
|
|
{
|
|
|
|
renderer_native->use_modifiers =
|
|
|
|
g_strcmp0 (use_kms_modifiers_debug_env, "1") == 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
renderer_native->use_modifiers =
|
|
|
|
!meta_gpu_kms_disable_modifiers (renderer_native->primary_gpu_kms);
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_topic (META_DEBUG_KMS, "Usage of KMS modifiers is %s",
|
|
|
|
renderer_native->use_modifiers ? "enabled" : "disabled");
|
2021-02-09 08:32:55 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!create_renderer_gpu_data (renderer_native, NULL, error))
|
|
|
|
return FALSE;
|
|
|
|
}
|
2020-09-14 14:36:17 -04:00
|
|
|
|
2017-07-10 06:19:32 -04:00
|
|
|
return TRUE;
|
2016-08-17 23:14:03 -04:00
|
|
|
}
|
|
|
|
|
2016-05-09 09:22:01 -04:00
|
|
|
static void
|
|
|
|
initable_iface_init (GInitableIface *initable_iface)
|
|
|
|
{
|
|
|
|
initable_iface->init = meta_renderer_native_initable_init;
|
|
|
|
}
|
|
|
|
|
2017-07-10 06:19:32 -04:00
|
|
|
static void
|
|
|
|
meta_renderer_native_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (object);
|
|
|
|
|
2020-10-23 04:21:54 -04:00
|
|
|
clear_kept_alive_onscreens (renderer_native);
|
|
|
|
|
2021-04-09 18:49:51 -04:00
|
|
|
g_clear_list (&renderer_native->power_save_page_flip_onscreens,
|
|
|
|
g_object_unref);
|
|
|
|
g_clear_handle_id (&renderer_native->power_save_page_flip_source_id,
|
|
|
|
g_source_remove);
|
2019-03-25 05:24:46 -04:00
|
|
|
|
2020-10-09 17:17:06 -04:00
|
|
|
g_list_free (renderer_native->pending_mode_set_views);
|
|
|
|
|
2017-07-10 06:19:32 -04:00
|
|
|
g_hash_table_destroy (renderer_native->gpu_datas);
|
2017-07-24 22:21:04 -04:00
|
|
|
g_clear_object (&renderer_native->gles3);
|
2017-07-10 06:19:32 -04:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (meta_renderer_native_parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
2018-04-11 08:39:15 -04:00
|
|
|
static void
|
|
|
|
meta_renderer_native_constructed (GObject *object)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (object);
|
2019-10-01 05:51:53 -04:00
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
|
|
|
MetaBackend *backend = meta_renderer_get_backend (renderer);
|
2018-04-11 08:39:15 -04:00
|
|
|
MetaSettings *settings = meta_backend_get_settings (backend);
|
backend/native: Add and use transactional KMS API
This commit introduces, and makes use of, a transactional API used for
setting up KMS state, later to be applied, potentially atomically. From
an API point of view, so is always the case, but in the current
implementation, it still uses legacy drmMode* API to apply the state
non-atomically.
The API consists of various buliding blocks:
* MetaKmsUpdate - a set of configuration changes, the higher level
handle for handing over configuration to the impl backend. It's used to
set mode, assign framebuffers to planes, queue page flips and set
connector properties.
* MetaKmsPlaneAssignment - the assignment of a framebuffer to a plane.
Currently used to map a framebuffer to the primary plane of a CRTC. In
the legacy KMS implementation, the plane assignment is used to derive
the framebuffer used for mode setting and page flipping.
This also means various high level changes:
State, excluding configuring the cursor plane and creating/destroying
DRM framebuffer handles, are applied in the end of a clutter frame, in
one go. From an API point of view, this is done atomically, but as
mentioned, only the non-atomic implementation exists so far.
From MetaRendererNative's point of view, a page flip now initially
always succeeds; the handling of EBUSY errors are done asynchronously in
the MetaKmsImpl backend (still by retrying at refresh rate, but
postponing flip callbacks instead of manipulating the frame clock).
Handling of falling back to mode setting instead of page flipping is
notified after the fact by a more precise page flip feedback API.
EGLStream based page flipping relies on the impl backend not being
atomic, as the page flipping is done in the EGLStream backend (e.g.
nvidia driver). It uses a 'custom' page flip queueing method, keeping
the EGLStream logic inside meta-renderer-native.c.
Page flip handling is moved to meta-kms-impl-device.c from
meta-gpu-kms.c. It goes via an extra idle callback before reaching
meta-renderer-native.c to make sure callbacks are invoked outside of the
impl context.
While dummy power save page flipping is kept in meta-renderer-native.c, the
EBUSY handling is moved to meta-kms-impl-simple.c. Instead of freezing the
frame clock, actual page flip callbacks are postponed until all EBUSY retries
have either succeeded or failed due to some other error than EBUSY. This
effectively inhibits new frames to be drawn, meaning we won't stall waiting on
the file descriptor for pending page flips.
https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-04-04 16:36:41 -04:00
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
meta_backend_get_monitor_manager (backend);
|
2018-04-11 08:39:15 -04:00
|
|
|
|
|
|
|
if (meta_settings_is_experimental_feature_enabled (
|
|
|
|
settings, META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS))
|
|
|
|
renderer_native->use_modifiers = TRUE;
|
|
|
|
|
2019-01-11 09:35:42 -05:00
|
|
|
g_signal_connect (backend, "gpu-added",
|
2018-09-17 07:03:18 -04:00
|
|
|
G_CALLBACK (on_gpu_added), renderer_native);
|
backend/native: Add and use transactional KMS API
This commit introduces, and makes use of, a transactional API used for
setting up KMS state, later to be applied, potentially atomically. From
an API point of view, so is always the case, but in the current
implementation, it still uses legacy drmMode* API to apply the state
non-atomically.
The API consists of various buliding blocks:
* MetaKmsUpdate - a set of configuration changes, the higher level
handle for handing over configuration to the impl backend. It's used to
set mode, assign framebuffers to planes, queue page flips and set
connector properties.
* MetaKmsPlaneAssignment - the assignment of a framebuffer to a plane.
Currently used to map a framebuffer to the primary plane of a CRTC. In
the legacy KMS implementation, the plane assignment is used to derive
the framebuffer used for mode setting and page flipping.
This also means various high level changes:
State, excluding configuring the cursor plane and creating/destroying
DRM framebuffer handles, are applied in the end of a clutter frame, in
one go. From an API point of view, this is done atomically, but as
mentioned, only the non-atomic implementation exists so far.
From MetaRendererNative's point of view, a page flip now initially
always succeeds; the handling of EBUSY errors are done asynchronously in
the MetaKmsImpl backend (still by retrying at refresh rate, but
postponing flip callbacks instead of manipulating the frame clock).
Handling of falling back to mode setting instead of page flipping is
notified after the fact by a more precise page flip feedback API.
EGLStream based page flipping relies on the impl backend not being
atomic, as the page flipping is done in the EGLStream backend (e.g.
nvidia driver). It uses a 'custom' page flip queueing method, keeping
the EGLStream logic inside meta-renderer-native.c.
Page flip handling is moved to meta-kms-impl-device.c from
meta-gpu-kms.c. It goes via an extra idle callback before reaching
meta-renderer-native.c to make sure callbacks are invoked outside of the
impl context.
While dummy power save page flipping is kept in meta-renderer-native.c, the
EBUSY handling is moved to meta-kms-impl-simple.c. Instead of freezing the
frame clock, actual page flip callbacks are postponed until all EBUSY retries
have either succeeded or failed due to some other error than EBUSY. This
effectively inhibits new frames to be drawn, meaning we won't stall waiting on
the file descriptor for pending page flips.
https://gitlab.gnome.org/GNOME/mutter/issues/548
https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
2019-04-04 16:36:41 -04:00
|
|
|
g_signal_connect (monitor_manager, "power-save-mode-changed",
|
|
|
|
G_CALLBACK (on_power_save_mode_changed), renderer_native);
|
2018-09-17 07:03:18 -04:00
|
|
|
|
2018-04-11 08:39:15 -04:00
|
|
|
G_OBJECT_CLASS (meta_renderer_native_parent_class)->constructed (object);
|
|
|
|
}
|
|
|
|
|
2016-05-07 11:07:46 -04:00
|
|
|
static void
|
|
|
|
meta_renderer_native_init (MetaRendererNative *renderer_native)
|
|
|
|
{
|
2017-07-10 06:19:32 -04:00
|
|
|
renderer_native->gpu_datas =
|
|
|
|
g_hash_table_new_full (NULL, NULL,
|
|
|
|
NULL,
|
|
|
|
(GDestroyNotify) meta_renderer_native_gpu_data_free);
|
2016-05-07 11:07:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_renderer_native_class_init (MetaRendererNativeClass *klass)
|
|
|
|
{
|
2016-05-07 11:09:59 -04:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
2016-05-08 21:59:54 -04:00
|
|
|
MetaRendererClass *renderer_class = META_RENDERER_CLASS (klass);
|
2016-05-07 11:09:59 -04:00
|
|
|
|
2016-05-09 09:22:01 -04:00
|
|
|
object_class->finalize = meta_renderer_native_finalize;
|
2018-04-11 08:39:15 -04:00
|
|
|
object_class->constructed = meta_renderer_native_constructed;
|
2016-05-07 11:09:59 -04:00
|
|
|
|
2016-05-08 21:59:54 -04:00
|
|
|
renderer_class->create_cogl_renderer = meta_renderer_native_create_cogl_renderer;
|
2016-06-08 05:05:31 -04:00
|
|
|
renderer_class->create_view = meta_renderer_native_create_view;
|
2019-06-19 14:57:14 -04:00
|
|
|
renderer_class->rebuild_views = meta_renderer_native_rebuild_views;
|
2016-05-07 11:07:46 -04:00
|
|
|
}
|
2016-05-09 09:22:01 -04:00
|
|
|
|
|
|
|
MetaRendererNative *
|
2019-01-11 09:35:42 -05:00
|
|
|
meta_renderer_native_new (MetaBackendNative *backend_native,
|
|
|
|
GError **error)
|
2016-05-09 09:22:01 -04:00
|
|
|
{
|
2017-10-05 10:47:25 -04:00
|
|
|
return g_initable_new (META_TYPE_RENDERER_NATIVE,
|
|
|
|
NULL,
|
|
|
|
error,
|
2019-01-11 09:35:42 -05:00
|
|
|
"backend", backend_native,
|
2017-10-05 10:47:25 -04:00
|
|
|
NULL);
|
2016-05-09 09:22:01 -04:00
|
|
|
}
|