xorg-x11-server/u_xfree86-activate-GPU-screens-on-autobind.patch

268 lines
8.3 KiB
Diff
Raw Permalink Normal View History

From 358448649d39b6cf4de49c0f65ce2b5f4c702c65 Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied@redhat.com>
Date: Sun, 2 Jan 2022 01:27:31 +0200
Subject: [PATCH xserver] xfree86: activate GPU screens on autobind
Part of the original patch by Dave Airlie has landed
078277e4d92f05a90c4715d61b89b9d9d38d68ea, this contains the remainder of
what was in SUSE before Xorg 21.1.
Signed-off-by: Dave Airlie <airlied@gmail.com>
---
dix/main.c | 4 +
hw/xfree86/common/xf86Init.c | 185 +++++++++++++++++++++++++++++++++++
include/dix.h | 2 +
3 files changed, 191 insertions(+)
diff --git a/dix/main.c b/dix/main.c
index bfc8addbe..c7b8ed49e 100644
--- a/dix/main.c
+++ b/dix/main.c
@@ -121,6 +121,8 @@ extern void Dispatch(void);
CallbackListPtr RootWindowFinalizeCallback = NULL;
+CallbackListPtr RootWindowInitialized = NULL;
+
int
dix_main(int argc, char *argv[], char *envp[])
{
@@ -242,6 +244,8 @@ dix_main(int argc, char *argv[], char *envp[])
for (i = 0; i < screenInfo.numScreens; i++)
InitRootWindow(screenInfo.screens[i]->root);
+ CallCallbacks(&RootWindowInitialized, NULL);
+
InitCoreDevices();
InitInput(argc, argv);
InitAndStartDevices();
diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c
index 380288ca4..9839cb19c 100644
--- a/hw/xfree86/common/xf86Init.c
+++ b/hw/xfree86/common/xf86Init.c
@@ -204,6 +204,9 @@ xf86HasTTYs(void)
#endif
}
+static void
+xf86AutoConfigProviderOutputs(CallbackListPtr *pcbl, void *data, void *call_data);
+
static void
xf86AutoConfigOutputDevices(void)
{
@@ -217,6 +220,8 @@ xf86AutoConfigOutputDevices(void)
RRProviderAutoConfigGpuScreen(xf86ScrnToScreen(xf86GPUScreens[i]),
xf86ScrnToScreen(xf86Screens[scrnum]));
}
+
+ AddCallback(&RootWindowInitialized, xf86AutoConfigProviderOutputs, NULL);
}
static void
@@ -258,6 +263,189 @@ AddVTAtoms(CallbackListPtr *pcbl, void *data, void *screen)
"Failed to register VT properties\n");
}
+
+/*
+ * This function activates all outputs of all GPU screens associated with the
+ * given master screen and sets them to their preferred resolution next to
+ * each other left-to-right.
+ */
+static void
+xf86AutoConfigureProviderOutputsForMaster(ScreenPtr pMasterScreen)
+{
+ ScreenPtr pScreen;
+ rrScrPrivPtr pMasterScrPriv, pScrPriv;
+ RROutputPtr pOutput;
+ RRCrtcPtr pCrtc;
+ RRCrtcPtr *pUsedCrtcs;
+ int usedCrtcsCount;
+ int screenWidth, screenHeight, screenWidthMM, screenHeightMM;
+ int i, j, k, l;
+
+ struct OutputConfig {
+ RROutputPtr pOutput;
+ RRCrtcPtr pCrtc;
+
+ int x;
+ int y;
+ } *outputConfigs;
+ int outputConfigsCount = 0, outputConfigsUsed = 0;
+
+ if (!dixPrivateKeyRegistered(rrPrivKey))
+ return;
+
+ pMasterScrPriv = rrGetScrPriv(pMasterScreen);
+ if (!pMasterScrPriv)
+ return;
+
+ // Count the potential maximum of outputs that we will try to auto configure
+ for (i = 0; i < xf86NumGPUScreens; i++) {
+ pScreen = xf86GPUScreens[i]->pScreen;
+ if (pScreen->current_primary != pMasterScreen || !pScreen->is_output_secondary)
+ continue;
+
+ pScrPriv = rrGetScrPriv(pScreen);
+ if (!pScrPriv)
+ continue;
+
+ outputConfigsCount += pScrPriv->numOutputs;
+ }
+
+ if (outputConfigsCount == 0)
+ return;
+
+ outputConfigs = calloc(outputConfigsCount, sizeof(*outputConfigs));
+
+ screenWidth = 0;
+ screenHeight = 0;
+
+ // Consider the master's own outputs/crtcs that were already configured
+ for (i = 0; i < pMasterScrPriv->numCrtcs; i++) {
+ if (!pMasterScrPriv->crtcs[i]->mode)
+ continue;
+
+ screenWidth = max(screenWidth, pMasterScrPriv->crtcs[i]->x + pMasterScrPriv->crtcs[i]->mode->mode.width);
+ screenHeight = max(screenHeight, pMasterScrPriv->crtcs[i]->y + pMasterScrPriv->crtcs[i]->mode->mode.height);
+ }
+
+ // Now add as many outputs from slave GPUs as we can next to it
+ for (i = 0; i < xf86NumGPUScreens; i++) {
+ pScreen = xf86GPUScreens[i]->pScreen;
+ if (pScreen->current_primary != pMasterScreen || !pScreen->is_output_secondary)
+ continue;
+
+ pScrPriv = rrGetScrPriv(pScreen);
+ if (!pScrPriv)
+ continue;
+
+ pUsedCrtcs = calloc(pScrPriv->numCrtcs, sizeof(*pUsedCrtcs));
+ if (!pUsedCrtcs)
+ continue;
+
+ usedCrtcsCount = 0;
+
+ for (j = 0; j < pScrPriv->numOutputs; j++) {
+ pOutput = pScrPriv->outputs[j];
+
+ if (pOutput->connection != RR_Connected ||
+ pOutput->nonDesktop ||
+ pOutput->numModes == 0 ||
+ pOutput->numCrtcs == 0)
+ continue;
+
+ if (screenWidth + pOutput->modes[0]->mode.width > pMasterScrPriv->maxWidth ||
+ screenHeight + pOutput->modes[0]->mode.height > pMasterScrPriv->maxHeight)
+ {
+ // It can't fit into the maximal size, skip
+ continue;
+ }
+
+ for (k = 0; k < pOutput->numCrtcs; k++) {
+ pCrtc = pOutput->crtcs[k];
+ for (l = 0; l < usedCrtcsCount; l++) {
+ if (pCrtc == pUsedCrtcs[l]) {
+ pCrtc = NULL;
+ break;
+ }
+ }
+ if (pCrtc) {
+ break;
+ }
+ }
+
+ if (!pCrtc) {
+ // No more free CRTCs to setup this output, skip
+ continue;
+ }
+
+ pUsedCrtcs[usedCrtcsCount] = pCrtc;
+ usedCrtcsCount++;
+
+ assert(outputConfigsUsed < outputConfigsCount);
+ outputConfigs[outputConfigsUsed].pOutput = pOutput;
+ outputConfigs[outputConfigsUsed].pCrtc = pCrtc;
+ outputConfigs[outputConfigsUsed].x = screenWidth;
+ outputConfigs[outputConfigsUsed].y = 0;
+ outputConfigsUsed++;
+
+ screenWidth += pOutput->modes[0]->mode.width;
+ screenHeight += pOutput->modes[0]->mode.height;
+ }
+
+ free(pUsedCrtcs);
+ }
+
+ if (outputConfigsUsed == 0)
+ goto out;
+
+ if (screenWidth < pMasterScrPriv->minWidth)
+ screenWidth = pMasterScrPriv->minWidth;
+ if (screenHeight < pMasterScrPriv->minHeight)
+ screenHeight = pMasterScrPriv->minHeight;
+
+ if (pMasterScrPriv->mmWidth > 0 &&
+ pMasterScrPriv->mmHeight > 0 &&
+ pMasterScrPriv->width > 0 &&
+ pMasterScrPriv->height > 0)
+ {
+ // If the master screen already has some DPI, keep it
+ screenWidthMM = pMasterScrPriv->mmWidth * screenWidth / pMasterScreen->width;
+ screenHeightMM = pMasterScrPriv->mmHeight * screenHeight / pMasterScreen->height;
+ } else {
+ assert(outputConfigsUsed > 0);
+ // Otherwise use DPI of the first output
+ screenWidthMM = outputConfigs[0].pOutput->mmWidth * screenWidth / outputConfigs[0].pOutput->modes[0]->mode.width;
+ screenHeightMM = outputConfigs[0].pOutput->mmHeight * screenHeight / outputConfigs[0].pOutput->modes[0]->mode.height;
+ }
+
+ if (!RRScreenSizeSet(pMasterScreen, screenWidth, screenHeight, screenWidthMM, screenHeightMM))
+ goto out;
+
+ for (i = 0; i < outputConfigsUsed; i++) {
+ RRCrtcSet(
+ outputConfigs[i].pCrtc,
+ outputConfigs[i].pOutput->modes[0],
+ outputConfigs[i].x,
+ outputConfigs[i].y,
+ RR_Rotate_0,
+ 1,
+ &outputConfigs[i].pOutput
+ );
+ }
+
+out:
+ free(outputConfigs);
+}
+
+static void
+xf86AutoConfigProviderOutputs(CallbackListPtr *pcbl, void *data, void *call_data)
+{
+ int i;
+
+ for (i = 0; i < xf86NumScreens; i++) {
+ xf86AutoConfigureProviderOutputsForMaster(xf86Screens[i]->pScreen);
+ }
+}
+
static Bool
xf86ScreenInit(ScreenPtr pScreen, int argc, char **argv)
{
diff --git a/include/dix.h b/include/dix.h
index 0dcd09b65..ecc73d1d9 100644
--- a/include/dix.h
+++ b/include/dix.h
@@ -620,6 +620,8 @@ typedef struct {
extern _X_EXPORT CallbackListPtr RootWindowFinalizeCallback;
+extern _X_EXPORT CallbackListPtr RootWindowInitialized;
+
extern int
XItoCoreType(int xi_type);
extern Bool
--
2.25.1