From c6511d0142040654140bdedd6f03d43af0abba21 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 2 Oct 2013 15:47:54 +0200 Subject: [PATCH 01/10] exa: only draw valid trapezoids Fixes freedesktop.org bug https://bugs.freedesktop.org/show_bug.cgi?id=67484 If t->bottom is close to MIN_INT, removing top can wraparound, so do the check properly. A similar fix should also be applied to pixman. Signed-off-by: Maarten Lankhorst Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- exa/exa_render.c | 3 ++- render/picture.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/exa/exa_render.c b/exa/exa_render.c index fc3ddea79..b24bec052 100644 --- a/exa/exa_render.c +++ b/exa/exa_render.c @@ -1141,7 +1141,8 @@ exaTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); for (; ntrap; ntrap--, traps++) - (*ps->RasterizeTrapezoid) (pPicture, traps, -bounds.x1, -bounds.y1); + if (xTrapezoidValid(traps)) + (*ps->RasterizeTrapezoid) (pPicture, traps, -bounds.x1, -bounds.y1); exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); xRel = bounds.x1 + xSrc - xDst; diff --git a/render/picture.h b/render/picture.h index 087e54d7a..4499a0021 100644 --- a/render/picture.h +++ b/render/picture.h @@ -211,7 +211,7 @@ typedef pixman_fixed_t xFixed; /* whether 't' is a well defined not obviously empty trapezoid */ #define xTrapezoidValid(t) ((t)->left.p1.y != (t)->left.p2.y && \ (t)->right.p1.y != (t)->right.p2.y && \ - (int) ((t)->bottom - (t)->top) > 0) + ((t)->bottom > (t)->top)) /* * Standard NTSC luminance conversions: From fbe660b7652b945bdd8e3eb0780179d83cc7de96 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Feb 2015 09:58:43 +0000 Subject: [PATCH 02/10] present: Improve scaling of vblank handler With large numbers of queued vblank, the list iteration on every interupt dominates processing time. If we reorder the list to be in ascending event order, then not only is also likely to be in order for notification queries (i.e. the notification will be near the start of the list), we can also stop iterating when past the target event_id. Signed-off-by: Chris Wilson Reviewed-and-tested-by: Mario Kleiner Signed-off-by: Hans de Goede --- present/present.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/present/present.c b/present/present.c index 105e2bf47..2ae7d3a80 100644 --- a/present/present.c +++ b/present/present.c @@ -517,19 +517,22 @@ present_flip_notify(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc) void present_event_notify(uint64_t event_id, uint64_t ust, uint64_t msc) { - present_vblank_ptr vblank, tmp; + present_vblank_ptr vblank; int s; if (!event_id) return; DebugPresent(("\te %lld ust %lld msc %lld\n", event_id, ust, msc)); - xorg_list_for_each_entry_safe(vblank, tmp, &present_exec_queue, event_queue) { - if (vblank->event_id == event_id) { + xorg_list_for_each_entry(vblank, &present_exec_queue, event_queue) { + int64_t match = event_id - vblank->event_id; + if (match == 0) { present_execute(vblank, ust, msc); return; } + if (match < 0) + break; } - xorg_list_for_each_entry_safe(vblank, tmp, &present_flip_queue, event_queue) { + xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) { if (vblank->event_id == event_id) { present_flip_notify(vblank, ust, msc); return; @@ -943,7 +946,7 @@ present_pixmap(WindowPtr window, vblank->pixmap->drawable.id, vblank->window->drawable.id, target_crtc, vblank->flip, vblank->sync_flip, vblank->serial)); - xorg_list_add(&vblank->event_queue, &present_exec_queue); + xorg_list_append(&vblank->event_queue, &present_exec_queue); vblank->queued = TRUE; if (msc_is_after(target_msc, crtc_msc)) { ret = present_queue_vblank(screen, target_crtc, vblank->event_id, target_msc); @@ -967,7 +970,7 @@ no_mem: void present_abort_vblank(ScreenPtr screen, RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) { - present_vblank_ptr vblank, tmp; + present_vblank_ptr vblank; if (crtc == NULL) present_fake_abort_vblank(screen, event_id, msc); @@ -978,14 +981,17 @@ present_abort_vblank(ScreenPtr screen, RRCrtcPtr crtc, uint64_t event_id, uint64 (*screen_priv->info->abort_vblank) (crtc, event_id, msc); } - xorg_list_for_each_entry_safe(vblank, tmp, &present_exec_queue, event_queue) { - if (vblank->event_id == event_id) { + xorg_list_for_each_entry(vblank, &present_exec_queue, event_queue) { + int64_t match = event_id - vblank->event_id; + if (match == 0) { xorg_list_del(&vblank->event_queue); vblank->queued = FALSE; return; } + if (match < 0) + break; } - xorg_list_for_each_entry_safe(vblank, tmp, &present_flip_queue, event_queue) { + xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) { if (vblank->event_id == event_id) { xorg_list_del(&vblank->event_queue); return; From bab0f450a719a11799491043b82c2f293fed27fe Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Feb 2015 09:58:44 +0000 Subject: [PATCH 03/10] present: Fix presentation of flips out of order The flip queue currently only holds events submitted to the driver for flipping, awaiting the completion notifier. It is short. We therefore can speed up interrupt processing by keeping the small number of events ready to be flipped on the end of the flip queue. By appending the events to the flip_queue in the order that they become ready, we also resolve one issue causing Present to display frames out of order. Signed-off-by: Chris Wilson Reviewed-and-tested-by: Mario Kleiner Signed-off-by: Hans de Goede --- present/present.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/present/present.c b/present/present.c index 2ae7d3a80..cebd2f786 100644 --- a/present/present.c +++ b/present/present.c @@ -353,10 +353,10 @@ present_re_execute(present_vblank_ptr vblank) static void present_flip_try_ready(ScreenPtr screen) { - present_vblank_ptr vblank, tmp; + present_vblank_ptr vblank; - xorg_list_for_each_entry_safe(vblank, tmp, &present_exec_queue, event_queue) { - if (vblank->flip_ready) { + xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) { + if (vblank->queued) { present_re_execute(vblank); return; } @@ -656,6 +656,8 @@ present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc) DebugPresent(("\tr %lld %p (pending %p unflip %lld)\n", vblank->event_id, vblank, screen_priv->flip_pending, screen_priv->unflip_event_id)); + xorg_list_del(&vblank->event_queue); + xorg_list_append(&vblank->event_queue, &present_flip_queue); vblank->flip_ready = TRUE; return; } @@ -994,6 +996,7 @@ present_abort_vblank(ScreenPtr screen, RRCrtcPtr crtc, uint64_t event_id, uint64 xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) { if (vblank->event_id == event_id) { xorg_list_del(&vblank->event_queue); + vblank->queued = FALSE; return; } } From 5c7af02b103790ac1fb6a71822788892c70290b6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 13 May 2016 15:58:10 +0200 Subject: [PATCH 04/10] xrandrprovider: Do not use separate lists for unbound / source / offload slaves A single provider can be both a offload and source slave at the same time, the use of seperate lists breaks in this case e.g. : xrandr --listproviders Providers: number : 2 Provider 0: id: 0x7b cap: 0xf, Source Output, Sink Output, Source Offload, Sink Offload crtcs: 3 outputs: 2 associated providers: 0 name:modesetting Provider 1: id: 0x46 cap: 0xf, Source Output, Sink Output, Source Offload, Sink Offload crtcs: 2 outputs: 5 associated providers: 0 name:modesetting xrandr --setprovideroutputsource 1 0x7b xrandr --listproviders Providers: number : 2 Provider 0: id: 0x7b cap: 0xf, Source Output, Sink Output, Source Offload, Sink Offload crtcs: 3 outputs: 2 associated providers: 1 name:modesetting Provider 1: id: 0x46 cap: 0xf, Source Output, Sink Output, Source Offload, Sink Offload crtcs: 2 outputs: 5 associated providers: 1 name:modesetting xrandr --setprovideroffloadsink 1 0x7b xrandr --listproviders Providers: number : 3 Provider 0: id: 0x7b cap: 0xf, Source Output, Sink Output, Source Offload, Sink Offload crtcs: 3 outputs: 2 associated providers: 2 name:modesetting Provider 1: id: 0x46 cap: 0xf, Source Output, Sink Output, Source Offload, Sink Offload crtcs: 2 outputs: 5 associated providers: 2 name:modesetting Provider 2: id: 0x46 cap: 0xf, Source Output, Sink Output, Source Offload, Sink Offload crtcs: 2 outputs: 5 associated providers: 2 name:modesetting Not good. The problem is that the provider with id 0x46 now is on both the output_slave_list and the offload_slave_list of the master screen. This commit fixes this by unifying all 3 lists into a single slaves list. Note that this does change the struct _Screen definition, so this is an ABI break. I do not expect any of the drivers to actually use the removed / changed fields so a recompile should suffice. Signed-off-by: Hans de Goede Reviewed-by: Dave Airlie --- dix/dispatch.c | 30 +++++++++++--------- hw/xfree86/dri2/dri2.c | 7 +++-- hw/xfree86/modes/xf86RandR12.c | 11 ++------ include/scrnintstr.h | 15 +++++----- present/present.c | 2 +- randr/randr.c | 42 +++++++++++----------------- randr/rrcrtc.c | 16 +++++++++-- randr/rrmonitor.c | 17 ++++++++++-- randr/rroutput.c | 10 +++---- randr/rrprovider.c | 50 +++++++++++----------------------- randr/rrscreen.c | 12 ++++++-- 11 files changed, 104 insertions(+), 108 deletions(-) diff --git a/dix/dispatch.c b/dix/dispatch.c index 86124c683..8a7eff712 100644 --- a/dix/dispatch.c +++ b/dix/dispatch.c @@ -3789,9 +3789,7 @@ static int init_screen(ScreenPtr pScreen, int i, Bool gpu) pScreen->CreateScreenResources = 0; xorg_list_init(&pScreen->pixmap_dirty_list); - xorg_list_init(&pScreen->unattached_list); - xorg_list_init(&pScreen->output_slave_list); - xorg_list_init(&pScreen->offload_slave_list); + xorg_list_init(&pScreen->slave_list); /* * This loop gets run once for every Screen that gets added, @@ -3950,7 +3948,7 @@ AttachUnboundGPU(ScreenPtr pScreen, ScreenPtr new) { assert(new->isGPU); assert(!new->current_master); - xorg_list_add(&new->unattached_head, &pScreen->unattached_list); + xorg_list_add(&new->slave_head, &pScreen->slave_list); new->current_master = pScreen; } @@ -3958,7 +3956,9 @@ void DetachUnboundGPU(ScreenPtr slave) { assert(slave->isGPU); - xorg_list_del(&slave->unattached_head); + assert(!slave->is_output_slave); + assert(!slave->is_offload_slave); + xorg_list_del(&slave->slave_head); slave->current_master = NULL; } @@ -3966,31 +3966,35 @@ void AttachOutputGPU(ScreenPtr pScreen, ScreenPtr new) { assert(new->isGPU); - xorg_list_add(&new->output_head, &pScreen->output_slave_list); - new->current_master = pScreen; + assert(!new->is_output_slave); + assert(new->current_master == pScreen); + new->is_output_slave = TRUE; + new->current_master->output_slaves++; } void DetachOutputGPU(ScreenPtr slave) { assert(slave->isGPU); - xorg_list_del(&slave->output_head); - slave->current_master = NULL; + assert(slave->is_output_slave); + slave->current_master->output_slaves--; + slave->is_output_slave = FALSE; } void AttachOffloadGPU(ScreenPtr pScreen, ScreenPtr new) { assert(new->isGPU); - xorg_list_add(&new->offload_head, &pScreen->offload_slave_list); - new->current_master = pScreen; + assert(!new->is_offload_slave); + assert(new->current_master == pScreen); + new->is_offload_slave = TRUE; } void DetachOffloadGPU(ScreenPtr slave) { assert(slave->isGPU); - xorg_list_del(&slave->offload_head); - slave->current_master = NULL; + assert(slave->is_offload_slave); + slave->is_offload_slave = FALSE; } diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c index f80599fb7..2165603d9 100644 --- a/hw/xfree86/dri2/dri2.c +++ b/hw/xfree86/dri2/dri2.c @@ -186,12 +186,15 @@ static ScreenPtr GetScreenPrime(ScreenPtr master, int prime_id) { ScreenPtr slave; - if (prime_id == 0 || xorg_list_is_empty(&master->offload_slave_list)) { + if (prime_id == 0) { return master; } - xorg_list_for_each_entry(slave, &master->offload_slave_list, offload_head) { + xorg_list_for_each_entry(slave, &master->slave_list, slave_head) { DRI2ScreenPtr ds; + if (!slave->is_offload_slave) + continue; + ds = DRI2GetScreen(slave); if (ds == NULL) continue; diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c index 60d22543e..4a21766e0 100644 --- a/hw/xfree86/modes/xf86RandR12.c +++ b/hw/xfree86/modes/xf86RandR12.c @@ -1836,10 +1836,7 @@ xf86RandR14ProviderSetOutputSource(ScreenPtr pScreen, { if (!source_provider) { if (provider->output_source) { - ScreenPtr cmScreen = pScreen->current_master; - xf86DetachOutputGPU(pScreen); - AttachUnboundGPU(cmScreen, pScreen); } provider->output_source = NULL; return TRUE; @@ -1850,7 +1847,6 @@ xf86RandR14ProviderSetOutputSource(ScreenPtr pScreen, SetRootClip(source_provider->pScreen, ROOT_CLIP_NONE); - DetachUnboundGPU(pScreen); AttachOutputGPU(source_provider->pScreen, pScreen); provider->output_source = source_provider; @@ -1865,9 +1861,7 @@ xf86RandR14ProviderSetOffloadSink(ScreenPtr pScreen, { if (!sink_provider) { if (provider->offload_sink) { - ScreenPtr cmScreen = pScreen->current_master; xf86DetachOutputGPU(pScreen); - AttachUnboundGPU(cmScreen, pScreen); } provider->offload_sink = NULL; @@ -1877,7 +1871,6 @@ xf86RandR14ProviderSetOffloadSink(ScreenPtr pScreen, if (provider->offload_sink == sink_provider) return TRUE; - DetachUnboundGPU(pScreen); AttachOffloadGPU(sink_provider->pScreen, pScreen); provider->offload_sink = sink_provider; @@ -1956,12 +1949,12 @@ xf86RandR14ProviderDestroy(ScreenPtr screen, RRProviderPtr provider) config->randr_provider->offload_sink = NULL; RRSetChanged(screen); } - else if (config->randr_provider->output_source) { + if (config->randr_provider->output_source) { xf86DetachOutputGPU(screen); config->randr_provider->output_source = NULL; RRSetChanged(screen); } - else if (screen->current_master) + if (screen->current_master) DetachUnboundGPU(screen); } config->randr_provider = NULL; diff --git a/include/scrnintstr.h b/include/scrnintstr.h index 2e617c466..63ef55c10 100644 --- a/include/scrnintstr.h +++ b/include/scrnintstr.h @@ -590,13 +590,14 @@ typedef struct _Screen { Bool isGPU; - struct xorg_list unattached_list; - struct xorg_list unattached_head; - + /* Info on this screen's slaves (if any) */ + struct xorg_list slave_list; + struct xorg_list slave_head; + int output_slaves; + /* Info for when this screen is a slave */ ScreenPtr current_master; - - struct xorg_list output_slave_list; - struct xorg_list output_head; + Bool is_output_slave; + Bool is_offload_slave; SharePixmapBackingProcPtr SharePixmapBacking; SetSharedPixmapBackingProcPtr SetSharedPixmapBacking; @@ -605,8 +606,6 @@ typedef struct _Screen { StopPixmapTrackingProcPtr StopPixmapTracking; struct xorg_list pixmap_dirty_list; - struct xorg_list offload_slave_list; - struct xorg_list offload_head; ReplaceScanoutPixmapProcPtr ReplaceScanoutPixmap; XYToWindowProcPtr XYToWindow; diff --git a/present/present.c b/present/present.c index cebd2f786..521083287 100644 --- a/present/present.c +++ b/present/present.c @@ -145,7 +145,7 @@ present_check_flip(RRCrtcPtr crtc, return FALSE; /* Fail to flip if we have slave outputs */ - if (!xorg_list_is_empty(&screen->output_slave_list)) + if (screen->output_slaves) return FALSE; /* Make sure the window hasn't been redirected with Composite */ diff --git a/randr/randr.c b/randr/randr.c index 3aabb1981..95ed7e5e6 100644 --- a/randr/randr.c +++ b/randr/randr.c @@ -483,7 +483,10 @@ TellChanged(WindowPtr pWin, void *value) RRDeliverCrtcEvent(client, pWin, crtc); } - xorg_list_for_each_entry(iter, &pScreen->output_slave_list, output_head) { + xorg_list_for_each_entry(iter, &pScreen->slave_list, slave_head) { + if (!iter->is_output_slave) + continue; + pSlaveScrPriv = rrGetScrPriv(iter); for (i = 0; i < pSlaveScrPriv->numCrtcs; i++) { RRCrtcPtr crtc = pSlaveScrPriv->crtcs[i]; @@ -502,7 +505,10 @@ TellChanged(WindowPtr pWin, void *value) RRDeliverOutputEvent(client, pWin, output); } - xorg_list_for_each_entry(iter, &pScreen->output_slave_list, output_head) { + xorg_list_for_each_entry(iter, &pScreen->slave_list, slave_head) { + if (!iter->is_output_slave) + continue; + pSlaveScrPriv = rrGetScrPriv(iter); for (i = 0; i < pSlaveScrPriv->numOutputs; i++) { RROutputPtr output = pSlaveScrPriv->outputs[i]; @@ -514,17 +520,7 @@ TellChanged(WindowPtr pWin, void *value) } if (pRREvent->mask & RRProviderChangeNotifyMask) { - xorg_list_for_each_entry(iter, &pScreen->output_slave_list, output_head) { - pSlaveScrPriv = rrGetScrPriv(iter); - if (pSlaveScrPriv->provider->changed) - RRDeliverProviderEvent(client, pWin, pSlaveScrPriv->provider); - } - xorg_list_for_each_entry(iter, &pScreen->offload_slave_list, offload_head) { - pSlaveScrPriv = rrGetScrPriv(iter); - if (pSlaveScrPriv->provider->changed) - RRDeliverProviderEvent(client, pWin, pSlaveScrPriv->provider); - } - xorg_list_for_each_entry(iter, &pScreen->unattached_list, unattached_head) { + xorg_list_for_each_entry(iter, &pScreen->slave_list, slave_head) { pSlaveScrPriv = rrGetScrPriv(iter); if (pSlaveScrPriv->provider->changed) RRDeliverProviderEvent(client, pWin, pSlaveScrPriv->provider); @@ -602,21 +598,15 @@ RRTellChanged(ScreenPtr pScreen) for (i = 0; i < pScrPriv->numCrtcs; i++) pScrPriv->crtcs[i]->changed = FALSE; - xorg_list_for_each_entry(iter, &master->output_slave_list, output_head) { - pSlaveScrPriv = rrGetScrPriv(iter); - pSlaveScrPriv->provider->changed = FALSE; - for (i = 0; i < pSlaveScrPriv->numOutputs; i++) - pSlaveScrPriv->outputs[i]->changed = FALSE; - for (i = 0; i < pSlaveScrPriv->numCrtcs; i++) - pSlaveScrPriv->crtcs[i]->changed = FALSE; - } - xorg_list_for_each_entry(iter, &master->offload_slave_list, offload_head) { - pSlaveScrPriv = rrGetScrPriv(iter); - pSlaveScrPriv->provider->changed = FALSE; - } - xorg_list_for_each_entry(iter, &master->unattached_list, unattached_head) { + xorg_list_for_each_entry(iter, &master->slave_list, slave_head) { pSlaveScrPriv = rrGetScrPriv(iter); pSlaveScrPriv->provider->changed = FALSE; + if (iter->is_output_slave) { + for (i = 0; i < pSlaveScrPriv->numOutputs; i++) + pSlaveScrPriv->outputs[i]->changed = FALSE; + for (i = 0; i < pSlaveScrPriv->numCrtcs; i++) + pSlaveScrPriv->crtcs[i]->changed = FALSE; + } } if (mastersp->layoutChanged) { diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c index 54471332d..ea91ab703 100644 --- a/randr/rrcrtc.c +++ b/randr/rrcrtc.c @@ -526,8 +526,12 @@ rrCheckPixmapBounding(ScreenPtr pScreen, RegionUnion(&total_region, &total_region, &new_crtc_region); } - xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) { + xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) { rrScrPrivPtr slave_priv = rrGetScrPriv(slave); + + if (!slave->is_output_slave) + continue; + for (c = 0; c < slave_priv->numCrtcs; c++) { RRCrtcPtr slave_crtc = slave_priv->crtcs[c]; @@ -1700,7 +1704,10 @@ RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x, if (ret == TRUE) return; - xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) { + xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) { + if (!slave->is_output_slave) + continue; + ret = check_all_screen_crtcs(slave, x, y); if (ret == TRUE) return; @@ -1711,7 +1718,10 @@ RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x, if (ret == TRUE) return; - xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) { + xorg_list_for_each_entry(slave, &pScreen->slave_list, slave_head) { + if (!slave->is_output_slave) + continue; + ret = constrain_all_screen_crtcs(pDev, slave, x, y); if (ret == TRUE) return; diff --git a/randr/rrmonitor.c b/randr/rrmonitor.c index ba310eaa4..3f6e03e7d 100644 --- a/randr/rrmonitor.c +++ b/randr/rrmonitor.c @@ -202,8 +202,12 @@ RRMonitorInitList(ScreenPtr screen, RRMonitorListPtr mon_list, Bool get_active) /* Count the number of crtcs in this and any slave screens */ numCrtcs = pScrPriv->numCrtcs; - xorg_list_for_each_entry(slave, &screen->output_slave_list, output_head) { + xorg_list_for_each_entry(slave, &screen->slave_list, slave_head) { rrScrPrivPtr pSlavePriv; + + if (!slave->is_output_slave) + continue; + pSlavePriv = rrGetScrPriv(slave); numCrtcs += pSlavePriv->numCrtcs; } @@ -220,8 +224,12 @@ RRMonitorInitList(ScreenPtr screen, RRMonitorListPtr mon_list, Bool get_active) mon_list->server_crtc[c] = pScrPriv->crtcs[sc]; } - xorg_list_for_each_entry(slave, &screen->output_slave_list, output_head) { + xorg_list_for_each_entry(slave, &screen->slave_list, slave_head) { rrScrPrivPtr pSlavePriv; + + if (!slave->is_output_slave) + continue; + pSlavePriv = rrGetScrPriv(slave); for (sc = 0; sc < pSlavePriv->numCrtcs; sc++, c++) { if (pSlavePriv->crtcs[sc]->mode != NULL) @@ -471,7 +479,10 @@ RRMonitorAdd(ClientPtr client, ScreenPtr screen, RRMonitorPtr monitor) return BadValue; } - xorg_list_for_each_entry(slave, &screen->output_slave_list, output_head) { + xorg_list_for_each_entry(slave, &screen->slave_list, slave_head) { + if (!slave->is_output_slave) + continue; + if (RRMonitorMatchesOutputName(slave, monitor->name)) { client->errorValue = monitor->name; return BadValue; diff --git a/randr/rroutput.c b/randr/rroutput.c index 686ae49a6..a8efec409 100644 --- a/randr/rroutput.c +++ b/randr/rroutput.c @@ -570,12 +570,10 @@ ProcRRSetOutputPrimary(ClientPtr client) RRSetPrimaryOutput(pWin->drawable.pScreen, pScrPriv, output); xorg_list_for_each_entry(slave, - &pWin->drawable.pScreen->output_slave_list, - output_head) { - rrScrPrivPtr pSlavePriv; - pSlavePriv = rrGetScrPriv(slave); - - RRSetPrimaryOutput(slave, pSlavePriv, output); + &pWin->drawable.pScreen->slave_list, + slave_head) { + if (slave->is_output_slave) + RRSetPrimaryOutput(slave, rrGetScrPriv(slave), output); } } diff --git a/randr/rrprovider.c b/randr/rrprovider.c index 5329f410b..8ef47260c 100644 --- a/randr/rrprovider.c +++ b/randr/rrprovider.c @@ -72,15 +72,7 @@ ProcRRGetProviders (ClientPtr client) if (pScrPriv->provider) total_providers++; - xorg_list_for_each_entry(iter, &pScreen->output_slave_list, output_head) { - pScrPriv = rrGetScrPriv(iter); - total_providers += pScrPriv->provider ? 1 : 0; - } - xorg_list_for_each_entry(iter, &pScreen->offload_slave_list, offload_head) { - pScrPriv = rrGetScrPriv(iter); - total_providers += pScrPriv->provider ? 1 : 0; - } - xorg_list_for_each_entry(iter, &pScreen->unattached_list, unattached_head) { + xorg_list_for_each_entry(iter, &pScreen->slave_list, slave_head) { pScrPriv = rrGetScrPriv(iter); total_providers += pScrPriv->provider ? 1 : 0; } @@ -116,13 +108,7 @@ ProcRRGetProviders (ClientPtr client) providers = (RRProvider *)extra; ADD_PROVIDER(pScreen); - xorg_list_for_each_entry(iter, &pScreen->output_slave_list, output_head) { - ADD_PROVIDER(iter); - } - xorg_list_for_each_entry(iter, &pScreen->offload_slave_list, offload_head) { - ADD_PROVIDER(iter); - } - xorg_list_for_each_entry(iter, &pScreen->unattached_list, unattached_head) { + xorg_list_for_each_entry(iter, &pScreen->slave_list, slave_head) { ADD_PROVIDER(iter); } } @@ -182,12 +168,13 @@ ProcRRGetProviderInfo (ClientPtr client) /* count associated providers */ if (provider->offload_sink) rep.nAssociatedProviders++; - if (provider->output_source) - rep.nAssociatedProviders++; - xorg_list_for_each_entry(provscreen, &pScreen->output_slave_list, output_head) - rep.nAssociatedProviders++; - xorg_list_for_each_entry(provscreen, &pScreen->offload_slave_list, offload_head) + if (provider->output_source && + provider->output_source != provider->offload_sink) rep.nAssociatedProviders++; + xorg_list_for_each_entry(provscreen, &pScreen->slave_list, slave_head) { + if (provscreen->is_output_slave || provscreen->is_offload_slave) + rep.nAssociatedProviders++; + } rep.length = (pScrPriv->numCrtcs + pScrPriv->numOutputs + (rep.nAssociatedProviders * 2) + bytes_to_int32(rep.nameLength)); @@ -237,27 +224,22 @@ ProcRRGetProviderInfo (ClientPtr client) swapl(&prov_cap[i]); i++; } - xorg_list_for_each_entry(provscreen, &pScreen->output_slave_list, output_head) { + xorg_list_for_each_entry(provscreen, &pScreen->slave_list, slave_head) { + if (!provscreen->is_output_slave && !provscreen->is_offload_slave) + continue; pScrProvPriv = rrGetScrPriv(provscreen); providers[i] = pScrProvPriv->provider->id; if (client->swapped) swapl(&providers[i]); - prov_cap[i] = RR_Capability_SinkOutput; + prov_cap[i] = 0; + if (provscreen->is_output_slave) + prov_cap[i] |= RR_Capability_SinkOutput; + if (provscreen->is_offload_slave) + prov_cap[i] |= RR_Capability_SourceOffload; if (client->swapped) swapl(&prov_cap[i]); i++; } - xorg_list_for_each_entry(provscreen, &pScreen->offload_slave_list, offload_head) { - pScrProvPriv = rrGetScrPriv(provscreen); - providers[i] = pScrProvPriv->provider->id; - if (client->swapped) - swapl(&providers[i]); - prov_cap[i] = RR_Capability_SourceOffload; - if (client->swapped) - swapl(&prov_cap[i]); - i++; - } - memcpy(name, provider->name, rep.nameLength); if (client->swapped) { diff --git a/randr/rrscreen.c b/randr/rrscreen.c index b5e2090d9..d6c499580 100644 --- a/randr/rrscreen.c +++ b/randr/rrscreen.c @@ -394,7 +394,10 @@ rrGetMultiScreenResources(ClientPtr client, Bool query, ScreenPtr pScreen) update_totals(pScreen, pScrPriv); - xorg_list_for_each_entry(iter, &pScreen->output_slave_list, output_head) { + xorg_list_for_each_entry(iter, &pScreen->slave_list, slave_head) { + if (!iter->is_output_slave) + continue; + pScrPriv = rrGetScrPriv(iter); if (query) @@ -450,7 +453,10 @@ rrGetMultiScreenResources(ClientPtr client, Bool query, ScreenPtr pScreen) } update_arrays(pScreen, pScrPriv, primary_crtc, has_primary); - xorg_list_for_each_entry(iter, &pScreen->output_slave_list, output_head) { + xorg_list_for_each_entry(iter, &pScreen->slave_list, slave_head) { + if (!iter->is_output_slave) + continue; + pScrPriv = rrGetScrPriv(iter); update_arrays(iter, pScrPriv, primary_crtc, has_primary); @@ -503,7 +509,7 @@ rrGetScreenResources(ClientPtr client, Bool query) if (!RRGetInfo(pScreen, query)) return BadAlloc; - if (!xorg_list_is_empty(&pScreen->output_slave_list)) + if (pScreen->output_slaves) return rrGetMultiScreenResources(client, query, pScreen); if (!pScrPriv) { From 15595d29c2c3992f260a3314f26fa691f1e5cec8 Mon Sep 17 00:00:00 2001 From: Nikhil Mahale Date: Thu, 26 May 2016 21:50:16 +0530 Subject: [PATCH 05/10] randr: Adjust master's last set time with slaves In prime configurations master's last set time may not be latest and greatest, adjust it with slaves last set time, pick up greatest one. Otherwise xserver may end with events which has lastSetTime < lastConfigTime even if that's not the case and confuse xrandr client. [hdegoede: rebase on "xrandrprovider: Do not use separate lists for unbound / source / offload slaves"] Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- randr/randr.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/randr/randr.c b/randr/randr.c index 95ed7e5e6..0138dc100 100644 --- a/randr/randr.c +++ b/randr/randr.c @@ -580,6 +580,18 @@ RRTellChanged(ScreenPtr pScreen) mastersp = pScrPriv; } + xorg_list_for_each_entry(iter, &master->slave_list, slave_head) { + pSlaveScrPriv = rrGetScrPriv(iter); + + if (!iter->is_output_slave) + continue; + + if (CompareTimeStamps(mastersp->lastSetTime, + pSlaveScrPriv->lastSetTime) == EARLIER) { + mastersp->lastSetTime = pSlaveScrPriv->lastSetTime; + } + } + if (mastersp->changed) { UpdateCurrentTimeIf(); if (mastersp->configChanged) { From b8ef71fb07a8ba9587aeaca942b4de20b59266ca Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 1 Jun 2016 14:59:38 +0200 Subject: [PATCH 06/10] modesetting: Properly cleanup fb for reverse-prime-offload drmmode_set_scanout_pixmap_gpu(pix) adds drmmod->fb_id through a call to drmmode_xf86crtc_resize(), but on a subsequent drmmode_set_scanout_pixmap_gpu(NULL) it would not remove the fb. This keeps the crtc marked as busy, which causes the dgpu to not being able to runtime suspend, after an output attached to the dgpu has been used once. Which causes burning through an additional 10W of power and the laptop to run quite hot. This commit adds the missing remove fb call, allowing the dgpu to runtime suspend after an external monitor has been plugged into the laptop. Note this also makes drmmode_set_scanout_pixmap_gpu(NULL) match the behavior of drmmode_set_scanout_pixmap_cpu(NULL) which was already removing the fb. Signed-off-by: Hans de Goede Reviewed-by: Dave Airlie --- hw/xfree86/drivers/modesetting/drmmode_display.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index d192d0537..04d9df325 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -635,11 +635,17 @@ drmmode_set_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix) PixmapPtr screenpix = screen->GetScreenPixmap(screen); xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; int c, total_width = 0, max_height = 0, this_x = 0; if (!ppix) { - if (crtc->randr_crtc->scanout_pixmap) + if (crtc->randr_crtc->scanout_pixmap) { PixmapStopDirtyTracking(crtc->randr_crtc->scanout_pixmap, screenpix); + if (drmmode->fb_id) { + drmModeRmFB(drmmode->fd, drmmode->fb_id); + drmmode->fb_id = 0; + } + } drmmode_crtc->prime_pixmap_x = 0; return TRUE; } From 210d83ad492f0e91889472eaae549106d9b4ebf5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 1 Jun 2016 15:07:22 +0200 Subject: [PATCH 07/10] modesetting: Set ppix->fb_id to 0 after removing the fb This ensures the fb gets re-added when a shared pixmap is re-used for a second drmmode_set_scanout_pixmap_cpu call. Note currently the xserver never re-uses a shared pixmap in this way, so this is mostly a sanity fix. Signed-off-by: Hans de Goede Reviewed-by: Dave Airlie --- hw/xfree86/drivers/modesetting/drmmode_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 04d9df325..e6bc80d24 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -693,6 +693,7 @@ drmmode_set_scanout_pixmap_cpu(xf86CrtcPtr crtc, PixmapPtr ppix) if (crtc->randr_crtc->scanout_pixmap) { ppriv = msGetPixmapPriv(drmmode, crtc->randr_crtc->scanout_pixmap); drmModeRmFB(drmmode->fd, ppriv->fb_id); + ppriv->fb_id = 0; } if (drmmode_crtc->slave_damage) { DamageUnregister(drmmode_crtc->slave_damage); From 877453212166fdc912e0d687cdecee11aba563b5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 1 Jun 2016 15:11:05 +0200 Subject: [PATCH 08/10] modesetting: Remove unnecessary fb addition from drmmode_xf86crtc_resize drmmode_set_mode_major() is the only user of drmmode->fb_id and will create it if necessary. Signed-off-by: Hans de Goede Reviewed-by: Dave Airlie --- hw/xfree86/drivers/modesetting/drmmode_display.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index e6bc80d24..6aa935ff5 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -1697,7 +1697,6 @@ drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) drmmode_crtc = xf86_config->crtc[0]->driver_private; drmmode_ptr drmmode = drmmode_crtc->drmmode; drmmode_bo old_front; - Bool ret; ScreenPtr screen = xf86ScrnToScreen(scrn); uint32_t old_fb_id; int i, pitch, old_width, old_height, old_pitch; @@ -1719,8 +1718,9 @@ drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) old_width = scrn->virtualX; old_height = scrn->virtualY; old_pitch = drmmode_bo_get_pitch(&drmmode->front_bo); - old_fb_id = drmmode->fb_id; old_front = drmmode->front_bo; + old_fb_id = drmmode->fb_id; + drmmode->fb_id = 0; if (!drmmode_create_bo(drmmode, &drmmode->front_bo, width, height, scrn->bitsPerPixel)) @@ -1732,13 +1732,6 @@ drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) scrn->virtualY = height; scrn->displayWidth = pitch / cpp; - ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth, - scrn->bitsPerPixel, pitch, - drmmode_bo_get_handle(&drmmode->front_bo), - &drmmode->fb_id); - if (ret) - goto fail; - if (!drmmode->gbm) { new_pixels = drmmode_map_front_bo(drmmode); if (!new_pixels) From 4313122dea0df9affc280ee698e929489061ccc6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 1 Jun 2016 15:14:32 +0200 Subject: [PATCH 09/10] modesetting: Only add main fb if necessary If we're doing reverse-prime; or doing rotation the main fb is not used, and there is no reason to add it in this case. Signed-off-by: Hans de Goede Reviewed-by: Dave Airlie --- .../drivers/modesetting/drmmode_display.c | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 6aa935ff5..7e5901a71 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -408,24 +408,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, int output_count = 0; Bool ret = TRUE; int i; - uint32_t fb_id; + uint32_t fb_id = 0; drmModeModeInfo kmode; - int height; - - height = pScrn->virtualY; - - if (drmmode->fb_id == 0) { - ret = drmModeAddFB(drmmode->fd, - pScrn->virtualX, height, - pScrn->depth, pScrn->bitsPerPixel, - drmmode_bo_get_pitch(&drmmode->front_bo), - drmmode_bo_get_handle(&drmmode->front_bo), - &drmmode->fb_id); - if (ret < 0) { - ErrorF("failed to add fb %d\n", ret); - return FALSE; - } - } saved_mode = crtc->mode; saved_x = crtc->x; @@ -484,6 +468,22 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, fb_id = drmmode_crtc->rotate_fb_id; x = y = 0; } + + if (fb_id == 0) { + ret = drmModeAddFB(drmmode->fd, + pScrn->virtualX, pScrn->virtualY, + pScrn->depth, pScrn->bitsPerPixel, + drmmode_bo_get_pitch(&drmmode->front_bo), + drmmode_bo_get_handle(&drmmode->front_bo), + &drmmode->fb_id); + if (ret < 0) { + ErrorF("failed to add fb %d\n", ret); + ret = FALSE; + goto done; + } + fb_id = drmmode->fb_id; + } + if (drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, fb_id, x, y, output_ids, output_count, &kmode)) { xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, From 848089e0dde38f043c85332785520946103e77c1 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Mon, 13 Jun 2016 15:31:02 -0400 Subject: [PATCH 10/10] modesetting: Clear drmmode->fb_id before unflipping [fix copied from 40191d82370e in xf86-video-ati] Without this, we end up setting rotated CRTCs back to their previous framebuffer right after we perform a rotation. Reproducer: - Have two monitors connected at the same resolution - Rotate one monitor from normal straight to inverted - Watch as the monitor you didn't rotate either freezes or shows intense flickering Signed-off-by: Lyude Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- hw/xfree86/drivers/modesetting/present.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c index d65c8c845..9a596de75 100644 --- a/hw/xfree86/drivers/modesetting/present.c +++ b/hw/xfree86/drivers/modesetting/present.c @@ -626,6 +626,15 @@ ms_present_unflip(ScreenPtr screen, uint64_t event_id) if (!crtc->enabled) continue; + /* info->drmmode.fb_id still points to the FB for the last flipped BO. + * Clear it, drmmode_set_mode_major will re-create it + */ + if (drmmode_crtc->drmmode->fb_id) { + drmModeRmFB(drmmode_crtc->drmmode->fd, + drmmode_crtc->drmmode->fb_id); + drmmode_crtc->drmmode->fb_id = 0; + } + if (drmmode_crtc->dpms_mode == DPMSModeOn) crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x, crtc->y);