summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMario Kleiner <mario.kleiner.de@gmail.com>2014-08-18 09:53:27 +0200
committerBen Skeggs <bskeggs@redhat.com>2014-09-01 08:50:19 +1000
commit10729a442be3cf018c5806c95ec4218977917ef3 (patch)
tree3777944c6e16ca45f7916dfeacec75f17710e80c
parentbe96a5a62df5e1f286690311a6bc4df4f2a99e57 (diff)
xv/dri2/dri3: Switch to optimized crtc selection for drawables.
Make crtc selection consistent with ati and intel ddx. Pick the crtc to use for vblank events, swap scheduling and kms-pageflip completion events as the one with maximum pixel area intersection between its viewport and the drawable. If multiple crtc's viewports display the same amount of area of a drawable, select the crtc whose output is the designated "primary output" for the x-screen. The latter allows, e.g., in a clone display setup, to select the important output on which tearing should be minimized. The former makes sure to minimize or avoid tearing on the display which shows the largest part of the drawable. This method is transplanted from the ati ddx. Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--src/nouveau_dri2.c32
-rw-r--r--src/nouveau_present.c16
-rw-r--r--src/nouveau_xv.c94
-rw-r--r--src/nv50_accel.c17
-rw-r--r--src/nv_accel_common.c17
-rw-r--r--src/nv_proto.h2
-rw-r--r--src/nvc0_accel.c17
7 files changed, 138 insertions, 57 deletions
diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c
index cc16cb1..3361869 100644
--- a/src/nouveau_dri2.c
+++ b/src/nouveau_dri2.c
@@ -434,7 +434,7 @@ nouveau_dri2_flip_handler(void *priv, uint64_t name, uint64_t ust, uint32_t msc)
static Bool
dri2_page_flip(DrawablePtr draw, PixmapPtr back, void *priv,
- unsigned int ref_crtc_hw_id)
+ xf86CrtcPtr ref_crtc)
{
ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
@@ -489,7 +489,7 @@ dri2_page_flip(DrawablePtr draw, PixmapPtr back, void *priv,
/* Only the reference crtc will finally deliver its page flip
* completion event. All other crtc's events will be discarded.
*/
- flipcarrier->dispatch_me = ((1 << i) == ref_crtc_hw_id);
+ flipcarrier->dispatch_me = (config->crtc[i] == ref_crtc);
flipcarrier->flipdata = flipdata;
ret = drmModePageFlip(pNv->dev->fd, head, next_fb,
@@ -565,20 +565,19 @@ nouveau_wait_vblank(DrawablePtr draw, int type, CARD64 msc,
CARD64 *pmsc, CARD64 *pust, void *data)
{
ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
- xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
NVPtr pNv = NVPTR(scrn);
- int crtcs = nv_window_belongs_to_crtc(scrn, draw->x, draw->y,
- draw->width, draw->height);
+ xf86CrtcPtr crtc;
drmVBlank vbl;
struct dri2_vblank *event = NULL;
void *token = NULL;
int ret;
int head;
- /* Select crtc with smallest index from bitmask of crtcs */
- crtcs = ffs(crtcs) - 1;
+ /* Select crtc which shows the largest part of the drawable */
+ crtc = nouveau_pick_best_crtc(scrn, FALSE,
+ draw->x, draw->y, draw->width, draw->height);
- if (crtcs < 0) {
+ if (!crtc) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"Wait for VBlank failed: No valid crtc for drawable.\n");
return -EINVAL;
@@ -596,7 +595,7 @@ nouveau_wait_vblank(DrawablePtr draw, int type, CARD64 msc,
}
/* Map xf86CrtcPtr to drmWaitVBlank compatible display head index. */
- head = drmmode_head(config->crtc[crtcs]);
+ head = drmmode_head(crtc);
if (head == 1)
type |= DRM_VBLANK_SECONDARY;
@@ -647,21 +646,14 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame,
RegionRec reg;
int type, ret;
Bool front_updated, will_exchange;
+ xf86CrtcPtr ref_crtc;
REGION_INIT(0, &reg, (&(BoxRec){ 0, 0, draw->width, draw->height }), 0);
REGION_TRANSLATE(0, &reg, draw->x, draw->y);
/* Main crtc for this drawable shall finally deliver pageflip event. */
- unsigned int ref_crtc_hw_id = nv_window_belongs_to_crtc(scrn, draw->x,
- draw->y,
- draw->width,
- draw->height);
-
- /* Choose crtc with smallest index as reference, as its
- * vblank event triggered this swap. ref_crtc_hw_id is
- * a bit field (crtc 0 = bit 0, crtc 1 = bit 1 ...)
- */
- ref_crtc_hw_id = 1 << (ffs(ref_crtc_hw_id) - 1);
+ ref_crtc = nouveau_pick_best_crtc(scrn, FALSE, draw->x, draw->y,
+ draw->width, draw->height);
/* Update frontbuffer pixmap and name: Could have changed due to
* window (un)redirection as part of compositing.
@@ -711,7 +703,7 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame,
if (nouveau_exa_pixmap_is_onscreen(dst_pix)) {
type = DRI2_FLIP_COMPLETE;
ret = dri2_page_flip(draw, src_pix, violate_oml(draw) ?
- NULL : s, ref_crtc_hw_id);
+ NULL : s, ref_crtc);
if (!ret)
goto out;
}
diff --git a/src/nouveau_present.c b/src/nouveau_present.c
index f4cdcc8..ea1686e 100644
--- a/src/nouveau_present.c
+++ b/src/nouveau_present.c
@@ -36,21 +36,17 @@ static RRCrtcPtr
nouveau_present_crtc(WindowPtr window)
{
ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen);
- xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CrtcPtr crtc;
- unsigned mask;
- int head;
- mask = nv_window_belongs_to_crtc(scrn, window->drawable.x,
- window->drawable.y,
- window->drawable.width,
- window->drawable.height);
+ crtc = nouveau_pick_best_crtc(scrn, FALSE,
+ window->drawable.x,
+ window->drawable.y,
+ window->drawable.width,
+ window->drawable.height);
- head = ffs(mask) - 1;
- if (head < 0 || head >= xf86_config->num_crtc)
+ if (!crtc)
return NULL;
- crtc = xf86_config->crtc[head];
if (crtc->rotatedData)
return NULL;
diff --git a/src/nouveau_xv.c b/src/nouveau_xv.c
index e40d6ba..a479d38 100644
--- a/src/nouveau_xv.c
+++ b/src/nouveau_xv.c
@@ -196,6 +196,100 @@ static XF86ImageRec NVImages[NUM_IMAGES_ALL] =
XVIMAGE_RGB
};
+static void
+nouveau_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
+{
+ dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1;
+ dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2;
+ dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1;
+ dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2;
+
+ if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2)
+ dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
+}
+
+static void
+nouveau_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
+{
+ if (crtc->enabled) {
+ crtc_box->x1 = crtc->x;
+ crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation);
+ crtc_box->y1 = crtc->y;
+ crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation);
+ } else
+ crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
+}
+
+static int
+nouveau_box_area(BoxPtr box)
+{
+ return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1);
+}
+
+xf86CrtcPtr
+nouveau_pick_best_crtc(ScrnInfoPtr pScrn, Bool consider_disabled,
+ int x, int y, int w, int h)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ int coverage, best_coverage, c;
+ BoxRec box, crtc_box, cover_box;
+ RROutputPtr primary_output = NULL;
+ xf86CrtcPtr best_crtc = NULL, primary_crtc = NULL;
+
+ if (!pScrn->vtSema)
+ return NULL;
+
+ box.x1 = x;
+ box.x2 = x + w;
+ box.y1 = y;
+ box.y2 = y + h;
+ best_coverage = 0;
+
+ /* Prefer the CRTC of the primary output */
+#ifdef HAS_DIXREGISTERPRIVATEKEY
+ if (dixPrivateKeyRegistered(rrPrivKey))
+#endif
+ {
+ primary_output = RRFirstOutput(pScrn->pScreen);
+ }
+ if (primary_output && primary_output->crtc)
+ primary_crtc = primary_output->crtc->devPrivate;
+
+ /* first consider only enabled CRTCs */
+ for (c = 0; c < xf86_config->num_crtc; c++) {
+ xf86CrtcPtr crtc = xf86_config->crtc[c];
+
+ if (!crtc->enabled)
+ continue;
+
+ nouveau_crtc_box(crtc, &crtc_box);
+ nouveau_box_intersect(&cover_box, &crtc_box, &box);
+ coverage = nouveau_box_area(&cover_box);
+ if (coverage > best_coverage ||
+ (coverage == best_coverage && crtc == primary_crtc)) {
+ best_crtc = crtc;
+ best_coverage = coverage;
+ }
+ }
+ if (best_crtc || !consider_disabled)
+ return best_crtc;
+
+ /* if we found nothing, repeat the search including disabled CRTCs */
+ for (c = 0; c < xf86_config->num_crtc; c++) {
+ xf86CrtcPtr crtc = xf86_config->crtc[c];
+
+ nouveau_crtc_box(crtc, &crtc_box);
+ nouveau_box_intersect(&cover_box, &crtc_box, &box);
+ coverage = nouveau_box_area(&cover_box);
+ if (coverage > best_coverage ||
+ (coverage == best_coverage && crtc == primary_crtc)) {
+ best_crtc = crtc;
+ best_coverage = coverage;
+ }
+ }
+ return best_crtc;
+}
+
unsigned int
nv_window_belongs_to_crtc(ScrnInfoPtr pScrn, int x, int y, int w, int h)
{
diff --git a/src/nv50_accel.c b/src/nv50_accel.c
index 3d489d0..b27f67a 100644
--- a/src/nv50_accel.c
+++ b/src/nv50_accel.c
@@ -31,25 +31,24 @@ void
NV50SyncToVBlank(PixmapPtr ppix, BoxPtr box)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen);
- xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
NVPtr pNv = NVPTR(pScrn);
struct nouveau_pushbuf *push = pNv->pushbuf;
- int crtcs;
+ int head;
+ xf86CrtcPtr crtc;
if (!nouveau_exa_pixmap_is_onscreen(ppix))
return;
- crtcs = nv_window_belongs_to_crtc(pScrn, box->x1, box->y1,
- box->x2 - box->x1,
- box->y2 - box->y1);
- if (!crtcs)
+ crtc = nouveau_pick_best_crtc(pScrn, FALSE, box->x1, box->y1,
+ box->x2 - box->x1,
+ box->y2 - box->y1);
+ if (!crtc)
return;
if (!PUSH_SPACE(push, 10))
return;
- crtcs = ffs(crtcs) - 1;
- crtcs = drmmode_head(config->crtc[crtcs]);
+ head = drmmode_head(crtc);
BEGIN_NV04(push, SUBC_NVSW(0x0060), 2);
PUSH_DATA (push, pNv->vblank_sem->handle);
@@ -58,7 +57,7 @@ NV50SyncToVBlank(PixmapPtr ppix, BoxPtr box)
PUSH_DATA (push, 0x22222222);
BEGIN_NV04(push, SUBC_NVSW(0x0404), 2);
PUSH_DATA (push, 0x11111111);
- PUSH_DATA (push, crtcs);
+ PUSH_DATA (push, head);
BEGIN_NV04(push, SUBC_NVSW(0x0068), 1);
PUSH_DATA (push, 0x11111111);
}
diff --git a/src/nv_accel_common.c b/src/nv_accel_common.c
index bd9dc8a..4484c1c 100644
--- a/src/nv_accel_common.c
+++ b/src/nv_accel_common.c
@@ -133,30 +133,29 @@ void
NV11SyncToVBlank(PixmapPtr ppix, BoxPtr box)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen);
- xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
NVPtr pNv = NVPTR(pScrn);
struct nouveau_pushbuf *push = pNv->pushbuf;
- int crtcs;
+ int head;
+ xf86CrtcPtr crtc;
if (!nouveau_exa_pixmap_is_onscreen(ppix))
return;
- crtcs = nv_window_belongs_to_crtc(pScrn, box->x1, box->y1,
- box->x2 - box->x1,
- box->y2 - box->y1);
- if (!crtcs)
+ crtc = nouveau_pick_best_crtc(pScrn, FALSE, box->x1, box->y1,
+ box->x2 - box->x1,
+ box->y2 - box->y1);
+ if (!crtc)
return;
if (!PUSH_SPACE(push, 8))
return;
- crtcs = ffs(crtcs) - 1;
- crtcs = drmmode_head(config->crtc[crtcs]);
+ head = drmmode_head(crtc);
BEGIN_NV04(push, SUBC_BLIT(0x0000012C), 1);
PUSH_DATA (push, 0);
BEGIN_NV04(push, SUBC_BLIT(0x00000134), 1);
- PUSH_DATA (push, crtcs);
+ PUSH_DATA (push, head);
BEGIN_NV04(push, SUBC_BLIT(0x00000100), 1);
PUSH_DATA (push, 0);
BEGIN_NV04(push, SUBC_BLIT(0x00000130), 1);
diff --git a/src/nv_proto.h b/src/nv_proto.h
index 27354e0..cc4fd09 100644
--- a/src/nv_proto.h
+++ b/src/nv_proto.h
@@ -43,6 +43,8 @@ void NVTakedownVideo(ScrnInfoPtr);
void NVSetPortDefaults (ScrnInfoPtr pScrn, NVPortPrivPtr pPriv);
void NVXVComputeBicubicFilter(struct nouveau_bo *, unsigned, unsigned);
unsigned int nv_window_belongs_to_crtc(ScrnInfoPtr, int, int, int, int);
+xf86CrtcPtr nouveau_pick_best_crtc(ScrnInfoPtr pScrn, Bool consider_disabled,
+ int x, int y, int w, int h);
/* in nouveau_exa.c */
Bool nouveau_exa_init(ScreenPtr pScreen);
diff --git a/src/nvc0_accel.c b/src/nvc0_accel.c
index 375ccc8..c04e270 100644
--- a/src/nvc0_accel.c
+++ b/src/nvc0_accel.c
@@ -63,25 +63,24 @@ void
NVC0SyncToVBlank(PixmapPtr ppix, BoxPtr box)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen);
- xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
NVPtr pNv = NVPTR(pScrn);
struct nouveau_pushbuf *push = pNv->pushbuf;
- int crtcs;
+ int head;
+ xf86CrtcPtr crtc;
if (!pNv->NvSW || !nouveau_exa_pixmap_is_onscreen(ppix))
return;
- crtcs = nv_window_belongs_to_crtc(pScrn, box->x1, box->y1,
- box->x2 - box->x1,
- box->y2 - box->y1);
- if (!crtcs)
+ crtc = nouveau_pick_best_crtc(pScrn, FALSE, box->x1, box->y1,
+ box->x2 - box->x1,
+ box->y2 - box->y1);
+ if (!crtc)
return;
if (!PUSH_SPACE(push, 32))
return;
- crtcs = ffs(crtcs) - 1;
- crtcs = drmmode_head(config->crtc[crtcs]);
+ head = drmmode_head(crtc);
BEGIN_NVC0(push, NV01_SUBC(NVSW, OBJECT), 1);
PUSH_DATA (push, pNv->NvSW->handle);
@@ -94,7 +93,7 @@ NVC0SyncToVBlank(PixmapPtr ppix, BoxPtr box)
PUSH_DATA (push, (pNv->scratch->offset + SEMA_OFFSET) >> 32);
PUSH_DATA (push, (pNv->scratch->offset + SEMA_OFFSET));
PUSH_DATA (push, 0x11111111);
- PUSH_DATA (push, crtcs);
+ PUSH_DATA (push, head);
BEGIN_NVC0(push, NV84_SUBC(NVSW, SEMAPHORE_ADDRESS_HIGH), 4);
PUSH_DATA (push, (pNv->scratch->offset + SEMA_OFFSET) >> 32);
PUSH_DATA (push, (pNv->scratch->offset + SEMA_OFFSET));