summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-06-08 13:32:59 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2011-06-08 19:27:33 +0100
commit715d466ad44e82b740f5454c41db944863420596 (patch)
treeae6a6095189629050aa8151899eed151da1513f1
parenta62db5b050dee10246c02c72385358acb5e72b56 (diff)
sna/dri: valgrindify
Lots of scary warnings found by valgrind. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--src/sna/kgem.c1
-rw-r--r--src/sna/sna.h47
-rw-r--r--src/sna/sna_accel.c1
-rw-r--r--src/sna/sna_display.c374
-rw-r--r--src/sna/sna_dri.c606
-rw-r--r--src/sna/sna_driver.c13
-rw-r--r--src/sna/sna_render.c4
-rw-r--r--src/sna/sna_video.c178
8 files changed, 691 insertions, 533 deletions
diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 46cd4749..979a5525 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -199,7 +199,6 @@ gem_madvise(int fd, uint32_t handle, uint32_t state)
madv.madv = state;
madv.retained = 1;
ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_MADVISE, &madv);
- assert(ret == 0);
return madv.retained;
(void)ret;
diff --git a/src/sna/sna.h b/src/sna/sna.h
index e36ef481..ea2422aa 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -130,21 +130,6 @@ enum DRI2FrameEventType {
#define CREATE_PIXMAP_USAGE_SCRATCH_HEADER -1
#endif
-typedef struct _DRI2FrameEvent {
- XID drawable_id;
- XID client_id; /* fake client ID to track client destruction */
- ClientPtr client;
- enum DRI2FrameEventType type;
- int frame;
- int pipe;
-
- /* for swaps & flips only */
- DRI2SwapEventPtr event_complete;
- void *event_data;
- DRI2BufferPtr front;
- DRI2BufferPtr back;
-} DRI2FrameEventRec, *DRI2FrameEventPtr;
-
#define SNA_CURSOR_X 64
#define SNA_CURSOR_Y SNA_CURSOR_X
@@ -230,17 +215,16 @@ struct sna {
drmModeResPtr mode_res;
int cpp;
- drmEventContext event_context;
- DRI2FrameEventPtr flip_info;
- int flip_count;
+ struct list outputs;
+ struct list crtcs;
+ } mode;
+
+ struct sna_dri {
int flip_pending[2];
unsigned int fe_frame;
unsigned int fe_tv_sec;
unsigned int fe_tv_usec;
-
- struct list outputs;
- struct list crtcs;
- } mode;
+ } dri;
unsigned int tiling;
#define SNA_TILING_FB 0x1
@@ -285,16 +269,20 @@ struct sna {
};
Bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna);
-extern void sna_mode_init(struct sna *sna);
extern void sna_mode_remove_fb(struct sna *sna);
extern void sna_mode_fini(struct sna *sna);
extern int sna_crtc_id(xf86CrtcPtr crtc);
extern int sna_output_dpms_status(xf86OutputPtr output);
-extern Bool sna_do_pageflip(struct sna *sna,
+extern int sna_do_pageflip(struct sna *sna,
PixmapPtr pixmap,
- DRI2FrameEventPtr flip_info, int ref_crtc_hw_id);
+ void *data,
+ int ref_crtc_hw_id,
+ PixmapPtr *old_front,
+ uint32_t *old_fb);
+
+void sna_mode_delete_fb(struct sna *sna, PixmapPtr pixmap, uint32_t fb);
static inline struct sna *
to_sna(ScrnInfoPtr scrn)
@@ -326,12 +314,9 @@ extern xf86CrtcPtr sna_covering_crtc(ScrnInfoPtr scrn, BoxPtr box,
extern bool sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
xf86CrtcPtr crtc, RegionPtr clip);
-Bool sna_dri2_open(struct sna *sna, ScreenPtr pScreen);
-void sna_dri2_close(struct sna *sna, ScreenPtr pScreen);
-void sna_dri2_frame_event(unsigned int frame, unsigned int tv_sec,
- unsigned int tv_usec, DRI2FrameEventPtr flip_info);
-void sna_dri2_flip_event(unsigned int frame, unsigned int tv_sec,
- unsigned int tv_usec, DRI2FrameEventPtr flip_info);
+Bool sna_dri_open(struct sna *sna, ScreenPtr pScreen);
+void sna_dri_wakeup(struct sna *sna);
+void sna_dri_close(struct sna *sna, ScreenPtr pScreen);
extern Bool sna_crtc_on(xf86CrtcPtr crtc);
int sna_crtc_to_pipe(xf86CrtcPtr crtc);
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index d1f5abf2..8e2bc33f 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -3203,6 +3203,7 @@ Bool sna_accel_init(ScreenPtr screen, struct sna *sna)
list_init(&sna->dirty_pixmaps);
list_init(&sna->deferred_free);
+ AddGeneralSocket(sna->kgem.fd);
sna_accel_install_timers(sna);
screen->CreateGC = sna_create_gc;
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 847d8212..4d110634 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -41,6 +41,7 @@
#include <X11/Xatom.h>
#include "sna.h"
+#include "sna_reg.h"
#if DEBUG_DISPLAY
#undef DBG
@@ -353,14 +354,12 @@ sna_crtc_apply(xf86CrtcPtr crtc)
struct sna_crtc *sna_crtc = crtc->driver_private;
struct sna_mode *mode = &sna->mode;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
- uint32_t *output_ids;
+ uint32_t output_ids[16];
int output_count = 0;
int fb_id, x, y;
int i, ret = FALSE;
- output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
- if (!output_ids)
- return FALSE;
+ assert(xf86_config->num_output < ARRAY_SIZE(output_ids));
for (i = 0; i < xf86_config->num_output; i++) {
xf86OutputPtr output = xf86_config->output[i];
@@ -375,8 +374,10 @@ sna_crtc_apply(xf86CrtcPtr crtc)
output_count++;
}
- if (!xf86CrtcRotate(crtc))
- goto done;
+ if (!xf86CrtcRotate(crtc)) {
+ DBG(("%s: failed to rotate crtc\n", __FUNCTION__));
+ return FALSE;
+ }
crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
crtc->gamma_blue, crtc->gamma_size);
@@ -389,6 +390,15 @@ sna_crtc_apply(xf86CrtcPtr crtc)
x = 0;
y = 0;
}
+
+ DBG(("%s: applying crtc [%d] mode=%dx%d@%d, fb=%d%s update to %d outputs\n",
+ __FUNCTION__, crtc_id(sna_crtc),
+ sna_crtc->kmode.hdisplay,
+ sna_crtc->kmode.vdisplay,
+ sna_crtc->kmode.clock,
+ fb_id, sna_crtc->shadow_fb_id ? " [shadow]" : "",
+ output_count));
+
ret = drmModeSetCrtc(sna->kgem.fd, crtc_id(sna_crtc),
fb_id, x, y, output_ids, output_count,
&sna_crtc->kmode);
@@ -396,14 +406,14 @@ sna_crtc_apply(xf86CrtcPtr crtc)
xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
"failed to set mode: %s\n", strerror(-ret));
ret = FALSE;
- } else
+ } else {
+ sna_crtc->active = 1;
ret = TRUE;
+ }
if (scrn->pScreen)
xf86_reload_cursors(scrn->pScreen);
-done:
- free(output_ids);
return ret;
}
@@ -420,14 +430,16 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
DisplayModeRec saved_mode;
int ret = TRUE;
- DBG(("%s(rotation=%d, x=%d, y=%d)\n",
- __FUNCTION__, rotation, x, y));
+ DBG(("%s(rotation=%d, x=%d, y=%d, mode=%dx%d@%d)\n",
+ __FUNCTION__, rotation, x, y,
+ mode->HDisplay, mode->VDisplay, mode->Clock));
if (sna_mode->fb_id == 0) {
struct kgem_bo *bo = sna_pixmap_pin(sna->front);
if (!bo)
return FALSE;
+ assert(bo->tiling != I915_TILING_Y);
ret = drmModeAddFB(sna->kgem.fd,
scrn->virtualX, scrn->virtualY,
scrn->depth, scrn->bitsPerPixel,
@@ -538,6 +550,7 @@ sna_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
return NULL;
}
+ assert(bo->tiling != I915_TILING_Y);
if (drmModeAddFB(sna->kgem.fd,
width, height, scrn->depth, scrn->bitsPerPixel,
bo->pitch, bo->handle,
@@ -747,7 +760,7 @@ sna_output_attach_edid(xf86OutputPtr output)
xf86OutputSetEDID(output, mon);
- if (edid_blob)
+ if (0&&edid_blob)
drmModeFreePropertyBlob(edid_blob);
}
@@ -1362,7 +1375,7 @@ sna_visit_set_window_pixmap(WindowPtr window, pointer data)
}
static void
-sn_redirect_screen_pixmap(ScrnInfoPtr scrn, PixmapPtr old, PixmapPtr new)
+sna_redirect_screen_pixmap(ScrnInfoPtr scrn, PixmapPtr old, PixmapPtr new)
{
ScreenPtr screen = scrn->pScreen;
struct sna_visit_set_pixmap_window visit;
@@ -1375,7 +1388,7 @@ sn_redirect_screen_pixmap(ScrnInfoPtr scrn, PixmapPtr old, PixmapPtr new)
}
static Bool
-sna_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
+sna_crtc_resize(ScrnInfoPtr scrn, int width, int height)
{
struct sna *sna = to_sna(scrn);
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
@@ -1409,6 +1422,7 @@ sna_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
if (!bo)
goto fail;
+ assert(bo->tiling != I915_TILING_Y);
if (drmModeAddFB(sna->kgem.fd, width, height,
scrn->depth, scrn->bitsPerPixel,
bo->pitch, bo->handle,
@@ -1420,6 +1434,9 @@ sna_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
goto fail;
}
+ DBG(("%s: handle %d attached to fb %d\n",
+ __FUNCTION__, bo->handle, mode->fb_id));
+
for (i = 0; i < xf86_config->num_crtc; i++) {
xf86CrtcPtr crtc = xf86_config->crtc[i];
@@ -1434,7 +1451,9 @@ sna_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
scrn->virtualY = height;
scrn->displayWidth = bo->pitch / sna->mode.cpp;
- sn_redirect_screen_pixmap(scrn, old_front, sna->front);
+ sna_redirect_screen_pixmap(scrn, old_front, sna->front);
+ assert(scrn->pScreen->GetScreenPixmap(scrn->pScreen) == sna->front);
+ assert(scrn->pScreen->GetWindowPixmap(scrn->pScreen->root) == sna->front);
if (old_fb_id)
drmModeRmFB(sna->kgem.fd, old_fb_id);
@@ -1443,6 +1462,7 @@ sna_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
return TRUE;
fail:
+ DBG(("%s: restoring original front pixmap and fb\n", __FUNCTION__));
if (old_fb_id != mode->fb_id)
drmModeRmFB(sna->kgem.fd, mode->fb_id);
mode->fb_id = old_fb_id;
@@ -1453,10 +1473,10 @@ fail:
return FALSE;
}
-static Bool do_page_flip(struct sna *sna,
- int ref_crtc_hw_id)
+static int do_page_flip(struct sna *sna, void *data, int ref_crtc_hw_id)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
+ int count = 0;
int i;
/*
@@ -1470,7 +1490,7 @@ static Bool do_page_flip(struct sna *sna,
*/
for (i = 0; i < config->num_crtc; i++) {
struct sna_crtc *crtc = config->crtc[i]->driver_private;
- uintptr_t data;
+ uintptr_t evdata;
if (!config->crtc[i]->enabled)
continue;
@@ -1478,41 +1498,54 @@ static Bool do_page_flip(struct sna *sna,
/* Only the reference crtc will finally deliver its page flip
* completion event. All other crtc's events will be discarded.
*/
+ evdata = (uintptr_t)data;
+ evdata |= sna_crtc_to_pipe(crtc->crtc) == ref_crtc_hw_id;
- data = (uintptr_t)sna;
- data |= sna_crtc_to_pipe(crtc->crtc) == ref_crtc_hw_id;
-
+ DBG(("%s: crtc %d [ref? %d] --> fb %d\n",
+ __FUNCTION__, crtc_id(crtc),
+ sna_crtc_to_pipe(crtc->crtc) == ref_crtc_hw_id,
+ sna->mode.fb_id));
if (drmModePageFlip(sna->kgem.fd,
crtc_id(crtc),
sna->mode.fb_id,
DRM_MODE_PAGE_FLIP_EVENT,
- (void*)data)) {
+ (void*)evdata)) {
xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
"flip queue failed: %s\n", strerror(errno));
- return FALSE;
+ continue;
}
+
+ count++;
}
- return TRUE;
+ return count;
}
-Bool
+int
sna_do_pageflip(struct sna *sna,
PixmapPtr pixmap,
- DRI2FrameEventPtr flip_info, int ref_crtc_hw_id)
+ void *data,
+ int ref_crtc_hw_id,
+ PixmapPtr *old_front,
+ uint32_t *old_fb)
{
ScrnInfoPtr scrn = sna->scrn;
struct sna_mode *mode = &sna->mode;
struct kgem_bo *bo = sna_pixmap_pin(pixmap);
- int old_fb_id;
+ int count;
+
+ assert(pixmap != sna->front);
if (!bo)
- return FALSE;
+ return 0;
+
+ *old_fb = mode->fb_id;
+ *old_front = sna->front;
/*
* Create a new handle for the back buffer
*/
- old_fb_id = mode->fb_id;
+ assert(bo->tiling != I915_TILING_Y);
if (drmModeAddFB(sna->kgem.fd, scrn->virtualX, scrn->virtualY,
scrn->depth, scrn->bitsPerPixel,
bo->pitch, bo->handle,
@@ -1521,9 +1554,14 @@ sna_do_pageflip(struct sna *sna,
__FUNCTION__,
scrn->virtualX, scrn->virtualY,
scrn->depth, scrn->bitsPerPixel, bo->pitch);
- return FALSE;
+ return 0;
}
+ DBG(("%s: handle %d attached to fb %d\n",
+ __FUNCTION__, bo->handle, mode->fb_id));
+
+ if (kgem_bo_is_dirty(bo))
+ kgem_emit_flush(&sna->kgem);
kgem_submit(&sna->kgem);
/*
@@ -1535,83 +1573,32 @@ sna_do_pageflip(struct sna *sna,
* Also, flips queued on disabled or incorrectly configured displays
* may never complete; this is a configuration error.
*/
- mode->fe_frame = 0;
- mode->fe_tv_sec = 0;
- mode->fe_tv_usec = 0;
-
- mode->flip_info = flip_info;
- mode->flip_count++;
-
- if (do_page_flip(sna, ref_crtc_hw_id)) {
- PixmapPtr old_front = sna->front;
-
+ count = do_page_flip(sna, data, ref_crtc_hw_id);
+ if (count > 0) {
sna->front = pixmap;
pixmap->refcnt++;
- sn_redirect_screen_pixmap(scrn, old_front, sna->front);
+ sna_redirect_screen_pixmap(scrn, *old_front, sna->front);
scrn->displayWidth = bo->pitch / sna->mode.cpp;
-
- drmModeRmFB(sna->kgem.fd, old_fb_id);
- scrn->pScreen->DestroyPixmap(old_front);
- return TRUE;
} else {
drmModeRmFB(sna->kgem.fd, mode->fb_id);
- mode->fb_id = old_fb_id;
- return FALSE;
+ mode->fb_id = *old_fb;
}
-}
-static const xf86CrtcConfigFuncsRec sna_xf86crtc_config_funcs = {
- sna_xf86crtc_resize
-};
-
-static void
-sna_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec,
- unsigned int tv_usec, void *event_data)
-{
- sna_dri2_frame_event(frame, tv_sec, tv_usec, event_data);
+ return count;
}
-static void
-sna_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
- unsigned int tv_usec, void *event_data)
+void sna_mode_delete_fb(struct sna *sna, PixmapPtr pixmap, uint32_t fb)
{
- struct sna *sna = (struct sna *)((uintptr_t)event_data & ~1);
- struct sna_mode *mode = &sna->mode;
-
- /* Is this the event whose info shall be delivered to higher level? */
- if ((uintptr_t)event_data & 1) {
- /* Yes: Cache msc, ust for later delivery. */
- mode->fe_frame = frame;
- mode->fe_tv_sec = tv_sec;
- mode->fe_tv_usec = tv_usec;
- }
-
- /* Last crtc completed flip? */
- if (--mode->flip_count > 0)
- return;
+ if (fb)
+ drmModeRmFB(sna->kgem.fd, fb);
- if (mode->flip_info == NULL)
- return;
-
- /* Deliver cached msc, ust from reference crtc to flip event handler */
- sna_dri2_flip_event(mode->fe_frame, mode->fe_tv_sec,
- mode->fe_tv_usec, mode->flip_info);
+ if (pixmap)
+ pixmap->drawable.pScreen->DestroyPixmap(pixmap);
}
-static void
-drm_wakeup_handler(pointer data, int err, pointer p)
-{
- struct sna *sna;
- fd_set *read_mask;
-
- if (data == NULL || err < 0)
- return;
-
- sna = data;
- read_mask = p;
- if (FD_ISSET(sna->kgem.fd, read_mask))
- drmHandleEvent(sna->kgem.fd, &sna->mode.event_context);
-}
+static const xf86CrtcConfigFuncsRec sna_crtc_config_funcs = {
+ sna_crtc_resize
+};
Bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
{
@@ -1621,7 +1608,7 @@ Bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
list_init(&mode->crtcs);
list_init(&mode->outputs);
- xf86CrtcConfigInit(scrn, &sna_xf86crtc_config_funcs);
+ xf86CrtcConfigInit(scrn, &sna_crtc_config_funcs);
mode->mode_res = drmModeGetResources(sna->kgem.fd);
if (!mode->mode_res) {
@@ -1642,29 +1629,10 @@ Bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
xf86InitialConfiguration(scrn, TRUE);
- mode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
- mode->event_context.vblank_handler = sna_vblank_handler;
- mode->event_context.page_flip_handler = sna_page_flip_handler;
-
return TRUE;
}
void
-sna_mode_init(struct sna *sna)
-{
- struct sna_mode *mode = &sna->mode;
-
- /* We need to re-register the mode->fd for the synchronisation
- * feedback on every server generation, so perform the
- * registration within ScreenInit and not PreInit.
- */
- mode->flip_count = 0;
- AddGeneralSocket(sna->kgem.fd);
- RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
- drm_wakeup_handler, sna);
-}
-
-void
sna_mode_remove_fb(struct sna *sna)
{
struct sna_mode *mode = &sna->mode;
@@ -1701,3 +1669,181 @@ sna_mode_fini(struct sna *sna)
/* mode->shadow_fb_id should have been destroyed already */
}
+
+static void sna_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 void sna_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 int sna_box_area(BoxPtr box)
+{
+ return (int)(box->x2 - box->x1) * (int)(box->y2 - box->y1);
+}
+
+/*
+ * Return the crtc covering 'box'. If two crtcs cover a portion of
+ * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc
+ * with greater coverage
+ */
+xf86CrtcPtr
+sna_covering_crtc(ScrnInfoPtr scrn,
+ BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ xf86CrtcPtr crtc, best_crtc;
+ int coverage, best_coverage;
+ int c;
+ BoxRec crtc_box, cover_box;
+
+ DBG(("%s for box=(%d, %d), (%d, %d)\n",
+ __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
+
+ best_crtc = NULL;
+ best_coverage = 0;
+ crtc_box_ret->x1 = 0;
+ crtc_box_ret->x2 = 0;
+ crtc_box_ret->y1 = 0;
+ crtc_box_ret->y2 = 0;
+ for (c = 0; c < xf86_config->num_crtc; c++) {
+ crtc = xf86_config->crtc[c];
+
+ /* If the CRTC is off, treat it as not covering */
+ if (!sna_crtc_on(crtc)) {
+ DBG(("%s: crtc %d off, skipping\n", __FUNCTION__, c));
+ continue;
+ }
+
+ sna_crtc_box(crtc, &crtc_box);
+ sna_box_intersect(&cover_box, &crtc_box, box);
+ coverage = sna_box_area(&cover_box);
+ if (coverage && crtc == desired) {
+ DBG(("%s: box is on desired crtc [%p]\n",
+ __FUNCTION__, crtc));
+ *crtc_box_ret = crtc_box;
+ return crtc;
+ }
+ if (coverage > best_coverage) {
+ *crtc_box_ret = crtc_box;
+ best_crtc = crtc;
+ best_coverage = coverage;
+ }
+ }
+ DBG(("%s: best crtc = %p\n", __FUNCTION__, best_crtc));
+ return best_crtc;
+}
+
+bool
+sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
+ xf86CrtcPtr crtc, RegionPtr clip)
+{
+ pixman_box16_t box, crtc_box;
+ int pipe, event;
+ Bool full_height;
+ int y1, y2;
+ uint32_t *b;
+
+ /* XXX no wait for scanline support on SNB? */
+ if (sna->kgem.gen >= 60)
+ return false;
+
+ if (!pixmap_is_scanout(pixmap))
+ return false;
+
+ if (crtc == NULL) {
+ if (clip) {
+ crtc_box = *REGION_EXTENTS(NULL, clip);
+ } else {
+ crtc_box.x1 = 0; /* XXX drawable offsets? */
+ crtc_box.y1 = 0;
+ crtc_box.x2 = pixmap->drawable.width;
+ crtc_box.y2 = pixmap->drawable.height;
+ }
+ crtc = sna_covering_crtc(sna->scrn, &crtc_box, NULL, &crtc_box);
+ }
+
+ if (crtc == NULL)
+ return false;
+
+ if (clip) {
+ box = *REGION_EXTENTS(unused, clip);
+
+ if (crtc->transform_in_use)
+ pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &box);
+
+ /* We could presume the clip was correctly computed... */
+ sna_crtc_box(crtc, &crtc_box);
+ sna_box_intersect(&box, &crtc_box, &box);
+
+ /*
+ * Make sure we don't wait for a scanline that will
+ * never occur
+ */
+ y1 = (crtc_box.y1 <= box.y1) ? box.y1 - crtc_box.y1 : 0;
+ y2 = (box.y2 <= crtc_box.y2) ?
+ box.y2 - crtc_box.y1 : crtc_box.y2 - crtc_box.y1;
+ if (y2 <= y1)
+ return false;
+
+ full_height = FALSE;
+ if (y1 == 0 && y2 == (crtc_box.y2 - crtc_box.y1))
+ full_height = TRUE;
+ } else {
+ sna_crtc_box(crtc, &crtc_box);
+ y1 = crtc_box.y1;
+ y2 = crtc_box.y2;
+ full_height = TRUE;
+ }
+
+ /*
+ * Pre-965 doesn't have SVBLANK, so we need a bit
+ * of extra time for the blitter to start up and
+ * do its job for a full height blit
+ */
+ if (sna_crtc_to_pipe(crtc) == 0) {
+ pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEA;
+ event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
+ if (full_height)
+ event = MI_WAIT_FOR_PIPEA_SVBLANK;
+ } else {
+ pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEB;
+ event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW;
+ if (full_height)
+ event = MI_WAIT_FOR_PIPEB_SVBLANK;
+ }
+
+ if (crtc->mode.Flags & V_INTERLACE) {
+ /* DSL count field lines */
+ y1 /= 2;
+ y2 /= 2;
+ }
+
+ b = kgem_get_batch(&sna->kgem, 5);
+ /* The documentation says that the LOAD_SCAN_LINES command
+ * always comes in pairs. Don't ask me why. */
+ b[0] = MI_LOAD_SCAN_LINES_INCL | pipe;
+ b[1] = (y1 << 16) | (y2-1);
+ b[2] = MI_LOAD_SCAN_LINES_INCL | pipe;
+ b[3] = (y1 << 16) | (y2-1);
+ b[4] = MI_WAIT_FOR_EVENT | event;
+ kgem_advance_batch(&sna->kgem, 5);
+ return true;
+}
+
diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index ea84fb21..c0bb8090 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -69,15 +69,43 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
#if DEBUG_DRI
#undef DBG
#define DBG(x) ErrorF x
+#else
+#define NDEBUG 1
#endif
-struct sna_dri2_private {
+struct sna_dri_private {
int refcnt;
PixmapPtr pixmap;
struct kgem_bo *bo;
unsigned int attachment;
};
+struct sna_dri_frame_event {
+ struct sna *sna;
+ XID drawable_id;
+ XID client_id; /* fake client ID to track client destruction */
+ ClientPtr client;
+ enum DRI2FrameEventType type;
+ int frame;
+ int pipe;
+ int count;
+
+ /* for swaps & flips only */
+ DRI2SwapEventPtr event_complete;
+ void *event_data;
+ DRI2BufferPtr front;
+ DRI2BufferPtr back;
+
+ PixmapPtr old_front;
+ uint32_t old_fb;
+};
+
+static struct sna_dri_frame_event *
+to_frame_event(void *data)
+{
+ return (struct sna_dri_frame_event *)((uintptr_t)data & ~1);
+}
+
static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
PixmapPtr pixmap)
{
@@ -104,14 +132,14 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
#if DRI2INFOREC_VERSION < 2
static DRI2BufferPtr
-sna_dri2_create_buffers(DrawablePtr drawable, unsigned int *attachments,
+sna_dri_create_buffers(DrawablePtr drawable, unsigned int *attachments,
int count)
{
ScreenPtr screen = drawable->pScreen;
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
struct sna *sna = to_sna(scrn);
DRI2BufferPtr buffers;
- struct sna_dri2_private *privates;
+ struct sna_dri_private *privates;
int depth = -1;
int i;
@@ -197,10 +225,10 @@ unwind:
}
static void
-sna_dri2_destroy_buffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count)
+sna_dri_destroy_buffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count)
{
ScreenPtr screen = drawable->pScreen;
- sna_dri2_private *private;
+ sna_dri_private *private;
int i;
for (i = 0; i < count; i++) {
@@ -220,25 +248,25 @@ sna_dri2_destroy_buffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count)
#else
static DRI2Buffer2Ptr
-sna_dri2_create_buffer(DrawablePtr drawable, unsigned int attachment,
+sna_dri_create_buffer(DrawablePtr drawable, unsigned int attachment,
unsigned int format)
{
ScreenPtr screen = drawable->pScreen;
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
struct sna *sna = to_sna(scrn);
DRI2Buffer2Ptr buffer;
- struct sna_dri2_private *private;
+ struct sna_dri_private *private;
PixmapPtr pixmap;
struct kgem_bo *bo;
int bpp, usage;
- DBG(("%s(attachment=%d, format=%d)\n",
- __FUNCTION__, attachment, format));
+ DBG(("%s(attachment=%d, format=%d, drawable=%dx%d)\n",
+ __FUNCTION__, attachment, format,drawable->width,drawable->height));
buffer = calloc(1, sizeof *buffer + sizeof *private);
if (buffer == NULL)
return NULL;
- private = (struct sna_dri2_private *)(buffer + 1);
+ private = (struct sna_dri_private *)(buffer + 1);
pixmap = NULL;
usage = CREATE_PIXMAP_USAGE_SCRATCH;
@@ -248,14 +276,17 @@ sna_dri2_create_buffer(DrawablePtr drawable, unsigned int attachment,
pixmap->refcnt++;
bo = sna_pixmap_set_dri(sna, pixmap);
bpp = pixmap->drawable.bitsPerPixel;
+ DBG(("%s: attaching to front buffer %dx%d\n",
+ __FUNCTION__,
+ pixmap->drawable.width, pixmap->drawable.height));
break;
- case DRI2BufferFakeFrontLeft:
- case DRI2BufferFakeFrontRight:
- usage = 0;
- case DRI2BufferFrontRight:
case DRI2BufferBackLeft:
case DRI2BufferBackRight:
+ case DRI2BufferFrontRight:
+ usage = 0;
+ case DRI2BufferFakeFrontLeft:
+ case DRI2BufferFakeFrontRight:
pixmap = screen->CreatePixmap(screen,
drawable->width,
drawable->height,
@@ -308,10 +339,10 @@ err:
return NULL;
}
-static void sna_dri2_destroy_buffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
+static void sna_dri_destroy_buffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
{
if (buffer && buffer->driverPrivate) {
- struct sna_dri2_private *private = buffer->driverPrivate;
+ struct sna_dri_private *private = buffer->driverPrivate;
if (--private->refcnt == 0) {
if (private->pixmap) {
ScreenPtr screen = private->pixmap->drawable.pScreen;
@@ -329,10 +360,10 @@ static void sna_dri2_destroy_buffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
#endif
-static void sna_dri2_reference_buffer(DRI2Buffer2Ptr buffer)
+static void sna_dri_reference_buffer(DRI2Buffer2Ptr buffer)
{
if (buffer) {
- struct sna_dri2_private *private = buffer->driverPrivate;
+ struct sna_dri_private *private = buffer->driverPrivate;
private->refcnt++;
}
}
@@ -396,12 +427,12 @@ static void damage(DrawablePtr drawable, RegionPtr region)
}
static void
-sna_dri2_copy_region(DrawablePtr drawable, RegionPtr region,
+sna_dri_copy_region(DrawablePtr drawable, RegionPtr region,
DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer)
{
struct sna *sna = to_sna_from_drawable(drawable);
- struct sna_dri2_private *srcPrivate = sourceBuffer->driverPrivate;
- struct sna_dri2_private *dstPrivate = destBuffer->driverPrivate;
+ struct sna_dri_private *srcPrivate = sourceBuffer->driverPrivate;
+ struct sna_dri_private *dstPrivate = destBuffer->driverPrivate;
ScreenPtr screen = drawable->pScreen;
DrawablePtr src = (srcPrivate->attachment == DRI2BufferFrontLeft)
? drawable : &srcPrivate->pixmap->drawable;
@@ -464,13 +495,16 @@ sna_dri2_copy_region(DrawablePtr drawable, RegionPtr region,
static int
-sna_dri2_get_pipe(DrawablePtr pDraw)
+sna_dri_get_pipe(DrawablePtr pDraw)
{
ScreenPtr pScreen = pDraw->pScreen;
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
BoxRec box, crtcbox;
xf86CrtcPtr crtc;
- int pipe = -1;
+ int pipe;
+
+ if (pDraw->type == DRAWABLE_PIXMAP)
+ return -1;
box.x1 = pDraw->x;
box.y1 = pDraw->y;
@@ -480,6 +514,7 @@ sna_dri2_get_pipe(DrawablePtr pDraw)
crtc = sna_covering_crtc(pScrn, &box, NULL, &crtcbox);
/* Make sure the CRTC is valid and this is the real front buffer */
+ pipe = -1;
if (crtc != NULL && !crtc->rotatedData)
pipe = sna_crtc_to_pipe(crtc);
@@ -495,9 +530,9 @@ sna_dri2_get_pipe(DrawablePtr pDraw)
static RESTYPE frame_event_client_type, frame_event_drawable_type;
static int
-sna_dri2_frame_event_client_gone(void *data, XID id)
+sna_dri_frame_event_client_gone(void *data, XID id)
{
- DRI2FrameEventPtr frame_event = data;
+ struct sna_dri_frame_event *frame_event = data;
frame_event->client = NULL;
frame_event->client_id = None;
@@ -505,25 +540,25 @@ sna_dri2_frame_event_client_gone(void *data, XID id)
}
static int
-sna_dri2_frame_event_drawable_gone(void *data, XID id)
+sna_dri_frame_event_drawable_gone(void *data, XID id)
{
- DRI2FrameEventPtr frame_event = data;
+ struct sna_dri_frame_event *frame_event = data;
frame_event->drawable_id = None;
return Success;
}
static Bool
-sna_dri2_register_frame_event_resource_types(void)
+sna_dri_register_frame_event_resource_types(void)
{
frame_event_client_type =
- CreateNewResourceType(sna_dri2_frame_event_client_gone,
+ CreateNewResourceType(sna_dri_frame_event_client_gone,
"Frame Event Client");
if (!frame_event_client_type)
return FALSE;
frame_event_drawable_type =
- CreateNewResourceType(sna_dri2_frame_event_drawable_gone,
+ CreateNewResourceType(sna_dri_frame_event_drawable_gone,
"Frame Event Drawable");
if (!frame_event_drawable_type)
return FALSE;
@@ -537,7 +572,7 @@ sna_dri2_register_frame_event_resource_types(void)
* client exits while the swap is pending
*/
static Bool
-sna_dri2_add_frame_event(DRI2FrameEventPtr frame_event)
+sna_dri_add_frame_event(struct sna_dri_frame_event *frame_event)
{
frame_event->client_id = FakeClientID(frame_event->client->index);
@@ -559,7 +594,7 @@ sna_dri2_add_frame_event(DRI2FrameEventPtr frame_event)
}
static void
-sna_dri2_del_frame_event(DRI2FrameEventPtr frame_event)
+sna_dri_del_frame_event(struct sna_dri_frame_event *frame_event)
{
if (frame_event->client_id)
FreeResourceByType(frame_event->client_id,
@@ -573,59 +608,17 @@ sna_dri2_del_frame_event(DRI2FrameEventPtr frame_event)
}
static void
-sna_dri2_exchange_buffers(DrawablePtr draw,
+sna_dri_exchange_buffers(DrawablePtr draw,
DRI2BufferPtr front, DRI2BufferPtr back)
{
- struct sna_dri2_private *front_priv, *back_priv;
- struct sna_pixmap *front_sna, *back_sna;
- struct kgem_bo *bo;
int tmp;
DBG(("%s()\n", __FUNCTION__));
- front_priv = front->driverPrivate;
- back_priv = back->driverPrivate;
-
- front_sna = sna_pixmap(front_priv->pixmap);
- back_sna = sna_pixmap(back_priv->pixmap);
-
- /* Force a copy/readback for the next CPU access */
- if (!front_sna->gpu_only) {
- sna_damage_all(&front_sna->gpu_damage,
- front_priv->pixmap->drawable.width,
- front_priv->pixmap->drawable.height);
- sna_damage_destroy(&front_sna->cpu_damage);
- }
- if (front_sna->mapped) {
- munmap(front_priv->pixmap->devPrivate.ptr,
- front_sna->gpu_bo->size);
- front_sna->mapped = false;
- }
- if (!back_sna->gpu_only) {
- sna_damage_all(&back_sna->gpu_damage,
- back_priv->pixmap->drawable.width,
- back_priv->pixmap->drawable.height);
- sna_damage_destroy(&back_sna->cpu_damage);
- }
- if (back_sna->mapped) {
- munmap(back_priv->pixmap->devPrivate.ptr,
- back_sna->gpu_bo->size);
- back_sna->mapped = false;
- }
-
/* Swap BO names so DRI works */
tmp = front->name;
front->name = back->name;
back->name = tmp;
-
- /* and swap bo so future flips work */
- bo = front_priv->bo;
- front_priv->bo = back_priv->bo;
- back_priv->bo = bo;
-
- bo = front_sna->gpu_bo;
- front_sna->gpu_bo = back_sna->gpu_bo;
- back_sna->gpu_bo = bo;
}
/*
@@ -633,56 +626,65 @@ sna_dri2_exchange_buffers(DrawablePtr draw,
* flipping buffers as necessary.
*/
static Bool
-sna_dri2_schedule_flip(struct sna *sna,
- ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
- DRI2BufferPtr back, DRI2SwapEventPtr func, void *data,
- unsigned int target_msc)
+sna_dri_schedule_flip(struct sna *sna,
+ ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
+ DRI2BufferPtr back, DRI2SwapEventPtr func, void *data,
+ unsigned int target_msc)
{
- struct sna_dri2_private *back_priv;
- DRI2FrameEventPtr flip_info;
+ struct sna_dri *dri = &sna->dri;
+ struct sna_dri_private *back_priv;
+ struct sna_dri_frame_event *info;
/* Main crtc for this drawable shall finally deliver pageflip event. */
- int ref_crtc_hw_id = sna_dri2_get_pipe(draw);
+ int ref_crtc_hw_id = sna_dri_get_pipe(draw);
DBG(("%s()\n", __FUNCTION__));
- flip_info = calloc(1, sizeof(DRI2FrameEventRec));
- if (!flip_info)
+ info = calloc(1, sizeof(struct sna_dri_frame_event));
+ if (!info)
return FALSE;
- flip_info->drawable_id = draw->id;
- flip_info->client = client;
- flip_info->type = DRI2_SWAP;
- flip_info->event_complete = func;
- flip_info->event_data = data;
- flip_info->frame = target_msc;
+ info->sna = sna;
+ info->drawable_id = draw->id;
+ info->client = client;
+ info->type = DRI2_SWAP;
+ info->event_complete = func;
+ info->event_data = data;
+ info->frame = target_msc;
- if (!sna_dri2_add_frame_event(flip_info)) {
- free(flip_info);
+ if (!sna_dri_add_frame_event(info)) {
+ free(info);
return FALSE;
}
+ dri->fe_frame = 0;
+ dri->fe_tv_sec = 0;
+ dri->fe_tv_usec = 0;
+
/* Page flip the full screen buffer */
back_priv = back->driverPrivate;
- if (sna_do_pageflip(sna,
- back_priv->pixmap,
- flip_info, ref_crtc_hw_id))
+ info->count = sna_do_pageflip(sna,
+ back_priv->pixmap,
+ info, ref_crtc_hw_id,
+ &info->old_front,
+ &info->old_fb);
+ if (info->count)
return TRUE;
- sna_dri2_del_frame_event(flip_info);
- free(flip_info);
+ sna_dri_del_frame_event(info);
+ free(info);
return FALSE;
}
static Bool
-can_exchange(DRI2BufferPtr front, DRI2BufferPtr back)
+can_exchange(DRI2BufferPtr front,
+ DRI2BufferPtr back)
{
- struct sna_dri2_private *front_priv = front->driverPrivate;
- struct sna_dri2_private *back_priv = back->driverPrivate;
+ struct sna_dri_private *front_priv = front->driverPrivate;
+ struct sna_dri_private *back_priv = back->driverPrivate;
PixmapPtr front_pixmap = front_priv->pixmap;
PixmapPtr back_pixmap = back_priv->pixmap;
- struct sna_pixmap *front_sna = sna_pixmap(front_pixmap);
- struct sna_pixmap *back_sna = sna_pixmap(back_pixmap);
+ struct sna_pixmap *front_sna, *back_sna;
if (front_pixmap->drawable.width != back_pixmap->drawable.width) {
DBG(("%s -- no, size mismatch: front width=%d, back=%d\n",
@@ -709,6 +711,8 @@ can_exchange(DRI2BufferPtr front, DRI2BufferPtr back)
}
/* prevent an implicit tiling mode change */
+ front_sna = sna_pixmap(front_pixmap);
+ back_sna = sna_pixmap(back_pixmap);
if (front_sna->gpu_bo->tiling != back_sna->gpu_bo->tiling) {
DBG(("%s -- no, tiling mismatch: front %d, back=%d\n",
__FUNCTION__,
@@ -726,9 +730,117 @@ can_exchange(DRI2BufferPtr front, DRI2BufferPtr back)
return TRUE;
}
-void sna_dri2_frame_event(unsigned int frame, unsigned int tv_sec,
- unsigned int tv_usec, DRI2FrameEventPtr swap_info)
+static Bool
+can_flip(struct sna * sna,
+ DrawablePtr draw,
+ DRI2BufferPtr front,
+ DRI2BufferPtr back)
{
+ struct sna_dri_private *front_priv = front->driverPrivate;
+ struct sna_dri_private *back_priv = back->driverPrivate;
+ struct sna_pixmap *front_sna, *back_sna;
+ WindowPtr win = (WindowPtr)draw;
+ PixmapPtr front_pixmap;
+ PixmapPtr back_pixmap = back_priv->pixmap;
+
+ ScreenPtr screen = draw->pScreen;
+
+ assert(draw->type == DRAWABLE_WINDOW);
+
+ if (front_priv->attachment != DRI2BufferFrontLeft) {
+ DBG(("%s: no, front attachment [%d] is not FrontLeft [%d]\n",
+ __FUNCTION__,
+ front_priv->attachment,
+ DRI2BufferFrontLeft));
+ return FALSE;
+ }
+
+ if (sna->shadow) {
+ DBG(("%s: no, shadow enabled\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ front_pixmap = screen->GetWindowPixmap(win);
+ if (front_pixmap != sna->front) {
+ DBG(("%s: no, window is not on the front buffer\n",
+ __FUNCTION__));
+ return FALSE;
+ }
+
+ if (!RegionEqual(&win->clipList, &screen->root->winSize)) {
+ DBG(("%s: no, window is clipped: clip region=(%d, %d), (%d, %d), root size=(%d, %d), (%d, %d)\n",
+ __FUNCTION__,
+ win->clipList.extents.x1,
+ win->clipList.extents.y1,
+ win->clipList.extents.x2,
+ win->clipList.extents.y2,
+ screen->root->winSize.extents.x1,
+ screen->root->winSize.extents.y1,
+ screen->root->winSize.extents.x2,
+ screen->root->winSize.extents.y2));
+ return FALSE;
+ }
+
+ if (draw->width != front_pixmap->drawable.width ||
+ draw->height != front_pixmap->drawable.height) {
+ DBG(("%s: no, window is not full size (%dx%d)!=(%dx%d)\n",
+ __FUNCTION__,
+ draw->width, draw->height,
+ front_pixmap->drawable.width,
+ front_pixmap->drawable.height));
+ return FALSE;
+ }
+
+ if (front_pixmap->drawable.width != back_pixmap->drawable.width) {
+ DBG(("%s -- no, size mismatch: front width=%d, back=%d\n",
+ __FUNCTION__,
+ front_pixmap->drawable.width,
+ back_pixmap->drawable.width));
+ return FALSE;
+ }
+
+ if (front_pixmap->drawable.height != back_pixmap->drawable.height) {
+ DBG(("%s -- no, size mismatch: front height=%d, back=%d\n",
+ __FUNCTION__,
+ front_pixmap->drawable.height,
+ back_pixmap->drawable.height));
+ return FALSE;
+ }
+
+ if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel) {
+ DBG(("%s -- no, depth mismatch: front bpp=%d, back=%d\n",
+ __FUNCTION__,
+ front_pixmap->drawable.bitsPerPixel,
+ back_pixmap->drawable.bitsPerPixel));
+ return FALSE;
+ }
+
+ /* prevent an implicit tiling mode change */
+ front_sna = sna_pixmap(front_pixmap);
+ back_sna = sna_pixmap(back_pixmap);
+ if (front_sna->gpu_bo->tiling != back_sna->gpu_bo->tiling) {
+ DBG(("%s -- no, tiling mismatch: front %d, back=%d\n",
+ __FUNCTION__,
+ front_sna->gpu_bo->tiling,
+ back_sna->gpu_bo->tiling));
+ return FALSE;
+ }
+
+ if (front_sna->gpu_only != back_sna->gpu_only) {
+ DBG(("%s -- no, mismatch in gpu_only: front %d, back=%d\n",
+ __FUNCTION__, front_sna->gpu_only, back_sna->gpu_only));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void sna_dri_vblank_handle(int fd,
+ unsigned int frame, unsigned int tv_sec,
+ unsigned int tv_usec,
+ void *data)
+{
+ struct sna_dri_frame_event *swap_info = data;
DrawablePtr drawable;
ScreenPtr screen;
ScrnInfoPtr scrn;
@@ -754,10 +866,9 @@ void sna_dri2_frame_event(unsigned int frame, unsigned int tv_sec,
switch (swap_info->type) {
case DRI2_FLIP:
/* If we can still flip... */
- if (DRI2CanFlip(drawable) &&
- !sna->shadow &&
- can_exchange(swap_info->front, swap_info->back) &&
- sna_dri2_schedule_flip(sna,
+ if (can_flip(sna, drawable,
+ swap_info->front, swap_info->back) &&
+ sna_dri_schedule_flip(sna,
swap_info->client,
drawable,
swap_info->front,
@@ -765,7 +876,7 @@ void sna_dri2_frame_event(unsigned int frame, unsigned int tv_sec,
swap_info->event_complete,
swap_info->event_data,
swap_info->frame)) {
- sna_dri2_exchange_buffers(drawable,
+ sna_dri_exchange_buffers(drawable,
swap_info->front,
swap_info->back);
break;
@@ -776,12 +887,12 @@ void sna_dri2_frame_event(unsigned int frame, unsigned int tv_sec,
if (DRI2CanExchange(drawable) &&
can_exchange(swap_info->front, swap_info->back)) {
- sna_dri2_exchange_buffers(drawable,
+ sna_dri_exchange_buffers(drawable,
swap_info->front,
swap_info->back);
swap_type = DRI2_EXCHANGE_COMPLETE;
} else {
- sna_dri2_copy_region(drawable, NULL,
+ sna_dri_copy_region(drawable, NULL,
swap_info->front,
swap_info->back);
swap_type = DRI2_BLIT_COMPLETE;
@@ -807,81 +918,108 @@ void sna_dri2_frame_event(unsigned int frame, unsigned int tv_sec,
}
done:
- sna_dri2_del_frame_event(swap_info);
- sna_dri2_destroy_buffer(drawable, swap_info->front);
- sna_dri2_destroy_buffer(drawable, swap_info->back);
+ sna_dri_del_frame_event(swap_info);
+ sna_dri_destroy_buffer(drawable, swap_info->front);
+ sna_dri_destroy_buffer(drawable, swap_info->back);
free(swap_info);
}
-void sna_dri2_flip_event(unsigned int frame, unsigned int tv_sec,
- unsigned int tv_usec, DRI2FrameEventPtr flip)
+static void sna_dri_flip_event(struct sna *sna, struct sna_dri_frame_event *flip)
{
DrawablePtr drawable;
- ScreenPtr screen;
- ScrnInfoPtr scrn;
int status;
DBG(("%s(frame=%d, tv=%d.%06d, type=%d)\n",
- __FUNCTION__, frame, tv_sec, tv_usec, flip->type));
+ __FUNCTION__,
+ sna->dri.fe_frame,
+ sna->dri.fe_tv_sec,
+ sna->dri.fe_tv_usec,
+ flip->type));
if (!flip->drawable_id)
- status = BadDrawable;
- else
- status = dixLookupDrawable(&drawable,
- flip->drawable_id,
- serverClient,
- M_ANY, DixWriteAccess);
- if (status != Success) {
- sna_dri2_del_frame_event(flip);
- free(flip);
return;
- }
- screen = drawable->pScreen;
- scrn = xf86Screens[screen->myNum];
+ status = dixLookupDrawable(&drawable,
+ flip->drawable_id,
+ serverClient,
+ M_ANY, DixWriteAccess);
+ if (status != Success)
+ return;
/* We assume our flips arrive in order, so we don't check the frame */
switch (flip->type) {
case DRI2_SWAP:
+ /* Deliver cached msc, ust from reference crtc */
/* Check for too small vblank count of pageflip completion, taking wraparound
* into account. This usually means some defective kms pageflip completion,
* causing wrong (msc, ust) return values and possible visual corruption.
*/
- if ((frame < flip->frame) && (flip->frame - frame < 5)) {
+ if ((sna->dri.fe_frame < flip->frame) &&
+ (flip->frame - sna->dri.fe_frame < 5)) {
static int limit = 5;
/* XXX we are currently hitting this path with older
* kernels, so make it quieter.
*/
if (limit) {
- xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
"%s: Pageflip completion has impossible msc %d < target_msc %d\n",
- __func__, frame, flip->frame);
+ __func__, sna->dri.fe_frame, flip->frame);
limit--;
}
/* All-0 values signal timestamping failure. */
- frame = tv_sec = tv_usec = 0;
+ sna->dri.fe_frame = sna->dri.fe_tv_sec = sna->dri.fe_tv_usec = 0;
}
DBG(("%s: swap complete\n", __FUNCTION__));
- DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec,
+ DRI2SwapComplete(flip->client, drawable,
+ sna->dri.fe_frame,
+ sna->dri.fe_tv_sec,
+ sna->dri.fe_tv_usec,
DRI2_FLIP_COMPLETE, flip->client ? flip->event_complete : NULL,
flip->event_data);
break;
+
case DRI2_ASYNC_SWAP:
- DBG(("%s: asunc swap flip completed\n", __FUNCTION__));
- to_sna(scrn)->mode.flip_pending[flip->pipe]--;
+ DBG(("%s: async swap flip completed on pipe %d, pending %d\n",
+ __FUNCTION__, flip->pipe, sna->dri.flip_pending[flip->pipe]));
+ sna->dri.flip_pending[flip->pipe]--;
break;
+
default:
- xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
"%s: unknown vblank event received\n", __func__);
/* Unknown type */
break;
}
+}
+
+static void
+sna_dri_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
+ unsigned int tv_usec, void *data)
+{
+ struct sna_dri_frame_event *info = to_frame_event(data);
+ struct sna_dri *dri = &info->sna->dri;
+
+ DBG(("%s: pending flip_count=%d\n", __FUNCTION__, info->count));
+
+ /* Is this the event whose info shall be delivered to higher level? */
+ if ((uintptr_t)data & 1) {
+ /* Yes: Cache msc, ust for later delivery. */
+ dri->fe_frame = frame;
+ dri->fe_tv_sec = tv_sec;
+ dri->fe_tv_usec = tv_usec;
+ }
+
+ if (--info->count)
+ return;
- sna_dri2_del_frame_event(flip);
- free(flip);
+ sna_dri_flip_event(info->sna, info);
+
+ sna_mode_delete_fb(info->sna, info->old_front, info->old_fb);
+ sna_dri_del_frame_event(info);
+ free(info);
}
/*
@@ -905,7 +1043,7 @@ void sna_dri2_flip_event(unsigned int frame, unsigned int tv_sec,
* can send any swap complete events that have been requested.
*/
static int
-sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
+sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor,
CARD64 remainder, DRI2SwapEventPtr func, void *data)
{
@@ -913,8 +1051,8 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
struct sna *sna = to_sna(scrn);
drmVBlank vbl;
- int ret, pipe = sna_dri2_get_pipe(draw), flip = 0;
- DRI2FrameEventPtr swap_info = NULL;
+ int ret, pipe = sna_dri_get_pipe(draw), flip = 0;
+ struct sna_dri_frame_event *swap_info = NULL;
enum DRI2FrameEventType swap_type = DRI2_SWAP;
CARD64 current_msc;
@@ -930,7 +1068,7 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
divisor &= 0xffffffff;
remainder &= 0xffffffff;
- swap_info = calloc(1, sizeof(DRI2FrameEventRec));
+ swap_info = calloc(1, sizeof(struct sna_dri_frame_event));
if (!swap_info)
goto blit_fallback;
@@ -941,14 +1079,14 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
swap_info->front = front;
swap_info->back = back;
- if (!sna_dri2_add_frame_event(swap_info)) {
+ if (!sna_dri_add_frame_event(swap_info)) {
free(swap_info);
swap_info = NULL;
goto blit_fallback;
}
- sna_dri2_reference_buffer(front);
- sna_dri2_reference_buffer(back);
+ sna_dri_reference_buffer(front);
+ sna_dri_reference_buffer(back);
/* Get current count */
vbl.request.type = DRM_VBLANK_RELATIVE;
@@ -966,7 +1104,7 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
current_msc = vbl.reply.sequence;
/* Flips need to be submitted one frame before */
- if (!sna->shadow && DRI2CanFlip(draw) && can_exchange(front, back)) {
+ if (can_flip(sna, draw, front, back)) {
DBG(("%s: can flip\n", __FUNCTION__));
swap_type = DRI2_FLIP;
flip = 1;
@@ -1069,13 +1207,13 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
blit_fallback:
DBG(("%s -- blit\n", __FUNCTION__));
- sna_dri2_copy_region(draw, NULL, front, back);
+ sna_dri_copy_region(draw, NULL, front, back);
DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
if (swap_info) {
- sna_dri2_del_frame_event(swap_info);
- sna_dri2_destroy_buffer(draw, swap_info->front);
- sna_dri2_destroy_buffer(draw, swap_info->back);
+ sna_dri_del_frame_event(swap_info);
+ sna_dri_destroy_buffer(draw, swap_info->front);
+ sna_dri_destroy_buffer(draw, swap_info->back);
free(swap_info);
}
*target_msc = 0; /* offscreen, so zero out target vblank count */
@@ -1084,14 +1222,14 @@ blit_fallback:
#if DRI2INFOREC_VERSION >= 6
static void
-sna_dri2_async_swap(ClientPtr client, DrawablePtr draw,
+sna_dri_async_swap(ClientPtr client, DrawablePtr draw,
DRI2BufferPtr front, DRI2BufferPtr back,
DRI2SwapEventPtr func, void *data)
{
ScreenPtr screen = draw->pScreen;
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
struct sna *sna = to_sna(scrn);
- int pipe = sna_dri2_get_pipe(draw);
+ int pipe = sna_dri_get_pipe(draw);
int type = DRI2_EXCHANGE_COMPLETE;
DBG(("%s()\n", __FUNCTION__));
@@ -1100,68 +1238,116 @@ sna_dri2_async_swap(ClientPtr client, DrawablePtr draw,
if (pipe == -1)
goto exchange;
- if (sna->shadow ||
- !DRI2CanFlip(draw) ||
- !can_exchange(front, back)) {
- sna_dri2_copy_region(draw, NULL, front, back);
+ if (!can_flip(sna, draw, front, back)) {
+ /* Do an synchronous copy instead */
+ struct sna_dri_private *front_priv = front->driverPrivate;
+ struct sna_dri_private *back_priv = back->driverPrivate;
+ BoxRec box, *boxes;
+ PixmapPtr dst;
+ int n;
+
+ DBG(("%s: fallback blit: %dx%d\n",
+ __FUNCTION__, draw->width, draw->height));
+
+ /* XXX clipping */
+ if (draw->type == DRAWABLE_PIXMAP) {
+ box.x1 = box.y1 = 0;
+ box.x2 = draw->width;
+ box.y2 = draw->height;
+
+ dst = front_priv->pixmap;
+ boxes = &box;
+ n = 1;
+ } else {
+ WindowPtr win = (WindowPtr)draw;
+
+ dst = sna->front;
+ boxes = REGION_RECTS(&win->clipList);
+ n = REGION_NUM_RECTS(&win->clipList);
+ }
+
+ sna->render.copy_boxes(sna, GXcopy,
+ back_priv->pixmap, back_priv->bo, 0, 0,
+ dst, sna_pixmap_get_bo(dst), 0, 0,
+ boxes, n);
+
DRI2SwapComplete(client, draw, 0, 0, 0,
DRI2_BLIT_COMPLETE, func, data);
return;
}
- if (!sna->mode.flip_pending[pipe]) {
- DRI2FrameEventPtr info;
- struct sna_dri2_private *backPrivate = back->driverPrivate;
- DrawablePtr src = &backPrivate->pixmap->drawable;
+ if (!sna->dri.flip_pending[pipe]) {
+ struct sna_dri_frame_event *info;
+ struct sna_dri_private *back_priv = back->driverPrivate;
+ struct sna_pixmap *priv;
+ PixmapPtr src = back_priv->pixmap;
PixmapPtr copy;
- GCPtr gc;
+ BoxRec box;
+
+ DBG(("%s: no pending flip on pipe %d, so updating scanout\n",
+ __FUNCTION__, pipe));
copy = screen->CreatePixmap(screen,
- src->width, src->height, src->depth,
- 0);
- if (!copy)
+ src->drawable.width,
+ src->drawable.height,
+ src->drawable.depth,
+ SNA_CREATE_FB);
+ if (copy == NullPixmap)
goto exchange;
- if (!sna_pixmap_force_to_gpu(copy)) {
+ priv = sna_pixmap_force_to_gpu(copy);
+ if (priv == NULL) {
screen->DestroyPixmap(copy);
goto exchange;
}
- /* copy back to new buffer, and schedule flip */
- gc = GetScratchGC(src->depth, screen);
- if (!gc) {
+ box.x1 = box.y1 = 0;
+ box.x2 = src->drawable.width;
+ box.y2 = src->drawable.height;
+ if (!sna->render.copy_boxes(sna, GXcopy,
+ src, back_priv->bo, 0, 0,
+ copy, priv->gpu_bo, 0, 0,
+ &box, 1)) {
screen->DestroyPixmap(copy);
goto exchange;
}
- ValidateGC(src, gc);
-
- gc->ops->CopyArea(src, &copy->drawable, gc,
- 0, 0,
- draw->width, draw->height,
- 0, 0);
- FreeScratchGC(gc);
+ sna_damage_all(&priv->gpu_damage,
+ src->drawable.width, src->drawable.height);
+ assert(priv->cpu_damage == NULL);
- info = calloc(1, sizeof(DRI2FrameEventRec));
+ info = calloc(1, sizeof(struct sna_dri_frame_event));
if (!info) {
screen->DestroyPixmap(copy);
goto exchange;
}
+ info->sna = sna;
info->drawable_id = draw->id;
info->client = client;
info->type = DRI2_ASYNC_SWAP;
info->pipe = pipe;
- sna->mode.flip_pending[pipe]++;
- sna_do_pageflip(sna, copy, info,
- sna_dri2_get_pipe(draw));
+ if (!sna_dri_add_frame_event(info)) {
+ free(info);
+ screen->DestroyPixmap(copy);
+ goto exchange;
+ }
+
+ info->count = sna_do_pageflip(sna, copy, info, pipe,
+ &info->old_front, &info->old_fb);
screen->DestroyPixmap(copy);
+ if (info->count == 0) {
+ free(info);
+ goto exchange;
+ }
+
type = DRI2_FLIP_COMPLETE;
+ sna->dri.flip_pending[pipe]++;
}
exchange:
- sna_dri2_exchange_buffers(draw, front, back);
+ sna_dri_exchange_buffers(draw, front, back);
DRI2SwapComplete(client, draw, 0, 0, 0, type, func, data);
}
#endif
@@ -1171,13 +1357,13 @@ exchange:
* crtc.
*/
static int
-sna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
+sna_dri_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
{
ScreenPtr screen = draw->pScreen;
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
struct sna *sna = to_sna(scrn);
drmVBlank vbl;
- int ret, pipe = sna_dri2_get_pipe(draw);
+ int ret, pipe = sna_dri_get_pipe(draw);
DBG(("%s()\n", __FUNCTION__));
@@ -1219,15 +1405,15 @@ sna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
* we receive it.
*/
static int
-sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
+sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
CARD64 divisor, CARD64 remainder)
{
ScreenPtr screen = draw->pScreen;
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
struct sna *sna = to_sna(scrn);
- DRI2FrameEventPtr wait_info;
+ struct sna_dri_frame_event *wait_info;
drmVBlank vbl;
- int ret, pipe = sna_dri2_get_pipe(draw);
+ int ret, pipe = sna_dri_get_pipe(draw);
CARD64 current_msc;
DBG(("%s(target_msc=%llu, divisor=%llu, rem=%llu)\n",
@@ -1246,7 +1432,7 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
if (pipe == -1)
goto out_complete;
- wait_info = calloc(1, sizeof(DRI2FrameEventRec));
+ wait_info = calloc(1, sizeof(struct sna_dri_frame_event));
if (!wait_info)
goto out_complete;
@@ -1358,7 +1544,7 @@ out_complete:
static int dri2_server_generation;
-Bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
+Bool sna_dri_open(struct sna *sna, ScreenPtr screen)
{
DRI2InfoRec info;
int dri2_major = 1;
@@ -1386,7 +1572,7 @@ Bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
if (serverGeneration != dri2_server_generation) {
dri2_server_generation = serverGeneration;
- if (!sna_dri2_register_frame_event_resource_types()) {
+ if (!sna_dri_register_frame_event_resource_types()) {
xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
"Cannot register DRI2 frame event resources\n");
return FALSE;
@@ -1403,34 +1589,34 @@ Bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
#if DRI2INFOREC_VERSION == 1
info.version = 1;
- info.CreateBuffers = sna_dri2_create_buffers;
- info.DestroyBuffers = sna_dri2_destroy_buffers;
+ info.CreateBuffers = sna_dri_create_buffers;
+ info.DestroyBuffers = sna_dri_destroy_buffers;
#elif DRI2INFOREC_VERSION == 2
/* The ABI between 2 and 3 was broken so we could get rid of
* the multi-buffer alloc functions. Make sure we indicate the
* right version so DRI2 can reject us if it's version 3 or above. */
info.version = 2;
- info.CreateBuffer = sna_dri2_create_buffer;
- info.DestroyBuffer = sna_dri2_destroy_buffer;
+ info.CreateBuffer = sna_dri_create_buffer;
+ info.DestroyBuffer = sna_dri_destroy_buffer;
#else
info.version = 3;
- info.CreateBuffer = sna_dri2_create_buffer;
- info.DestroyBuffer = sna_dri2_destroy_buffer;
+ info.CreateBuffer = sna_dri_create_buffer;
+ info.DestroyBuffer = sna_dri_destroy_buffer;
#endif
- info.CopyRegion = sna_dri2_copy_region;
+ info.CopyRegion = sna_dri_copy_region;
#if DRI2INFOREC_VERSION >= 4
{
info.version = 4;
- info.ScheduleSwap = sna_dri2_schedule_swap;
- info.GetMSC = sna_dri2_get_msc;
- info.ScheduleWaitMSC = sna_dri2_schedule_wait_msc;
+ info.ScheduleSwap = sna_dri_schedule_swap;
+ info.GetMSC = sna_dri_get_msc;
+ info.ScheduleWaitMSC = sna_dri_schedule_wait_msc;
info.numDrivers = 1;
info.driverNames = driverNames;
driverNames[0] = info.driverName;
#if DRI2INFOREC_VERSION >= 6
info.version = 6;
- info.AsyncSwap = sna_dri2_async_swap;
+ info.AsyncSwap = sna_dri_async_swap;
#endif
}
#endif
@@ -1438,7 +1624,21 @@ Bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
return DRI2ScreenInit(screen, &info);
}
-void sna_dri2_close(struct sna *sna, ScreenPtr screen)
+void
+sna_dri_wakeup(struct sna *sna)
+{
+ drmEventContext ctx;
+
+ DBG(("%s\n", __FUNCTION__));
+
+ ctx.version = DRM_EVENT_CONTEXT_VERSION;
+ ctx.vblank_handler = sna_dri_vblank_handle;
+ ctx.page_flip_handler = sna_dri_page_flip_handler;
+
+ drmHandleEvent(sna->kgem.fd, &ctx);
+}
+
+void sna_dri_close(struct sna *sna, ScreenPtr screen)
{
DBG(("%s()\n", __FUNCTION__));
DRI2CloseScreen(screen);
diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
index bbd1d494..9d8a067c 100644
--- a/src/sna/sna_driver.c
+++ b/src/sna/sna_driver.c
@@ -561,7 +561,14 @@ sna_wakeup_handler(int i, pointer data, unsigned long result, pointer read_mask)
sna->WakeupHandler = screen->WakeupHandler;
screen->WakeupHandler = sna_wakeup_handler;
+ /* despite all appearances, result is just a signed int */
+ if ((int)result < 0)
+ return;
+
sna_accel_wakeup_handler(sna);
+
+ if (FD_ISSET(sna->kgem.fd, (fd_set*)read_mask))
+ sna_dri_wakeup(sna);
}
#if HAVE_UDEV
@@ -704,7 +711,7 @@ static Bool sna_close_screen(int scrnIndex, ScreenPtr screen)
(*screen->CloseScreen) (scrnIndex, screen);
if (sna->directRenderingOpen) {
- sna_dri2_close(sna, screen);
+ sna_dri_close(sna, screen);
sna->directRenderingOpen = FALSE;
}
@@ -725,7 +732,7 @@ sna_screen_init(int scrnIndex, ScreenPtr screen, int argc, char **argv)
scrn->videoRam = device->regions[2].size / 1024;
#ifdef DRI2
- sna->directRenderingOpen = sna_dri2_open(sna, screen);
+ sna->directRenderingOpen = sna_dri_open(sna, screen);
if (sna->directRenderingOpen)
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"direct rendering: DRI2 Enabled\n");
@@ -823,8 +830,6 @@ sna_screen_init(int scrnIndex, ScreenPtr screen, int argc, char **argv)
if (serverGeneration == 1)
xf86ShowUnusedOptions(scrn->scrnIndex, scrn->options);
- sna_mode_init(sna);
-
sna->suspended = FALSE;
#if HAVE_UDEV
diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c
index d7d7e5f5..63747eaa 100644
--- a/src/sna/sna_render.c
+++ b/src/sna/sna_render.c
@@ -254,7 +254,7 @@ move_to_gpu(PixmapPtr pixmap, const BoxRec *box)
if (w == pixmap->drawable.width || h == pixmap->drawable.height) {
DBG(("%s: migrating whole pixmap (%dx%d) for source\n",
__FUNCTION__,
- pixmap->drawble->width,
+ pixmap->drawable.width,
pixmap->drawable.height));
return TRUE;
}
@@ -303,7 +303,7 @@ texture_is_cpu(PixmapPtr pixmap, const BoxRec *box)
{
Bool ret = _texture_is_cpu(pixmap, box);
ErrorF("%s(pixmap=%p, box=((%d, %d), (%d, %d)) = %d\n",
- __FUNCTION__, pixmap, box, ret);
+ __FUNCTION__, pixmap, box->x1, box->y1, box->x2, box->y2, ret);
return ret;
}
#else
diff --git a/src/sna/sna_video.c b/src/sna/sna_video.c
index b6cbda22..8839ab74 100644
--- a/src/sna/sna_video.c
+++ b/src/sna/sna_video.c
@@ -514,184 +514,6 @@ sna_video_copy_data(struct sna *sna,
return TRUE;
}
-static void sna_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 void sna_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 int sna_box_area(BoxPtr box)
-{
- return (int)(box->x2 - box->x1) * (int)(box->y2 - box->y1);
-}
-
-/*
- * Return the crtc covering 'box'. If two crtcs cover a portion of
- * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc
- * with greater coverage
- */
-
-xf86CrtcPtr
-sna_covering_crtc(ScrnInfoPtr scrn,
- BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret)
-{
- xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
- xf86CrtcPtr crtc, best_crtc;
- int coverage, best_coverage;
- int c;
- BoxRec crtc_box, cover_box;
-
- DBG(("%s for box=(%d, %d), (%d, %d)\n",
- __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
-
- best_crtc = NULL;
- best_coverage = 0;
- crtc_box_ret->x1 = 0;
- crtc_box_ret->x2 = 0;
- crtc_box_ret->y1 = 0;
- crtc_box_ret->y2 = 0;
- for (c = 0; c < xf86_config->num_crtc; c++) {
- crtc = xf86_config->crtc[c];
-
- /* If the CRTC is off, treat it as not covering */
- if (!sna_crtc_on(crtc)) {
- DBG(("%s: crtc %d off, skipping\n", __FUNCTION__, c));
- continue;
- }
-
- sna_crtc_box(crtc, &crtc_box);
- sna_box_intersect(&cover_box, &crtc_box, box);
- coverage = sna_box_area(&cover_box);
- if (coverage && crtc == desired) {
- DBG(("%s: box is on desired crtc [%p]\n",
- __FUNCTION__, crtc));
- *crtc_box_ret = crtc_box;
- return crtc;
- }
- if (coverage > best_coverage) {
- *crtc_box_ret = crtc_box;
- best_crtc = crtc;
- best_coverage = coverage;
- }
- }
- DBG(("%s: best crtc = %p\n", __FUNCTION__, best_crtc));
- return best_crtc;
-}
-
-bool
-sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
- xf86CrtcPtr crtc, RegionPtr clip)
-{
- pixman_box16_t box, crtc_box;
- int pipe, event;
- Bool full_height;
- int y1, y2;
- uint32_t *b;
-
- /* XXX no wait for scanline support on SNB? */
- if (sna->kgem.gen >= 60)
- return false;
-
- if (!pixmap_is_scanout(pixmap))
- return false;
-
- if (crtc == NULL) {
- if (clip) {
- crtc_box = *REGION_EXTENTS(NULL, clip);
- } else {
- crtc_box.x1 = 0; /* XXX drawable offsets? */
- crtc_box.y1 = 0;
- crtc_box.x2 = pixmap->drawable.width;
- crtc_box.y2 = pixmap->drawable.height;
- }
- crtc = sna_covering_crtc(sna->scrn, &crtc_box, NULL, &crtc_box);
- }
-
- if (crtc == NULL)
- return false;
-
- if (clip) {
- box = *REGION_EXTENTS(unused, clip);
-
- if (crtc->transform_in_use)
- pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &box);
-
- /* We could presume the clip was correctly computed... */
- sna_crtc_box(crtc, &crtc_box);
- sna_box_intersect(&box, &crtc_box, &box);
-
- /*
- * Make sure we don't wait for a scanline that will
- * never occur
- */
- y1 = (crtc_box.y1 <= box.y1) ? box.y1 - crtc_box.y1 : 0;
- y2 = (box.y2 <= crtc_box.y2) ?
- box.y2 - crtc_box.y1 : crtc_box.y2 - crtc_box.y1;
- if (y2 <= y1)
- return false;
-
- full_height = FALSE;
- if (y1 == 0 && y2 == (crtc_box.y2 - crtc_box.y1))
- full_height = TRUE;
- } else {
- sna_crtc_box(crtc, &crtc_box);
- y1 = crtc_box.y1;
- y2 = crtc_box.y2;
- full_height = TRUE;
- }
-
- /*
- * Pre-965 doesn't have SVBLANK, so we need a bit
- * of extra time for the blitter to start up and
- * do its job for a full height blit
- */
- if (sna_crtc_to_pipe(crtc) == 0) {
- pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEA;
- event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
- if (full_height)
- event = MI_WAIT_FOR_PIPEA_SVBLANK;
- } else {
- pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEB;
- event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW;
- if (full_height)
- event = MI_WAIT_FOR_PIPEB_SVBLANK;
- }
-
- if (crtc->mode.Flags & V_INTERLACE) {
- /* DSL count field lines */
- y1 /= 2;
- y2 /= 2;
- }
-
- b = kgem_get_batch(&sna->kgem, 5);
- /* The documentation says that the LOAD_SCAN_LINES command
- * always comes in pairs. Don't ask me why. */
- b[0] = MI_LOAD_SCAN_LINES_INCL | pipe;
- b[1] = (y1 << 16) | (y2-1);
- b[2] = MI_LOAD_SCAN_LINES_INCL | pipe;
- b[3] = (y1 << 16) | (y2-1);
- b[4] = MI_WAIT_FOR_EVENT | event;
- kgem_advance_batch(&sna->kgem, 5);
- return true;
-}
-
void sna_video_init(struct sna *sna, ScreenPtr screen)
{
XF86VideoAdaptorPtr *adaptors, *newAdaptors;