Commit 853edf45 authored by Alberts Muktupāvels's avatar Alberts Muktupāvels

backends: split out CRTC/output management to GfGpu

Based on mutter commit:
mutter@c1683073
parent 73a4e6d7
......@@ -38,6 +38,10 @@ libbackends_la_SOURCES = \
gf-display-config-shared.h \
gf-edid-parse.c \
gf-edid-private.h \
gf-gpu-private.h \
gf-gpu-xrandr-private.h \
gf-gpu-xrandr.c \
gf-gpu.c \
gf-logical-monitor-config-private.h \
gf-logical-monitor-config.c \
gf-logical-monitor-private.h \
......
......@@ -3,7 +3,7 @@
* Copyright (C) 2003 Rob Adams
* Copyright (C) 2004-2006 Elijah Newren
* Copyright (C) 2013 Red Hat Inc.
* Copyright (C) 2017 Alberts Muktupāvels
* Copyright (C) 2017-2019 Alberts Muktupāvels
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -27,9 +27,9 @@
#include <glib-object.h>
#include "gf-gpu-private.h"
#include "gf-monitor-manager-enums-private.h"
#include "gf-monitor-manager-types-private.h"
#include "gf-monitor-manager.h"
#include "gf-rectangle.h"
G_BEGIN_DECLS
......@@ -38,7 +38,7 @@ struct _GfCrtc
{
GObject parent;
GfMonitorManager *monitor_manager;
GfGpu *gpu;
glong crtc_id;
GfRectangle rect;
......@@ -91,7 +91,7 @@ G_DECLARE_FINAL_TYPE (GfCrtc, gf_crtc, GF, CRTC, GObject)
#define GF_TYPE_CRTC_MODE (gf_crtc_mode_get_type ())
G_DECLARE_FINAL_TYPE (GfCrtcMode, gf_crtc_mode, GF, CRTC_MODE, GObject)
GfMonitorManager *gf_crtc_get_monitor_manager (GfCrtc *crtc);
GfGpu *gf_crtc_get_gpu (GfCrtc *crtc);
G_END_DECLS
......
......@@ -26,11 +26,11 @@
#include <xcb/randr.h>
#include "gf-crtc-private.h"
#include "gf-monitor-manager-xrandr-private.h"
#include "gf-gpu-xrandr-private.h"
G_BEGIN_DECLS
GfCrtc *gf_create_xrandr_crtc (GfMonitorManager *monitor_manager,
GfCrtc *gf_create_xrandr_crtc (GfGpuXrandr *gpu_xrandr,
XRRCrtcInfo *xrandr_crtc,
RRCrtc crtc_id,
XRRScreenResources *resources);
......
......@@ -103,7 +103,7 @@ gf_monitor_transform_from_xrandr_all (Rotation rotation)
}
GfCrtc *
gf_create_xrandr_crtc (GfMonitorManager *monitor_manager,
gf_create_xrandr_crtc (GfGpuXrandr *gpu_xrandr,
XRRCrtcInfo *xrandr_crtc,
RRCrtc crtc_id,
XRRScreenResources *resources)
......@@ -111,10 +111,11 @@ gf_create_xrandr_crtc (GfMonitorManager *monitor_manager,
{
GfCrtc *crtc;
unsigned int i;
GList *modes;
crtc = g_object_new (GF_TYPE_CRTC, NULL);
crtc->monitor_manager = monitor_manager;
crtc->gpu = GF_GPU (gpu_xrandr);
crtc->crtc_id = crtc_id;
crtc->rect.x = xrandr_crtc->x;
crtc->rect.y = xrandr_crtc->y;
......@@ -124,11 +125,12 @@ gf_create_xrandr_crtc (GfMonitorManager *monitor_manager,
crtc->transform = gf_monitor_transform_from_xrandr (xrandr_crtc->rotation);
crtc->all_transforms = gf_monitor_transform_from_xrandr_all (xrandr_crtc->rotations);
modes = gf_gpu_get_modes (crtc->gpu);
for (i = 0; i < (guint) resources->nmode; i++)
{
if (resources->modes[i].id == xrandr_crtc->mode)
{
crtc->current_mode = g_list_nth_data (monitor_manager->modes, i);
crtc->current_mode = g_list_nth_data (modes, i);
break;
}
}
......@@ -148,6 +150,8 @@ gf_crtc_xrandr_set_config (GfCrtc *crtc,
int n_outputs,
xcb_timestamp_t *out_timestamp)
{
GfGpu *gpu;
GfGpuXrandr *gpu_xrandr;
GfMonitorManager *monitor_manager;
GfMonitorManagerXrandr *monitor_manager_xrandr;
Display *xdisplay;
......@@ -158,11 +162,14 @@ gf_crtc_xrandr_set_config (GfCrtc *crtc,
xcb_randr_set_crtc_config_reply_t *reply;
xcb_generic_error_t *xcb_error;
monitor_manager = gf_crtc_get_monitor_manager (crtc);
gpu = gf_crtc_get_gpu (crtc);
gpu_xrandr = GF_GPU_XRANDR (gpu);
monitor_manager = gf_gpu_get_monitor_manager (gpu);
monitor_manager_xrandr = GF_MONITOR_MANAGER_XRANDR (monitor_manager);
xdisplay = gf_monitor_manager_xrandr_get_xdisplay (monitor_manager_xrandr);
resources = gf_monitor_manager_xrandr_get_resources (monitor_manager_xrandr);
resources = gf_gpu_xrandr_get_resources (gpu_xrandr);
xcb_conn = XGetXCBConnection (xdisplay);
config_timestamp = resources->configTimestamp;
......
/*
* Copyright (C) 2017 Red Hat
* Copyright (C) 2018 Alberts Muktupāvels
* Copyright (C) 2018-2019 Alberts Muktupāvels
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -49,8 +49,8 @@ gf_crtc_init (GfCrtc *crtc)
{
}
GfMonitorManager *
gf_crtc_get_monitor_manager (GfCrtc *crtc)
GfGpu *
gf_crtc_get_gpu (GfCrtc *crtc)
{
return crtc->monitor_manager;
return crtc->gpu;
}
/*
* Copyright (C) 2017 Red Hat
* Copyright (C) 2019 Alberts Muktupāvels
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GF_GPU_PRIVATE_H
#define GF_GPU_PRIVATE_H
#include <glib-object.h>
#include "gf-monitor-manager-private.h"
G_BEGIN_DECLS
#define GF_TYPE_GPU (gf_gpu_get_type ())
G_DECLARE_DERIVABLE_TYPE (GfGpu, gf_gpu, GF, GPU, GObject)
struct _GfGpuClass
{
GObjectClass parent_class;
gboolean (* read_current) (GfGpu *gpu,
GError **error);
};
gboolean gf_gpu_read_current (GfGpu *gpu,
GError **error);
gboolean gf_gpu_has_hotplug_mode_update (GfGpu *gpu);
GfMonitorManager *gf_gpu_get_monitor_manager (GfGpu *gpu);
GList *gf_gpu_get_outputs (GfGpu *gpu);
GList *gf_gpu_get_crtcs (GfGpu *gpu);
GList *gf_gpu_get_modes (GfGpu *gpu);
void gf_gpu_take_outputs (GfGpu *gpu,
GList *outputs);
void gf_gpu_take_crtcs (GfGpu *gpu,
GList *crtcs);
void gf_gpu_take_modes (GfGpu *gpu,
GList *modes);
G_END_DECLS
#endif
/*
* Copyright (C) 2017 Red Hat
* Copyright (C) 2019 Alberts Muktupāvels
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GF_GPU_XRANDR_PRIVATE_H
#define GF_GPU_XRANDR_PRIVATE_H
#include <glib-object.h>
#include <X11/extensions/Xrandr.h>
#include "gf-gpu-private.h"
#include "gf-monitor-manager-xrandr-private.h"
G_BEGIN_DECLS
#define GF_TYPE_GPU_XRANDR (gf_gpu_xrandr_get_type ())
G_DECLARE_FINAL_TYPE (GfGpuXrandr, gf_gpu_xrandr, GF, GPU_XRANDR, GfGpu)
GfGpuXrandr *gf_gpu_xrandr_new (GfMonitorManagerXrandr *monitor_manager_xrandr);
XRRScreenResources *gf_gpu_xrandr_get_resources (GfGpuXrandr *gpu_xrandr);
void gf_gpu_xrandr_get_max_screen_size (GfGpuXrandr *gpu_xrandr,
int *max_width,
int *max_height);
G_END_DECLS
#endif
/*
* Copyright (C) 2001, 2002 Havoc Pennington
* Copyright (C) 2002, 2003 Red Hat Inc.
* Some ICCCM manager selection code derived from fvwm2,
* Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
* Copyright (C) 2003 Rob Adams
* Copyright (C) 2004-2006 Elijah Newren
* Copyright (C) 2013-2017 Red Hat Inc.
* Copyright (C) 2019 Alberts Muktupāvels
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gf-gpu-xrandr-private.h"
#include <X11/extensions/dpms.h>
#include <X11/Xlibint.h>
#include "gf-crtc-xrandr-private.h"
#include "gf-monitor-manager-xrandr-private.h"
#include "gf-output-private.h"
#include "gf-output-xrandr-private.h"
struct _GfGpuXrandr
{
GfGpu parent;
XRRScreenResources *resources;
int max_screen_width;
int max_screen_height;
};
G_DEFINE_TYPE (GfGpuXrandr, gf_gpu_xrandr, GF_TYPE_GPU)
static gint
compare_outputs (const void *one,
const void *two)
{
const GfOutput *o_one = one, *o_two = two;
return strcmp (o_one->name, o_two->name);
}
static char *
get_xmode_name (XRRModeInfo *xmode)
{
int width = xmode->width;
int height = xmode->height;
return g_strdup_printf ("%dx%d", width, height);
}
static void
gf_gpu_xrandr_finalize (GObject *object)
{
GfGpuXrandr *gpu_xrandr;
gpu_xrandr = GF_GPU_XRANDR (object);
g_clear_pointer (&gpu_xrandr->resources, XRRFreeScreenResources);
G_OBJECT_CLASS (gf_gpu_xrandr_parent_class)->finalize (object);
}
static gboolean
gf_gpu_xrandr_read_current (GfGpu *gpu,
GError **error)
{
GfGpuXrandr *gpu_xrandr;
GfMonitorManager *monitor_manager;
GfMonitorManagerXrandr *monitor_manager_xrandr;
Display *xdisplay;
XRRScreenResources *resources;
CARD16 dpms_state;
BOOL dpms_enabled;
gint min_width;
gint min_height;
Screen *screen;
GList *outputs;
GList *modes;
GList *crtcs;
guint i, j;
GList *l;
RROutput primary_output;
gpu_xrandr = GF_GPU_XRANDR (gpu);
monitor_manager = gf_gpu_get_monitor_manager (gpu);
monitor_manager_xrandr = GF_MONITOR_MANAGER_XRANDR (monitor_manager);
xdisplay = gf_monitor_manager_xrandr_get_xdisplay (monitor_manager_xrandr);
g_clear_pointer (&gpu_xrandr->resources, XRRFreeScreenResources);
if (DPMSCapable (xdisplay) &&
DPMSInfo (xdisplay, &dpms_state, &dpms_enabled) &&
dpms_enabled)
{
switch (dpms_state)
{
case DPMSModeOn:
monitor_manager->power_save_mode = GF_POWER_SAVE_ON;
break;
case DPMSModeStandby:
monitor_manager->power_save_mode = GF_POWER_SAVE_STANDBY;
break;
case DPMSModeSuspend:
monitor_manager->power_save_mode = GF_POWER_SAVE_SUSPEND;
break;
case DPMSModeOff:
monitor_manager->power_save_mode = GF_POWER_SAVE_OFF;
break;
default:
monitor_manager->power_save_mode = GF_POWER_SAVE_UNSUPPORTED;
break;
}
}
else
{
monitor_manager->power_save_mode = GF_POWER_SAVE_UNSUPPORTED;
}
XRRGetScreenSizeRange (xdisplay, DefaultRootWindow (xdisplay),
&min_width, &min_height,
&gpu_xrandr->max_screen_width,
&gpu_xrandr->max_screen_height);
screen = ScreenOfDisplay (xdisplay, DefaultScreen (xdisplay));
/* This is updated because we called RRUpdateConfiguration below */
monitor_manager->screen_width = WidthOfScreen (screen);
monitor_manager->screen_height = HeightOfScreen (screen);
resources = XRRGetScreenResourcesCurrent (xdisplay, DefaultRootWindow (xdisplay));
if (!resources)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to retrieve Xrandr screen resources");
return FALSE;
}
gpu_xrandr->resources = resources;
outputs = NULL;
modes = NULL;
crtcs = NULL;
for (i = 0; i < (guint) resources->nmode; i++)
{
XRRModeInfo *xmode;
GfCrtcMode *mode;
xmode = &resources->modes[i];
mode = g_object_new (GF_TYPE_CRTC_MODE, NULL);
mode->mode_id = xmode->id;
mode->width = xmode->width;
mode->height = xmode->height;
mode->refresh_rate = (xmode->dotClock / ((gfloat) xmode->hTotal * xmode->vTotal));
mode->flags = xmode->modeFlags;
mode->name = get_xmode_name (xmode);
modes = g_list_append (modes, mode);
}
gf_gpu_take_modes (gpu, modes);
for (i = 0; i < (guint) resources->ncrtc; i++)
{
XRRCrtcInfo *xrandr_crtc;
RRCrtc crtc_id;
GfCrtc *crtc;
crtc_id = resources->crtcs[i];
xrandr_crtc = XRRGetCrtcInfo (xdisplay, resources, crtc_id);
crtc = gf_create_xrandr_crtc (gpu_xrandr, xrandr_crtc, crtc_id, resources);
crtcs = g_list_append (crtcs, crtc);
XRRFreeCrtcInfo (xrandr_crtc);
}
gf_gpu_take_crtcs (gpu, crtcs);
primary_output = XRRGetOutputPrimary (xdisplay, DefaultRootWindow (xdisplay));
for (i = 0; i < (guint) resources->noutput; i++)
{
RROutput output_id;
XRROutputInfo *xrandr_output;
output_id = resources->outputs[i];
xrandr_output = XRRGetOutputInfo (xdisplay, resources, output_id);
if (!xrandr_output)
continue;
if (xrandr_output->connection != RR_Disconnected)
{
GfOutput *output;
output = gf_create_xrandr_output (gpu_xrandr,
xrandr_output,
output_id,
primary_output);
if (output)
outputs = g_list_prepend (outputs, output);
}
XRRFreeOutputInfo (xrandr_output);
}
/* Sort the outputs for easier handling in GfMonitorConfig */
outputs = g_list_sort (outputs, compare_outputs);
gf_gpu_take_outputs (gpu, outputs);
/* Now fix the clones */
for (l = outputs; l; l = l->next)
{
GfOutput *output;
GList *k;
output = l->data;
for (j = 0; j < output->n_possible_clones; j++)
{
RROutput clone = GPOINTER_TO_INT (output->possible_clones[j]);
for (k = outputs; k; k = k->next)
{
GfOutput *possible_clone = k->data;
if (clone == (XID) possible_clone->winsys_id)
{
output->possible_clones[j] = possible_clone;
break;
}
}
}
}
return TRUE;
}
static void
gf_gpu_xrandr_class_init (GfGpuXrandrClass *gpu_xrandr_class)
{
GObjectClass *object_class;
GfGpuClass *gpu_class;
object_class = G_OBJECT_CLASS (gpu_xrandr_class);
gpu_class = GF_GPU_CLASS (gpu_xrandr_class);
object_class->finalize = gf_gpu_xrandr_finalize;
gpu_class->read_current = gf_gpu_xrandr_read_current;
}
static void
gf_gpu_xrandr_init (GfGpuXrandr *gpu_xrandr)
{
}
GfGpuXrandr *
gf_gpu_xrandr_new (GfMonitorManagerXrandr *monitor_manager_xrandr)
{
return g_object_new (GF_TYPE_GPU_XRANDR,
"monitor-manager", monitor_manager_xrandr,
NULL);
}
XRRScreenResources *
gf_gpu_xrandr_get_resources (GfGpuXrandr *gpu_xrandr)
{
return gpu_xrandr->resources;
}
void
gf_gpu_xrandr_get_max_screen_size (GfGpuXrandr *gpu_xrandr,
int *max_width,
int *max_height)
{
*max_width = gpu_xrandr->max_screen_width;
*max_height = gpu_xrandr->max_screen_height;
}
/*
* Copyright (C) 2017 Red Hat
* Copyright (C) 2019 Alberts Muktupāvels
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gf-gpu-private.h"
#include "gf-output-private.h"
typedef struct
{
GfMonitorManager *monitor_manager;
GList *outputs;
GList *crtcs;
GList *modes;
} GfGpuPrivate;
enum
{
PROP_0,
PROP_MONITOR_MANAGER,
LAST_PROP
};
static GParamSpec *gpu_properties[LAST_PROP] = { NULL };
G_DEFINE_TYPE_WITH_PRIVATE (GfGpu, gf_gpu, G_TYPE_OBJECT)
static void
gf_gpu_finalize (GObject *object)
{
GfGpu *gpu;
GfGpuPrivate *priv;
gpu = GF_GPU (object);
priv = gf_gpu_get_instance_private (gpu);
g_list_free_full (priv->outputs, g_object_unref);
g_list_free_full (priv->modes, g_object_unref);
g_list_free_full (priv->crtcs, g_object_unref);
G_OBJECT_CLASS (gf_gpu_parent_class)->finalize (object);
}
static void
gf_gpu_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GfGpu *gpu;
GfGpuPrivate *priv;
gpu = GF_GPU (object);
priv = gf_gpu_get_instance_private (gpu);
switch (property_id)
{
case PROP_MONITOR_MANAGER:
g_value_set_object (value, priv->monitor_manager);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gf_gpu_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GfGpu *gpu;
GfGpuPrivate *priv;
gpu = GF_GPU (object);
priv = gf_gpu_get_instance_private (gpu);
switch (property_id)
{
case PROP_MONITOR_MANAGER:
priv->monitor_manager = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gf_gpu_install_properties (GObjectClass *object_class)
{
gpu_properties[PROP_MONITOR_MANAGER] =
g_param_spec_object ("monitor-manager",
"GfMonitorManager",
"GfMonitorManager",
GF_TYPE_MONITOR_MANAGER,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, LAST_PROP,
gpu_properties);
}
static void
gf_gpu_class_init (GfGpuClass *gpu_class)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (gpu_class);
object_class->finalize = gf_gpu_finalize;
object_class->get_property = gf_gpu_get_property;
object_class->set_property = gf_gpu_set_property;
gf_gpu_install_properties (object_class);
}
static void
gf_gpu_init (GfGpu *gpu)
{
}
gboolean
gf_gpu_read_current (GfGpu *gpu,
GError **error)
{
GfGpuPrivate *priv;
gboolean ret;
GList *old_outputs;
GList *old_crtcs;
GList *old_modes;
priv = gf_gpu_get_instance_private (gpu);
/* TODO: Get rid of this when objects incref:s what they need instead. */
old_outputs = priv->outputs;
old_crtcs = priv->crtcs;
old_modes = priv->modes;
ret = GF_GPU_GET_CLASS (gpu)->read_current (gpu, error);
g_list_free_full (old_outputs, g_object_unref);
g_list_free_full (old_modes, g_object_unref);
g_list_free_full (old_crtcs, g_object_unref);
return ret;
}
gboolean
gf_gpu_has_hotplug_mode_update (GfGpu *gpu)
{
GfGpuPrivate *priv;
GList *l;
priv = gf_gpu_get_instance_private (gpu);
for (l = priv->outputs; l; l = l->next)
{
GfOutput *output = l->data;
if (output->hotplug_mode_update)
return TRUE;
}
return FALSE;
}
GfMonitorManager *
gf_gpu_get_monitor_manager (GfGpu *gpu)
{
GfGpuPrivate *priv;