2016-05-07 15:07:46 +00:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
|
|
|
|
/*
|
2016-05-09 11:51:29 +00:00
|
|
|
* Copyright (C) 2011 Intel Corporation.
|
2016-05-07 15:07:46 +00:00
|
|
|
* Copyright (C) 2016 Red Hat
|
2018-09-05 07:38:09 +00:00
|
|
|
* Copyright (c) 2018 DisplayLink (UK) Ltd.
|
2016-05-07 15:07:46 +00: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 11:51:29 +00: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 15:07:46 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2018-07-10 08:36:24 +00:00
|
|
|
#include <drm_fourcc.h>
|
2016-05-09 11:51:29 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <gbm.h>
|
2016-05-09 13:22:01 +00:00
|
|
|
#include <gio/gio.h>
|
|
|
|
#include <glib-object.h>
|
2016-05-09 11:51:29 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2016-08-18 03:28:59 +00:00
|
|
|
#include <sys/mman.h>
|
2016-05-09 11:51:29 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <xf86drm.h>
|
2016-05-07 15:07:46 +00:00
|
|
|
|
2016-05-09 11:51:29 +00:00
|
|
|
#include "backends/meta-backend-private.h"
|
2017-03-28 04:35:19 +00:00
|
|
|
#include "backends/meta-crtc.h"
|
2016-08-18 03:28:59 +00:00
|
|
|
#include "backends/meta-egl-ext.h"
|
2018-07-10 08:36:24 +00:00
|
|
|
#include "backends/meta-egl.h"
|
|
|
|
#include "backends/meta-gles3.h"
|
2016-12-13 02:37:11 +00:00
|
|
|
#include "backends/meta-logical-monitor.h"
|
2017-03-24 09:35:51 +00:00
|
|
|
#include "backends/meta-output.h"
|
2016-06-08 09:05:31 +00:00
|
|
|
#include "backends/meta-renderer-view.h"
|
2017-08-03 14:42:50 +00:00
|
|
|
#include "backends/native/meta-crtc-kms.h"
|
2019-05-20 20:08:35 +00:00
|
|
|
#include "backends/native/meta-drm-buffer-dumb.h"
|
|
|
|
#include "backends/native/meta-drm-buffer-gbm.h"
|
2019-05-20 19:20:17 +00:00
|
|
|
#include "backends/native/meta-drm-buffer.h"
|
2017-07-10 10:19:32 +00:00
|
|
|
#include "backends/native/meta-gpu-kms.h"
|
2016-05-11 08:26:34 +00:00
|
|
|
#include "backends/native/meta-monitor-manager-kms.h"
|
2017-07-25 02:21:04 +00:00
|
|
|
#include "backends/native/meta-renderer-native-gles3.h"
|
2018-07-10 08:36:24 +00:00
|
|
|
#include "backends/native/meta-renderer-native.h"
|
2018-06-27 09:19:27 +00:00
|
|
|
#include "meta-marshal.h"
|
2016-05-07 15:09:59 +00:00
|
|
|
#include "cogl/cogl.h"
|
2016-06-08 09:05:31 +00:00
|
|
|
#include "core/boxes-private.h"
|
2016-05-07 15:09:59 +00:00
|
|
|
|
2016-08-18 03:28:59 +00:00
|
|
|
#ifndef EGL_DRM_MASTER_FD_EXT
|
|
|
|
#define EGL_DRM_MASTER_FD_EXT 0x333C
|
|
|
|
#endif
|
|
|
|
|
2018-11-21 13:25:07 +00:00
|
|
|
/* added in libdrm 2.4.95 */
|
|
|
|
#ifndef DRM_FORMAT_INVALID
|
|
|
|
#define DRM_FORMAT_INVALID 0
|
|
|
|
#endif
|
|
|
|
|
2016-05-07 15:09:59 +00:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
|
|
|
|
2017-07-06 08:00:56 +00:00
|
|
|
PROP_MONITOR_MANAGER,
|
2016-05-07 15:09:59 +00:00
|
|
|
|
|
|
|
PROP_LAST
|
|
|
|
};
|
2016-05-07 15:07:46 +00:00
|
|
|
|
2017-07-06 08:00:56 +00:00
|
|
|
static GParamSpec *obj_props[PROP_LAST];
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
typedef enum _MetaSharedFramebufferCopyMode
|
|
|
|
{
|
|
|
|
META_SHARED_FRAMEBUFFER_COPY_MODE_GPU,
|
|
|
|
META_SHARED_FRAMEBUFFER_COPY_MODE_CPU
|
|
|
|
} MetaSharedFramebufferCopyMode;
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
typedef struct _MetaRendererNativeGpuData
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native;
|
|
|
|
|
|
|
|
struct {
|
|
|
|
struct gbm_device *device;
|
|
|
|
} gbm;
|
|
|
|
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
struct {
|
|
|
|
EGLDeviceEXT device;
|
|
|
|
} egl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
MetaRendererNativeMode mode;
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
EGLDisplay egl_display;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fields used for blitting iGPU framebuffer content onto dGPU framebuffers.
|
|
|
|
*/
|
|
|
|
struct {
|
|
|
|
MetaSharedFramebufferCopyMode copy_mode;
|
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 14:49:58 +00:00
|
|
|
gboolean is_hardware_rendering;
|
2017-07-25 02:21:04 +00:00
|
|
|
|
|
|
|
/* For GPU blit mode */
|
|
|
|
EGLContext egl_context;
|
|
|
|
EGLConfig egl_config;
|
|
|
|
} secondary;
|
2017-07-10 10:19:32 +00:00
|
|
|
} MetaRendererNativeGpuData;
|
|
|
|
|
2017-07-24 07:38:46 +00:00
|
|
|
typedef struct _MetaDumbBuffer
|
|
|
|
{
|
|
|
|
uint32_t fb_id;
|
|
|
|
uint32_t handle;
|
|
|
|
void *map;
|
|
|
|
uint64_t map_size;
|
2018-09-05 08:48:08 +00:00
|
|
|
int width;
|
|
|
|
int height;
|
2018-09-05 09:07:59 +00:00
|
|
|
int stride_bytes;
|
2018-11-09 12:22:18 +00:00
|
|
|
uint32_t drm_format;
|
2017-07-24 07:38:46 +00:00
|
|
|
} MetaDumbBuffer;
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
typedef struct _MetaOnscreenNativeSecondaryGpuState
|
2016-05-27 07:07:41 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaGpuKms *gpu_kms;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
|
|
|
|
EGLSurface egl_surface;
|
|
|
|
|
|
|
|
struct {
|
|
|
|
struct gbm_surface *surface;
|
2019-05-20 19:20:17 +00:00
|
|
|
MetaDrmBuffer *current_fb;
|
|
|
|
MetaDrmBuffer *next_fb;
|
2017-07-25 02:21:04 +00:00
|
|
|
} gbm;
|
|
|
|
|
|
|
|
struct {
|
|
|
|
MetaDumbBuffer *dumb_fb;
|
|
|
|
MetaDumbBuffer dumb_fbs[2];
|
|
|
|
} cpu;
|
|
|
|
|
|
|
|
int pending_flips;
|
|
|
|
} MetaOnscreenNativeSecondaryGpuState;
|
|
|
|
|
|
|
|
typedef struct _MetaOnscreenNative
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native;
|
|
|
|
MetaGpuKms *render_gpu;
|
|
|
|
MetaLogicalMonitor *logical_monitor;
|
|
|
|
|
|
|
|
GHashTable *secondary_gpu_states;
|
2017-07-10 10:19:32 +00:00
|
|
|
|
2016-08-18 03:11:30 +00:00
|
|
|
struct {
|
|
|
|
struct gbm_surface *surface;
|
2019-05-20 19:20:17 +00:00
|
|
|
MetaDrmBuffer *current_fb;
|
|
|
|
MetaDrmBuffer *next_fb;
|
2016-08-18 03:11:30 +00:00
|
|
|
} gbm;
|
|
|
|
|
2016-08-18 03:28:59 +00:00
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
struct {
|
|
|
|
EGLStreamKHR stream;
|
|
|
|
|
2017-07-24 07:38:46 +00:00
|
|
|
MetaDumbBuffer dumb_fb;
|
2016-08-18 03:28:59 +00:00
|
|
|
} egl;
|
|
|
|
#endif
|
|
|
|
|
2016-09-29 14:15:26 +00:00
|
|
|
gboolean pending_queue_swap_notify;
|
2016-05-27 07:07:41 +00:00
|
|
|
gboolean pending_swap_notify;
|
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
gboolean pending_set_crtc;
|
|
|
|
|
2016-12-05 18:18:24 +00:00
|
|
|
int64_t pending_queue_swap_notify_frame_count;
|
|
|
|
int64_t pending_swap_notify_frame_count;
|
|
|
|
|
2019-02-12 18:10:59 +00:00
|
|
|
GList *pending_page_flip_retries;
|
|
|
|
GSource *retry_page_flips_source;
|
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
MetaRendererView *view;
|
2017-07-25 02:21:04 +00:00
|
|
|
int total_pending_flips;
|
2016-05-27 07:07:41 +00:00
|
|
|
} MetaOnscreenNative;
|
|
|
|
|
2016-05-07 15:07:46 +00:00
|
|
|
struct _MetaRendererNative
|
|
|
|
{
|
|
|
|
MetaRenderer parent;
|
2016-05-07 15:09:59 +00:00
|
|
|
|
2017-07-06 08:00:56 +00:00
|
|
|
MetaMonitorManagerKms *monitor_manager_kms;
|
2018-12-10 12:19:25 +00:00
|
|
|
MetaGpuKms *primary_gpu_kms;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaGles3 *gles3;
|
2016-08-18 02:37:16 +00:00
|
|
|
|
2018-04-11 12:39:15 +00:00
|
|
|
gboolean use_modifiers;
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
GHashTable *gpu_datas;
|
2016-08-18 03:28:59 +00:00
|
|
|
|
2016-05-09 13:22:01 +00:00
|
|
|
CoglClosure *swap_notify_idle;
|
2016-05-10 02:16:45 +00:00
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
int64_t frame_counter;
|
2017-09-28 15:59:27 +00:00
|
|
|
gboolean pending_unset_disabled_crtcs;
|
2019-03-25 09:24:46 +00:00
|
|
|
|
|
|
|
GList *power_save_page_flip_closures;
|
|
|
|
guint power_save_page_flip_source_id;
|
2016-05-07 15:07:46 +00:00
|
|
|
};
|
|
|
|
|
2016-05-09 13:22:01 +00: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 15:07:46 +00:00
|
|
|
|
2016-05-09 11:51:29 +00:00
|
|
|
static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable;
|
|
|
|
static const CoglWinsysVtable *parent_vtable;
|
|
|
|
|
2017-07-24 07:38:46 +00:00
|
|
|
static void
|
|
|
|
release_dumb_fb (MetaDumbBuffer *dumb_fb,
|
|
|
|
MetaGpuKms *gpu_kms);
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
init_dumb_fb (MetaDumbBuffer *dumb_fb,
|
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
int width,
|
|
|
|
int height,
|
|
|
|
uint32_t format,
|
|
|
|
GError **error);
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
static MetaEgl *
|
|
|
|
meta_renderer_native_get_egl (MetaRendererNative *renderer_native);
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_current_secondary_bo (MetaGpuKms *gpu_kms,
|
|
|
|
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state);
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_next_secondary_bo (MetaGpuKms *gpu_kms,
|
|
|
|
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state);
|
|
|
|
|
2018-11-21 13:25:07 +00:00
|
|
|
static gboolean
|
|
|
|
cogl_pixel_format_from_drm_format (uint32_t drm_format,
|
|
|
|
CoglPixelFormat *out_format,
|
|
|
|
CoglTextureComponents *out_components);
|
|
|
|
|
2019-04-02 13:34:01 +00:00
|
|
|
static MetaBackend *
|
|
|
|
backend_from_renderer_native (MetaRendererNative *renderer_native)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
|
|
|
|
|
|
|
|
return meta_monitor_manager_get_backend (monitor_manager);
|
|
|
|
}
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
static void
|
|
|
|
meta_renderer_native_gpu_data_free (MetaRendererNativeGpuData *renderer_gpu_data)
|
|
|
|
{
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
|
|
|
|
MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
|
|
|
|
|
|
|
|
if (renderer_gpu_data->egl_display != EGL_NO_DISPLAY)
|
|
|
|
meta_egl_terminate (egl, renderer_gpu_data->egl_display, NULL);
|
|
|
|
|
2017-11-06 19:39:56 +00:00
|
|
|
g_clear_pointer (&renderer_gpu_data->gbm.device, gbm_device_destroy);
|
2017-07-10 10:19:32 +00:00
|
|
|
g_free (renderer_gpu_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static MetaRendererNativeGpuData *
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
meta_gpu_get_monitor_manager (META_GPU (gpu_kms));
|
|
|
|
MetaBackend *backend = meta_monitor_manager_get_backend (monitor_manager);
|
|
|
|
|
|
|
|
return META_RENDERER_NATIVE (meta_backend_get_renderer (backend));
|
|
|
|
}
|
|
|
|
|
|
|
|
struct gbm_device *
|
|
|
|
meta_gbm_device_from_gpu (MetaGpuKms *gpu_kms)
|
|
|
|
{
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaRendererNative *renderer_native = meta_renderer_native_from_gpu (gpu_kms);
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
|
|
|
|
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
|
|
|
gpu_kms);
|
|
|
|
|
|
|
|
return renderer_gpu_data->gbm.device;
|
|
|
|
}
|
|
|
|
|
|
|
|
static MetaRendererNativeGpuData *
|
|
|
|
meta_create_renderer_native_gpu_data (MetaGpuKms *gpu_kms)
|
|
|
|
{
|
|
|
|
return g_new0 (MetaRendererNativeGpuData, 1);
|
|
|
|
}
|
|
|
|
|
2019-02-12 18:10:59 +00:00
|
|
|
static MetaOnscreenNativeSecondaryGpuState *
|
|
|
|
meta_onscreen_native_get_secondary_gpu_state (MetaOnscreenNative *onscreen_native,
|
|
|
|
MetaGpuKms *gpu_kms)
|
|
|
|
{
|
|
|
|
return g_hash_table_lookup (onscreen_native->secondary_gpu_states, gpu_kms);
|
|
|
|
}
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
static MetaOnscreenNativeSecondaryGpuState *
|
|
|
|
get_secondary_gpu_state (CoglOnscreen *onscreen,
|
|
|
|
MetaGpuKms *gpu_kms)
|
|
|
|
{
|
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
|
|
|
|
2019-02-12 18:10:59 +00:00
|
|
|
return meta_onscreen_native_get_secondary_gpu_state (onscreen_native,
|
|
|
|
gpu_kms);
|
2017-07-25 02:21:04 +00:00
|
|
|
}
|
|
|
|
|
2017-07-24 07:54:29 +00:00
|
|
|
static MetaEgl *
|
|
|
|
meta_renderer_native_get_egl (MetaRendererNative *renderer_native)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
|
|
|
|
MetaBackend *backend = meta_monitor_manager_get_backend (monitor_manager);
|
|
|
|
|
|
|
|
return meta_backend_get_egl (backend);
|
|
|
|
}
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
static MetaEgl *
|
|
|
|
meta_onscreen_native_get_egl (MetaOnscreenNative *onscreen_native)
|
|
|
|
{
|
|
|
|
return meta_renderer_native_get_egl (onscreen_native->renderer_native);
|
|
|
|
}
|
|
|
|
|
2018-02-14 18:27:28 +00:00
|
|
|
static GArray *
|
|
|
|
get_supported_kms_modifiers (CoglOnscreen *onscreen,
|
|
|
|
MetaGpu *gpu,
|
|
|
|
uint32_t format)
|
|
|
|
{
|
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
|
|
|
MetaLogicalMonitor *logical_monitor = onscreen_native->logical_monitor;
|
|
|
|
GArray *modifiers;
|
|
|
|
GArray *base_mods;
|
|
|
|
GList *l_crtc;
|
|
|
|
MetaCrtc *base_crtc = NULL;
|
|
|
|
GList *other_crtcs = NULL;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
if (!logical_monitor)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Find our base CRTC to intersect against. */
|
|
|
|
for (l_crtc = meta_gpu_get_crtcs (gpu); l_crtc; l_crtc = l_crtc->next)
|
|
|
|
{
|
|
|
|
MetaCrtc *crtc = l_crtc->data;
|
|
|
|
|
|
|
|
if (crtc->logical_monitor != logical_monitor)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!base_crtc)
|
|
|
|
base_crtc = crtc;
|
|
|
|
else if (crtc == base_crtc)
|
|
|
|
continue;
|
|
|
|
else if (g_list_index (other_crtcs, crtc) == -1)
|
|
|
|
other_crtcs = g_list_append (other_crtcs, crtc);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!base_crtc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
base_mods = meta_crtc_kms_get_modifiers (base_crtc, format);
|
|
|
|
if (!base_mods)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this is the only CRTC we have, we don't need to intersect the sets of
|
|
|
|
* modifiers.
|
|
|
|
*/
|
|
|
|
if (other_crtcs == NULL)
|
|
|
|
{
|
|
|
|
modifiers = g_array_sized_new (FALSE, FALSE, sizeof (uint64_t),
|
|
|
|
base_mods->len);
|
|
|
|
g_array_append_vals (modifiers, base_mods->data, base_mods->len);
|
|
|
|
return modifiers;
|
|
|
|
}
|
|
|
|
|
|
|
|
modifiers = g_array_new (FALSE, FALSE, sizeof (uint64_t));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For each modifier from base_crtc, check if it's available on all other
|
|
|
|
* CRTCs.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < base_mods->len; i++)
|
|
|
|
{
|
|
|
|
uint64_t modifier = g_array_index (base_mods, uint64_t, i);
|
|
|
|
gboolean found_everywhere = TRUE;
|
|
|
|
GList *k;
|
|
|
|
|
|
|
|
/* Check if we have the same modifier available for all CRTCs. */
|
|
|
|
for (k = other_crtcs; k; k = k->next)
|
|
|
|
{
|
|
|
|
MetaCrtc *crtc = k->data;
|
|
|
|
GArray *crtc_mods;
|
|
|
|
unsigned int m;
|
|
|
|
gboolean found_here = FALSE;
|
|
|
|
|
|
|
|
if (crtc->logical_monitor != logical_monitor)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
crtc_mods = meta_crtc_kms_get_modifiers (crtc, format);
|
|
|
|
if (!crtc_mods)
|
|
|
|
{
|
|
|
|
g_array_free (modifiers, TRUE);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (m = 0; m < crtc_mods->len; m++)
|
|
|
|
{
|
|
|
|
uint64_t local_mod = g_array_index (crtc_mods, uint64_t, m);
|
|
|
|
|
|
|
|
if (local_mod == modifier)
|
|
|
|
{
|
|
|
|
found_here = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found_here)
|
|
|
|
{
|
|
|
|
found_everywhere = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found_everywhere)
|
|
|
|
g_array_append_val (modifiers, modifier);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (modifiers->len == 0)
|
|
|
|
{
|
|
|
|
g_array_free (modifiers, TRUE);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
return modifiers;
|
|
|
|
|
|
|
|
out:
|
|
|
|
g_list_free (other_crtcs);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GArray *
|
|
|
|
get_supported_egl_modifiers (CoglOnscreen *onscreen,
|
|
|
|
MetaGpu *gpu,
|
|
|
|
uint32_t format)
|
|
|
|
{
|
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
|
|
|
MetaRendererNative *renderer_native = onscreen_native->renderer_native;
|
|
|
|
MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
EGLint num_modifiers;
|
|
|
|
GArray *modifiers;
|
|
|
|
GError *error = NULL;
|
|
|
|
gboolean ret;
|
|
|
|
|
|
|
|
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
|
|
|
META_GPU_KMS (gpu));
|
|
|
|
|
|
|
|
if (!meta_egl_has_extensions (egl, renderer_gpu_data->egl_display, NULL,
|
|
|
|
"EGL_EXT_image_dma_buf_import_modifiers",
|
|
|
|
NULL))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ret = meta_egl_query_dma_buf_modifiers (egl, renderer_gpu_data->egl_display,
|
|
|
|
format, 0, NULL, NULL,
|
|
|
|
&num_modifiers, NULL);
|
|
|
|
if (!ret || num_modifiers == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
modifiers = g_array_sized_new (FALSE, FALSE, sizeof (uint64_t),
|
|
|
|
num_modifiers);
|
|
|
|
ret = meta_egl_query_dma_buf_modifiers (egl, renderer_gpu_data->egl_display,
|
|
|
|
format, num_modifiers,
|
|
|
|
(EGLuint64KHR *) modifiers->data, NULL,
|
|
|
|
&num_modifiers, &error);
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
{
|
|
|
|
g_warning ("Failed to query DMABUF modifiers: %s", error->message);
|
|
|
|
g_error_free (error);
|
|
|
|
g_array_free (modifiers, TRUE);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return modifiers;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GArray *
|
|
|
|
get_supported_modifiers (CoglOnscreen *onscreen,
|
|
|
|
uint32_t format)
|
|
|
|
{
|
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
|
|
|
MetaLogicalMonitor *logical_monitor = onscreen_native->logical_monitor;
|
|
|
|
GArray *modifiers = NULL;
|
|
|
|
GArray *gpu_mods;
|
|
|
|
GList *l_monitor;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
if (!logical_monitor)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Find our base CRTC to intersect against. */
|
|
|
|
for (l_monitor = meta_logical_monitor_get_monitors (logical_monitor);
|
|
|
|
l_monitor;
|
|
|
|
l_monitor = l_monitor->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l_monitor->data;
|
|
|
|
MetaGpu *gpu = meta_monitor_get_gpu (monitor);
|
|
|
|
|
|
|
|
if (gpu == META_GPU (onscreen_native->render_gpu))
|
|
|
|
gpu_mods = get_supported_kms_modifiers (onscreen, gpu, format);
|
|
|
|
else
|
|
|
|
gpu_mods = get_supported_egl_modifiers (onscreen, gpu, format);
|
|
|
|
|
|
|
|
if (!gpu_mods)
|
|
|
|
{
|
|
|
|
g_array_free (modifiers, TRUE);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!modifiers)
|
|
|
|
{
|
|
|
|
modifiers = gpu_mods;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < modifiers->len; i++)
|
|
|
|
{
|
|
|
|
uint64_t modifier = g_array_index (modifiers, uint64_t, i);
|
|
|
|
gboolean found = FALSE;
|
|
|
|
unsigned int m;
|
|
|
|
|
|
|
|
for (m = 0; m < gpu_mods->len; m++)
|
|
|
|
{
|
|
|
|
uint64_t gpu_mod = g_array_index (gpu_mods, uint64_t, m);
|
|
|
|
|
|
|
|
if (gpu_mod == modifier)
|
|
|
|
{
|
|
|
|
found = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
{
|
|
|
|
g_array_remove_index_fast (modifiers, i);
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_array_free (gpu_mods, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (modifiers && modifiers->len == 0)
|
|
|
|
{
|
|
|
|
g_array_free (modifiers, TRUE);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return modifiers;
|
|
|
|
}
|
|
|
|
|
2018-11-21 13:25:07 +00:00
|
|
|
typedef struct _GetSupportedKmsFormatsData
|
|
|
|
{
|
|
|
|
GArray *formats;
|
|
|
|
MetaGpu *gpu;
|
|
|
|
} GetSupportedKmsFormatsData;
|
|
|
|
|
|
|
|
static void
|
|
|
|
get_supported_kms_formats_crtc_func (MetaLogicalMonitor *logical_monitor,
|
|
|
|
MetaCrtc *crtc,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
GetSupportedKmsFormatsData *data = user_data;
|
|
|
|
gboolean supported = TRUE;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
if (crtc->gpu != data->gpu)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!data->formats)
|
|
|
|
{
|
|
|
|
/* MetaCrtcKms guarantees a non-empty list. */
|
|
|
|
data->formats = meta_crtc_kms_copy_drm_format_list (crtc);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* formats must be supported by all other CRTCs too */
|
|
|
|
for (i = 0; i < data->formats->len; i++)
|
|
|
|
{
|
|
|
|
uint32_t drm_format = g_array_index (data->formats, uint32_t, i);
|
|
|
|
|
|
|
|
if (!meta_crtc_kms_supports_format (crtc, drm_format))
|
|
|
|
{
|
|
|
|
supported = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!supported)
|
|
|
|
g_array_remove_index_fast (data->formats, i--);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GArray *
|
|
|
|
get_supported_kms_formats (CoglOnscreen *onscreen,
|
|
|
|
MetaGpu *gpu)
|
|
|
|
{
|
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
|
|
|
MetaLogicalMonitor *logical_monitor = onscreen_native->logical_monitor;
|
|
|
|
GetSupportedKmsFormatsData data = {
|
|
|
|
.formats = NULL,
|
|
|
|
.gpu = gpu
|
|
|
|
};
|
|
|
|
|
|
|
|
meta_logical_monitor_foreach_crtc (logical_monitor,
|
|
|
|
get_supported_kms_formats_crtc_func,
|
|
|
|
&data);
|
|
|
|
if (data.formats->len == 0)
|
|
|
|
{
|
|
|
|
g_array_free (data.formats, TRUE);
|
|
|
|
data.formats = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return data.formats;
|
|
|
|
}
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
static gboolean
|
|
|
|
init_secondary_gpu_state_gpu_copy_mode (MetaRendererNative *renderer_native,
|
|
|
|
CoglOnscreen *onscreen,
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data,
|
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
|
|
|
MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
|
|
|
|
int width, height;
|
|
|
|
EGLNativeWindowType egl_native_window;
|
|
|
|
struct gbm_surface *gbm_surface;
|
|
|
|
EGLSurface egl_surface;
|
|
|
|
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
|
|
|
|
|
|
|
|
width = cogl_framebuffer_get_width (framebuffer);
|
|
|
|
height = cogl_framebuffer_get_height (framebuffer);
|
|
|
|
|
|
|
|
gbm_surface = gbm_surface_create (renderer_gpu_data->gbm.device,
|
|
|
|
width, height,
|
|
|
|
GBM_FORMAT_XRGB8888,
|
|
|
|
GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
|
|
|
|
if (!gbm_surface)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Failed to create gbm_surface: %s", strerror (errno));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
egl_native_window = (EGLNativeWindowType) gbm_surface;
|
|
|
|
egl_surface =
|
|
|
|
meta_egl_create_window_surface (egl,
|
|
|
|
renderer_gpu_data->egl_display,
|
|
|
|
renderer_gpu_data->secondary.egl_config,
|
|
|
|
egl_native_window,
|
|
|
|
NULL,
|
|
|
|
error);
|
|
|
|
if (egl_surface == EGL_NO_SURFACE)
|
|
|
|
{
|
|
|
|
gbm_surface_destroy (gbm_surface);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
secondary_gpu_state = g_new0 (MetaOnscreenNativeSecondaryGpuState, 1);
|
|
|
|
|
|
|
|
secondary_gpu_state->gpu_kms = gpu_kms;
|
|
|
|
secondary_gpu_state->renderer_gpu_data = renderer_gpu_data;
|
|
|
|
secondary_gpu_state->gbm.surface = gbm_surface;
|
|
|
|
secondary_gpu_state->egl_surface = egl_surface;
|
|
|
|
|
|
|
|
g_hash_table_insert (onscreen_native->secondary_gpu_states,
|
|
|
|
gpu_kms, secondary_gpu_state);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
|
|
|
|
{
|
|
|
|
MetaBackend *backend = meta_get_backend ();
|
|
|
|
MetaEgl *egl = meta_backend_get_egl (backend);
|
|
|
|
MetaGpuKms *gpu_kms = secondary_gpu_state->gpu_kms;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
if (secondary_gpu_state->egl_surface != EGL_NO_SURFACE)
|
|
|
|
{
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
|
|
|
|
renderer_gpu_data = secondary_gpu_state->renderer_gpu_data;
|
|
|
|
meta_egl_destroy_surface (egl,
|
|
|
|
renderer_gpu_data->egl_display,
|
|
|
|
secondary_gpu_state->egl_surface,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
free_current_secondary_bo (gpu_kms, secondary_gpu_state);
|
|
|
|
free_next_secondary_bo (gpu_kms, secondary_gpu_state);
|
|
|
|
g_clear_pointer (&secondary_gpu_state->gbm.surface, gbm_surface_destroy);
|
|
|
|
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (secondary_gpu_state->cpu.dumb_fbs); i++)
|
|
|
|
{
|
|
|
|
MetaDumbBuffer *dumb_fb = &secondary_gpu_state->cpu.dumb_fbs[i];
|
|
|
|
|
|
|
|
if (dumb_fb->fb_id)
|
|
|
|
release_dumb_fb (dumb_fb, gpu_kms);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (secondary_gpu_state);
|
|
|
|
}
|
|
|
|
|
2018-11-21 13:25:07 +00:00
|
|
|
static uint32_t
|
|
|
|
pick_secondary_gpu_framebuffer_format_for_cpu (CoglOnscreen *onscreen,
|
|
|
|
MetaGpu *gpu)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* cogl_framebuffer_read_pixels_into_bitmap () supported formats in
|
|
|
|
* preference order. Ideally these should depend on the render buffer
|
|
|
|
* format copy_shared_framebuffer_cpu () will be reading from but
|
|
|
|
* alpha channel ignored.
|
|
|
|
*/
|
|
|
|
static const uint32_t preferred_formats[] =
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* DRM_FORMAT_XBGR8888 a.k.a GL_RGBA, GL_UNSIGNED_BYTE on
|
|
|
|
* little-endian is possibly the most optimized glReadPixels
|
|
|
|
* output format. glReadPixels cannot avoid manufacturing an alpha
|
|
|
|
* channel if the render buffer does not have one and converting
|
|
|
|
* to ABGR8888 may be more optimized than ARGB8888.
|
|
|
|
*/
|
|
|
|
DRM_FORMAT_XBGR8888,
|
|
|
|
/* The rest are other fairly commonly used formats in OpenGL. */
|
|
|
|
DRM_FORMAT_XRGB8888,
|
|
|
|
};
|
|
|
|
g_autoptr (GArray) formats;
|
|
|
|
size_t k;
|
|
|
|
unsigned int i;
|
|
|
|
uint32_t drm_format;
|
|
|
|
|
|
|
|
formats = get_supported_kms_formats (onscreen, gpu);
|
|
|
|
|
|
|
|
/* Check if any of our preferred formats are supported. */
|
|
|
|
for (k = 0; k < G_N_ELEMENTS (preferred_formats); k++)
|
|
|
|
{
|
|
|
|
g_assert (cogl_pixel_format_from_drm_format (preferred_formats[k],
|
|
|
|
NULL,
|
|
|
|
NULL));
|
|
|
|
|
|
|
|
for (i = 0; i < formats->len; i++)
|
|
|
|
{
|
|
|
|
drm_format = g_array_index (formats, uint32_t, i);
|
|
|
|
|
|
|
|
if (drm_format == preferred_formats[k])
|
|
|
|
return drm_format;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise just pick an arbitrary format we recognize. The formats
|
|
|
|
* list is not in any specific order and we don't know any better
|
|
|
|
* either.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < formats->len; i++)
|
|
|
|
{
|
|
|
|
drm_format = g_array_index (formats, uint32_t, i);
|
|
|
|
|
|
|
|
if (cogl_pixel_format_from_drm_format (drm_format, NULL, NULL))
|
|
|
|
return drm_format;
|
|
|
|
}
|
|
|
|
|
|
|
|
return DRM_FORMAT_INVALID;
|
|
|
|
}
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
static gboolean
|
|
|
|
init_secondary_gpu_state_cpu_copy_mode (MetaRendererNative *renderer_native,
|
|
|
|
CoglOnscreen *onscreen,
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data,
|
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
|
|
|
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
|
|
|
|
int width, height;
|
|
|
|
unsigned int i;
|
2018-11-21 13:25:07 +00:00
|
|
|
uint32_t drm_format;
|
2018-11-22 14:26:01 +00:00
|
|
|
MetaDrmFormatBuf tmp;
|
2018-11-21 13:25:07 +00:00
|
|
|
|
|
|
|
drm_format = pick_secondary_gpu_framebuffer_format_for_cpu (onscreen,
|
|
|
|
META_GPU (gpu_kms));
|
|
|
|
if (drm_format == DRM_FORMAT_INVALID)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Could not find a suitable pixel format in CPU copy mode");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2017-07-25 02:21:04 +00:00
|
|
|
|
|
|
|
width = cogl_framebuffer_get_width (framebuffer);
|
|
|
|
height = cogl_framebuffer_get_height (framebuffer);
|
|
|
|
|
2018-11-22 14:26:01 +00:00
|
|
|
g_debug ("Secondary GPU %s using DRM format '%s' (0x%x) for a %dx%d output.",
|
|
|
|
meta_gpu_kms_get_file_path (gpu_kms),
|
|
|
|
meta_drm_format_to_string (&tmp, drm_format),
|
|
|
|
drm_format,
|
|
|
|
width, height);
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
secondary_gpu_state = g_new0 (MetaOnscreenNativeSecondaryGpuState, 1);
|
|
|
|
secondary_gpu_state->renderer_gpu_data = renderer_gpu_data;
|
|
|
|
secondary_gpu_state->gpu_kms = gpu_kms;
|
|
|
|
secondary_gpu_state->egl_surface = EGL_NO_SURFACE;
|
|
|
|
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (secondary_gpu_state->cpu.dumb_fbs); i++)
|
|
|
|
{
|
|
|
|
MetaDumbBuffer *dumb_fb = &secondary_gpu_state->cpu.dumb_fbs[i];
|
|
|
|
|
|
|
|
if (!init_dumb_fb (dumb_fb,
|
|
|
|
gpu_kms,
|
|
|
|
width, height,
|
2018-11-21 13:25:07 +00:00
|
|
|
drm_format,
|
2017-07-25 02:21:04 +00:00
|
|
|
error))
|
|
|
|
{
|
|
|
|
secondary_gpu_state_free (secondary_gpu_state);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_hash_table_insert (onscreen_native->secondary_gpu_states,
|
|
|
|
gpu_kms, secondary_gpu_state);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
init_secondary_gpu_state (MetaRendererNative *renderer_native,
|
|
|
|
CoglOnscreen *onscreen,
|
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
|
|
|
|
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
|
|
|
gpu_kms);
|
|
|
|
|
|
|
|
switch (renderer_gpu_data->secondary.copy_mode)
|
|
|
|
{
|
|
|
|
case META_SHARED_FRAMEBUFFER_COPY_MODE_GPU:
|
|
|
|
if (!init_secondary_gpu_state_gpu_copy_mode (renderer_native,
|
|
|
|
onscreen,
|
|
|
|
renderer_gpu_data,
|
|
|
|
gpu_kms,
|
|
|
|
error))
|
|
|
|
return FALSE;
|
|
|
|
break;
|
|
|
|
case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
|
|
|
|
if (!init_secondary_gpu_state_cpu_copy_mode (renderer_native,
|
|
|
|
onscreen,
|
|
|
|
renderer_gpu_data,
|
|
|
|
gpu_kms,
|
|
|
|
error))
|
|
|
|
return FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2016-05-09 11:51:29 +00:00
|
|
|
static void
|
2016-06-01 09:53:07 +00:00
|
|
|
meta_renderer_native_disconnect (CoglRenderer *cogl_renderer)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2017-07-14 07:20:41 +00:00
|
|
|
g_slice_free (CoglRendererEGL, cogl_renderer_egl);
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-06-08 09:05:31 +00:00
|
|
|
flush_pending_swap_notify (CoglFramebuffer *framebuffer)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
|
|
|
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
|
|
|
|
{
|
|
|
|
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2016-05-27 07:07:41 +00:00
|
|
|
if (onscreen_native->pending_swap_notify)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2016-12-05 18:18:24 +00:00
|
|
|
CoglFrameInfo *info;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2016-12-05 18:18:24 +00:00
|
|
|
while ((info = g_queue_peek_head (&onscreen->pending_frame_infos)) &&
|
|
|
|
info->global_frame_counter <= onscreen_native->pending_swap_notify_frame_count)
|
|
|
|
{
|
|
|
|
_cogl_onscreen_notify_frame_sync (onscreen, info);
|
|
|
|
_cogl_onscreen_notify_complete (onscreen, info);
|
|
|
|
cogl_object_unref (info);
|
|
|
|
g_queue_pop_head (&onscreen->pending_frame_infos);
|
|
|
|
}
|
2016-06-08 09:05:31 +00:00
|
|
|
|
2016-05-27 07:07:41 +00:00
|
|
|
onscreen_native->pending_swap_notify = FALSE;
|
2016-06-08 09:05:31 +00:00
|
|
|
cogl_object_unref (onscreen);
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
flush_pending_swap_notify_idle (void *user_data)
|
|
|
|
{
|
2016-06-01 09:53:07 +00:00
|
|
|
CoglContext *cogl_context = user_data;
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_context->display->renderer->winsys;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
|
|
|
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
|
2016-06-08 09:05:31 +00:00
|
|
|
GList *l;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
/* This needs to be disconnected before invoking the callbacks in
|
|
|
|
* case the callbacks cause it to be queued again */
|
2016-05-09 13:22:01 +00:00
|
|
|
_cogl_closure_disconnect (renderer_native->swap_notify_idle);
|
|
|
|
renderer_native->swap_notify_idle = NULL;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
l = cogl_context->framebuffers;
|
|
|
|
while (l)
|
|
|
|
{
|
|
|
|
GList *next = l->next;
|
|
|
|
CoglFramebuffer *framebuffer = l->data;
|
|
|
|
|
|
|
|
flush_pending_swap_notify (framebuffer);
|
|
|
|
|
|
|
|
l = next;
|
|
|
|
}
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
static void
|
|
|
|
free_current_secondary_bo (MetaGpuKms *gpu_kms,
|
|
|
|
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
|
|
|
|
{
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
|
|
|
|
renderer_gpu_data = secondary_gpu_state->renderer_gpu_data;
|
|
|
|
switch (renderer_gpu_data->secondary.copy_mode)
|
|
|
|
{
|
|
|
|
case META_SHARED_FRAMEBUFFER_COPY_MODE_GPU:
|
2018-01-30 09:47:17 +00:00
|
|
|
g_clear_object (&secondary_gpu_state->gbm.current_fb);
|
2017-07-25 02:21:04 +00:00
|
|
|
break;
|
|
|
|
case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-09 11:51:29 +00:00
|
|
|
static void
|
|
|
|
free_current_bo (CoglOnscreen *onscreen)
|
|
|
|
{
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2018-01-30 09:47:17 +00:00
|
|
|
g_clear_object (&onscreen_native->gbm.current_fb);
|
2017-07-25 02:21:04 +00:00
|
|
|
|
|
|
|
g_hash_table_foreach (onscreen_native->secondary_gpu_states,
|
|
|
|
(GHFunc) free_current_secondary_bo,
|
|
|
|
NULL);
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-06-08 09:05:31 +00:00
|
|
|
meta_onscreen_native_queue_swap_notify (CoglOnscreen *onscreen)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaRendererNative *renderer_native = onscreen_native->renderer_native;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2016-12-05 18:18:24 +00:00
|
|
|
onscreen_native->pending_swap_notify_frame_count =
|
|
|
|
onscreen_native->pending_queue_swap_notify_frame_count;
|
|
|
|
|
2016-11-23 14:46:26 +00:00
|
|
|
if (onscreen_native->pending_swap_notify)
|
|
|
|
return;
|
|
|
|
|
2016-05-09 11:51:29 +00:00
|
|
|
/* We only want to notify that the swap is complete when the
|
|
|
|
* application calls cogl_context_dispatch so instead of
|
|
|
|
* immediately notifying we queue an idle callback */
|
2016-05-09 13:22:01 +00:00
|
|
|
if (!renderer_native->swap_notify_idle)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2017-07-25 02:21:04 +00:00
|
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
|
|
|
CoglContext *cogl_context = framebuffer->context;
|
|
|
|
CoglRenderer *cogl_renderer = cogl_context->display->renderer;
|
|
|
|
|
2016-05-09 13:22:01 +00:00
|
|
|
renderer_native->swap_notify_idle =
|
2016-06-01 09:53:07 +00:00
|
|
|
_cogl_poll_renderer_add_idle (cogl_renderer,
|
2016-05-09 11:51:29 +00:00
|
|
|
flush_pending_swap_notify_idle,
|
2016-06-01 09:53:07 +00:00
|
|
|
cogl_context,
|
2016-05-09 11:51:29 +00:00
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
/*
|
|
|
|
* The framebuffer will have its own referenc while the swap notify is
|
|
|
|
* pending. Otherwise when destroying the view would drop the pending
|
|
|
|
* notification with if the destruction happens before the idle callback
|
|
|
|
* is invoked.
|
|
|
|
*/
|
|
|
|
cogl_object_ref (onscreen);
|
2016-05-27 07:07:41 +00:00
|
|
|
onscreen_native->pending_swap_notify = TRUE;
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
|
2016-08-18 02:21:12 +00:00
|
|
|
static gboolean
|
2016-05-27 07:13:09 +00:00
|
|
|
meta_renderer_native_connect (CoglRenderer *cogl_renderer,
|
2016-08-18 02:21:12 +00:00
|
|
|
GError **error)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglRendererEGL *cogl_renderer_egl;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaGpuKms *gpu_kms = cogl_renderer->custom_winsys_user_data;
|
|
|
|
MetaRendererNative *renderer_native = meta_renderer_native_from_gpu (gpu_kms);
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
cogl_renderer->winsys = g_slice_new0 (CoglRendererEGL);
|
2017-07-14 07:20:41 +00:00
|
|
|
cogl_renderer_egl = cogl_renderer->winsys;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
|
|
|
gpu_kms);
|
|
|
|
|
2017-07-14 07:20:41 +00:00
|
|
|
cogl_renderer_egl->platform_vtable = &_cogl_winsys_egl_vtable;
|
2017-07-25 02:21:04 +00:00
|
|
|
cogl_renderer_egl->platform = renderer_gpu_data;
|
|
|
|
cogl_renderer_egl->edpy = renderer_gpu_data->egl_display;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
if (!_cogl_winsys_egl_renderer_connect_common (cogl_renderer, error))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
fail:
|
2016-05-27 07:13:09 +00:00
|
|
|
meta_renderer_native_disconnect (cogl_renderer);
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2016-09-26 07:54:27 +00:00
|
|
|
static int
|
|
|
|
meta_renderer_native_add_egl_config_attributes (CoglDisplay *cogl_display,
|
|
|
|
CoglFramebufferConfig *config,
|
|
|
|
EGLint *attributes)
|
|
|
|
{
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_display->renderer->winsys;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
2016-09-26 07:54:27 +00:00
|
|
|
int i = 0;
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
switch (renderer_gpu_data->mode)
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
|
|
|
case META_RENDERER_NATIVE_MODE_GBM:
|
|
|
|
attributes[i++] = EGL_SURFACE_TYPE;
|
|
|
|
attributes[i++] = EGL_WINDOW_BIT;
|
|
|
|
break;
|
|
|
|
#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 07:54:27 +00:00
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2018-02-23 14:14:07 +00: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 23:29:44 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
2018-02-23 14:14:07 +00:00
|
|
|
EGLDisplay egl_display = cogl_renderer_egl->edpy;
|
|
|
|
|
2018-06-07 23:29:44 +00: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);
|
|
|
|
#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 14:14:07 +00:00
|
|
|
}
|
|
|
|
|
2016-08-18 02:21:12 +00:00
|
|
|
static gboolean
|
2016-06-01 09:53:07 +00:00
|
|
|
meta_renderer_native_setup_egl_display (CoglDisplay *cogl_display,
|
2016-08-18 02:21:12 +00:00
|
|
|
GError **error)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
|
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_display->renderer->winsys;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
|
|
|
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2017-07-14 07:20:41 +00:00
|
|
|
cogl_display_egl->platform = renderer_native;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
/* Force a full modeset / drmModeSetCrtc on
|
|
|
|
* the first swap buffers call.
|
|
|
|
*/
|
2016-06-08 09:05:31 +00:00
|
|
|
meta_renderer_native_queue_modes_reset (renderer_native);
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-06-01 09:53:07 +00:00
|
|
|
meta_renderer_native_destroy_egl_display (CoglDisplay *cogl_display)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-08-31 03:25:45 +00: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 14:13:11 +00:00
|
|
|
if (!meta_egl_choose_first_config (egl, egl_display, pbuffer_config_attribs,
|
|
|
|
&pbuffer_config, error))
|
2016-08-31 03:25:45 +00:00
|
|
|
return EGL_NO_SURFACE;
|
|
|
|
|
|
|
|
return meta_egl_create_pbuffer_surface (egl, egl_display,
|
|
|
|
pbuffer_config, pbuffer_attribs,
|
|
|
|
error);
|
|
|
|
}
|
|
|
|
|
2016-08-18 02:21:12 +00:00
|
|
|
static gboolean
|
2016-06-01 09:53:07 +00:00
|
|
|
meta_renderer_native_egl_context_created (CoglDisplay *cogl_display,
|
2016-08-18 02:21:12 +00:00
|
|
|
GError **error)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
|
2016-06-01 09:53:07 +00:00
|
|
|
CoglRenderer *cogl_renderer = cogl_display->renderer;
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2017-07-14 07:20:41 +00:00
|
|
|
if ((cogl_renderer_egl->private_features &
|
2016-05-09 11:51:29 +00:00
|
|
|
COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT) == 0)
|
|
|
|
{
|
2017-07-14 07:20:41 +00: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-31 03:25:45 +00:00
|
|
|
return FALSE;
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
|
2016-06-01 09:53:07 +00:00
|
|
|
if (!_cogl_winsys_egl_make_current (cogl_display,
|
2017-07-14 07:20:41 +00:00
|
|
|
cogl_display_egl->dummy_surface,
|
|
|
|
cogl_display_egl->dummy_surface,
|
|
|
|
cogl_display_egl->egl_context))
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2019-06-17 16:18:12 +00:00
|
|
|
g_set_error (error, COGL_WINSYS_ERROR,
|
2016-05-09 11:51:29 +00:00
|
|
|
COGL_WINSYS_ERROR_CREATE_CONTEXT,
|
|
|
|
"Failed to make context current");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-06-01 09:53:07 +00:00
|
|
|
meta_renderer_native_egl_cleanup_context (CoglDisplay *cogl_display)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
|
2016-06-01 09:53:07 +00:00
|
|
|
CoglRenderer *cogl_renderer = cogl_display->renderer;
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
|
|
|
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
|
2017-07-24 08:19:55 +00:00
|
|
|
MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2017-07-14 07:20:41 +00:00
|
|
|
if (cogl_display_egl->dummy_surface != EGL_NO_SURFACE)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2017-07-24 08:19:55 +00:00
|
|
|
meta_egl_destroy_surface (egl,
|
|
|
|
cogl_renderer_egl->edpy,
|
|
|
|
cogl_display_egl->dummy_surface,
|
|
|
|
NULL);
|
2017-07-14 07:20:41 +00:00
|
|
|
cogl_display_egl->dummy_surface = EGL_NO_SURFACE;
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
static void
|
|
|
|
swap_secondary_drm_fb (MetaGpuKms *gpu_kms,
|
|
|
|
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
|
|
|
|
{
|
2018-01-30 09:47:17 +00:00
|
|
|
g_set_object (&secondary_gpu_state->gbm.current_fb,
|
|
|
|
secondary_gpu_state->gbm.next_fb);
|
|
|
|
g_clear_object (&secondary_gpu_state->gbm.next_fb);
|
2017-07-25 02:21:04 +00:00
|
|
|
}
|
|
|
|
|
2016-05-12 06:55:06 +00:00
|
|
|
static void
|
2016-06-08 09:05:31 +00:00
|
|
|
meta_onscreen_native_swap_drm_fb (CoglOnscreen *onscreen)
|
2016-05-12 06:55:06 +00:00
|
|
|
{
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
2016-05-12 06:55:06 +00:00
|
|
|
|
|
|
|
free_current_bo (onscreen);
|
|
|
|
|
2018-01-30 09:47:17 +00:00
|
|
|
g_set_object (&onscreen_native->gbm.current_fb, onscreen_native->gbm.next_fb);
|
|
|
|
g_clear_object (&onscreen_native->gbm.next_fb);
|
2017-07-25 02:21:04 +00:00
|
|
|
|
|
|
|
g_hash_table_foreach (onscreen_native->secondary_gpu_states,
|
|
|
|
(GHFunc) swap_secondary_drm_fb,
|
|
|
|
NULL);
|
2016-06-08 09:05:31 +00:00
|
|
|
}
|
2016-05-12 06:55:06 +00:00
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
static void
|
|
|
|
on_crtc_flipped (GClosure *closure,
|
2017-07-24 09:29:22 +00:00
|
|
|
MetaGpuKms *gpu_kms,
|
2018-06-27 09:19:27 +00:00
|
|
|
MetaCrtc *crtc,
|
|
|
|
int64_t page_flip_time_ns,
|
2016-06-08 09:05:31 +00:00
|
|
|
MetaRendererView *view)
|
|
|
|
{
|
|
|
|
ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view);
|
|
|
|
CoglFramebuffer *framebuffer =
|
2016-08-01 00:44:57 +00:00
|
|
|
clutter_stage_view_get_onscreen (stage_view);
|
2016-06-08 09:05:31 +00:00
|
|
|
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaRendererNative *renderer_native = onscreen_native->renderer_native;
|
|
|
|
MetaGpuKms *render_gpu = onscreen_native->render_gpu;
|
2018-06-27 09:19:27 +00:00
|
|
|
CoglFrameInfo *frame_info;
|
|
|
|
float refresh_rate;
|
|
|
|
|
|
|
|
frame_info = g_queue_peek_tail (&onscreen->pending_frame_infos);
|
|
|
|
refresh_rate = crtc && crtc->current_mode ?
|
|
|
|
crtc->current_mode->refresh_rate :
|
|
|
|
0.0f;
|
|
|
|
|
|
|
|
/* Only keep the frame info for the fastest CRTC in use, which may not be
|
|
|
|
* the first one to complete a flip. By only telling the compositor about the
|
|
|
|
* fastest monitor(s) we direct it to produce new frames fast enough to
|
|
|
|
* satisfy all monitors.
|
|
|
|
*/
|
|
|
|
if (refresh_rate >= frame_info->refresh_rate)
|
|
|
|
{
|
|
|
|
frame_info->presentation_time = page_flip_time_ns;
|
|
|
|
frame_info->refresh_rate = refresh_rate;
|
|
|
|
}
|
2017-07-25 02:21:04 +00:00
|
|
|
|
|
|
|
if (gpu_kms != render_gpu)
|
|
|
|
{
|
|
|
|
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
|
2016-06-08 09:05:31 +00:00
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
secondary_gpu_state = get_secondary_gpu_state (onscreen, gpu_kms);
|
|
|
|
secondary_gpu_state->pending_flips--;
|
|
|
|
}
|
|
|
|
|
|
|
|
onscreen_native->total_pending_flips--;
|
|
|
|
if (onscreen_native->total_pending_flips == 0)
|
2016-06-08 09:05:31 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
|
2016-09-29 14:15:26 +00:00
|
|
|
onscreen_native->pending_queue_swap_notify = FALSE;
|
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
meta_onscreen_native_queue_swap_notify (onscreen);
|
2016-08-18 03:28:59 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
renderer_gpu_data =
|
|
|
|
meta_renderer_native_get_gpu_data (renderer_native,
|
2017-07-25 02:21:04 +00:00
|
|
|
onscreen_native->render_gpu);
|
2017-07-10 10:19:32 +00:00
|
|
|
switch (renderer_gpu_data->mode)
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
|
|
|
case META_RENDERER_NATIVE_MODE_GBM:
|
|
|
|
meta_onscreen_native_swap_drm_fb (onscreen);
|
|
|
|
break;
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
2016-06-08 09:05:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
static void
|
|
|
|
free_next_secondary_bo (MetaGpuKms *gpu_kms,
|
|
|
|
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
|
|
|
|
{
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
|
|
|
|
renderer_gpu_data = secondary_gpu_state->renderer_gpu_data;
|
|
|
|
switch (renderer_gpu_data->secondary.copy_mode)
|
|
|
|
{
|
|
|
|
case META_SHARED_FRAMEBUFFER_COPY_MODE_GPU:
|
2018-01-30 09:47:17 +00:00
|
|
|
g_clear_object (&secondary_gpu_state->gbm.next_fb);
|
2017-07-25 02:21:04 +00:00
|
|
|
break;
|
|
|
|
case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
static void
|
|
|
|
flip_closure_destroyed (MetaRendererView *view)
|
|
|
|
{
|
|
|
|
ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view);
|
|
|
|
CoglFramebuffer *framebuffer =
|
2016-08-01 00:44:57 +00:00
|
|
|
clutter_stage_view_get_onscreen (stage_view);
|
2016-06-08 09:05:31 +00:00
|
|
|
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaRendererNative *renderer_native = onscreen_native->renderer_native;
|
|
|
|
MetaGpuKms *render_gpu = onscreen_native->render_gpu;
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
|
|
|
render_gpu);
|
2017-07-10 10:19:32 +00:00
|
|
|
switch (renderer_gpu_data->mode)
|
2016-06-08 09:05:31 +00:00
|
|
|
{
|
2016-08-18 03:28:59 +00:00
|
|
|
case META_RENDERER_NATIVE_MODE_GBM:
|
2018-01-30 09:47:17 +00:00
|
|
|
g_clear_object (&onscreen_native->gbm.next_fb);
|
2016-06-08 09:05:31 +00:00
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
g_hash_table_foreach (onscreen_native->secondary_gpu_states,
|
|
|
|
(GHFunc) free_next_secondary_bo,
|
|
|
|
NULL);
|
|
|
|
|
2016-08-18 03:28:59 +00:00
|
|
|
break;
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
|
|
|
break;
|
|
|
|
#endif
|
2016-09-29 14:15:26 +00:00
|
|
|
}
|
2016-06-08 09:05:31 +00:00
|
|
|
|
2016-09-29 14:15:26 +00:00
|
|
|
if (onscreen_native->pending_queue_swap_notify)
|
|
|
|
{
|
2016-06-08 09:05:31 +00:00
|
|
|
meta_onscreen_native_queue_swap_notify (onscreen);
|
2016-09-29 14:15:26 +00:00
|
|
|
onscreen_native->pending_queue_swap_notify = FALSE;
|
2016-06-08 09:05:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
g_object_unref (view);
|
|
|
|
}
|
|
|
|
|
2016-08-18 03:28:59 +00:00
|
|
|
#ifdef HAVE_EGL_DEVICE
|
2017-02-02 02:15:53 +00:00
|
|
|
static gboolean
|
2017-07-10 10:19:32 +00:00
|
|
|
flip_egl_stream (MetaOnscreenNative *onscreen_native,
|
2016-08-18 03:28:59 +00:00
|
|
|
GClosure *flip_closure)
|
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
2017-07-25 02:21:04 +00:00
|
|
|
EGLDisplay *egl_display;
|
|
|
|
MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
|
2017-11-14 08:08:52 +00:00
|
|
|
MetaGpuKmsFlipClosureContainer *closure_container;
|
2016-08-18 03:28:59 +00:00
|
|
|
EGLAttrib *acquire_attribs;
|
|
|
|
GError *error = NULL;
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
renderer_gpu_data =
|
2017-07-25 02:21:04 +00:00
|
|
|
meta_renderer_native_get_gpu_data (onscreen_native->renderer_native,
|
|
|
|
onscreen_native->render_gpu);
|
2016-08-18 03:28:59 +00:00
|
|
|
|
2017-11-14 08:08:52 +00:00
|
|
|
closure_container =
|
2018-06-27 09:19:27 +00:00
|
|
|
meta_gpu_kms_wrap_flip_closure (onscreen_native->render_gpu,
|
|
|
|
NULL,
|
|
|
|
flip_closure);
|
2017-11-14 08:08:52 +00:00
|
|
|
|
2016-08-18 03:28:59 +00:00
|
|
|
acquire_attribs = (EGLAttrib[]) {
|
|
|
|
EGL_DRM_FLIP_EVENT_DATA_NV,
|
2017-11-14 08:08:52 +00:00
|
|
|
(EGLAttrib) closure_container,
|
2016-08-18 03:28:59 +00:00
|
|
|
EGL_NONE
|
|
|
|
};
|
2017-02-02 02:15:53 +00:00
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
egl_display = renderer_gpu_data->egl_display;
|
2016-08-18 03:28:59 +00:00
|
|
|
if (!meta_egl_stream_consumer_acquire_attrib (egl,
|
2017-07-25 02:21:04 +00:00
|
|
|
egl_display,
|
2016-08-18 03:28:59 +00:00
|
|
|
onscreen_native->egl.stream,
|
|
|
|
acquire_attribs,
|
|
|
|
&error))
|
|
|
|
{
|
2017-02-02 02:15:53 +00:00
|
|
|
if (error->domain != META_EGL_ERROR ||
|
|
|
|
error->code != EGL_RESOURCE_BUSY_EXT)
|
|
|
|
{
|
2019-01-11 15:05:09 +00:00
|
|
|
g_warning ("Failed to flip EGL stream: %s", error->message);
|
2017-02-02 02:15:53 +00:00
|
|
|
}
|
2016-08-18 03:28:59 +00:00
|
|
|
g_error_free (error);
|
2017-11-14 08:08:52 +00:00
|
|
|
meta_gpu_kms_flip_closure_container_free (closure_container);
|
2017-02-02 02:15:53 +00:00
|
|
|
return FALSE;
|
2016-08-18 03:28:59 +00:00
|
|
|
}
|
|
|
|
|
2017-02-02 02:15:53 +00:00
|
|
|
return TRUE;
|
2016-08-18 03:28:59 +00:00
|
|
|
}
|
|
|
|
#endif /* HAVE_EGL_DEVICE */
|
|
|
|
|
2019-02-12 18:10:59 +00:00
|
|
|
static gboolean
|
|
|
|
is_timestamp_earlier_than (uint64_t ts1,
|
|
|
|
uint64_t ts2)
|
|
|
|
{
|
|
|
|
if (ts1 == ts2)
|
|
|
|
return FALSE;
|
|
|
|
else
|
|
|
|
return ts2 - ts1 < UINT64_MAX / 2;
|
|
|
|
}
|
|
|
|
|
2019-03-25 09:24:46 +00:00
|
|
|
static gboolean
|
|
|
|
dummy_power_save_page_flip_cb (gpointer user_data)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = user_data;
|
|
|
|
|
|
|
|
g_list_free_full (renderer_native->power_save_page_flip_closures,
|
|
|
|
(GDestroyNotify) g_closure_unref);
|
|
|
|
renderer_native->power_save_page_flip_closures = NULL;
|
|
|
|
renderer_native->power_save_page_flip_source_id = 0;
|
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
queue_dummy_power_save_page_flip (MetaRendererNative *renderer_native,
|
|
|
|
GClosure *flip_closure)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
renderer_native->power_save_page_flip_closures =
|
|
|
|
g_list_prepend (renderer_native->power_save_page_flip_closures,
|
|
|
|
g_closure_ref (flip_closure));
|
|
|
|
}
|
|
|
|
|
2019-02-12 18:10:59 +00:00
|
|
|
typedef struct _RetryPageFlipData
|
|
|
|
{
|
|
|
|
MetaCrtc *crtc;
|
|
|
|
uint32_t fb_id;
|
|
|
|
GClosure *flip_closure;
|
|
|
|
uint64_t retry_time_us;
|
|
|
|
} RetryPageFlipData;
|
|
|
|
|
|
|
|
static void
|
|
|
|
retry_page_flip_data_free (RetryPageFlipData *retry_page_flip_data)
|
|
|
|
{
|
|
|
|
g_closure_unref (retry_page_flip_data->flip_closure);
|
|
|
|
g_free (retry_page_flip_data);
|
|
|
|
}
|
|
|
|
|
2019-03-25 09:19:21 +00:00
|
|
|
static void
|
|
|
|
retry_page_flip_data_fake_flipped (RetryPageFlipData *retry_page_flip_data,
|
|
|
|
MetaOnscreenNative *onscreen_native)
|
|
|
|
{
|
|
|
|
MetaCrtc *crtc = retry_page_flip_data->crtc;
|
|
|
|
MetaGpuKms *gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
|
|
|
|
|
|
|
|
if (gpu_kms != onscreen_native->render_gpu)
|
|
|
|
{
|
|
|
|
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
|
|
|
|
|
|
|
|
secondary_gpu_state =
|
|
|
|
meta_onscreen_native_get_secondary_gpu_state (onscreen_native,
|
|
|
|
gpu_kms);
|
|
|
|
secondary_gpu_state->pending_flips--;
|
|
|
|
}
|
|
|
|
|
|
|
|
onscreen_native->total_pending_flips--;
|
|
|
|
}
|
|
|
|
|
2019-02-12 18:10:59 +00:00
|
|
|
static gboolean
|
|
|
|
retry_page_flips (gpointer user_data)
|
|
|
|
{
|
|
|
|
MetaOnscreenNative *onscreen_native = user_data;
|
2019-03-25 09:19:21 +00:00
|
|
|
MetaRendererNative *renderer_native = onscreen_native->renderer_native;
|
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
|
2019-02-12 18:10:59 +00:00
|
|
|
uint64_t now_us;
|
2019-03-25 09:19:21 +00:00
|
|
|
MetaPowerSave power_save_mode;
|
2019-02-12 18:10:59 +00:00
|
|
|
GList *l;
|
|
|
|
|
|
|
|
now_us = g_source_get_time (onscreen_native->retry_page_flips_source);
|
2019-03-25 09:19:21 +00:00
|
|
|
power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
|
2019-02-12 18:10:59 +00:00
|
|
|
|
|
|
|
l = onscreen_native->pending_page_flip_retries;
|
|
|
|
while (l)
|
|
|
|
{
|
|
|
|
RetryPageFlipData *retry_page_flip_data = l->data;
|
|
|
|
MetaCrtc *crtc = retry_page_flip_data->crtc;
|
|
|
|
MetaGpuKms *gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
|
|
|
|
GList *l_next = l->next;
|
|
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
gboolean did_flip;
|
|
|
|
|
2019-03-25 09:19:21 +00:00
|
|
|
if (power_save_mode != META_POWER_SAVE_ON)
|
|
|
|
{
|
|
|
|
onscreen_native->pending_page_flip_retries =
|
|
|
|
g_list_remove_link (onscreen_native->pending_page_flip_retries, l);
|
|
|
|
|
|
|
|
retry_page_flip_data_fake_flipped (retry_page_flip_data,
|
|
|
|
onscreen_native);
|
|
|
|
retry_page_flip_data_free (retry_page_flip_data);
|
|
|
|
|
|
|
|
l = l_next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-02-12 18:10:59 +00:00
|
|
|
if (is_timestamp_earlier_than (now_us,
|
|
|
|
retry_page_flip_data->retry_time_us))
|
|
|
|
{
|
|
|
|
l = l_next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
did_flip = meta_gpu_kms_flip_crtc (gpu_kms,
|
|
|
|
crtc,
|
|
|
|
retry_page_flip_data->fb_id,
|
|
|
|
retry_page_flip_data->flip_closure,
|
|
|
|
&error);
|
|
|
|
if (!did_flip &&
|
|
|
|
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_BUSY))
|
|
|
|
{
|
|
|
|
retry_page_flip_data->retry_time_us +=
|
2019-03-22 17:54:20 +00:00
|
|
|
(uint64_t) (G_USEC_PER_SEC / crtc->current_mode->refresh_rate);
|
2019-02-12 18:10:59 +00:00
|
|
|
l = l_next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
onscreen_native->pending_page_flip_retries =
|
|
|
|
g_list_remove_link (onscreen_native->pending_page_flip_retries, l);
|
|
|
|
|
|
|
|
if (!did_flip)
|
|
|
|
{
|
|
|
|
if (!g_error_matches (error,
|
|
|
|
G_IO_ERROR,
|
|
|
|
G_IO_ERROR_PERMISSION_DENIED))
|
|
|
|
g_critical ("Failed to page flip: %s", error->message);
|
|
|
|
|
2019-03-25 09:19:21 +00:00
|
|
|
retry_page_flip_data_fake_flipped (retry_page_flip_data,
|
|
|
|
onscreen_native);
|
2019-02-12 18:10:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
retry_page_flip_data_free (retry_page_flip_data);
|
|
|
|
|
|
|
|
l = l_next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (onscreen_native->pending_page_flip_retries)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
uint64_t earliest_retry_time_us = 0;
|
|
|
|
|
|
|
|
for (l = onscreen_native->pending_page_flip_retries; l; l = l->next)
|
|
|
|
{
|
|
|
|
RetryPageFlipData *retry_page_flip_data = l->data;
|
|
|
|
|
|
|
|
if (l == onscreen_native->pending_page_flip_retries ||
|
|
|
|
is_timestamp_earlier_than (retry_page_flip_data->retry_time_us,
|
|
|
|
earliest_retry_time_us))
|
|
|
|
earliest_retry_time_us = retry_page_flip_data->retry_time_us;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_source_set_ready_time (onscreen_native->retry_page_flips_source,
|
|
|
|
earliest_retry_time_us);
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-03-29 19:56:57 +00:00
|
|
|
MetaBackend *backend = backend_from_renderer_native (renderer_native);
|
|
|
|
|
|
|
|
meta_backend_thaw_updates (backend);
|
2019-02-12 18:10:59 +00:00
|
|
|
g_clear_pointer (&onscreen_native->retry_page_flips_source,
|
|
|
|
g_source_unref);
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
retry_page_flips_source_dispatch (GSource *source,
|
|
|
|
GSourceFunc callback,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
return callback (user_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GSourceFuncs retry_page_flips_source_funcs = {
|
|
|
|
.dispatch = retry_page_flips_source_dispatch,
|
|
|
|
};
|
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
static void
|
2019-02-12 18:10:59 +00:00
|
|
|
schedule_retry_page_flip (MetaOnscreenNative *onscreen_native,
|
|
|
|
MetaCrtc *crtc,
|
|
|
|
uint32_t fb_id,
|
|
|
|
GClosure *flip_closure)
|
|
|
|
{
|
|
|
|
RetryPageFlipData *retry_page_flip_data;
|
|
|
|
uint64_t now_us;
|
|
|
|
uint64_t retry_time_us;
|
|
|
|
|
|
|
|
now_us = g_get_monotonic_time ();
|
|
|
|
retry_time_us =
|
2019-03-22 17:54:20 +00:00
|
|
|
now_us + (uint64_t) (G_USEC_PER_SEC / crtc->current_mode->refresh_rate);
|
2019-02-12 18:10:59 +00:00
|
|
|
|
|
|
|
retry_page_flip_data = g_new0 (RetryPageFlipData, 1);
|
|
|
|
retry_page_flip_data->crtc = crtc;
|
|
|
|
retry_page_flip_data->fb_id = fb_id;
|
|
|
|
retry_page_flip_data->flip_closure = g_closure_ref (flip_closure);
|
|
|
|
retry_page_flip_data->retry_time_us = retry_time_us;
|
|
|
|
|
|
|
|
if (!onscreen_native->retry_page_flips_source)
|
|
|
|
{
|
2019-03-29 19:56:57 +00:00
|
|
|
MetaBackend *backend =
|
|
|
|
backend_from_renderer_native (onscreen_native->renderer_native);
|
2019-02-12 18:10:59 +00:00
|
|
|
GSource *source;
|
|
|
|
|
|
|
|
source = g_source_new (&retry_page_flips_source_funcs, sizeof (GSource));
|
|
|
|
g_source_set_callback (source, retry_page_flips, onscreen_native, NULL);
|
|
|
|
g_source_set_ready_time (source, retry_time_us);
|
|
|
|
g_source_attach (source, NULL);
|
|
|
|
|
|
|
|
onscreen_native->retry_page_flips_source = source;
|
2019-03-29 19:56:57 +00:00
|
|
|
meta_backend_freeze_updates (backend);
|
2019-02-12 18:10:59 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = onscreen_native->pending_page_flip_retries; l; l = l->next)
|
|
|
|
{
|
|
|
|
RetryPageFlipData *pending_retry_page_flip_data = l->data;
|
|
|
|
uint64_t pending_retry_time_us =
|
|
|
|
pending_retry_page_flip_data->retry_time_us;
|
|
|
|
|
|
|
|
if (is_timestamp_earlier_than (retry_time_us, pending_retry_time_us))
|
|
|
|
{
|
|
|
|
g_source_set_ready_time (onscreen_native->retry_page_flips_source,
|
|
|
|
retry_time_us);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onscreen_native->pending_page_flip_retries =
|
|
|
|
g_list_append (onscreen_native->pending_page_flip_retries,
|
|
|
|
retry_page_flip_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
|
|
|
|
GClosure *flip_closure,
|
|
|
|
MetaCrtc *crtc,
|
|
|
|
GError **error)
|
2017-07-25 02:21:04 +00:00
|
|
|
{
|
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
|
|
|
MetaRendererNative *renderer_native = onscreen_native->renderer_native;
|
|
|
|
MetaGpuKms *render_gpu = onscreen_native->render_gpu;
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaGpuKms *gpu_kms;
|
|
|
|
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state = NULL;
|
|
|
|
uint32_t fb_id;
|
2016-06-08 09:05:31 +00:00
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
|
2019-03-25 09:24:46 +00:00
|
|
|
|
|
|
|
g_assert (meta_gpu_kms_is_crtc_active (gpu_kms, crtc));
|
2016-06-08 09:05:31 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
2017-07-25 02:21:04 +00:00
|
|
|
render_gpu);
|
2017-07-10 10:19:32 +00:00
|
|
|
switch (renderer_gpu_data->mode)
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
|
|
|
case META_RENDERER_NATIVE_MODE_GBM:
|
2017-07-25 02:21:04 +00:00
|
|
|
if (gpu_kms == render_gpu)
|
|
|
|
{
|
2019-05-20 19:20:17 +00:00
|
|
|
fb_id = meta_drm_buffer_get_fb_id (onscreen_native->gbm.next_fb);
|
2017-07-25 02:21:04 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
secondary_gpu_state = get_secondary_gpu_state (onscreen, gpu_kms);
|
2019-05-20 19:20:17 +00:00
|
|
|
fb_id = meta_drm_buffer_get_fb_id (secondary_gpu_state->gbm.next_fb);
|
2017-07-25 02:21:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!meta_gpu_kms_flip_crtc (gpu_kms,
|
|
|
|
crtc,
|
|
|
|
fb_id,
|
|
|
|
flip_closure,
|
2019-02-12 18:10:59 +00:00
|
|
|
error))
|
|
|
|
{
|
|
|
|
if (g_error_matches (*error,
|
|
|
|
G_IO_ERROR,
|
|
|
|
G_IO_ERROR_BUSY))
|
|
|
|
{
|
|
|
|
g_clear_error (error);
|
|
|
|
schedule_retry_page_flip (onscreen_native, crtc,
|
|
|
|
fb_id, flip_closure);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
2017-07-25 02:21:04 +00:00
|
|
|
|
|
|
|
onscreen_native->total_pending_flips++;
|
|
|
|
if (secondary_gpu_state)
|
|
|
|
secondary_gpu_state->pending_flips++;
|
|
|
|
|
2016-08-18 03:28:59 +00:00
|
|
|
break;
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
2017-07-10 10:19:32 +00:00
|
|
|
if (flip_egl_stream (onscreen_native,
|
2017-02-02 02:15:53 +00:00
|
|
|
flip_closure))
|
2017-07-25 02:21:04 +00:00
|
|
|
onscreen_native->total_pending_flips++;
|
2016-08-18 03:28:59 +00:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
2016-06-08 09:05:31 +00:00
|
|
|
|
2019-02-12 18:10:59 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
2017-03-28 04:17:38 +00:00
|
|
|
|
|
|
|
static void
|
2019-02-12 18:10:59 +00:00
|
|
|
set_crtc_fb (CoglOnscreen *onscreen,
|
|
|
|
MetaLogicalMonitor *logical_monitor,
|
2017-03-28 04:17:38 +00:00
|
|
|
MetaCrtc *crtc,
|
2019-02-12 18:10:59 +00:00
|
|
|
uint32_t render_fb_id)
|
2017-03-28 04:17:38 +00:00
|
|
|
{
|
2019-02-12 18:10:59 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
|
|
|
MetaGpuKms *render_gpu = onscreen_native->render_gpu;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaGpuKms *gpu_kms;
|
2017-03-28 04:17:38 +00:00
|
|
|
int x, y;
|
2019-02-12 18:10:59 +00:00
|
|
|
uint32_t fb_id;
|
2017-03-28 04:17:38 +00:00
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
|
|
|
|
if (gpu_kms == render_gpu)
|
|
|
|
{
|
2019-02-12 18:10:59 +00:00
|
|
|
fb_id = render_fb_id;
|
2017-07-25 02:21:04 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
|
|
|
|
|
|
|
|
secondary_gpu_state = get_secondary_gpu_state (onscreen, gpu_kms);
|
|
|
|
if (!secondary_gpu_state)
|
|
|
|
return;
|
|
|
|
|
2019-05-20 19:20:17 +00:00
|
|
|
fb_id = meta_drm_buffer_get_fb_id (secondary_gpu_state->gbm.next_fb);
|
2017-07-25 02:21:04 +00:00
|
|
|
}
|
|
|
|
|
2017-03-28 04:17:38 +00:00
|
|
|
x = crtc->rect.x - logical_monitor->rect.x;
|
|
|
|
y = crtc->rect.y - logical_monitor->rect.y;
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
meta_gpu_kms_apply_crtc_mode (gpu_kms, crtc, x, y, fb_id);
|
2017-03-28 04:17:38 +00:00
|
|
|
}
|
|
|
|
|
2019-02-12 18:10:59 +00:00
|
|
|
typedef struct _SetCrtcFbData
|
|
|
|
{
|
|
|
|
CoglOnscreen *onscreen;
|
|
|
|
uint32_t fb_id;
|
|
|
|
} SetCrtcFbData;
|
|
|
|
|
|
|
|
static void
|
|
|
|
set_crtc_fb_cb (MetaLogicalMonitor *logical_monitor,
|
|
|
|
MetaCrtc *crtc,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
SetCrtcFbData *data = user_data;
|
|
|
|
CoglOnscreen *onscreen = data->onscreen;
|
|
|
|
|
|
|
|
set_crtc_fb (onscreen, logical_monitor, crtc, data->fb_id);
|
|
|
|
}
|
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
static void
|
2017-07-25 02:21:04 +00:00
|
|
|
meta_onscreen_native_set_crtc_modes (CoglOnscreen *onscreen)
|
2016-06-08 09:05:31 +00:00
|
|
|
{
|
2017-07-25 02:21:04 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
|
|
|
MetaRendererNative *renderer_native = onscreen_native->renderer_native;
|
|
|
|
MetaGpuKms *render_gpu = onscreen_native->render_gpu;
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
2016-06-08 09:05:31 +00:00
|
|
|
MetaRendererView *view = onscreen_native->view;
|
2016-08-18 03:28:59 +00:00
|
|
|
uint32_t fb_id = 0;
|
2016-11-25 06:31:38 +00:00
|
|
|
MetaLogicalMonitor *logical_monitor;
|
2016-06-08 09:05:31 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
2017-07-25 02:21:04 +00:00
|
|
|
render_gpu);
|
2017-07-10 10:19:32 +00:00
|
|
|
switch (renderer_gpu_data->mode)
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
|
|
|
case META_RENDERER_NATIVE_MODE_GBM:
|
2019-05-20 19:20:17 +00:00
|
|
|
fb_id = meta_drm_buffer_get_fb_id (onscreen_native->gbm.next_fb);
|
2016-08-18 03:28:59 +00:00
|
|
|
break;
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
|
|
|
fb_id = onscreen_native->egl.dumb_fb.fb_id;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert (fb_id != 0);
|
|
|
|
|
2016-11-25 06:31:38 +00:00
|
|
|
logical_monitor = meta_renderer_view_get_logical_monitor (view);
|
|
|
|
if (logical_monitor)
|
2016-06-08 09:05:31 +00:00
|
|
|
{
|
2017-03-28 04:17:38 +00:00
|
|
|
SetCrtcFbData data = {
|
2017-07-25 02:21:04 +00:00
|
|
|
.onscreen = onscreen,
|
2017-07-06 08:00:56 +00:00
|
|
|
.fb_id = fb_id
|
2017-03-28 04:17:38 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
meta_logical_monitor_foreach_crtc (logical_monitor,
|
2019-02-12 18:10:59 +00:00
|
|
|
set_crtc_fb_cb,
|
2017-03-28 04:17:38 +00:00
|
|
|
&data);
|
2016-06-08 09:05:31 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-03-28 04:35:19 +00:00
|
|
|
GList *l;
|
2016-06-08 09:05:31 +00:00
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
for (l = meta_gpu_get_crtcs (META_GPU (render_gpu)); l; l = l->next)
|
2016-06-08 09:05:31 +00:00
|
|
|
{
|
2017-03-28 04:35:19 +00:00
|
|
|
MetaCrtc *crtc = l->data;
|
2016-06-08 09:05:31 +00:00
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
meta_gpu_kms_apply_crtc_mode (render_gpu,
|
2017-07-10 10:19:32 +00:00
|
|
|
crtc,
|
|
|
|
crtc->rect.x, crtc->rect.y,
|
|
|
|
fb_id);
|
2016-06-08 09:05:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-12 18:10:59 +00:00
|
|
|
static gboolean
|
|
|
|
crtc_mode_set_fallback (CoglOnscreen *onscreen,
|
|
|
|
MetaLogicalMonitor *logical_monitor,
|
|
|
|
MetaCrtc *crtc)
|
|
|
|
{
|
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
|
|
|
MetaGpuKms *render_gpu = onscreen_native->render_gpu;
|
|
|
|
MetaRendererNative *renderer_native;
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
uint32_t fb_id;
|
|
|
|
static gboolean warned_once = FALSE;
|
|
|
|
|
|
|
|
if (!warned_once)
|
|
|
|
{
|
|
|
|
g_warning ("Page flipping not supported by driver, "
|
|
|
|
"relying on the clock from now on");
|
|
|
|
warned_once = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
renderer_native = meta_renderer_native_from_gpu (render_gpu);
|
|
|
|
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
|
|
|
render_gpu);
|
|
|
|
if (renderer_gpu_data->mode != META_RENDERER_NATIVE_MODE_GBM)
|
|
|
|
{
|
|
|
|
g_warning ("Mode set fallback not handled for EGLStreams");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2019-05-20 19:20:17 +00:00
|
|
|
fb_id = meta_drm_buffer_get_fb_id (onscreen_native->gbm.next_fb);
|
2019-02-12 18:10:59 +00:00
|
|
|
set_crtc_fb (onscreen, logical_monitor, crtc, fb_id);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-03-28 04:17:38 +00:00
|
|
|
typedef struct _FlipCrtcData
|
|
|
|
{
|
2017-07-25 02:21:04 +00:00
|
|
|
CoglOnscreen *onscreen;
|
2017-03-28 04:17:38 +00:00
|
|
|
GClosure *flip_closure;
|
|
|
|
|
2019-02-12 18:10:59 +00:00
|
|
|
gboolean did_flip;
|
|
|
|
gboolean did_mode_set;
|
2017-03-28 04:17:38 +00:00
|
|
|
} FlipCrtcData;
|
|
|
|
|
|
|
|
static void
|
|
|
|
flip_crtc (MetaLogicalMonitor *logical_monitor,
|
|
|
|
MetaCrtc *crtc,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
FlipCrtcData *data = user_data;
|
2019-02-12 18:10:59 +00:00
|
|
|
GError *error = NULL;
|
2017-03-28 04:17:38 +00:00
|
|
|
|
2019-02-12 18:10:59 +00:00
|
|
|
if (!meta_onscreen_native_flip_crtc (data->onscreen,
|
|
|
|
data->flip_closure,
|
|
|
|
crtc,
|
|
|
|
&error))
|
|
|
|
{
|
|
|
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT))
|
|
|
|
{
|
|
|
|
if (crtc_mode_set_fallback (data->onscreen, logical_monitor, crtc))
|
|
|
|
data->did_mode_set = TRUE;
|
|
|
|
}
|
|
|
|
else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED))
|
|
|
|
{
|
|
|
|
g_warning ("Failed to flip onscreen: %s", error->message);
|
|
|
|
}
|
|
|
|
g_error_free (error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
data->did_flip = TRUE;
|
|
|
|
}
|
2017-03-28 04:17:38 +00:00
|
|
|
}
|
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
static void
|
|
|
|
meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen)
|
|
|
|
{
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
2016-06-08 09:05:31 +00:00
|
|
|
MetaRendererView *view = onscreen_native->view;
|
2019-03-25 09:24:46 +00:00
|
|
|
MetaRendererNative *renderer_native = onscreen_native->renderer_native;
|
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
|
2016-06-08 09:05:31 +00:00
|
|
|
GClosure *flip_closure;
|
2019-03-25 09:24:46 +00:00
|
|
|
MetaPowerSave power_save_mode;
|
2016-11-25 06:31:38 +00:00
|
|
|
MetaLogicalMonitor *logical_monitor;
|
2016-06-08 09:05:31 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a closure that either will be invoked or destructed.
|
|
|
|
* Invoking the closure represents a completed flip. If the closure
|
|
|
|
* is destructed before being invoked, the framebuffer references will be
|
|
|
|
* cleaned up accordingly.
|
|
|
|
*
|
|
|
|
* Each successful flip will each own one reference to the closure, thus keep
|
|
|
|
* it alive until either invoked or destructed. If flipping failed, the
|
|
|
|
* closure will be destructed before this function goes out of scope.
|
|
|
|
*/
|
|
|
|
flip_closure = g_cclosure_new (G_CALLBACK (on_crtc_flipped),
|
|
|
|
g_object_ref (view),
|
|
|
|
(GClosureNotify) flip_closure_destroyed);
|
2018-06-27 09:19:27 +00:00
|
|
|
g_closure_set_marshal (flip_closure, meta_marshal_VOID__OBJECT_OBJECT_INT64);
|
2016-06-08 09:05:31 +00:00
|
|
|
|
2019-03-25 09:24:46 +00:00
|
|
|
power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
|
|
|
|
if (power_save_mode == META_POWER_SAVE_ON)
|
|
|
|
{
|
|
|
|
FlipCrtcData data = {
|
|
|
|
.onscreen = onscreen,
|
|
|
|
.flip_closure = flip_closure,
|
|
|
|
};
|
|
|
|
logical_monitor = meta_renderer_view_get_logical_monitor (view);
|
|
|
|
meta_logical_monitor_foreach_crtc (logical_monitor, flip_crtc, &data);
|
2017-07-25 02:21:04 +00:00
|
|
|
|
2019-03-25 09:24:46 +00:00
|
|
|
/*
|
|
|
|
* If we didn't queue a page flip, but instead directly changed the mode
|
|
|
|
* due to the driver not supporting mode setting, we must swap the
|
|
|
|
* buffers directly as we won't get a page flip callback.
|
|
|
|
*/
|
|
|
|
if (!data.did_flip && data.did_mode_set)
|
|
|
|
meta_onscreen_native_swap_drm_fb (onscreen);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
queue_dummy_power_save_page_flip (renderer_native, flip_closure);
|
|
|
|
}
|
2017-07-25 02:21:04 +00:00
|
|
|
|
|
|
|
onscreen_native->pending_queue_swap_notify = TRUE;
|
|
|
|
|
|
|
|
g_closure_unref (flip_closure);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wait_for_pending_flips (CoglOnscreen *onscreen)
|
|
|
|
{
|
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
|
|
|
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, onscreen_native->secondary_gpu_states);
|
|
|
|
while (g_hash_table_iter_next (&iter,
|
|
|
|
NULL,
|
|
|
|
(gpointer *) &secondary_gpu_state))
|
|
|
|
{
|
|
|
|
while (secondary_gpu_state->pending_flips)
|
|
|
|
meta_gpu_kms_wait_for_flip (secondary_gpu_state->gpu_kms, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (onscreen_native->total_pending_flips)
|
|
|
|
meta_gpu_kms_wait_for_flip (onscreen_native->render_gpu, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
copy_shared_framebuffer_gpu (CoglOnscreen *onscreen,
|
|
|
|
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data,
|
|
|
|
gboolean *egl_context_changed)
|
|
|
|
{
|
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
|
|
|
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
|
|
|
|
MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
|
|
|
|
GError *error = NULL;
|
2019-05-20 20:08:35 +00:00
|
|
|
MetaDrmBufferGbm *buffer_gbm;
|
|
|
|
struct gbm_bo *bo;
|
2017-07-25 02:21:04 +00:00
|
|
|
|
|
|
|
if (!meta_egl_make_current (egl,
|
|
|
|
renderer_gpu_data->egl_display,
|
|
|
|
secondary_gpu_state->egl_surface,
|
|
|
|
secondary_gpu_state->egl_surface,
|
|
|
|
renderer_gpu_data->secondary.egl_context,
|
|
|
|
&error))
|
|
|
|
{
|
|
|
|
g_warning ("Failed to make current: %s", error->message);
|
|
|
|
g_error_free (error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
*egl_context_changed = TRUE;
|
|
|
|
|
2019-05-20 20:08:35 +00:00
|
|
|
buffer_gbm = META_DRM_BUFFER_GBM (onscreen_native->gbm.next_fb);
|
|
|
|
bo = meta_drm_buffer_gbm_get_bo (buffer_gbm);
|
2017-07-25 02:21:04 +00:00
|
|
|
if (!meta_renderer_native_gles3_blit_shared_bo (egl,
|
|
|
|
renderer_native->gles3,
|
|
|
|
renderer_gpu_data->egl_display,
|
|
|
|
renderer_gpu_data->secondary.egl_context,
|
|
|
|
secondary_gpu_state->egl_surface,
|
2019-05-20 20:08:35 +00:00
|
|
|
bo,
|
2017-07-25 02:21:04 +00:00
|
|
|
&error))
|
|
|
|
{
|
|
|
|
g_warning ("Failed to blit shared framebuffer: %s", error->message);
|
|
|
|
g_error_free (error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!meta_egl_swap_buffers (egl,
|
|
|
|
renderer_gpu_data->egl_display,
|
|
|
|
secondary_gpu_state->egl_surface,
|
|
|
|
&error))
|
|
|
|
{
|
|
|
|
g_warning ("Failed to swap buffers: %s", error->message);
|
|
|
|
g_error_free (error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-30 09:47:17 +00:00
|
|
|
g_clear_object (&secondary_gpu_state->gbm.next_fb);
|
2019-05-20 20:08:35 +00:00
|
|
|
buffer_gbm = meta_drm_buffer_gbm_new (secondary_gpu_state->gpu_kms,
|
|
|
|
secondary_gpu_state->gbm.surface,
|
|
|
|
renderer_native->use_modifiers,
|
|
|
|
&error);
|
|
|
|
secondary_gpu_state->gbm.next_fb = META_DRM_BUFFER (buffer_gbm);
|
2018-01-30 09:47:17 +00:00
|
|
|
if (!secondary_gpu_state->gbm.next_fb)
|
|
|
|
{
|
2019-05-20 20:08:35 +00:00
|
|
|
g_warning ("meta_drm_buffer_gbm_new failed: %s",
|
2018-01-30 09:47:17 +00:00
|
|
|
error->message);
|
|
|
|
g_error_free (error);
|
|
|
|
return;
|
|
|
|
}
|
2017-07-25 02:21:04 +00:00
|
|
|
}
|
|
|
|
|
2018-11-29 11:54:31 +00:00
|
|
|
static MetaDumbBuffer *
|
|
|
|
secondary_gpu_get_next_dumb_buffer (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
|
|
|
|
{
|
|
|
|
MetaDumbBuffer *current_dumb_fb;
|
|
|
|
|
|
|
|
current_dumb_fb = secondary_gpu_state->cpu.dumb_fb;
|
|
|
|
if (current_dumb_fb == &secondary_gpu_state->cpu.dumb_fbs[0])
|
|
|
|
return &secondary_gpu_state->cpu.dumb_fbs[1];
|
|
|
|
else
|
|
|
|
return &secondary_gpu_state->cpu.dumb_fbs[0];
|
|
|
|
}
|
|
|
|
|
renderer/native: use cogl for CPU copy path
Use cogl_framebuffer_read_pixels_into_bitmap () instead of
glReadPixels () for the CPU copy path in multi-GPU support.
The cogl function employs several tricks to make the read-pixels as fast
as possible and does the y-flip as necessary. This should make the copy
more performant over all kinds of hardware.
This is expected to be used on virtual outputs (e.g. DisplayLink USB
docks and monitors) foremost, where the dumb buffer memory is just
regular system memory. If the dumb buffer memory is somehow slow, like
residing in discrete VRAM or having an unexpected caching mode, it may
be possible for the cogl function perform worse because it might do the
y-flip in-place in the dumb buffer. Hopefully that does not happen in
any practical scenario.
Calling meta_renderer_native_gles3_read_pixels () here was conceptually
wrong to begin with because it was done with the Cogl GL context of the
primary GPU, not on the GL ES 3 context of a secondary GPU. However,
due eglBindAPI being a no-op in Mesa and the glReadPixels () arguments
being compatible, it worked.
This patch adds a pixel format conversion table between DRM and Cogl
formats. It contains more formats than absolutely necessary and the
texture components field which is currently unused for completeness. See
Mutter issue #323. Making the table more complete documents better how
the pixel formats actually map so that posterity should be less likely
to be confused. This table could be shared with
shm_buffer_get_cogl_pixel_format () as well, but not with
meta_wayland_dma_buf_buffer_attach ().
On HP ProBook 4520s laptop (Mesa DRI Intel(R) Ironlake Mobile, Mesa
18.0.5), without this patch copy_shared_framebuffer_cpu () for a
DisplayLink output takes 5 seconds with a 1080p frame. Obviously that
makes Mutter and gnome-shell completely unusable. With this patch, that
function takes 13-18 ms which makes it usable if not fluent.
On Intel i7-4790 (Mesa DRI Intel(R) Haswell Desktop) machine, this patch
makes no significant difference (the copy takes 4-5 ms).
2018-09-27 13:42:19 +00:00
|
|
|
typedef struct _PixelFormatMap {
|
|
|
|
uint32_t drm_format;
|
|
|
|
CoglPixelFormat cogl_format;
|
|
|
|
CoglTextureComponents cogl_components;
|
|
|
|
} PixelFormatMap;
|
|
|
|
|
|
|
|
static const PixelFormatMap pixel_format_map[] = {
|
|
|
|
/* DRM formats are defined as little-endian, not machine endian. */
|
|
|
|
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
|
|
|
{ DRM_FORMAT_RGB565, COGL_PIXEL_FORMAT_RGB_565, COGL_TEXTURE_COMPONENTS_RGB },
|
|
|
|
{ DRM_FORMAT_ABGR8888, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
|
|
|
|
{ DRM_FORMAT_XBGR8888, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
|
|
|
|
{ DRM_FORMAT_ARGB8888, COGL_PIXEL_FORMAT_BGRA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
|
|
|
|
{ DRM_FORMAT_XRGB8888, COGL_PIXEL_FORMAT_BGRA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
|
|
|
|
{ DRM_FORMAT_BGRA8888, COGL_PIXEL_FORMAT_ARGB_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
|
|
|
|
{ DRM_FORMAT_BGRX8888, COGL_PIXEL_FORMAT_ARGB_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
|
|
|
|
{ DRM_FORMAT_RGBA8888, COGL_PIXEL_FORMAT_ABGR_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
|
|
|
|
{ DRM_FORMAT_RGBX8888, COGL_PIXEL_FORMAT_ABGR_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
|
|
|
|
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
|
|
|
/* DRM_FORMAT_RGB565 cannot be expressed. */
|
|
|
|
{ DRM_FORMAT_ABGR8888, COGL_PIXEL_FORMAT_ABGR_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
|
|
|
|
{ DRM_FORMAT_XBGR8888, COGL_PIXEL_FORMAT_ABGR_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
|
|
|
|
{ DRM_FORMAT_ARGB8888, COGL_PIXEL_FORMAT_ARGB_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
|
|
|
|
{ DRM_FORMAT_XRGB8888, COGL_PIXEL_FORMAT_ARGB_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
|
|
|
|
{ DRM_FORMAT_BGRA8888, COGL_PIXEL_FORMAT_BGRA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
|
|
|
|
{ DRM_FORMAT_BGRX8888, COGL_PIXEL_FORMAT_BGRA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
|
|
|
|
{ DRM_FORMAT_RGBA8888, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGBA },
|
|
|
|
{ DRM_FORMAT_RGBX8888, COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_TEXTURE_COMPONENTS_RGB },
|
|
|
|
#else
|
|
|
|
#error "unexpected G_BYTE_ORDER"
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
cogl_pixel_format_from_drm_format (uint32_t drm_format,
|
|
|
|
CoglPixelFormat *out_format,
|
|
|
|
CoglTextureComponents *out_components)
|
|
|
|
{
|
|
|
|
const size_t n = G_N_ELEMENTS (pixel_format_map);
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
if (pixel_format_map[i].drm_format == drm_format)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == n)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (out_format)
|
|
|
|
*out_format = pixel_format_map[i].cogl_format;
|
|
|
|
|
|
|
|
if (out_components)
|
|
|
|
*out_components = pixel_format_map[i].cogl_components;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
static void
|
|
|
|
copy_shared_framebuffer_cpu (CoglOnscreen *onscreen,
|
|
|
|
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data)
|
|
|
|
{
|
|
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
renderer/native: use cogl for CPU copy path
Use cogl_framebuffer_read_pixels_into_bitmap () instead of
glReadPixels () for the CPU copy path in multi-GPU support.
The cogl function employs several tricks to make the read-pixels as fast
as possible and does the y-flip as necessary. This should make the copy
more performant over all kinds of hardware.
This is expected to be used on virtual outputs (e.g. DisplayLink USB
docks and monitors) foremost, where the dumb buffer memory is just
regular system memory. If the dumb buffer memory is somehow slow, like
residing in discrete VRAM or having an unexpected caching mode, it may
be possible for the cogl function perform worse because it might do the
y-flip in-place in the dumb buffer. Hopefully that does not happen in
any practical scenario.
Calling meta_renderer_native_gles3_read_pixels () here was conceptually
wrong to begin with because it was done with the Cogl GL context of the
primary GPU, not on the GL ES 3 context of a secondary GPU. However,
due eglBindAPI being a no-op in Mesa and the glReadPixels () arguments
being compatible, it worked.
This patch adds a pixel format conversion table between DRM and Cogl
formats. It contains more formats than absolutely necessary and the
texture components field which is currently unused for completeness. See
Mutter issue #323. Making the table more complete documents better how
the pixel formats actually map so that posterity should be less likely
to be confused. This table could be shared with
shm_buffer_get_cogl_pixel_format () as well, but not with
meta_wayland_dma_buf_buffer_attach ().
On HP ProBook 4520s laptop (Mesa DRI Intel(R) Ironlake Mobile, Mesa
18.0.5), without this patch copy_shared_framebuffer_cpu () for a
DisplayLink output takes 5 seconds with a 1080p frame. Obviously that
makes Mutter and gnome-shell completely unusable. With this patch, that
function takes 13-18 ms which makes it usable if not fluent.
On Intel i7-4790 (Mesa DRI Intel(R) Haswell Desktop) machine, this patch
makes no significant difference (the copy takes 4-5 ms).
2018-09-27 13:42:19 +00:00
|
|
|
CoglContext *cogl_context = framebuffer->context;
|
2018-11-29 11:54:31 +00:00
|
|
|
MetaDumbBuffer *dumb_fb;
|
renderer/native: use cogl for CPU copy path
Use cogl_framebuffer_read_pixels_into_bitmap () instead of
glReadPixels () for the CPU copy path in multi-GPU support.
The cogl function employs several tricks to make the read-pixels as fast
as possible and does the y-flip as necessary. This should make the copy
more performant over all kinds of hardware.
This is expected to be used on virtual outputs (e.g. DisplayLink USB
docks and monitors) foremost, where the dumb buffer memory is just
regular system memory. If the dumb buffer memory is somehow slow, like
residing in discrete VRAM or having an unexpected caching mode, it may
be possible for the cogl function perform worse because it might do the
y-flip in-place in the dumb buffer. Hopefully that does not happen in
any practical scenario.
Calling meta_renderer_native_gles3_read_pixels () here was conceptually
wrong to begin with because it was done with the Cogl GL context of the
primary GPU, not on the GL ES 3 context of a secondary GPU. However,
due eglBindAPI being a no-op in Mesa and the glReadPixels () arguments
being compatible, it worked.
This patch adds a pixel format conversion table between DRM and Cogl
formats. It contains more formats than absolutely necessary and the
texture components field which is currently unused for completeness. See
Mutter issue #323. Making the table more complete documents better how
the pixel formats actually map so that posterity should be less likely
to be confused. This table could be shared with
shm_buffer_get_cogl_pixel_format () as well, but not with
meta_wayland_dma_buf_buffer_attach ().
On HP ProBook 4520s laptop (Mesa DRI Intel(R) Ironlake Mobile, Mesa
18.0.5), without this patch copy_shared_framebuffer_cpu () for a
DisplayLink output takes 5 seconds with a 1080p frame. Obviously that
makes Mutter and gnome-shell completely unusable. With this patch, that
function takes 13-18 ms which makes it usable if not fluent.
On Intel i7-4790 (Mesa DRI Intel(R) Haswell Desktop) machine, this patch
makes no significant difference (the copy takes 4-5 ms).
2018-09-27 13:42:19 +00:00
|
|
|
CoglBitmap *dumb_bitmap;
|
|
|
|
CoglPixelFormat cogl_format;
|
|
|
|
gboolean ret;
|
2019-05-20 20:08:35 +00:00
|
|
|
MetaDrmBufferDumb *buffer_dumb;
|
2017-07-25 02:21:04 +00:00
|
|
|
|
2018-11-29 11:54:31 +00:00
|
|
|
dumb_fb = secondary_gpu_get_next_dumb_buffer (secondary_gpu_state);
|
2018-09-05 08:48:08 +00:00
|
|
|
|
2018-11-29 11:54:31 +00:00
|
|
|
g_assert (cogl_framebuffer_get_width (framebuffer) == dumb_fb->width);
|
|
|
|
g_assert (cogl_framebuffer_get_height (framebuffer) == dumb_fb->height);
|
renderer/native: use cogl for CPU copy path
Use cogl_framebuffer_read_pixels_into_bitmap () instead of
glReadPixels () for the CPU copy path in multi-GPU support.
The cogl function employs several tricks to make the read-pixels as fast
as possible and does the y-flip as necessary. This should make the copy
more performant over all kinds of hardware.
This is expected to be used on virtual outputs (e.g. DisplayLink USB
docks and monitors) foremost, where the dumb buffer memory is just
regular system memory. If the dumb buffer memory is somehow slow, like
residing in discrete VRAM or having an unexpected caching mode, it may
be possible for the cogl function perform worse because it might do the
y-flip in-place in the dumb buffer. Hopefully that does not happen in
any practical scenario.
Calling meta_renderer_native_gles3_read_pixels () here was conceptually
wrong to begin with because it was done with the Cogl GL context of the
primary GPU, not on the GL ES 3 context of a secondary GPU. However,
due eglBindAPI being a no-op in Mesa and the glReadPixels () arguments
being compatible, it worked.
This patch adds a pixel format conversion table between DRM and Cogl
formats. It contains more formats than absolutely necessary and the
texture components field which is currently unused for completeness. See
Mutter issue #323. Making the table more complete documents better how
the pixel formats actually map so that posterity should be less likely
to be confused. This table could be shared with
shm_buffer_get_cogl_pixel_format () as well, but not with
meta_wayland_dma_buf_buffer_attach ().
On HP ProBook 4520s laptop (Mesa DRI Intel(R) Ironlake Mobile, Mesa
18.0.5), without this patch copy_shared_framebuffer_cpu () for a
DisplayLink output takes 5 seconds with a 1080p frame. Obviously that
makes Mutter and gnome-shell completely unusable. With this patch, that
function takes 13-18 ms which makes it usable if not fluent.
On Intel i7-4790 (Mesa DRI Intel(R) Haswell Desktop) machine, this patch
makes no significant difference (the copy takes 4-5 ms).
2018-09-27 13:42:19 +00:00
|
|
|
|
2018-11-29 11:54:31 +00:00
|
|
|
ret = cogl_pixel_format_from_drm_format (dumb_fb->drm_format,
|
renderer/native: use cogl for CPU copy path
Use cogl_framebuffer_read_pixels_into_bitmap () instead of
glReadPixels () for the CPU copy path in multi-GPU support.
The cogl function employs several tricks to make the read-pixels as fast
as possible and does the y-flip as necessary. This should make the copy
more performant over all kinds of hardware.
This is expected to be used on virtual outputs (e.g. DisplayLink USB
docks and monitors) foremost, where the dumb buffer memory is just
regular system memory. If the dumb buffer memory is somehow slow, like
residing in discrete VRAM or having an unexpected caching mode, it may
be possible for the cogl function perform worse because it might do the
y-flip in-place in the dumb buffer. Hopefully that does not happen in
any practical scenario.
Calling meta_renderer_native_gles3_read_pixels () here was conceptually
wrong to begin with because it was done with the Cogl GL context of the
primary GPU, not on the GL ES 3 context of a secondary GPU. However,
due eglBindAPI being a no-op in Mesa and the glReadPixels () arguments
being compatible, it worked.
This patch adds a pixel format conversion table between DRM and Cogl
formats. It contains more formats than absolutely necessary and the
texture components field which is currently unused for completeness. See
Mutter issue #323. Making the table more complete documents better how
the pixel formats actually map so that posterity should be less likely
to be confused. This table could be shared with
shm_buffer_get_cogl_pixel_format () as well, but not with
meta_wayland_dma_buf_buffer_attach ().
On HP ProBook 4520s laptop (Mesa DRI Intel(R) Ironlake Mobile, Mesa
18.0.5), without this patch copy_shared_framebuffer_cpu () for a
DisplayLink output takes 5 seconds with a 1080p frame. Obviously that
makes Mutter and gnome-shell completely unusable. With this patch, that
function takes 13-18 ms which makes it usable if not fluent.
On Intel i7-4790 (Mesa DRI Intel(R) Haswell Desktop) machine, this patch
makes no significant difference (the copy takes 4-5 ms).
2018-09-27 13:42:19 +00:00
|
|
|
&cogl_format,
|
|
|
|
NULL);
|
|
|
|
g_assert (ret);
|
|
|
|
|
|
|
|
dumb_bitmap = cogl_bitmap_new_for_data (cogl_context,
|
2018-11-29 11:54:31 +00:00
|
|
|
dumb_fb->width,
|
|
|
|
dumb_fb->height,
|
renderer/native: use cogl for CPU copy path
Use cogl_framebuffer_read_pixels_into_bitmap () instead of
glReadPixels () for the CPU copy path in multi-GPU support.
The cogl function employs several tricks to make the read-pixels as fast
as possible and does the y-flip as necessary. This should make the copy
more performant over all kinds of hardware.
This is expected to be used on virtual outputs (e.g. DisplayLink USB
docks and monitors) foremost, where the dumb buffer memory is just
regular system memory. If the dumb buffer memory is somehow slow, like
residing in discrete VRAM or having an unexpected caching mode, it may
be possible for the cogl function perform worse because it might do the
y-flip in-place in the dumb buffer. Hopefully that does not happen in
any practical scenario.
Calling meta_renderer_native_gles3_read_pixels () here was conceptually
wrong to begin with because it was done with the Cogl GL context of the
primary GPU, not on the GL ES 3 context of a secondary GPU. However,
due eglBindAPI being a no-op in Mesa and the glReadPixels () arguments
being compatible, it worked.
This patch adds a pixel format conversion table between DRM and Cogl
formats. It contains more formats than absolutely necessary and the
texture components field which is currently unused for completeness. See
Mutter issue #323. Making the table more complete documents better how
the pixel formats actually map so that posterity should be less likely
to be confused. This table could be shared with
shm_buffer_get_cogl_pixel_format () as well, but not with
meta_wayland_dma_buf_buffer_attach ().
On HP ProBook 4520s laptop (Mesa DRI Intel(R) Ironlake Mobile, Mesa
18.0.5), without this patch copy_shared_framebuffer_cpu () for a
DisplayLink output takes 5 seconds with a 1080p frame. Obviously that
makes Mutter and gnome-shell completely unusable. With this patch, that
function takes 13-18 ms which makes it usable if not fluent.
On Intel i7-4790 (Mesa DRI Intel(R) Haswell Desktop) machine, this patch
makes no significant difference (the copy takes 4-5 ms).
2018-09-27 13:42:19 +00:00
|
|
|
cogl_format,
|
2018-11-29 11:54:31 +00:00
|
|
|
dumb_fb->stride_bytes,
|
|
|
|
dumb_fb->map);
|
renderer/native: use cogl for CPU copy path
Use cogl_framebuffer_read_pixels_into_bitmap () instead of
glReadPixels () for the CPU copy path in multi-GPU support.
The cogl function employs several tricks to make the read-pixels as fast
as possible and does the y-flip as necessary. This should make the copy
more performant over all kinds of hardware.
This is expected to be used on virtual outputs (e.g. DisplayLink USB
docks and monitors) foremost, where the dumb buffer memory is just
regular system memory. If the dumb buffer memory is somehow slow, like
residing in discrete VRAM or having an unexpected caching mode, it may
be possible for the cogl function perform worse because it might do the
y-flip in-place in the dumb buffer. Hopefully that does not happen in
any practical scenario.
Calling meta_renderer_native_gles3_read_pixels () here was conceptually
wrong to begin with because it was done with the Cogl GL context of the
primary GPU, not on the GL ES 3 context of a secondary GPU. However,
due eglBindAPI being a no-op in Mesa and the glReadPixels () arguments
being compatible, it worked.
This patch adds a pixel format conversion table between DRM and Cogl
formats. It contains more formats than absolutely necessary and the
texture components field which is currently unused for completeness. See
Mutter issue #323. Making the table more complete documents better how
the pixel formats actually map so that posterity should be less likely
to be confused. This table could be shared with
shm_buffer_get_cogl_pixel_format () as well, but not with
meta_wayland_dma_buf_buffer_attach ().
On HP ProBook 4520s laptop (Mesa DRI Intel(R) Ironlake Mobile, Mesa
18.0.5), without this patch copy_shared_framebuffer_cpu () for a
DisplayLink output takes 5 seconds with a 1080p frame. Obviously that
makes Mutter and gnome-shell completely unusable. With this patch, that
function takes 13-18 ms which makes it usable if not fluent.
On Intel i7-4790 (Mesa DRI Intel(R) Haswell Desktop) machine, this patch
makes no significant difference (the copy takes 4-5 ms).
2018-09-27 13:42:19 +00:00
|
|
|
|
|
|
|
if (!cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
|
|
|
|
0 /* x */,
|
|
|
|
0 /* y */,
|
|
|
|
COGL_READ_PIXELS_COLOR_BUFFER,
|
|
|
|
dumb_bitmap))
|
|
|
|
g_warning ("Failed to CPU-copy to a secondary GPU output");
|
|
|
|
|
|
|
|
cogl_object_unref (dumb_bitmap);
|
2016-06-08 09:05:31 +00:00
|
|
|
|
2018-01-30 09:47:17 +00:00
|
|
|
g_clear_object (&secondary_gpu_state->gbm.next_fb);
|
2018-11-29 11:54:31 +00:00
|
|
|
buffer_dumb = meta_drm_buffer_dumb_new (dumb_fb->fb_id);
|
2019-05-20 20:08:35 +00:00
|
|
|
secondary_gpu_state->gbm.next_fb = META_DRM_BUFFER (buffer_dumb);
|
2018-11-29 11:54:31 +00:00
|
|
|
secondary_gpu_state->cpu.dumb_fb = dumb_fb;
|
2017-07-25 02:21:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen)
|
|
|
|
{
|
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
|
|
|
GHashTableIter iter;
|
|
|
|
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, onscreen_native->secondary_gpu_states);
|
|
|
|
while (g_hash_table_iter_next (&iter,
|
|
|
|
NULL,
|
|
|
|
(gpointer *) &secondary_gpu_state))
|
2016-06-08 09:05:31 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
renderer_gpu_data = secondary_gpu_state->renderer_gpu_data;
|
|
|
|
switch (renderer_gpu_data->secondary.copy_mode)
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
2017-07-25 02:21:04 +00:00
|
|
|
case META_SHARED_FRAMEBUFFER_COPY_MODE_GPU:
|
|
|
|
/* Done after eglSwapBuffers. */
|
2016-08-18 03:28:59 +00:00
|
|
|
break;
|
2017-07-25 02:21:04 +00:00
|
|
|
case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
|
|
|
|
copy_shared_framebuffer_cpu (onscreen,
|
|
|
|
secondary_gpu_state,
|
|
|
|
renderer_gpu_data);
|
2016-08-18 03:28:59 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-06-08 09:05:31 +00:00
|
|
|
}
|
2016-05-12 06:55:06 +00:00
|
|
|
}
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
static void
|
|
|
|
update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen,
|
|
|
|
gboolean *egl_context_changed)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaRendererNative *renderer_native = onscreen_native->renderer_native;
|
|
|
|
GHashTableIter iter;
|
|
|
|
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, onscreen_native->secondary_gpu_states);
|
|
|
|
while (g_hash_table_iter_next (&iter,
|
|
|
|
NULL,
|
|
|
|
(gpointer *) &secondary_gpu_state))
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
renderer_gpu_data =
|
|
|
|
meta_renderer_native_get_gpu_data (renderer_native,
|
|
|
|
secondary_gpu_state->gpu_kms);
|
|
|
|
switch (renderer_gpu_data->secondary.copy_mode)
|
|
|
|
{
|
|
|
|
case META_SHARED_FRAMEBUFFER_COPY_MODE_GPU:
|
|
|
|
copy_shared_framebuffer_gpu (onscreen,
|
|
|
|
secondary_gpu_state,
|
|
|
|
renderer_gpu_data,
|
|
|
|
egl_context_changed);
|
|
|
|
break;
|
|
|
|
case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
|
|
|
|
/* Done before eglSwapBuffers. */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-09-29 14:33:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
|
|
|
|
const int *rectangles,
|
|
|
|
int n_rectangles)
|
|
|
|
{
|
|
|
|
CoglContext *cogl_context = COGL_FRAMEBUFFER (onscreen)->context;
|
2017-07-25 02:21:04 +00:00
|
|
|
CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
|
2016-09-29 14:33:02 +00:00
|
|
|
CoglRenderer *cogl_renderer = cogl_context->display->renderer;
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
|
|
|
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
|
2019-03-25 09:24:46 +00:00
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaGpuKms *render_gpu = onscreen_native->render_gpu;
|
2016-09-29 14:33:02 +00:00
|
|
|
CoglFrameInfo *frame_info;
|
2017-07-25 02:21:04 +00:00
|
|
|
gboolean egl_context_changed = FALSE;
|
2019-03-25 09:24:46 +00:00
|
|
|
MetaPowerSave power_save_mode;
|
2018-01-30 09:47:17 +00:00
|
|
|
g_autoptr (GError) error = NULL;
|
2019-05-20 20:08:35 +00:00
|
|
|
MetaDrmBufferGbm *buffer_gbm;
|
2016-09-29 14:33:02 +00:00
|
|
|
|
2018-10-04 10:53:17 +00:00
|
|
|
/*
|
|
|
|
* Wait for the flip callback before continuing, as we might have started the
|
|
|
|
* animation earlier due to the animation being driven by some other monitor.
|
|
|
|
*/
|
|
|
|
wait_for_pending_flips (onscreen);
|
|
|
|
|
2016-09-29 14:33:02 +00:00
|
|
|
frame_info = g_queue_peek_tail (&onscreen->pending_frame_infos);
|
|
|
|
frame_info->global_frame_counter = renderer_native->frame_counter;
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
update_secondary_gpu_state_pre_swap_buffers (onscreen);
|
2016-09-29 14:33:02 +00:00
|
|
|
|
|
|
|
parent_vtable->onscreen_swap_buffers_with_damage (onscreen,
|
|
|
|
rectangles,
|
|
|
|
n_rectangles);
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
2017-07-25 02:21:04 +00:00
|
|
|
render_gpu);
|
2017-07-10 10:19:32 +00:00
|
|
|
switch (renderer_gpu_data->mode)
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
|
|
|
case META_RENDERER_NATIVE_MODE_GBM:
|
2018-01-30 09:47:17 +00:00
|
|
|
g_warn_if_fail (onscreen_native->gbm.next_fb == NULL);
|
|
|
|
g_clear_object (&onscreen_native->gbm.next_fb);
|
2019-05-20 20:08:35 +00:00
|
|
|
|
|
|
|
buffer_gbm = meta_drm_buffer_gbm_new (render_gpu,
|
|
|
|
onscreen_native->gbm.surface,
|
|
|
|
renderer_native->use_modifiers,
|
|
|
|
&error);
|
|
|
|
onscreen_native->gbm.next_fb = META_DRM_BUFFER (buffer_gbm);
|
2018-01-30 09:47:17 +00:00
|
|
|
if (!onscreen_native->gbm.next_fb)
|
|
|
|
{
|
2019-05-20 20:08:35 +00:00
|
|
|
g_warning ("meta_drm_buffer_gbm_new failed: %s",
|
2018-01-30 09:47:17 +00:00
|
|
|
error->message);
|
|
|
|
return;
|
|
|
|
}
|
2016-08-18 03:28:59 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
2016-09-29 14:33:02 +00:00
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
update_secondary_gpu_state_post_swap_buffers (onscreen, &egl_context_changed);
|
|
|
|
|
2016-05-09 11:51:29 +00:00
|
|
|
/* If this is the first framebuffer to be presented then we now setup the
|
|
|
|
* crtc modes, else we flip from the previous buffer */
|
2019-03-25 09:24:46 +00:00
|
|
|
|
|
|
|
power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
|
|
|
|
if (onscreen_native->pending_set_crtc &&
|
|
|
|
power_save_mode == META_POWER_SAVE_ON)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2017-07-25 02:21:04 +00:00
|
|
|
meta_onscreen_native_set_crtc_modes (onscreen);
|
2016-06-08 09:05:31 +00:00
|
|
|
onscreen_native->pending_set_crtc = FALSE;
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
|
2016-12-05 18:18:24 +00:00
|
|
|
onscreen_native->pending_queue_swap_notify_frame_count = renderer_native->frame_counter;
|
2016-06-08 09:05:31 +00:00
|
|
|
meta_onscreen_native_flip_crtcs (onscreen);
|
2017-07-25 02:21:04 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we changed EGL context, cogl will have the wrong idea about what is
|
|
|
|
* current, making it fail to set it when it needs to. Avoid that by making
|
|
|
|
* EGL_NO_CONTEXT current now, making cogl eventually set the correct
|
|
|
|
* context.
|
|
|
|
*/
|
|
|
|
if (egl_context_changed)
|
2018-04-19 15:28:07 +00:00
|
|
|
_cogl_winsys_egl_ensure_current (cogl_display);
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
|
2016-08-18 02:21:12 +00:00
|
|
|
static gboolean
|
2016-06-01 09:53:07 +00:00
|
|
|
meta_renderer_native_init_egl_context (CoglContext *cogl_context,
|
2016-08-18 02:21:12 +00:00
|
|
|
GError **error)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2016-10-20 07:59:09 +00:00
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
CoglRenderer *cogl_renderer = cogl_context->display->renderer;
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
2016-10-20 07:59:09 +00:00
|
|
|
#endif
|
|
|
|
|
2018-11-30 07:22:00 +00:00
|
|
|
COGL_FLAGS_SET (cogl_context->features,
|
|
|
|
COGL_FEATURE_ID_PRESENTATION_TIME, TRUE);
|
2016-06-01 09:53:07 +00:00
|
|
|
COGL_FLAGS_SET (cogl_context->features,
|
2016-05-09 11:51:29 +00:00
|
|
|
COGL_FEATURE_ID_SWAP_BUFFERS_EVENT, TRUE);
|
|
|
|
/* TODO: remove this deprecated feature */
|
2016-06-01 09:53:07 +00:00
|
|
|
COGL_FLAGS_SET (cogl_context->winsys_features,
|
2016-05-09 11:51:29 +00:00
|
|
|
COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT,
|
|
|
|
TRUE);
|
2016-06-01 09:53:07 +00:00
|
|
|
COGL_FLAGS_SET (cogl_context->winsys_features,
|
2016-05-09 11:51:29 +00:00
|
|
|
COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT,
|
|
|
|
TRUE);
|
2016-06-08 09:05:31 +00:00
|
|
|
COGL_FLAGS_SET (cogl_context->winsys_features,
|
|
|
|
COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN,
|
|
|
|
TRUE);
|
|
|
|
|
2018-07-10 09:46:02 +00:00
|
|
|
/* COGL_WINSYS_FEATURE_SWAP_THROTTLE is always true for this renderer
|
|
|
|
* because we have the call to wait_for_pending_flips on every frame.
|
|
|
|
*/
|
|
|
|
COGL_FLAGS_SET (cogl_context->winsys_features,
|
|
|
|
COGL_WINSYS_FEATURE_SWAP_THROTTLE,
|
|
|
|
TRUE);
|
|
|
|
|
2016-10-20 07:59:09 +00:00
|
|
|
#ifdef HAVE_EGL_DEVICE
|
2017-07-25 02:21:04 +00:00
|
|
|
if (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_EGL_DEVICE)
|
2016-10-20 07:59:09 +00:00
|
|
|
COGL_FLAGS_SET (cogl_context->features,
|
|
|
|
COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL, TRUE);
|
|
|
|
#endif
|
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2017-07-25 02:21:04 +00:00
|
|
|
should_surface_be_sharable (CoglOnscreen *onscreen)
|
|
|
|
{
|
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
|
|
|
MetaRendererNative *renderer_native = onscreen_native->renderer_native;
|
|
|
|
CoglContext *cogl_context = COGL_FRAMEBUFFER (onscreen)->context;
|
|
|
|
CoglRenderer *cogl_renderer = cogl_context->display->renderer;
|
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
if (!onscreen_native->logical_monitor)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
for (l = meta_logical_monitor_get_monitors (onscreen_native->logical_monitor);
|
|
|
|
l;
|
|
|
|
l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
MetaGpuKms *gpu_kms = META_GPU_KMS (meta_monitor_get_gpu (monitor));
|
|
|
|
|
|
|
|
if (renderer_gpu_data != meta_renderer_native_get_gpu_data (renderer_native,
|
|
|
|
gpu_kms))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_renderer_native_create_surface_gbm (CoglOnscreen *onscreen,
|
2016-08-18 03:11:30 +00:00
|
|
|
int width,
|
|
|
|
int height,
|
|
|
|
struct gbm_surface **gbm_surface,
|
|
|
|
EGLSurface *egl_surface,
|
|
|
|
GError **error)
|
2016-06-08 09:05:31 +00:00
|
|
|
{
|
2017-07-25 02:21:04 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
|
|
|
MetaRendererNative *renderer_native = onscreen_native->renderer_native;
|
|
|
|
MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
|
|
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
|
|
|
CoglContext *cogl_context = framebuffer->context;
|
2016-06-08 09:05:31 +00:00
|
|
|
CoglDisplay *cogl_display = cogl_context->display;
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
|
2017-07-25 02:21:04 +00:00
|
|
|
CoglRenderer *cogl_renderer = cogl_display->renderer;
|
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
2018-04-02 16:14:53 +00:00
|
|
|
struct gbm_surface *new_gbm_surface = NULL;
|
2016-06-08 09:05:31 +00:00
|
|
|
EGLNativeWindowType egl_native_window;
|
|
|
|
EGLSurface new_egl_surface;
|
2017-08-03 14:42:50 +00:00
|
|
|
uint32_t format = GBM_FORMAT_XRGB8888;
|
|
|
|
GArray *modifiers;
|
2016-06-08 09:05:31 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
renderer_gpu_data =
|
|
|
|
meta_renderer_native_get_gpu_data (renderer_native,
|
2017-07-25 02:21:04 +00:00
|
|
|
onscreen_native->render_gpu);
|
2017-08-03 14:42:50 +00:00
|
|
|
|
2018-04-11 12:39:15 +00:00
|
|
|
if (renderer_native->use_modifiers)
|
|
|
|
modifiers = get_supported_modifiers (onscreen, format);
|
|
|
|
else
|
|
|
|
modifiers = NULL;
|
2017-08-03 14:42:50 +00:00
|
|
|
|
|
|
|
if (modifiers)
|
|
|
|
{
|
|
|
|
new_gbm_surface =
|
|
|
|
gbm_surface_create_with_modifiers (renderer_gpu_data->gbm.device,
|
|
|
|
width, height, format,
|
|
|
|
(uint64_t *) modifiers->data,
|
|
|
|
modifiers->len);
|
|
|
|
g_array_free (modifiers, TRUE);
|
|
|
|
}
|
2018-04-02 16:14:53 +00:00
|
|
|
|
|
|
|
if (!new_gbm_surface)
|
2017-08-03 14:42:50 +00:00
|
|
|
{
|
|
|
|
uint32_t flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
|
|
|
|
|
|
|
|
if (should_surface_be_sharable (onscreen))
|
|
|
|
flags |= GBM_BO_USE_LINEAR;
|
|
|
|
|
|
|
|
new_gbm_surface = gbm_surface_create (renderer_gpu_data->gbm.device,
|
|
|
|
width, height,
|
|
|
|
format,
|
|
|
|
flags);
|
|
|
|
}
|
2016-06-08 09:05:31 +00:00
|
|
|
|
|
|
|
if (!new_gbm_surface)
|
|
|
|
{
|
|
|
|
g_set_error (error, COGL_WINSYS_ERROR,
|
|
|
|
COGL_WINSYS_ERROR_CREATE_ONSCREEN,
|
|
|
|
"Failed to allocate surface");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
egl_native_window = (EGLNativeWindowType) new_gbm_surface;
|
2017-07-24 08:19:55 +00:00
|
|
|
new_egl_surface =
|
|
|
|
meta_egl_create_window_surface (egl,
|
|
|
|
cogl_renderer_egl->edpy,
|
|
|
|
cogl_display_egl->egl_config,
|
|
|
|
egl_native_window,
|
|
|
|
NULL,
|
|
|
|
error);
|
2016-06-08 09:05:31 +00:00
|
|
|
if (new_egl_surface == EGL_NO_SURFACE)
|
|
|
|
{
|
|
|
|
gbm_surface_destroy (new_gbm_surface);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*gbm_surface = new_gbm_surface;
|
|
|
|
*egl_surface = new_egl_surface;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2016-08-18 03:28:59 +00:00
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
static gboolean
|
2017-07-25 02:21:04 +00:00
|
|
|
meta_renderer_native_create_surface_egl_device (CoglOnscreen *onscreen,
|
2016-11-25 06:31:38 +00:00
|
|
|
MetaLogicalMonitor *logical_monitor,
|
2016-08-18 03:28:59 +00:00
|
|
|
int width,
|
|
|
|
int height,
|
|
|
|
EGLStreamKHR *out_egl_stream,
|
|
|
|
EGLSurface *out_egl_surface,
|
|
|
|
GError **error)
|
|
|
|
{
|
2017-07-25 02:21:04 +00:00
|
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
|
|
|
CoglContext *cogl_context = framebuffer->context;
|
|
|
|
CoglDisplay *cogl_display = cogl_context->display;
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
|
2016-08-18 03:28:59 +00:00
|
|
|
CoglRenderer *cogl_renderer = cogl_display->renderer;
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
|
|
|
|
MetaEgl *egl =
|
|
|
|
meta_renderer_native_get_egl (renderer_gpu_data->renderer_native);
|
|
|
|
EGLDisplay egl_display = renderer_gpu_data->egl_display;
|
2016-12-13 13:44:16 +00:00
|
|
|
MetaMonitor *monitor;
|
|
|
|
MetaOutput *output;
|
2017-11-03 10:25:30 +00:00
|
|
|
MetaCrtc *crtc;
|
2016-08-18 03:28:59 +00:00
|
|
|
EGLConfig egl_config;
|
|
|
|
EGLStreamKHR egl_stream;
|
|
|
|
EGLSurface egl_surface;
|
|
|
|
EGLint num_layers;
|
|
|
|
EGLOutputLayerEXT output_layer;
|
2016-12-13 13:44:16 +00:00
|
|
|
EGLAttrib output_attribs[3];
|
2016-08-18 03:28:59 +00:00
|
|
|
EGLint stream_attribs[] = {
|
2019-01-11 15:03:37 +00:00
|
|
|
EGL_STREAM_FIFO_LENGTH_KHR, 0,
|
2016-08-18 03:28:59 +00:00
|
|
|
EGL_CONSUMER_AUTO_ACQUIRE_EXT, EGL_FALSE,
|
|
|
|
EGL_NONE
|
|
|
|
};
|
|
|
|
EGLint stream_producer_attribs[] = {
|
|
|
|
EGL_WIDTH, width,
|
|
|
|
EGL_HEIGHT, height,
|
|
|
|
EGL_NONE
|
|
|
|
};
|
|
|
|
|
|
|
|
egl_stream = meta_egl_create_stream (egl, egl_display, stream_attribs, error);
|
|
|
|
if (egl_stream == EGL_NO_STREAM_KHR)
|
|
|
|
return FALSE;
|
|
|
|
|
2016-12-13 13:44:16 +00:00
|
|
|
monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
|
|
|
|
output = meta_monitor_get_main_output (monitor);
|
2017-11-03 10:25:30 +00:00
|
|
|
crtc = meta_output_get_assigned_crtc (output);
|
2016-12-13 13:44:16 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* An "logical_monitor" may have multiple outputs/crtcs in case its tiled,
|
|
|
|
* but as far as I can tell, EGL only allows you to pass one crtc_id, so
|
|
|
|
* lets pass the first one.
|
|
|
|
*/
|
|
|
|
output_attribs[0] = EGL_DRM_CRTC_EXT;
|
2017-11-03 10:25:30 +00:00
|
|
|
output_attribs[1] = crtc->crtc_id;
|
2016-12-13 13:44:16 +00:00
|
|
|
output_attribs[2] = EGL_NONE;
|
|
|
|
|
2016-08-18 03:28:59 +00:00
|
|
|
if (!meta_egl_get_output_layers (egl, egl_display,
|
|
|
|
output_attribs,
|
|
|
|
&output_layer, 1, &num_layers,
|
|
|
|
error))
|
|
|
|
{
|
|
|
|
meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num_layers < 1)
|
|
|
|
{
|
|
|
|
meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
G_IO_ERROR_FAILED,
|
|
|
|
"Unable to find output layers.");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!meta_egl_stream_consumer_output (egl, egl_display,
|
|
|
|
egl_stream, output_layer,
|
|
|
|
error))
|
|
|
|
{
|
|
|
|
meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-07-14 07:20:41 +00:00
|
|
|
egl_config = cogl_display_egl->egl_config;
|
2016-08-18 03:28:59 +00:00
|
|
|
egl_surface = meta_egl_create_stream_producer_surface (egl,
|
|
|
|
egl_display,
|
|
|
|
egl_config,
|
|
|
|
egl_stream,
|
|
|
|
stream_producer_attribs,
|
|
|
|
error);
|
|
|
|
if (egl_surface == EGL_NO_SURFACE)
|
|
|
|
{
|
|
|
|
meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*out_egl_stream = egl_stream;
|
|
|
|
*out_egl_surface = egl_surface;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
2017-10-09 11:39:50 +00:00
|
|
|
#endif /* HAVE_EGL_DEVICE */
|
2016-08-18 03:28:59 +00:00
|
|
|
|
|
|
|
static gboolean
|
2017-07-24 07:38:46 +00:00
|
|
|
init_dumb_fb (MetaDumbBuffer *dumb_fb,
|
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
int width,
|
|
|
|
int height,
|
|
|
|
uint32_t format,
|
|
|
|
GError **error)
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
|
|
|
struct drm_mode_create_dumb create_arg;
|
|
|
|
struct drm_mode_destroy_dumb destroy_arg;
|
|
|
|
struct drm_mode_map_dumb map_arg;
|
|
|
|
uint32_t fb_id = 0;
|
|
|
|
void *map;
|
2017-07-06 08:00:56 +00:00
|
|
|
int kms_fd;
|
2018-01-09 15:50:37 +00:00
|
|
|
uint32_t handles[4] = { 0, };
|
|
|
|
uint32_t pitches[4] = { 0, };
|
|
|
|
uint32_t offsets[4] = { 0, };
|
2017-07-06 08:00:56 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
|
2016-08-18 03:28:59 +00:00
|
|
|
|
|
|
|
create_arg = (struct drm_mode_create_dumb) {
|
|
|
|
.bpp = 32, /* RGBX8888 */
|
|
|
|
.width = width,
|
|
|
|
.height = height
|
|
|
|
};
|
2017-07-06 08:00:56 +00:00
|
|
|
if (drmIoctl (kms_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg) != 0)
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
G_IO_ERROR_FAILED,
|
|
|
|
"Failed to create dumb drm buffer: %s",
|
|
|
|
g_strerror (errno));
|
|
|
|
goto err_ioctl;
|
|
|
|
}
|
|
|
|
|
2018-01-09 15:50:37 +00:00
|
|
|
handles[0] = create_arg.handle;
|
|
|
|
pitches[0] = create_arg.pitch;
|
2016-08-18 03:28:59 +00:00
|
|
|
|
2018-01-09 15:50:37 +00:00
|
|
|
if (drmModeAddFB2 (kms_fd, width, height, format,
|
|
|
|
handles, pitches, offsets,
|
|
|
|
&fb_id, 0) != 0)
|
|
|
|
{
|
|
|
|
g_debug ("drmModeAddFB2 failed (%s), falling back to drmModeAddFB",
|
|
|
|
g_strerror (errno));
|
2016-08-18 03:28:59 +00:00
|
|
|
}
|
|
|
|
|
2018-01-09 15:50:37 +00:00
|
|
|
if (fb_id == 0)
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
2018-09-05 07:38:09 +00:00
|
|
|
if (format != DRM_FORMAT_XRGB8888)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
G_IO_ERROR_FAILED,
|
|
|
|
"drmModeAddFB does not support format 0x%x",
|
|
|
|
format);
|
|
|
|
goto err_add_fb;
|
|
|
|
}
|
|
|
|
|
2017-07-06 08:00:56 +00:00
|
|
|
if (drmModeAddFB (kms_fd, width, height,
|
2016-08-18 03:28:59 +00:00
|
|
|
24 /* depth of RGBX8888 */,
|
|
|
|
32 /* bpp of RGBX8888 */,
|
|
|
|
create_arg.pitch,
|
|
|
|
create_arg.handle,
|
|
|
|
&fb_id) != 0)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
G_IO_ERROR_FAILED,
|
|
|
|
"drmModeAddFB failed: %s",
|
|
|
|
g_strerror (errno));
|
|
|
|
goto err_add_fb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
map_arg = (struct drm_mode_map_dumb) {
|
|
|
|
.handle = create_arg.handle
|
|
|
|
};
|
2017-07-06 08:00:56 +00:00
|
|
|
if (drmIoctl (kms_fd, DRM_IOCTL_MODE_MAP_DUMB,
|
2016-08-18 03:28:59 +00:00
|
|
|
&map_arg) != 0)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
G_IO_ERROR_FAILED,
|
|
|
|
"Failed to map dumb drm buffer: %s",
|
|
|
|
g_strerror (errno));
|
|
|
|
goto err_map_dumb;
|
|
|
|
}
|
|
|
|
|
|
|
|
map = mmap (NULL, create_arg.size, PROT_WRITE, MAP_SHARED,
|
2017-07-06 08:00:56 +00:00
|
|
|
kms_fd, map_arg.offset);
|
2016-08-18 03:28:59 +00:00
|
|
|
if (map == MAP_FAILED)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
G_IO_ERROR_FAILED,
|
|
|
|
"Failed to mmap dumb drm buffer memory: %s",
|
|
|
|
g_strerror (errno));
|
|
|
|
goto err_mmap;
|
|
|
|
}
|
|
|
|
|
2017-07-24 07:38:46 +00:00
|
|
|
dumb_fb->fb_id = fb_id;
|
|
|
|
dumb_fb->handle = create_arg.handle;
|
|
|
|
dumb_fb->map = map;
|
|
|
|
dumb_fb->map_size = create_arg.size;
|
2018-09-05 08:48:08 +00:00
|
|
|
dumb_fb->width = width;
|
|
|
|
dumb_fb->height = height;
|
2018-09-05 09:07:59 +00:00
|
|
|
dumb_fb->stride_bytes = create_arg.pitch;
|
2018-11-09 12:22:18 +00:00
|
|
|
dumb_fb->drm_format = format;
|
2016-08-18 03:28:59 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
err_mmap:
|
|
|
|
err_map_dumb:
|
2017-07-06 08:00:56 +00:00
|
|
|
drmModeRmFB (kms_fd, fb_id);
|
2016-08-18 03:28:59 +00:00
|
|
|
|
|
|
|
err_add_fb:
|
|
|
|
destroy_arg = (struct drm_mode_destroy_dumb) {
|
|
|
|
.handle = create_arg.handle
|
|
|
|
};
|
2017-07-06 08:00:56 +00:00
|
|
|
drmIoctl (kms_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
|
2016-08-18 03:28:59 +00:00
|
|
|
|
|
|
|
err_ioctl:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-07-24 07:38:46 +00:00
|
|
|
release_dumb_fb (MetaDumbBuffer *dumb_fb,
|
|
|
|
MetaGpuKms *gpu_kms)
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
|
|
|
struct drm_mode_destroy_dumb destroy_arg;
|
2017-07-06 08:00:56 +00:00
|
|
|
int kms_fd;
|
2016-08-18 03:28:59 +00:00
|
|
|
|
2017-07-24 07:38:46 +00:00
|
|
|
if (!dumb_fb->map)
|
2016-08-18 03:28:59 +00:00
|
|
|
return;
|
|
|
|
|
2017-07-24 07:38:46 +00:00
|
|
|
munmap (dumb_fb->map, dumb_fb->map_size);
|
|
|
|
dumb_fb->map = NULL;
|
2016-08-18 03:28:59 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
|
2017-07-06 08:00:56 +00:00
|
|
|
|
2017-07-24 07:38:46 +00:00
|
|
|
drmModeRmFB (kms_fd, dumb_fb->fb_id);
|
2016-08-18 03:28:59 +00:00
|
|
|
|
|
|
|
destroy_arg = (struct drm_mode_destroy_dumb) {
|
2017-07-24 07:38:46 +00:00
|
|
|
.handle = dumb_fb->handle
|
2016-08-18 03:28:59 +00:00
|
|
|
};
|
2017-07-06 08:00:56 +00:00
|
|
|
drmIoctl (kms_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
|
2016-08-18 03:28:59 +00:00
|
|
|
}
|
|
|
|
|
2016-08-18 02:21:12 +00:00
|
|
|
static gboolean
|
2016-05-27 07:13:09 +00:00
|
|
|
meta_renderer_native_init_onscreen (CoglOnscreen *onscreen,
|
2016-08-18 02:21:12 +00:00
|
|
|
GError **error)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
|
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
2016-06-01 09:53:07 +00:00
|
|
|
CoglContext *cogl_context = framebuffer->context;
|
|
|
|
CoglDisplay *cogl_display = cogl_context->display;
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
|
|
|
|
CoglOnscreenEGL *onscreen_egl;
|
2016-05-27 07:07:41 +00:00
|
|
|
MetaOnscreenNative *onscreen_native;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2017-07-14 07:20:41 +00:00
|
|
|
_COGL_RETURN_VAL_IF_FAIL (cogl_display_egl->egl_context, FALSE);
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
onscreen->winsys = g_slice_new0 (CoglOnscreenEGL);
|
2017-07-14 07:20:41 +00:00
|
|
|
onscreen_egl = onscreen->winsys;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2016-05-27 07:07:41 +00:00
|
|
|
onscreen_native = g_slice_new0 (MetaOnscreenNative);
|
2017-07-14 07:20:41 +00:00
|
|
|
onscreen_egl->platform = onscreen_native;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2016-09-29 14:46:34 +00:00
|
|
|
/*
|
|
|
|
* Don't actually initialize anything here, since we may not have the
|
|
|
|
* information available yet, and there is no way to pass it at this stage.
|
|
|
|
* To properly allocate a MetaOnscreenNative, the caller must call
|
|
|
|
* meta_onscreen_native_allocate() after cogl_framebuffer_allocate().
|
|
|
|
*
|
|
|
|
* TODO: Turn CoglFramebuffer/CoglOnscreen into GObjects, so it's possible
|
|
|
|
* to add backend specific properties.
|
|
|
|
*/
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_onscreen_native_allocate (CoglOnscreen *onscreen,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
2016-09-29 14:46:34 +00:00
|
|
|
struct gbm_surface *gbm_surface;
|
|
|
|
EGLSurface egl_surface;
|
|
|
|
int width;
|
|
|
|
int height;
|
2016-08-18 03:28:59 +00:00
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
MetaRendererView *view;
|
2016-11-25 06:31:38 +00:00
|
|
|
MetaLogicalMonitor *logical_monitor;
|
2016-08-18 03:28:59 +00:00
|
|
|
EGLStreamKHR egl_stream;
|
|
|
|
#endif
|
2016-09-29 14:46:34 +00:00
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
onscreen_native->pending_set_crtc = TRUE;
|
|
|
|
|
2016-05-09 11:51:29 +00:00
|
|
|
/* If a kms_fd is set then the display width and height
|
|
|
|
* won't be available until meta_renderer_native_set_layout
|
|
|
|
* is called. In that case, defer creating the surface
|
|
|
|
* until then.
|
|
|
|
*/
|
2016-06-08 09:05:31 +00:00
|
|
|
width = cogl_framebuffer_get_width (framebuffer);
|
|
|
|
height = cogl_framebuffer_get_height (framebuffer);
|
|
|
|
if (width == 0 || height == 0)
|
2016-05-09 11:51:29 +00:00
|
|
|
return TRUE;
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
renderer_gpu_data =
|
2017-07-25 02:21:04 +00:00
|
|
|
meta_renderer_native_get_gpu_data (onscreen_native->renderer_native,
|
|
|
|
onscreen_native->render_gpu);
|
2017-07-10 10:19:32 +00:00
|
|
|
switch (renderer_gpu_data->mode)
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
|
|
|
case META_RENDERER_NATIVE_MODE_GBM:
|
2017-07-25 02:21:04 +00:00
|
|
|
if (!meta_renderer_native_create_surface_gbm (onscreen,
|
2016-08-18 03:28:59 +00:00
|
|
|
width, height,
|
|
|
|
&gbm_surface,
|
|
|
|
&egl_surface,
|
|
|
|
error))
|
|
|
|
return FALSE;
|
2016-08-18 03:11:30 +00:00
|
|
|
|
2016-08-18 03:28:59 +00:00
|
|
|
onscreen_native->gbm.surface = gbm_surface;
|
2017-07-14 07:20:41 +00:00
|
|
|
onscreen_egl->egl_surface = egl_surface;
|
2016-08-18 03:28:59 +00:00
|
|
|
break;
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
2017-07-24 07:38:46 +00:00
|
|
|
if (!init_dumb_fb (&onscreen_native->egl.dumb_fb,
|
2017-07-25 02:21:04 +00:00
|
|
|
onscreen_native->render_gpu,
|
2017-07-24 07:38:46 +00:00
|
|
|
width, height,
|
2018-11-09 12:17:12 +00:00
|
|
|
DRM_FORMAT_XRGB8888,
|
2017-07-24 07:38:46 +00:00
|
|
|
error))
|
2016-08-18 03:28:59 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
view = onscreen_native->view;
|
2016-11-25 06:31:38 +00:00
|
|
|
logical_monitor = meta_renderer_view_get_logical_monitor (view);
|
2017-07-25 02:21:04 +00:00
|
|
|
if (!meta_renderer_native_create_surface_egl_device (onscreen,
|
2016-11-25 06:31:38 +00:00
|
|
|
logical_monitor,
|
2016-08-18 03:28:59 +00:00
|
|
|
width, height,
|
|
|
|
&egl_stream,
|
|
|
|
&egl_surface,
|
|
|
|
error))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
onscreen_native->egl.stream = egl_stream;
|
2017-07-14 07:20:41 +00:00
|
|
|
onscreen_egl->egl_surface = egl_surface;
|
2016-08-18 03:28:59 +00:00
|
|
|
break;
|
|
|
|
#endif /* HAVE_EGL_DEVICE */
|
|
|
|
}
|
2016-08-18 03:11:30 +00:00
|
|
|
|
|
|
|
return TRUE;
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-05-27 07:13:09 +00:00
|
|
|
meta_renderer_native_release_onscreen (CoglOnscreen *onscreen)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
|
|
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
2016-06-01 09:53:07 +00:00
|
|
|
CoglContext *cogl_context = framebuffer->context;
|
2019-06-17 16:18:42 +00:00
|
|
|
CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
|
|
|
|
CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
|
2016-06-01 09:53:07 +00:00
|
|
|
CoglRenderer *cogl_renderer = cogl_context->display->renderer;
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
|
2017-07-24 08:19:55 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
2016-05-27 07:07:41 +00:00
|
|
|
MetaOnscreenNative *onscreen_native;
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
/* If we never successfully allocated then there's nothing to do */
|
2017-07-14 07:20:41 +00:00
|
|
|
if (onscreen_egl == NULL)
|
2016-05-09 11:51:29 +00:00
|
|
|
return;
|
|
|
|
|
2017-07-14 07:20:41 +00:00
|
|
|
onscreen_native = onscreen_egl->platform;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2019-06-17 16:18:42 +00:00
|
|
|
if (onscreen_egl->egl_surface != EGL_NO_SURFACE &&
|
|
|
|
(cogl_display_egl->current_draw_surface == onscreen_egl->egl_surface ||
|
|
|
|
cogl_display_egl->current_read_surface == onscreen_egl->egl_surface))
|
|
|
|
{
|
|
|
|
if (!_cogl_winsys_egl_make_current (cogl_display,
|
|
|
|
cogl_display_egl->dummy_surface,
|
|
|
|
cogl_display_egl->dummy_surface,
|
|
|
|
cogl_display_egl->egl_context))
|
|
|
|
g_warning ("Failed to clear current context");
|
|
|
|
}
|
|
|
|
|
2019-02-12 18:10:59 +00:00
|
|
|
g_list_free_full (onscreen_native->pending_page_flip_retries,
|
|
|
|
(GDestroyNotify) retry_page_flip_data_free);
|
2019-03-29 19:56:57 +00:00
|
|
|
if (onscreen_native->retry_page_flips_source)
|
|
|
|
{
|
|
|
|
MetaBackend *backend =
|
|
|
|
backend_from_renderer_native (onscreen_native->renderer_native);
|
|
|
|
|
|
|
|
meta_backend_thaw_updates (backend);
|
|
|
|
g_clear_pointer (&onscreen_native->retry_page_flips_source,
|
|
|
|
g_source_destroy);
|
|
|
|
}
|
2019-02-12 18:10:59 +00:00
|
|
|
|
2017-07-14 07:20:41 +00:00
|
|
|
if (onscreen_egl->egl_surface != EGL_NO_SURFACE)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
|
|
|
|
|
2017-07-24 08:19:55 +00:00
|
|
|
meta_egl_destroy_surface (egl,
|
|
|
|
cogl_renderer_egl->edpy,
|
|
|
|
onscreen_egl->egl_surface,
|
|
|
|
NULL);
|
2017-07-14 07:20:41 +00:00
|
|
|
onscreen_egl->egl_surface = EGL_NO_SURFACE;
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
renderer_gpu_data =
|
2017-07-25 02:21:04 +00:00
|
|
|
meta_renderer_native_get_gpu_data (onscreen_native->renderer_native,
|
|
|
|
onscreen_native->render_gpu);
|
2017-07-10 10:19:32 +00:00
|
|
|
switch (renderer_gpu_data->mode)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2016-08-18 03:28:59 +00:00
|
|
|
case META_RENDERER_NATIVE_MODE_GBM:
|
|
|
|
/* flip state takes a reference on the onscreen so there should
|
|
|
|
* never be outstanding flips when we reach here. */
|
2018-01-30 09:47:17 +00:00
|
|
|
g_return_if_fail (onscreen_native->gbm.next_fb == NULL);
|
2016-08-18 03:28:59 +00:00
|
|
|
|
|
|
|
free_current_bo (onscreen);
|
|
|
|
|
|
|
|
if (onscreen_native->gbm.surface)
|
|
|
|
{
|
|
|
|
gbm_surface_destroy (onscreen_native->gbm.surface);
|
|
|
|
onscreen_native->gbm.surface = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
2017-07-24 07:38:46 +00:00
|
|
|
release_dumb_fb (&onscreen_native->egl.dumb_fb,
|
2017-07-25 02:21:04 +00:00
|
|
|
onscreen_native->render_gpu);
|
2016-08-18 03:28:59 +00:00
|
|
|
if (onscreen_native->egl.stream != EGL_NO_STREAM_KHR)
|
|
|
|
{
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
|
2016-08-18 03:28:59 +00:00
|
|
|
|
|
|
|
meta_egl_destroy_stream (egl,
|
2017-07-14 07:20:41 +00:00
|
|
|
cogl_renderer_egl->edpy,
|
2016-08-18 03:28:59 +00:00
|
|
|
onscreen_native->egl.stream,
|
|
|
|
NULL);
|
|
|
|
onscreen_native->egl.stream = EGL_NO_STREAM_KHR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif /* HAVE_EGL_DEVICE */
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
g_hash_table_destroy (onscreen_native->secondary_gpu_states);
|
|
|
|
|
2016-05-27 07:07:41 +00:00
|
|
|
g_slice_free (MetaOnscreenNative, onscreen_native);
|
2016-05-09 11:51:29 +00:00
|
|
|
g_slice_free (CoglOnscreenEGL, onscreen->winsys);
|
|
|
|
onscreen->winsys = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const CoglWinsysEGLVtable
|
|
|
|
_cogl_winsys_egl_vtable = {
|
2016-09-26 07:54:27 +00:00
|
|
|
.add_config_attributes = meta_renderer_native_add_egl_config_attributes,
|
2018-02-23 14:14:07 +00:00
|
|
|
.choose_config = meta_renderer_native_choose_egl_config,
|
2016-05-27 07:13:09 +00: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 11:51:29 +00:00
|
|
|
};
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
gboolean
|
|
|
|
meta_renderer_native_supports_mirroring (MetaRendererNative *renderer_native)
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
|
|
|
|
GList *l;
|
2016-08-18 03:28:59 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
for (l = monitor_manager->gpus; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaGpuKms *gpu_kms = META_GPU_KMS (l->data);
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
|
|
|
|
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
|
|
|
gpu_kms);
|
|
|
|
switch (renderer_gpu_data->mode)
|
|
|
|
{
|
|
|
|
case META_RENDERER_NATIVE_MODE_GBM:
|
|
|
|
break;
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
|
|
|
|
return FALSE;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native)
|
|
|
|
{
|
2016-06-08 09:05:31 +00:00
|
|
|
MetaRenderer *renderer = META_RENDERER (renderer_native);
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
for (l = meta_renderer_get_views (renderer); l; l = l->next)
|
|
|
|
{
|
|
|
|
ClutterStageView *stage_view = l->data;
|
|
|
|
CoglFramebuffer *framebuffer =
|
2016-08-01 00:44:57 +00:00
|
|
|
clutter_stage_view_get_onscreen (stage_view);
|
2016-06-08 09:05:31 +00:00
|
|
|
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
|
|
|
|
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
|
2016-06-08 09:05:31 +00:00
|
|
|
|
|
|
|
onscreen_native->pending_set_crtc = TRUE;
|
|
|
|
}
|
2017-09-28 15:59:27 +00:00
|
|
|
|
|
|
|
renderer_native->pending_unset_disabled_crtcs = TRUE;
|
2016-05-09 11:51:29 +00:00
|
|
|
}
|
|
|
|
|
2016-08-01 01:47:11 +00:00
|
|
|
static CoglOnscreen *
|
2017-07-25 02:21:04 +00:00
|
|
|
meta_renderer_native_create_onscreen (MetaRendererNative *renderer_native,
|
|
|
|
MetaGpuKms *render_gpu,
|
|
|
|
MetaLogicalMonitor *logical_monitor,
|
2017-07-10 10:19:32 +00:00
|
|
|
CoglContext *context,
|
|
|
|
MetaMonitorTransform transform,
|
|
|
|
gint view_width,
|
2017-07-24 09:35:55 +00:00
|
|
|
gint view_height,
|
|
|
|
GError **error)
|
2016-08-01 01:47:11 +00:00
|
|
|
{
|
|
|
|
CoglOnscreen *onscreen;
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl;
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaOnscreenNative *onscreen_native;
|
2016-08-01 01:47:11 +00:00
|
|
|
gint width, height;
|
2017-07-25 02:21:04 +00:00
|
|
|
GList *l;
|
2016-08-01 01:47:11 +00:00
|
|
|
|
|
|
|
if (meta_monitor_transform_is_rotated (transform))
|
|
|
|
{
|
|
|
|
width = view_height;
|
|
|
|
height = view_width;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
width = view_width;
|
|
|
|
height = view_height;
|
|
|
|
}
|
|
|
|
|
|
|
|
onscreen = cogl_onscreen_new (context, width, height);
|
2018-07-10 09:46:02 +00:00
|
|
|
|
2017-07-24 09:35:55 +00:00
|
|
|
if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (onscreen), error))
|
2016-08-01 01:47:11 +00:00
|
|
|
{
|
|
|
|
cogl_object_unref (onscreen);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-07-14 07:20:41 +00:00
|
|
|
onscreen_egl = onscreen->winsys;
|
|
|
|
onscreen_native = onscreen_egl->platform;
|
2017-07-25 02:21:04 +00:00
|
|
|
onscreen_native->renderer_native = renderer_native;
|
|
|
|
onscreen_native->render_gpu = render_gpu;
|
|
|
|
onscreen_native->logical_monitor = logical_monitor;
|
|
|
|
onscreen_native->secondary_gpu_states =
|
|
|
|
g_hash_table_new_full (NULL, NULL,
|
|
|
|
NULL,
|
|
|
|
(GDestroyNotify) secondary_gpu_state_free);
|
|
|
|
|
|
|
|
for (l = meta_logical_monitor_get_monitors (logical_monitor); l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaMonitor *monitor = l->data;
|
|
|
|
MetaGpuKms *gpu_kms = META_GPU_KMS (meta_monitor_get_gpu (monitor));
|
|
|
|
|
|
|
|
if (gpu_kms == render_gpu)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (get_secondary_gpu_state (onscreen, gpu_kms))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!init_secondary_gpu_state (renderer_native, onscreen, gpu_kms, error))
|
|
|
|
{
|
|
|
|
cogl_object_unref (onscreen);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2017-07-10 10:19:32 +00:00
|
|
|
|
2016-08-01 01:47:11 +00:00
|
|
|
return onscreen;
|
|
|
|
}
|
|
|
|
|
2016-08-01 01:48:30 +00:00
|
|
|
static CoglOffscreen *
|
|
|
|
meta_renderer_native_create_offscreen (MetaRendererNative *renderer,
|
|
|
|
CoglContext *context,
|
|
|
|
MetaMonitorTransform transform,
|
|
|
|
gint view_width,
|
2017-07-24 09:35:55 +00:00
|
|
|
gint view_height,
|
|
|
|
GError **error)
|
2016-08-01 01:48:30 +00: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 09:35:55 +00:00
|
|
|
if (!cogl_texture_allocate (COGL_TEXTURE (tex), error))
|
2016-08-01 01:48:30 +00:00
|
|
|
{
|
|
|
|
cogl_object_unref (tex);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
fb = cogl_offscreen_new_with_texture (COGL_TEXTURE (tex));
|
|
|
|
cogl_object_unref (tex);
|
2017-07-24 09:35:55 +00:00
|
|
|
if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (fb), error))
|
2016-08-01 01:48:30 +00:00
|
|
|
{
|
|
|
|
cogl_object_unref (fb);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fb;
|
|
|
|
}
|
|
|
|
|
2018-06-27 09:19:27 +00:00
|
|
|
static int64_t
|
|
|
|
meta_renderer_native_get_clock_time (CoglContext *context)
|
|
|
|
{
|
|
|
|
CoglRenderer *cogl_renderer = cogl_context_get_renderer (context);
|
|
|
|
MetaGpuKms *gpu_kms = cogl_renderer->custom_winsys_user_data;
|
|
|
|
|
|
|
|
return meta_gpu_kms_get_current_time_ns (gpu_kms);
|
|
|
|
}
|
|
|
|
|
2016-05-09 11:51:29 +00:00
|
|
|
static const CoglWinsysVtable *
|
2016-09-23 03:49:10 +00:00
|
|
|
get_native_cogl_winsys_vtable (CoglRenderer *cogl_renderer)
|
2016-05-09 11:51:29 +00:00
|
|
|
{
|
2016-08-18 02:21:12 +00:00
|
|
|
static gboolean vtable_inited = FALSE;
|
2016-05-09 11:51:29 +00: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 07:13:09 +00:00
|
|
|
vtable.renderer_connect = meta_renderer_native_connect;
|
|
|
|
vtable.renderer_disconnect = meta_renderer_native_disconnect;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2016-05-27 07:13:09 +00:00
|
|
|
vtable.onscreen_init = meta_renderer_native_init_onscreen;
|
|
|
|
vtable.onscreen_deinit = meta_renderer_native_release_onscreen;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
|
|
|
/* The KMS winsys doesn't support swap region */
|
|
|
|
vtable.onscreen_swap_region = NULL;
|
|
|
|
vtable.onscreen_swap_buffers_with_damage =
|
2016-05-27 07:13:09 +00:00
|
|
|
meta_onscreen_native_swap_buffers_with_damage;
|
2016-05-09 11:51:29 +00:00
|
|
|
|
2018-06-27 09:19:27 +00:00
|
|
|
vtable.context_get_clock_time = meta_renderer_native_get_clock_time;
|
|
|
|
|
2016-05-09 11:51:29 +00:00
|
|
|
vtable_inited = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &vtable;
|
|
|
|
}
|
|
|
|
|
2016-05-09 01:59:54 +00:00
|
|
|
static CoglRenderer *
|
2017-07-25 02:21:04 +00:00
|
|
|
create_cogl_renderer_for_gpu (MetaGpuKms *gpu_kms)
|
2016-05-09 01:59:54 +00:00
|
|
|
{
|
|
|
|
CoglRenderer *cogl_renderer;
|
|
|
|
|
|
|
|
cogl_renderer = cogl_renderer_new ();
|
|
|
|
cogl_renderer_set_custom_winsys (cogl_renderer,
|
2017-07-24 08:03:02 +00:00
|
|
|
get_native_cogl_winsys_vtable,
|
2017-07-25 02:21:04 +00:00
|
|
|
gpu_kms);
|
2016-05-09 01:59:54 +00:00
|
|
|
|
|
|
|
return cogl_renderer;
|
|
|
|
}
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
static CoglRenderer *
|
|
|
|
meta_renderer_native_create_cogl_renderer (MetaRenderer *renderer)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
|
|
|
|
|
2018-12-10 12:19:25 +00:00
|
|
|
return create_cogl_renderer_for_gpu (renderer_native->primary_gpu_kms);
|
2017-07-25 02:21:04 +00:00
|
|
|
}
|
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
static void
|
|
|
|
meta_onscreen_native_set_view (CoglOnscreen *onscreen,
|
|
|
|
MetaRendererView *view)
|
|
|
|
{
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl;
|
2016-06-08 09:05:31 +00:00
|
|
|
MetaOnscreenNative *onscreen_native;
|
|
|
|
|
2017-07-14 07:20:41 +00:00
|
|
|
onscreen_egl = onscreen->winsys;
|
|
|
|
onscreen_native = onscreen_egl->platform;
|
2016-06-08 09:05:31 +00:00
|
|
|
onscreen_native->view = view;
|
|
|
|
}
|
|
|
|
|
2017-03-08 08:05:00 +00:00
|
|
|
static MetaMonitorTransform
|
|
|
|
calculate_view_transform (MetaMonitorManager *monitor_manager,
|
|
|
|
MetaLogicalMonitor *logical_monitor)
|
|
|
|
{
|
|
|
|
MetaMonitor *main_monitor;
|
|
|
|
MetaOutput *main_output;
|
2017-11-03 10:25:30 +00:00
|
|
|
MetaCrtc *crtc;
|
2018-07-23 19:36:57 +00:00
|
|
|
MetaMonitorTransform crtc_transform;
|
|
|
|
|
2017-03-08 08:05:00 +00:00
|
|
|
main_monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
|
|
|
|
main_output = meta_monitor_get_main_output (main_monitor);
|
2017-11-03 10:25:30 +00:00
|
|
|
crtc = meta_output_get_assigned_crtc (main_output);
|
2018-07-23 19:36:57 +00:00
|
|
|
crtc_transform =
|
|
|
|
meta_monitor_logical_to_crtc_transform (main_monitor,
|
|
|
|
logical_monitor->transform);
|
2017-03-08 08:05:00 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Pick any monitor and output and check; all CRTCs of a logical monitor will
|
|
|
|
* always have the same transform assigned to them.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (meta_monitor_manager_is_transform_handled (monitor_manager,
|
2017-11-03 10:25:30 +00:00
|
|
|
crtc,
|
2018-07-23 19:36:57 +00:00
|
|
|
crtc_transform))
|
2017-03-08 08:05:00 +00:00
|
|
|
return META_MONITOR_TRANSFORM_NORMAL;
|
|
|
|
else
|
2018-07-23 19:36:57 +00:00
|
|
|
return crtc_transform;
|
2017-03-08 08:05:00 +00:00
|
|
|
}
|
|
|
|
|
2018-10-09 13:55:23 +00:00
|
|
|
static CoglContext *
|
|
|
|
cogl_context_from_renderer_native (MetaRendererNative *renderer_native)
|
|
|
|
{
|
2019-04-02 13:34:01 +00:00
|
|
|
MetaBackend *backend = backend_from_renderer_native (renderer_native);
|
2018-10-09 13:55:23 +00:00
|
|
|
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
|
|
|
|
|
|
|
|
return clutter_backend_get_cogl_context (clutter_backend);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
should_force_shadow_fb (MetaRendererNative *renderer_native,
|
|
|
|
MetaGpuKms *primary_gpu)
|
|
|
|
{
|
|
|
|
CoglContext *cogl_context =
|
|
|
|
cogl_context_from_renderer_native (renderer_native);
|
|
|
|
CoglGpuInfo *info = &cogl_context->gpu;
|
|
|
|
int kms_fd;
|
|
|
|
uint64_t prefer_shadow = 0;
|
|
|
|
|
|
|
|
switch (info->architecture)
|
|
|
|
{
|
|
|
|
case COGL_GPU_INFO_ARCHITECTURE_UNKNOWN:
|
|
|
|
case COGL_GPU_INFO_ARCHITECTURE_SANDYBRIDGE:
|
|
|
|
case COGL_GPU_INFO_ARCHITECTURE_SGX:
|
|
|
|
case COGL_GPU_INFO_ARCHITECTURE_MALI:
|
|
|
|
return FALSE;
|
|
|
|
case COGL_GPU_INFO_ARCHITECTURE_LLVMPIPE:
|
|
|
|
case COGL_GPU_INFO_ARCHITECTURE_SOFTPIPE:
|
|
|
|
case COGL_GPU_INFO_ARCHITECTURE_SWRAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
kms_fd = meta_gpu_kms_get_fd (primary_gpu);
|
|
|
|
if (drmGetCap (kms_fd, DRM_CAP_DUMB_PREFER_SHADOW, &prefer_shadow) == 0)
|
|
|
|
{
|
|
|
|
if (prefer_shadow)
|
|
|
|
{
|
|
|
|
static gboolean logged_once = FALSE;
|
|
|
|
|
|
|
|
if (!logged_once)
|
|
|
|
{
|
|
|
|
g_message ("Forcing shadow framebuffer");
|
|
|
|
logged_once = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
static MetaRendererView *
|
2016-11-25 06:31:38 +00:00
|
|
|
meta_renderer_native_create_view (MetaRenderer *renderer,
|
|
|
|
MetaLogicalMonitor *logical_monitor)
|
2016-06-08 09:05:31 +00:00
|
|
|
{
|
2017-07-06 08:00:56 +00:00
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
|
2017-03-08 08:05:00 +00:00
|
|
|
MetaMonitorManager *monitor_manager =
|
2018-12-10 12:19:25 +00:00
|
|
|
META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
|
2017-07-10 10:19:32 +00:00
|
|
|
CoglContext *cogl_context =
|
2018-10-09 13:55:23 +00:00
|
|
|
cogl_context_from_renderer_native (renderer_native);
|
2016-08-01 01:48:30 +00:00
|
|
|
CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
|
2017-07-25 02:21:04 +00:00
|
|
|
CoglDisplayEGL *cogl_display_egl;
|
2017-07-14 07:20:41 +00:00
|
|
|
CoglOnscreenEGL *onscreen_egl;
|
2017-03-08 08:05:00 +00:00
|
|
|
MetaMonitorTransform view_transform;
|
2016-08-01 01:47:11 +00:00
|
|
|
CoglOnscreen *onscreen = NULL;
|
2016-08-01 01:48:30 +00:00
|
|
|
CoglOffscreen *offscreen = NULL;
|
2017-05-25 08:12:51 +00:00
|
|
|
float scale;
|
2017-02-24 10:10:52 +00:00
|
|
|
int width, height;
|
2016-06-08 09:05:31 +00:00
|
|
|
MetaRendererView *view;
|
2016-09-29 14:46:34 +00:00
|
|
|
GError *error = NULL;
|
2016-06-08 09:05:31 +00:00
|
|
|
|
2017-03-08 08:05:00 +00:00
|
|
|
view_transform = calculate_view_transform (monitor_manager, logical_monitor);
|
2016-06-08 09:05:31 +00:00
|
|
|
|
2017-02-24 10:10:52 +00:00
|
|
|
if (meta_is_stage_views_scaled ())
|
2017-05-25 08:12:51 +00:00
|
|
|
scale = meta_logical_monitor_get_scale (logical_monitor);
|
2017-02-24 10:10:52 +00:00
|
|
|
else
|
2017-05-25 08:12:51 +00:00
|
|
|
scale = 1.0;
|
2017-02-24 10:10:52 +00:00
|
|
|
|
2017-08-29 13:38:18 +00:00
|
|
|
width = roundf (logical_monitor->rect.width * scale);
|
|
|
|
height = roundf (logical_monitor->rect.height * scale);
|
2017-02-24 10:10:52 +00:00
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
onscreen = meta_renderer_native_create_onscreen (renderer_native,
|
2018-12-10 12:19:25 +00:00
|
|
|
renderer_native->primary_gpu_kms,
|
2017-07-25 02:21:04 +00:00
|
|
|
logical_monitor,
|
2016-08-01 01:47:11 +00:00
|
|
|
cogl_context,
|
2017-03-08 08:05:00 +00:00
|
|
|
view_transform,
|
2017-02-24 10:10:52 +00:00
|
|
|
width,
|
2017-07-24 09:35:55 +00:00
|
|
|
height,
|
|
|
|
&error);
|
2016-08-01 01:47:11 +00:00
|
|
|
if (!onscreen)
|
2017-07-24 09:35:55 +00:00
|
|
|
g_error ("Failed to allocate onscreen framebuffer: %s", error->message);
|
2016-06-08 09:05:31 +00:00
|
|
|
|
2018-10-09 13:55:23 +00:00
|
|
|
if (view_transform != META_MONITOR_TRANSFORM_NORMAL ||
|
2018-12-10 12:19:25 +00:00
|
|
|
should_force_shadow_fb (renderer_native,
|
|
|
|
renderer_native->primary_gpu_kms))
|
2016-08-01 01:48:30 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
offscreen = meta_renderer_native_create_offscreen (renderer_native,
|
2016-08-01 01:48:30 +00:00
|
|
|
cogl_context,
|
2017-03-08 08:05:00 +00:00
|
|
|
view_transform,
|
2017-02-24 10:10:52 +00:00
|
|
|
width,
|
2017-07-24 09:35:55 +00:00
|
|
|
height,
|
|
|
|
&error);
|
2016-08-01 01:48:30 +00:00
|
|
|
if (!offscreen)
|
2017-07-24 09:35:55 +00:00
|
|
|
g_error ("Failed to allocate back buffer texture: %s", error->message);
|
2016-08-01 01:48:30 +00:00
|
|
|
}
|
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
view = g_object_new (META_TYPE_RENDERER_VIEW,
|
2016-11-25 06:31:38 +00:00
|
|
|
"layout", &logical_monitor->rect,
|
2017-05-25 08:12:51 +00:00
|
|
|
"scale", scale,
|
2016-08-01 01:47:11 +00:00
|
|
|
"framebuffer", onscreen,
|
2016-08-01 01:48:30 +00:00
|
|
|
"offscreen", offscreen,
|
2016-11-25 06:31:38 +00:00
|
|
|
"logical-monitor", logical_monitor,
|
2017-03-08 08:05:00 +00:00
|
|
|
"transform", view_transform,
|
2016-06-08 09:05:31 +00:00
|
|
|
NULL);
|
2016-08-01 01:48:30 +00:00
|
|
|
g_clear_pointer (&offscreen, cogl_object_unref);
|
2016-06-08 09:05:31 +00:00
|
|
|
|
|
|
|
meta_onscreen_native_set_view (onscreen, view);
|
|
|
|
|
2016-09-29 14:46:34 +00:00
|
|
|
if (!meta_onscreen_native_allocate (onscreen, &error))
|
|
|
|
{
|
|
|
|
g_warning ("Could not create onscreen: %s", error->message);
|
|
|
|
cogl_object_unref (onscreen);
|
|
|
|
g_object_unref (view);
|
|
|
|
g_error_free (error);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cogl_object_unref (onscreen);
|
|
|
|
|
|
|
|
/* Ensure we don't point to stale surfaces when creating the offscreen */
|
2017-07-14 07:20:41 +00:00
|
|
|
onscreen_egl = onscreen->winsys;
|
2017-07-25 02:21:04 +00:00
|
|
|
cogl_display_egl = cogl_display->winsys;
|
2016-09-29 14:46:34 +00:00
|
|
|
_cogl_winsys_egl_make_current (cogl_display,
|
2017-07-14 07:20:41 +00:00
|
|
|
onscreen_egl->egl_surface,
|
|
|
|
onscreen_egl->egl_surface,
|
|
|
|
cogl_display_egl->egl_context);
|
2016-09-29 14:46:34 +00:00
|
|
|
|
2016-06-08 09:05:31 +00:00
|
|
|
return view;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_renderer_native_finish_frame (MetaRendererNative *renderer_native)
|
|
|
|
{
|
|
|
|
renderer_native->frame_counter++;
|
2017-09-28 15:59:27 +00:00
|
|
|
|
|
|
|
if (renderer_native->pending_unset_disabled_crtcs)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *monitor_manager =
|
2017-07-10 10:19:32 +00:00
|
|
|
META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
|
2017-03-28 04:35:19 +00:00
|
|
|
GList *l;
|
2017-09-28 15:59:27 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
for (l = meta_monitor_manager_get_gpus (monitor_manager); l; l = l->next)
|
2017-09-28 15:59:27 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaGpu *gpu = l->data;
|
|
|
|
MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
|
|
|
|
GList *k;
|
2017-09-28 15:59:27 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
for (k = meta_gpu_get_crtcs (gpu); k; k = k->next)
|
|
|
|
{
|
|
|
|
MetaCrtc *crtc = k->data;
|
|
|
|
|
|
|
|
if (crtc->current_mode)
|
|
|
|
continue;
|
2017-09-28 15:59:27 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
meta_gpu_kms_apply_crtc_mode (gpu_kms, crtc, 0, 0, 0);
|
|
|
|
}
|
2017-09-28 15:59:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
renderer_native->pending_unset_disabled_crtcs = FALSE;
|
|
|
|
}
|
2016-06-08 09:05:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int64_t
|
|
|
|
meta_renderer_native_get_frame_counter (MetaRendererNative *renderer_native)
|
|
|
|
{
|
|
|
|
return renderer_native->frame_counter;
|
|
|
|
}
|
|
|
|
|
2016-05-07 15:09:59 +00:00
|
|
|
static void
|
|
|
|
meta_renderer_native_get_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (object);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
2017-07-06 08:00:56 +00:00
|
|
|
case PROP_MONITOR_MANAGER:
|
|
|
|
g_value_set_object (value, renderer_native->monitor_manager_kms);
|
2016-08-18 03:22:42 +00:00
|
|
|
break;
|
2016-05-07 15:09:59 +00:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-17 11:03:18 +00:00
|
|
|
static void
|
|
|
|
on_gpu_added (MetaMonitorManager *monitor_manager,
|
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
MetaRendererNative *renderer_native);
|
|
|
|
|
2016-05-07 15:09:59 +00:00
|
|
|
static void
|
|
|
|
meta_renderer_native_set_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (object);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
2017-07-06 08:00:56 +00:00
|
|
|
case PROP_MONITOR_MANAGER:
|
|
|
|
renderer_native->monitor_manager_kms = g_value_get_object (value);
|
2016-08-18 03:22:42 +00:00
|
|
|
break;
|
2016-05-07 15:09:59 +00:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-25 02:21:04 +00:00
|
|
|
static gboolean
|
2018-06-07 23:29:44 +00:00
|
|
|
create_secondary_egl_config (MetaEgl *egl,
|
|
|
|
MetaRendererNativeMode mode,
|
|
|
|
EGLDisplay egl_display,
|
|
|
|
EGLConfig *egl_config,
|
|
|
|
GError **error)
|
2017-07-25 02:21:04 +00: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 23:29:44 +00:00
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case META_RENDERER_NATIVE_MODE_GBM:
|
|
|
|
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-25 02:21:04 +00: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);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
|
|
|
|
MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
|
|
|
|
EGLDisplay egl_display = renderer_gpu_data->egl_display;
|
|
|
|
EGLConfig egl_config;
|
|
|
|
EGLContext egl_context;
|
2019-01-20 10:46:46 +00:00
|
|
|
const char **missing_gl_extensions;
|
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 14:49:58 +00:00
|
|
|
const char *renderer_str;
|
2017-07-25 02:21:04 +00:00
|
|
|
|
2018-06-07 23:29:44 +00:00
|
|
|
if (!create_secondary_egl_config (egl, renderer_gpu_data->mode, egl_display,
|
|
|
|
&egl_config, error))
|
2017-07-25 02:21:04 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
egl_context = create_secondary_egl_context (egl, egl_display, egl_config, error);
|
|
|
|
if (egl_context == EGL_NO_CONTEXT)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
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);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
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 14:49:58 +00:00
|
|
|
renderer_str = (const char *) glGetString (GL_RENDERER);
|
|
|
|
if (g_str_has_prefix (renderer_str, "llvmpipe") ||
|
|
|
|
g_str_has_prefix (renderer_str, "softpipe") ||
|
|
|
|
g_str_has_prefix (renderer_str, "swrast"))
|
2018-10-23 08:09:22 +00:00
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Do not want to use software renderer (%s), falling back to CPU copy path",
|
|
|
|
renderer_str);
|
2019-01-28 11:02:07 +00:00
|
|
|
goto out_fail_with_context;
|
2018-10-23 08:09:22 +00: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 14:49:58 +00:00
|
|
|
|
2017-07-25 02:21:04 +00: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 10:46:46 +00:00
|
|
|
missing_gl_extensions_str = g_strjoinv (", ",
|
|
|
|
(char **) missing_gl_extensions);
|
2017-07-25 02:21:04 +00: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 11:02:07 +00:00
|
|
|
|
|
|
|
goto out_fail_with_context;
|
2017-07-25 02:21:04 +00:00
|
|
|
}
|
|
|
|
|
2018-10-23 08:09:22 +00:00
|
|
|
renderer_gpu_data->secondary.is_hardware_rendering = TRUE;
|
2017-07-25 02:21:04 +00:00
|
|
|
renderer_gpu_data->secondary.egl_context = egl_context;
|
|
|
|
renderer_gpu_data->secondary.egl_config = egl_config;
|
|
|
|
renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_GPU;
|
|
|
|
|
|
|
|
return TRUE;
|
2019-01-28 11:02:07 +00:00
|
|
|
|
|
|
|
out_fail_with_context:
|
|
|
|
meta_egl_make_current (egl,
|
|
|
|
egl_display,
|
|
|
|
EGL_NO_SURFACE,
|
|
|
|
EGL_NO_SURFACE,
|
|
|
|
EGL_NO_CONTEXT,
|
|
|
|
NULL);
|
|
|
|
meta_egl_destroy_context (egl, egl_display, egl_context, NULL);
|
|
|
|
|
|
|
|
return FALSE;
|
2017-07-25 02:21:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
init_secondary_gpu_data_cpu (MetaRendererNativeGpuData *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 14:49:58 +00:00
|
|
|
renderer_gpu_data->secondary.is_hardware_rendering = FALSE;
|
2017-07-25 02:21:04 +00:00
|
|
|
renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_CPU;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
init_secondary_gpu_data (MetaRendererNativeGpuData *renderer_gpu_data)
|
|
|
|
{
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
if (init_secondary_gpu_data_gpu (renderer_gpu_data, &error))
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_warning ("Failed to initialize accelerated iGPU/dGPU framebuffer sharing: %s",
|
|
|
|
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 14:49:58 +00: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);
|
|
|
|
return data->secondary.is_hardware_rendering;
|
|
|
|
}
|
|
|
|
|
2019-04-03 10:11:45 +00:00
|
|
|
static EGLDisplay
|
|
|
|
init_gbm_egl_display (MetaRendererNative *renderer_native,
|
|
|
|
struct gbm_device *gbm_device,
|
|
|
|
GError **error)
|
2016-05-09 13:22:01 +00:00
|
|
|
{
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
|
2016-08-18 02:37:16 +00:00
|
|
|
EGLDisplay egl_display;
|
2016-05-09 13:22:01 +00:00
|
|
|
|
2016-09-01 03:04:22 +00:00
|
|
|
if (!meta_egl_has_extensions (egl, EGL_NO_DISPLAY, NULL,
|
|
|
|
"EGL_MESA_platform_gbm",
|
2017-11-03 03:59:00 +00:00
|
|
|
NULL) &&
|
|
|
|
!meta_egl_has_extensions (egl, EGL_NO_DISPLAY, NULL,
|
|
|
|
"EGL_KHR_platform_gbm",
|
2016-09-01 03:04:22 +00:00
|
|
|
NULL))
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
G_IO_ERROR_FAILED,
|
|
|
|
"Missing extension for GBM renderer: EGL_KHR_platform_gbm");
|
2019-04-03 10:11:45 +00:00
|
|
|
return EGL_NO_DISPLAY;
|
2016-09-01 03:04:22 +00:00
|
|
|
}
|
|
|
|
|
2019-04-03 10:11:45 +00:00
|
|
|
egl_display = meta_egl_get_platform_display (egl,
|
|
|
|
EGL_PLATFORM_GBM_KHR,
|
|
|
|
gbm_device, NULL, error);
|
|
|
|
if (egl_display == EGL_NO_DISPLAY)
|
|
|
|
return EGL_NO_DISPLAY;
|
|
|
|
|
|
|
|
if (!meta_egl_initialize (egl, egl_display, error))
|
|
|
|
return EGL_NO_DISPLAY;
|
|
|
|
|
|
|
|
return egl_display;
|
|
|
|
}
|
|
|
|
|
|
|
|
static MetaRendererNativeGpuData *
|
|
|
|
create_renderer_gpu_data_gbm (MetaRendererNative *renderer_native,
|
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
struct gbm_device *gbm_device;
|
|
|
|
int kms_fd;
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
g_autoptr (GError) local_error = NULL;
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
|
2017-07-06 08:00:56 +00:00
|
|
|
|
|
|
|
gbm_device = gbm_create_device (kms_fd);
|
2016-08-18 02:37:16 +00:00
|
|
|
if (!gbm_device)
|
2016-05-09 13:22:01 +00:00
|
|
|
{
|
2016-05-10 02:16:45 +00:00
|
|
|
g_set_error (error, G_IO_ERROR,
|
2016-05-09 13:22:01 +00:00
|
|
|
G_IO_ERROR_FAILED,
|
2016-10-28 07:35:31 +00:00
|
|
|
"Failed to create gbm device: %s", g_strerror (errno));
|
2017-07-10 10:19:32 +00:00
|
|
|
return NULL;
|
2016-05-09 13:22:01 +00:00
|
|
|
}
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
renderer_gpu_data = meta_create_renderer_native_gpu_data (gpu_kms);
|
|
|
|
renderer_gpu_data->renderer_native = renderer_native;
|
|
|
|
renderer_gpu_data->gbm.device = gbm_device;
|
|
|
|
renderer_gpu_data->mode = META_RENDERER_NATIVE_MODE_GBM;
|
|
|
|
|
2019-04-03 10:11:45 +00:00
|
|
|
renderer_gpu_data->egl_display = init_gbm_egl_display (renderer_native,
|
|
|
|
gbm_device,
|
|
|
|
&local_error);
|
|
|
|
if (renderer_gpu_data->egl_display == EGL_NO_DISPLAY)
|
|
|
|
{
|
|
|
|
g_debug ("GBM EGL init for %s failed: %s",
|
|
|
|
meta_gpu_kms_get_file_path (gpu_kms),
|
|
|
|
local_error->message);
|
2016-08-18 02:37:16 +00:00
|
|
|
|
2019-04-03 10:11:45 +00:00
|
|
|
init_secondary_gpu_data_cpu (renderer_gpu_data);
|
|
|
|
return renderer_gpu_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
init_secondary_gpu_data (renderer_gpu_data);
|
2017-07-10 10:19:32 +00:00
|
|
|
return renderer_gpu_data;
|
2016-05-09 13:22:01 +00:00
|
|
|
}
|
|
|
|
|
2016-08-18 03:28:59 +00:00
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
static const char *
|
|
|
|
get_drm_device_file (MetaEgl *egl,
|
|
|
|
EGLDeviceEXT device,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
if (!meta_egl_egl_device_has_extensions (egl, device,
|
|
|
|
NULL,
|
|
|
|
"EGL_EXT_device_drm",
|
|
|
|
NULL))
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
G_IO_ERROR_FAILED,
|
|
|
|
"Missing required EGLDevice extension EGL_EXT_device_drm");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return meta_egl_query_device_string (egl, device,
|
|
|
|
EGL_DRM_DEVICE_FILE_EXT,
|
|
|
|
error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static EGLDeviceEXT
|
2017-07-10 10:19:32 +00:00
|
|
|
find_egl_device (MetaRendererNative *renderer_native,
|
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
GError **error)
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
2017-07-24 07:54:29 +00:00
|
|
|
MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
|
2019-01-20 10:46:46 +00:00
|
|
|
const char **missing_extensions;
|
2016-08-18 03:28:59 +00:00
|
|
|
EGLint num_devices;
|
|
|
|
EGLDeviceEXT *devices;
|
2017-07-06 08:00:56 +00:00
|
|
|
const char *kms_file_path;
|
2016-08-18 03:28:59 +00:00
|
|
|
EGLDeviceEXT device;
|
|
|
|
EGLint i;
|
|
|
|
|
|
|
|
if (!meta_egl_has_extensions (egl,
|
|
|
|
EGL_NO_DISPLAY,
|
|
|
|
&missing_extensions,
|
|
|
|
"EGL_EXT_device_base",
|
|
|
|
NULL))
|
|
|
|
{
|
|
|
|
char *missing_extensions_str;
|
|
|
|
|
2019-01-20 10:46:46 +00:00
|
|
|
missing_extensions_str = g_strjoinv (", ", (char **) missing_extensions);
|
2016-08-18 03:28:59 +00:00
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
G_IO_ERROR_FAILED,
|
|
|
|
"Missing EGL extensions required for EGLDevice renderer: %s",
|
|
|
|
missing_extensions_str);
|
|
|
|
g_free (missing_extensions_str);
|
|
|
|
g_free (missing_extensions);
|
|
|
|
return EGL_NO_DEVICE_EXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!meta_egl_query_devices (egl, 0, NULL, &num_devices, error))
|
|
|
|
return EGL_NO_DEVICE_EXT;
|
|
|
|
|
|
|
|
devices = g_new0 (EGLDeviceEXT, num_devices);
|
|
|
|
if (!meta_egl_query_devices (egl, num_devices, devices, &num_devices,
|
|
|
|
error))
|
|
|
|
{
|
|
|
|
g_free (devices);
|
|
|
|
return EGL_NO_DEVICE_EXT;
|
|
|
|
}
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
kms_file_path = meta_gpu_kms_get_file_path (gpu_kms);
|
2017-07-06 08:00:56 +00:00
|
|
|
|
2016-08-18 03:28:59 +00:00
|
|
|
device = EGL_NO_DEVICE_EXT;
|
|
|
|
for (i = 0; i < num_devices; i++)
|
|
|
|
{
|
|
|
|
const char *egl_device_drm_path;
|
|
|
|
|
|
|
|
g_clear_error (error);
|
|
|
|
|
|
|
|
egl_device_drm_path = get_drm_device_file (egl, devices[i], error);
|
|
|
|
if (!egl_device_drm_path)
|
|
|
|
continue;
|
|
|
|
|
2017-07-06 08:00:56 +00:00
|
|
|
if (g_str_equal (egl_device_drm_path, kms_file_path))
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
|
|
|
device = devices[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_free (devices);
|
|
|
|
|
|
|
|
if (device == EGL_NO_DEVICE_EXT)
|
|
|
|
{
|
|
|
|
if (!*error)
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
G_IO_ERROR_FAILED,
|
|
|
|
"Failed to find matching EGLDeviceEXT");
|
|
|
|
return EGL_NO_DEVICE_EXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return device;
|
|
|
|
}
|
|
|
|
|
|
|
|
static EGLDisplay
|
2017-07-10 10:19:32 +00:00
|
|
|
get_egl_device_display (MetaRendererNative *renderer_native,
|
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
EGLDeviceEXT egl_device,
|
|
|
|
GError **error)
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
2017-07-24 07:54:29 +00:00
|
|
|
MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
|
2017-07-10 10:19:32 +00:00
|
|
|
int kms_fd = meta_gpu_kms_get_fd (gpu_kms);
|
2016-08-18 03:28:59 +00:00
|
|
|
EGLint platform_attribs[] = {
|
2017-07-06 08:00:56 +00:00
|
|
|
EGL_DRM_MASTER_FD_EXT, kms_fd,
|
2016-08-18 03:28:59 +00:00
|
|
|
EGL_NONE
|
|
|
|
};
|
|
|
|
|
|
|
|
return meta_egl_get_platform_display (egl, EGL_PLATFORM_DEVICE_EXT,
|
|
|
|
(void *) egl_device,
|
|
|
|
platform_attribs,
|
|
|
|
error);
|
|
|
|
}
|
|
|
|
|
2018-12-10 13:46:56 +00:00
|
|
|
static int
|
|
|
|
count_drm_devices (MetaRendererNative *renderer_native)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
|
|
|
|
|
|
|
|
return g_list_length (meta_monitor_manager_get_gpus (monitor_manager));
|
|
|
|
}
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
static MetaRendererNativeGpuData *
|
|
|
|
create_renderer_gpu_data_egl_device (MetaRendererNative *renderer_native,
|
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
GError **error)
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
2017-07-24 07:54:29 +00:00
|
|
|
MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
|
2019-01-20 10:46:46 +00:00
|
|
|
const char **missing_extensions;
|
2016-08-18 03:28:59 +00:00
|
|
|
EGLDeviceEXT egl_device;
|
|
|
|
EGLDisplay egl_display;
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
2016-08-18 03:28:59 +00:00
|
|
|
|
2018-12-10 13:46:56 +00:00
|
|
|
if (count_drm_devices (renderer_native) != 1)
|
2017-07-25 02:21:04 +00:00
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
G_IO_ERROR_FAILED,
|
|
|
|
"EGLDevice currently only works with single GPU systems");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
egl_device = find_egl_device (renderer_native, gpu_kms, error);
|
2016-08-18 03:28:59 +00:00
|
|
|
if (egl_device == EGL_NO_DEVICE_EXT)
|
2017-07-10 10:19:32 +00:00
|
|
|
return NULL;
|
2016-08-18 03:28:59 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
egl_display = get_egl_device_display (renderer_native, gpu_kms,
|
|
|
|
egl_device, error);
|
2016-08-18 03:28:59 +00:00
|
|
|
if (egl_display == EGL_NO_DISPLAY)
|
2017-07-10 10:19:32 +00:00
|
|
|
return NULL;
|
2016-08-18 03:28:59 +00:00
|
|
|
|
|
|
|
if (!meta_egl_initialize (egl, egl_display, error))
|
2017-07-10 10:19:32 +00:00
|
|
|
return NULL;
|
2016-08-18 03:28:59 +00:00
|
|
|
|
|
|
|
if (!meta_egl_has_extensions (egl,
|
|
|
|
egl_display,
|
|
|
|
&missing_extensions,
|
|
|
|
"EGL_NV_output_drm_flip_event",
|
|
|
|
"EGL_EXT_output_base",
|
|
|
|
"EGL_EXT_output_drm",
|
|
|
|
"EGL_KHR_stream",
|
|
|
|
"EGL_KHR_stream_producer_eglsurface",
|
|
|
|
"EGL_EXT_stream_consumer_egloutput",
|
|
|
|
"EGL_EXT_stream_acquire_mode",
|
|
|
|
NULL))
|
|
|
|
{
|
|
|
|
char *missing_extensions_str;
|
|
|
|
|
2019-01-20 10:46:46 +00:00
|
|
|
missing_extensions_str = g_strjoinv (", ", (char **) missing_extensions);
|
2016-08-18 03:28:59 +00:00
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
G_IO_ERROR_FAILED,
|
|
|
|
"Missing EGL extensions required for EGLDevice renderer: %s",
|
|
|
|
missing_extensions_str);
|
2019-06-12 16:58:54 +00:00
|
|
|
meta_egl_terminate (egl, egl_display, NULL);
|
2016-08-18 03:28:59 +00:00
|
|
|
g_free (missing_extensions_str);
|
|
|
|
g_free (missing_extensions);
|
2017-07-10 10:19:32 +00:00
|
|
|
return NULL;
|
2016-08-18 03:28:59 +00:00
|
|
|
}
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
renderer_gpu_data = meta_create_renderer_native_gpu_data (gpu_kms);
|
|
|
|
renderer_gpu_data->renderer_native = renderer_native;
|
|
|
|
renderer_gpu_data->egl.device = egl_device;
|
|
|
|
renderer_gpu_data->mode = META_RENDERER_NATIVE_MODE_EGL_DEVICE;
|
2017-07-25 02:21:04 +00:00
|
|
|
renderer_gpu_data->egl_display = egl_display;
|
2016-08-18 03:28:59 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
return renderer_gpu_data;
|
2016-08-18 03:28:59 +00:00
|
|
|
}
|
|
|
|
#endif /* HAVE_EGL_DEVICE */
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
static MetaRendererNativeGpuData *
|
|
|
|
meta_renderer_native_create_renderer_gpu_data (MetaRendererNative *renderer_native,
|
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
GError **error)
|
2016-08-18 03:14:03 +00:00
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
2016-08-18 03:28:59 +00:00
|
|
|
GError *gbm_error = NULL;
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
|
|
|
GError *egl_device_error = NULL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_EGL_DEVICE
|
2017-06-28 01:31:48 +00:00
|
|
|
/* Try to initialize the EGLDevice backend first. Whenever we use a
|
|
|
|
* non-NVIDIA GPU, the EGLDevice enumeration function won't find a match, and
|
|
|
|
* we'll fall back to GBM (which will always succeed as it has a software
|
|
|
|
* rendering fallback)
|
|
|
|
*/
|
2017-07-10 10:19:32 +00:00
|
|
|
renderer_gpu_data = create_renderer_gpu_data_egl_device (renderer_native,
|
|
|
|
gpu_kms,
|
|
|
|
&egl_device_error);
|
|
|
|
if (renderer_gpu_data)
|
|
|
|
return renderer_gpu_data;
|
2017-06-28 01:31:48 +00:00
|
|
|
#endif
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
renderer_gpu_data = create_renderer_gpu_data_gbm (renderer_native,
|
|
|
|
gpu_kms,
|
|
|
|
&gbm_error);
|
|
|
|
if (renderer_gpu_data)
|
2016-08-18 03:28:59 +00:00
|
|
|
{
|
2017-07-07 09:59:20 +00:00
|
|
|
#ifdef HAVE_EGL_DEVICE
|
2017-06-28 01:31:48 +00:00
|
|
|
g_error_free (egl_device_error);
|
2017-07-07 09:59:20 +00:00
|
|
|
#endif
|
2017-07-10 10:19:32 +00:00
|
|
|
return renderer_gpu_data;
|
2016-08-18 03:28:59 +00: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 10:19:32 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-09-17 11:03:18 +00: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;
|
|
|
|
|
|
|
|
g_hash_table_insert (renderer_native->gpu_datas,
|
|
|
|
gpu_kms,
|
|
|
|
renderer_gpu_data);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_gpu_added (MetaMonitorManager *monitor_manager,
|
|
|
|
MetaGpuKms *gpu_kms,
|
|
|
|
MetaRendererNative *renderer_native)
|
|
|
|
{
|
|
|
|
MetaBackend *backend = meta_monitor_manager_get_backend (monitor_manager);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-12-10 12:19:25 +00:00
|
|
|
static MetaGpuKms *
|
2019-04-03 10:34:09 +00:00
|
|
|
choose_primary_gpu_unchecked (MetaMonitorManager *manager,
|
|
|
|
MetaRendererNative *renderer_native)
|
2018-12-10 12:19:25 +00:00
|
|
|
{
|
|
|
|
GList *gpus = meta_monitor_manager_get_gpus (manager);
|
|
|
|
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 14:49:58 +00:00
|
|
|
int allow_sw;
|
2018-12-10 12:19:25 +00: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 14:49:58 +00:00
|
|
|
/*
|
|
|
|
* Check first hardware rendering devices, and if none found,
|
|
|
|
* then software rendering devices.
|
|
|
|
*/
|
|
|
|
for (allow_sw = 0; allow_sw < 2; allow_sw++)
|
|
|
|
{
|
|
|
|
/* 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)))
|
|
|
|
return gpu_kms;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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)))
|
|
|
|
return gpu_kms;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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))
|
|
|
|
return gpu_kms;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
return NULL;
|
2018-12-10 12:19:25 +00:00
|
|
|
}
|
|
|
|
|
2019-04-03 10:34:09 +00:00
|
|
|
static MetaGpuKms *
|
|
|
|
choose_primary_gpu (MetaMonitorManager *manager,
|
|
|
|
MetaRendererNative *renderer_native,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaGpuKms *gpu_kms;
|
|
|
|
MetaRendererNativeGpuData *renderer_gpu_data;
|
|
|
|
|
|
|
|
gpu_kms = choose_primary_gpu_unchecked (manager, renderer_native);
|
|
|
|
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
|
|
|
|
gpu_kms);
|
|
|
|
if (renderer_gpu_data->egl_display == EGL_NO_DISPLAY)
|
|
|
|
{
|
|
|
|
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 10:19:32 +00:00
|
|
|
static gboolean
|
|
|
|
meta_renderer_native_initable_init (GInitable *initable,
|
|
|
|
GCancellable *cancellable,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (initable);
|
|
|
|
MetaMonitorManagerKms *monitor_manager_kms =
|
|
|
|
renderer_native->monitor_manager_kms;
|
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
META_MONITOR_MANAGER (monitor_manager_kms);
|
|
|
|
GList *gpus;
|
2017-07-25 02:21:04 +00:00
|
|
|
GList *l;
|
2017-07-10 10:19:32 +00:00
|
|
|
|
|
|
|
gpus = meta_monitor_manager_get_gpus (monitor_manager);
|
2017-07-25 02:21:04 +00:00
|
|
|
for (l = gpus; l; l = l->next)
|
2017-07-10 10:19:32 +00:00
|
|
|
{
|
2017-07-25 02:21:04 +00:00
|
|
|
MetaGpuKms *gpu_kms = META_GPU_KMS (l->data);
|
2017-07-10 10:19:32 +00:00
|
|
|
|
2018-09-17 11:03:18 +00:00
|
|
|
if (!create_renderer_gpu_data (renderer_native, gpu_kms, error))
|
2017-07-25 02:21:04 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2017-07-10 10:19:32 +00: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 14:49:58 +00:00
|
|
|
renderer_native->primary_gpu_kms = choose_primary_gpu (monitor_manager,
|
2019-04-03 10:34:09 +00:00
|
|
|
renderer_native,
|
|
|
|
error);
|
|
|
|
if (!renderer_native->primary_gpu_kms)
|
|
|
|
return FALSE;
|
2018-10-12 12:19:24 +00:00
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
return TRUE;
|
2016-08-18 03:14:03 +00:00
|
|
|
}
|
|
|
|
|
2016-05-09 13:22:01 +00:00
|
|
|
static void
|
|
|
|
initable_iface_init (GInitableIface *initable_iface)
|
|
|
|
{
|
|
|
|
initable_iface->init = meta_renderer_native_initable_init;
|
|
|
|
}
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
static void
|
|
|
|
meta_renderer_native_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (object);
|
|
|
|
|
2019-03-25 09:24:46 +00:00
|
|
|
if (renderer_native->power_save_page_flip_closures)
|
|
|
|
{
|
|
|
|
g_list_free_full (renderer_native->power_save_page_flip_closures,
|
|
|
|
(GDestroyNotify) g_closure_unref);
|
|
|
|
g_source_remove (renderer_native->power_save_page_flip_source_id);
|
|
|
|
}
|
|
|
|
|
2017-07-10 10:19:32 +00:00
|
|
|
g_hash_table_destroy (renderer_native->gpu_datas);
|
2017-07-25 02:21:04 +00:00
|
|
|
g_clear_object (&renderer_native->gles3);
|
2017-07-10 10:19:32 +00:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (meta_renderer_native_parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
2018-04-11 12:39:15 +00:00
|
|
|
static void
|
|
|
|
meta_renderer_native_constructed (GObject *object)
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (object);
|
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
|
|
|
|
MetaBackend *backend = meta_monitor_manager_get_backend (monitor_manager);
|
|
|
|
MetaSettings *settings = meta_backend_get_settings (backend);
|
|
|
|
|
|
|
|
if (meta_settings_is_experimental_feature_enabled (
|
|
|
|
settings, META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS))
|
|
|
|
renderer_native->use_modifiers = TRUE;
|
|
|
|
|
2018-09-17 11:03:18 +00:00
|
|
|
g_signal_connect (renderer_native->monitor_manager_kms, "gpu-added",
|
|
|
|
G_CALLBACK (on_gpu_added), renderer_native);
|
|
|
|
|
2018-04-11 12:39:15 +00:00
|
|
|
G_OBJECT_CLASS (meta_renderer_native_parent_class)->constructed (object);
|
|
|
|
}
|
|
|
|
|
2016-05-07 15:07:46 +00:00
|
|
|
static void
|
|
|
|
meta_renderer_native_init (MetaRendererNative *renderer_native)
|
|
|
|
{
|
2017-07-10 10:19:32 +00:00
|
|
|
renderer_native->gpu_datas =
|
|
|
|
g_hash_table_new_full (NULL, NULL,
|
|
|
|
NULL,
|
|
|
|
(GDestroyNotify) meta_renderer_native_gpu_data_free);
|
2016-05-07 15:07:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_renderer_native_class_init (MetaRendererNativeClass *klass)
|
|
|
|
{
|
2016-05-07 15:09:59 +00:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
2016-05-09 01:59:54 +00:00
|
|
|
MetaRendererClass *renderer_class = META_RENDERER_CLASS (klass);
|
2016-05-07 15:09:59 +00:00
|
|
|
|
|
|
|
object_class->get_property = meta_renderer_native_get_property;
|
|
|
|
object_class->set_property = meta_renderer_native_set_property;
|
2016-05-09 13:22:01 +00:00
|
|
|
object_class->finalize = meta_renderer_native_finalize;
|
2018-04-11 12:39:15 +00:00
|
|
|
object_class->constructed = meta_renderer_native_constructed;
|
2016-05-07 15:09:59 +00:00
|
|
|
|
2016-05-09 01:59:54 +00:00
|
|
|
renderer_class->create_cogl_renderer = meta_renderer_native_create_cogl_renderer;
|
2016-06-08 09:05:31 +00:00
|
|
|
renderer_class->create_view = meta_renderer_native_create_view;
|
2016-05-09 01:59:54 +00:00
|
|
|
|
2017-07-06 08:00:56 +00:00
|
|
|
obj_props[PROP_MONITOR_MANAGER] =
|
|
|
|
g_param_spec_object ("monitor-manager",
|
|
|
|
"monitor-manager",
|
|
|
|
"MetaMonitorManagerKms",
|
|
|
|
META_TYPE_MONITOR_MANAGER_KMS,
|
|
|
|
G_PARAM_READWRITE |
|
|
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
g_object_class_install_properties (object_class, PROP_LAST, obj_props);
|
2016-05-07 15:07:46 +00:00
|
|
|
}
|
2016-05-09 13:22:01 +00:00
|
|
|
|
|
|
|
MetaRendererNative *
|
2017-07-06 08:00:56 +00:00
|
|
|
meta_renderer_native_new (MetaMonitorManagerKms *monitor_manager_kms,
|
|
|
|
GError **error)
|
2016-05-09 13:22:01 +00:00
|
|
|
{
|
2017-10-05 14:47:25 +00:00
|
|
|
return g_initable_new (META_TYPE_RENDERER_NATIVE,
|
|
|
|
NULL,
|
|
|
|
error,
|
|
|
|
"monitor-manager", monitor_manager_kms,
|
|
|
|
NULL);
|
2016-05-09 13:22:01 +00:00
|
|
|
}
|