summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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));