sna/dri: Fix tripple-buffering for vblank_mode=0
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
b199bc2b41
commit
ff262aca9c
|
|
@ -515,6 +515,7 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
|
|||
bo->deleted = 1;
|
||||
}
|
||||
|
||||
kgem->need_expire = true;
|
||||
list_move(&bo->list, (bo->rq || bo->needs_flush) ? &kgem->active : inactive(kgem, bo->size));
|
||||
if (bo->rq == NULL && bo->needs_flush) {
|
||||
assert(list_is_empty(&bo->request));
|
||||
|
|
@ -943,21 +944,6 @@ void kgem_throttle(struct kgem *kgem)
|
|||
}
|
||||
}
|
||||
|
||||
bool kgem_needs_expire(struct kgem *kgem)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!list_is_empty(&kgem->active))
|
||||
return true;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) {
|
||||
if (!list_is_empty(&kgem->inactive[i]))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool kgem_expire_cache(struct kgem *kgem)
|
||||
{
|
||||
time_t now, expire;
|
||||
|
|
@ -1018,6 +1004,7 @@ bool kgem_expire_cache(struct kgem *kgem)
|
|||
|
||||
DBG(("%s: purge? %d -- expired %d objects, %d bytes\n", __FUNCTION__, kgem->need_purge, count, size));
|
||||
|
||||
kgem->need_expire = !idle;
|
||||
kgem->need_purge = false;
|
||||
return idle;
|
||||
(void)count;
|
||||
|
|
@ -1539,7 +1526,11 @@ uint32_t kgem_bo_flink(struct kgem *kgem, struct kgem_bo *bo)
|
|||
if (ret)
|
||||
return 0;
|
||||
|
||||
bo->reusable = false;
|
||||
/* Ordinarily giving the name aware makes the buffer non-reusable.
|
||||
* However, we track the lifetime of all clients and their hold
|
||||
* on the buffer, and *presuming* they do not pass it on to a third
|
||||
* party, we track the lifetime accurately.
|
||||
*/
|
||||
return flink.name;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,8 +97,9 @@ struct kgem {
|
|||
uint16_t nreloc;
|
||||
uint16_t nfence;
|
||||
|
||||
uint32_t flush;
|
||||
uint32_t need_purge;
|
||||
uint32_t flush:1;
|
||||
uint32_t need_expire:1;
|
||||
uint32_t need_purge:1;
|
||||
|
||||
uint32_t has_vmap :1;
|
||||
uint32_t has_relaxed_fencing :1;
|
||||
|
|
@ -312,7 +313,6 @@ struct kgem_bo *kgem_create_buffer(struct kgem *kgem,
|
|||
void kgem_buffer_sync(struct kgem *kgem, struct kgem_bo *bo);
|
||||
|
||||
void kgem_throttle(struct kgem *kgem);
|
||||
bool kgem_needs_expire(struct kgem *kgem);
|
||||
bool kgem_expire_cache(struct kgem *kgem);
|
||||
|
||||
#if HAS_EXTRA_DEBUG
|
||||
|
|
|
|||
|
|
@ -120,13 +120,6 @@ static inline void list_add_tail(struct list *new, struct list *head)
|
|||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
enum DRI2FrameEventType {
|
||||
DRI2_SWAP,
|
||||
DRI2_ASYNC_SWAP,
|
||||
DRI2_FLIP,
|
||||
DRI2_WAITMSC,
|
||||
};
|
||||
|
||||
#ifndef CREATE_PIXMAP_USAGE_SCRATCH_HEADER
|
||||
#define CREATE_PIXMAP_USAGE_SCRATCH_HEADER -1
|
||||
#endif
|
||||
|
|
@ -182,7 +175,6 @@ enum {
|
|||
OPTION_PREFER_OVERLAY,
|
||||
OPTION_COLOR_KEY,
|
||||
OPTION_VIDEO_KEY,
|
||||
OPTION_SWAPBUFFERS_WAIT,
|
||||
OPTION_HOTPLUG,
|
||||
OPTION_THROTTLE,
|
||||
OPTION_RELAXED_FENCING,
|
||||
|
|
@ -201,7 +193,6 @@ struct sna {
|
|||
|
||||
unsigned flags;
|
||||
#define SNA_NO_THROTTLE 0x1
|
||||
#define SNA_SWAP_WAIT 0x2
|
||||
|
||||
int timer[NUM_TIMERS];
|
||||
int timer_active;
|
||||
|
|
@ -222,9 +213,6 @@ struct sna {
|
|||
|
||||
struct sna_dri {
|
||||
int flip_pending[2];
|
||||
unsigned int fe_frame;
|
||||
unsigned int fe_tv_sec;
|
||||
unsigned int fe_tv_usec;
|
||||
} dri;
|
||||
|
||||
unsigned int tiling;
|
||||
|
|
@ -239,7 +227,9 @@ struct sna {
|
|||
struct intel_chipset chipset;
|
||||
|
||||
ScreenBlockHandlerProcPtr BlockHandler;
|
||||
void *BlockData;
|
||||
ScreenWakeupHandlerProcPtr WakeupHandler;
|
||||
void *WakeupData;
|
||||
CloseScreenProcPtr CloseScreen;
|
||||
|
||||
union {
|
||||
|
|
@ -315,7 +305,7 @@ extern xf86CrtcPtr sna_covering_crtc(ScrnInfoPtr scrn,
|
|||
BoxPtr crtc_box_ret);
|
||||
|
||||
extern bool sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
|
||||
xf86CrtcPtr crtc, RegionPtr clip);
|
||||
xf86CrtcPtr crtc, const BoxRec *clip);
|
||||
|
||||
Bool sna_dri_open(struct sna *sna, ScreenPtr pScreen);
|
||||
void sna_dri_wakeup(struct sna *sna);
|
||||
|
|
|
|||
|
|
@ -3131,7 +3131,7 @@ static Bool sna_accel_do_expire(struct sna *sna)
|
|||
|
||||
return_if_timer_active(EXPIRE_TIMER);
|
||||
|
||||
if (!kgem_needs_expire(&sna->kgem))
|
||||
if (!sna->kgem.need_expire)
|
||||
return FALSE;
|
||||
|
||||
if (sna->timer[EXPIRE_TIMER] == -1)
|
||||
|
|
|
|||
|
|
@ -1310,11 +1310,8 @@ sna_output_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
|
|||
|
||||
if (xf86IsEntityShared(scrn->entityList[0])) {
|
||||
s = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
|
||||
if (s && !sna_zaphod_match(scrn, s, name)) {
|
||||
ErrorF("output '%s' not matched for zaphod '%s'\n",
|
||||
name, s);
|
||||
if (s && !sna_zaphod_match(scrn, s, name))
|
||||
goto cleanup_encoder;
|
||||
}
|
||||
}
|
||||
|
||||
output = xf86OutputCreate(scrn, &sna_output_funcs, name);
|
||||
|
|
@ -1492,7 +1489,8 @@ static int do_page_flip(struct sna *sna, void *data, int ref_crtc_hw_id)
|
|||
struct sna_crtc *crtc = config->crtc[i]->driver_private;
|
||||
uintptr_t evdata;
|
||||
|
||||
if (!config->crtc[i]->enabled)
|
||||
DBG(("%s: crtc %d active? %d\n",__FUNCTION__, i,crtc->active));
|
||||
if (!crtc->active)
|
||||
continue;
|
||||
|
||||
/* Only the reference crtc will finally deliver its page flip
|
||||
|
|
@ -1510,8 +1508,12 @@ static int do_page_flip(struct sna *sna, void *data, int ref_crtc_hw_id)
|
|||
sna->mode.fb_id,
|
||||
DRM_MODE_PAGE_FLIP_EVENT,
|
||||
(void*)evdata)) {
|
||||
int err = errno;
|
||||
DBG(("%s: flip [fb=%d] on crtc %d [%d] failed - %d\n",
|
||||
__FUNCTION__, sna->mode.fb_id,
|
||||
i, crtc_id(crtc), err));
|
||||
xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
|
||||
"flip queue failed: %s\n", strerror(errno));
|
||||
"flip queue failed: %s\n", strerror(err));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1531,11 +1533,12 @@ sna_do_pageflip(struct sna *sna,
|
|||
{
|
||||
ScrnInfoPtr scrn = sna->scrn;
|
||||
struct sna_mode *mode = &sna->mode;
|
||||
struct kgem_bo *bo = sna_pixmap_pin(pixmap);
|
||||
struct kgem_bo *bo;
|
||||
int count;
|
||||
|
||||
assert(pixmap != sna->front);
|
||||
|
||||
bo = sna_pixmap_pin(pixmap);
|
||||
if (!bo)
|
||||
return 0;
|
||||
|
||||
|
|
@ -1574,20 +1577,13 @@ sna_do_pageflip(struct sna *sna,
|
|||
* may never complete; this is a configuration error.
|
||||
*/
|
||||
count = do_page_flip(sna, data, ref_crtc_hw_id);
|
||||
DBG(("%s: page flipped %d crtcs\n", __FUNCTION__, count));
|
||||
if (count > 0) {
|
||||
int id = sna->front->drawable.serialNumber;
|
||||
|
||||
sna->front = pixmap;
|
||||
pixmap->refcnt++;
|
||||
|
||||
sna_redirect_screen_pixmap(scrn, *old_front, sna->front);
|
||||
scrn->displayWidth = bo->pitch / sna->mode.cpp;
|
||||
|
||||
/* DRI2 uses the serialNumber as a means for detecting
|
||||
* when to revoke its buffers after a reconfigureatin event.
|
||||
* For the ScreenPixmap this means set_size.
|
||||
*/
|
||||
pixmap->drawable.serialNumber = id;
|
||||
} else {
|
||||
drmModeRmFB(sna->kgem.fd, mode->fb_id);
|
||||
mode->fb_id = *old_fb;
|
||||
|
|
@ -1683,11 +1679,23 @@ 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);
|
||||
|
||||
switch (crtc->rotation & 0xf) {
|
||||
default:
|
||||
assert(0);
|
||||
case RR_Rotate_0:
|
||||
case RR_Rotate_180:
|
||||
crtc_box->x2 = crtc->x + crtc->mode.HDisplay;
|
||||
crtc_box->y2 = crtc->y + crtc->mode.VDisplay;
|
||||
break;
|
||||
|
||||
case RR_Rotate_90:
|
||||
case RR_Rotate_270:
|
||||
crtc_box->x2 = crtc->x + crtc->mode.VDisplay;
|
||||
crtc_box->y2 = crtc->y + crtc->mode.HDisplay;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
|
||||
}
|
||||
|
|
@ -1781,74 +1789,51 @@ sna_covering_crtc(ScrnInfoPtr scrn,
|
|||
return best_crtc;
|
||||
}
|
||||
|
||||
bool
|
||||
sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
|
||||
xf86CrtcPtr crtc, RegionPtr clip)
|
||||
/* Gen6 wait for scan line support */
|
||||
#define MI_LOAD_REGISTER_IMM (0x22<<23)
|
||||
|
||||
/* gen6: Scan lines register */
|
||||
#define GEN6_PIPEA_SLC (0x7004)
|
||||
#define GEN6_PIPEB_SLC (0x7104)
|
||||
|
||||
static void sna_emit_wait_for_scanline_gen6(struct sna *sna,
|
||||
int pipe, int y1, int y2,
|
||||
bool full_height)
|
||||
{
|
||||
pixman_box16_t box, crtc_box;
|
||||
int pipe, event;
|
||||
Bool full_height;
|
||||
int y1, y2;
|
||||
uint32_t event;
|
||||
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;
|
||||
/* We just wait until the trace passes the roi */
|
||||
if (pipe == 0) {
|
||||
pipe = GEN6_PIPEA_SLC;
|
||||
event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
|
||||
} else {
|
||||
sna_crtc_box(crtc, &crtc_box);
|
||||
y1 = crtc_box.y1;
|
||||
y2 = crtc_box.y2;
|
||||
full_height = TRUE;
|
||||
pipe = GEN6_PIPEB_SLC;
|
||||
event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW;
|
||||
}
|
||||
|
||||
kgem_set_mode(&sna->kgem, KGEM_RENDER);
|
||||
b = kgem_get_batch(&sna->kgem, 4);
|
||||
b[0] = MI_LOAD_REGISTER_IMM | 1;
|
||||
b[1] = pipe;
|
||||
b[2] = y2 - 1;
|
||||
b[3] = MI_WAIT_FOR_EVENT | event;
|
||||
kgem_advance_batch(&sna->kgem, 4);
|
||||
}
|
||||
|
||||
static void sna_emit_wait_for_scanline_gen2(struct sna *sna,
|
||||
int pipe, int y1, int y2,
|
||||
bool full_height)
|
||||
{
|
||||
uint32_t event;
|
||||
uint32_t *b;
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
if (pipe == 0) {
|
||||
pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEA;
|
||||
event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
|
||||
if (full_height)
|
||||
|
|
@ -1860,11 +1845,8 @@ sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
|
|||
event = MI_WAIT_FOR_PIPEB_SVBLANK;
|
||||
}
|
||||
|
||||
if (crtc->mode.Flags & V_INTERLACE) {
|
||||
/* DSL count field lines */
|
||||
y1 /= 2;
|
||||
y2 /= 2;
|
||||
}
|
||||
if (sna->kgem.mode == KGEM_NONE)
|
||||
kgem_set_mode(&sna->kgem, KGEM_BLT);
|
||||
|
||||
b = kgem_get_batch(&sna->kgem, 5);
|
||||
/* The documentation says that the LOAD_SCAN_LINES command
|
||||
|
|
@ -1875,5 +1857,66 @@ sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
|
|||
b[3] = (y1 << 16) | (y2-1);
|
||||
b[4] = MI_WAIT_FOR_EVENT | event;
|
||||
kgem_advance_batch(&sna->kgem, 5);
|
||||
}
|
||||
|
||||
bool
|
||||
sna_wait_for_scanline(struct sna *sna,
|
||||
PixmapPtr pixmap,
|
||||
xf86CrtcPtr crtc,
|
||||
const BoxRec *clip)
|
||||
{
|
||||
pixman_box16_t box, crtc_box;
|
||||
Bool full_height;
|
||||
int y1, y2, pipe;
|
||||
|
||||
if (sna->kgem.gen >= 60)
|
||||
return false;
|
||||
|
||||
if (!pixmap_is_scanout(pixmap))
|
||||
return false;
|
||||
|
||||
if (crtc == NULL) {
|
||||
crtc = sna_covering_crtc(sna->scrn, clip, NULL, &crtc_box);
|
||||
assert(crtc);
|
||||
} else
|
||||
sna_crtc_box(crtc, &crtc_box);
|
||||
|
||||
if (crtc->transform_in_use) {
|
||||
box = *clip;
|
||||
pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &box);
|
||||
clip = &box;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure we don't wait for a scanline that will
|
||||
* never occur
|
||||
*/
|
||||
y1 = clip->y1 - crtc_box.y1;
|
||||
if (y1 < 0)
|
||||
y1 = 0;
|
||||
y2 = clip->y2 - crtc_box.y1;
|
||||
if (y2 > crtc_box.y2 - crtc_box.y1)
|
||||
y2 = crtc_box.y2 - crtc_box.y1;
|
||||
DBG(("%s: clipped range = %d, %d\n", __FUNCTION__, y1, y2));
|
||||
if (y2 <= y1)
|
||||
return false;
|
||||
|
||||
full_height = y1 == 0 && y2 == crtc_box.y2 - crtc_box.y1;
|
||||
|
||||
if (crtc->mode.Flags & V_INTERLACE) {
|
||||
/* DSL count field lines */
|
||||
y1 /= 2;
|
||||
y2 /= 2;
|
||||
}
|
||||
|
||||
pipe = sna_crtc_to_pipe(crtc);
|
||||
DBG(("%s: pipe=%d, y1=%d, y2=%d, full_height?=%d\n",
|
||||
__FUNCTION__, pipe, y1, y2, full_height));
|
||||
|
||||
if (sna->kgem.gen >= 60)
|
||||
sna_emit_wait_for_scanline_gen6(sna, pipe, y1, y2, full_height);
|
||||
else
|
||||
sna_emit_wait_for_scanline_gen2(sna, pipe, y1, y2, full_height);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,6 +77,14 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#define NDEBUG 1
|
||||
#endif
|
||||
|
||||
enum frame_event_type {
|
||||
DRI2_SWAP,
|
||||
DRI2_SWAP_THROTTLE,
|
||||
DRI2_ASYNC_FLIP,
|
||||
DRI2_FLIP,
|
||||
DRI2_WAITMSC,
|
||||
};
|
||||
|
||||
struct sna_dri_private {
|
||||
int refcnt;
|
||||
PixmapPtr pixmap;
|
||||
|
|
@ -88,7 +96,7 @@ struct sna_dri_frame_event {
|
|||
XID drawable_id;
|
||||
XID client_id; /* fake client ID to track client destruction */
|
||||
ClientPtr client;
|
||||
enum DRI2FrameEventType type;
|
||||
enum frame_event_type type;
|
||||
int frame;
|
||||
int pipe;
|
||||
int count;
|
||||
|
|
@ -99,6 +107,10 @@ struct sna_dri_frame_event {
|
|||
DRI2BufferPtr front;
|
||||
DRI2BufferPtr back;
|
||||
|
||||
unsigned int fe_frame;
|
||||
unsigned int fe_tv_sec;
|
||||
unsigned int fe_tv_usec;
|
||||
|
||||
PixmapPtr old_front;
|
||||
uint32_t old_fb;
|
||||
};
|
||||
|
|
@ -291,13 +303,11 @@ static void sna_dri_reference_buffer(DRI2Buffer2Ptr buffer)
|
|||
}
|
||||
}
|
||||
|
||||
static void damage(DrawablePtr drawable, RegionPtr region)
|
||||
static void damage(DrawablePtr drawable, PixmapPtr pixmap, RegionPtr region)
|
||||
{
|
||||
PixmapPtr pixmap;
|
||||
struct sna_pixmap *priv;
|
||||
int16_t dx, dy;
|
||||
|
||||
pixmap = get_drawable_pixmap(drawable);
|
||||
get_drawable_deltas(drawable, pixmap, &dx, &dy);
|
||||
|
||||
priv = sna_pixmap(pixmap);
|
||||
|
|
@ -350,64 +360,49 @@ static void damage(DrawablePtr drawable, RegionPtr region)
|
|||
}
|
||||
|
||||
static void
|
||||
sna_dri_copy_region(DrawablePtr drawable, RegionPtr region,
|
||||
DRI2BufferPtr dst_buffer, DRI2BufferPtr src_buffer)
|
||||
sna_dri_copy_region(DrawablePtr draw,
|
||||
RegionPtr region,
|
||||
DRI2BufferPtr dst_buffer,
|
||||
DRI2BufferPtr src_buffer)
|
||||
{
|
||||
struct sna *sna = to_sna_from_drawable(drawable);
|
||||
struct sna_dri_private *srcPrivate = src_buffer->driverPrivate;
|
||||
struct sna_dri_private *dstPrivate = dst_buffer->driverPrivate;
|
||||
ScreenPtr screen = drawable->pScreen;
|
||||
DrawablePtr src = (src_buffer->attachment == DRI2BufferFrontLeft)
|
||||
? drawable : &srcPrivate->pixmap->drawable;
|
||||
DrawablePtr dst = (dst_buffer->attachment == DRI2BufferFrontLeft)
|
||||
? drawable : &dstPrivate->pixmap->drawable;
|
||||
GCPtr gc;
|
||||
bool flush = false;
|
||||
struct sna *sna = to_sna_from_drawable(draw);
|
||||
struct sna_dri_private *src_priv = src_buffer->driverPrivate;
|
||||
struct sna_dri_private *dst_priv = dst_buffer->driverPrivate;
|
||||
PixmapPtr src = src_priv->pixmap;
|
||||
PixmapPtr dst = dst_priv->pixmap;
|
||||
pixman_region16_t clip;
|
||||
|
||||
DBG(("%s(region=(%d, %d), (%d, %d)))\n", __FUNCTION__,
|
||||
region ? REGION_EXTENTS(NULL, region)->x1 : 0,
|
||||
region ? REGION_EXTENTS(NULL, region)->y1 : 0,
|
||||
region ? REGION_EXTENTS(NULL, region)->x2 : dst->width,
|
||||
region ? REGION_EXTENTS(NULL, region)->y2 : dst->height));
|
||||
region ? REGION_EXTENTS(NULL, region)->x2 : draw->width,
|
||||
region ? REGION_EXTENTS(NULL, region)->y2 : draw->height));
|
||||
|
||||
DBG(("%s: dst -- attachment=%d, name=%d, handle=%d\n",
|
||||
__FUNCTION__,
|
||||
dst_buffer->attachment,
|
||||
dst_buffer->name,
|
||||
dstPrivate->bo->handle));
|
||||
dst_priv->bo->handle));
|
||||
DBG(("%s: src -- attachment=%d, name=%d, handle=%d\n",
|
||||
__FUNCTION__,
|
||||
src_buffer->attachment,
|
||||
src_buffer->name,
|
||||
srcPrivate->bo->handle));
|
||||
src_priv->bo->handle));
|
||||
|
||||
gc = GetScratchGC(dst->depth, screen);
|
||||
if (!gc)
|
||||
return;
|
||||
if (draw->type == DRAWABLE_WINDOW) {
|
||||
WindowPtr win = (WindowPtr)draw;
|
||||
|
||||
if (region) {
|
||||
RegionPtr clip;
|
||||
|
||||
clip = REGION_CREATE(screen, NULL, 0);
|
||||
pixman_region_intersect_rect(clip, region,
|
||||
0, 0, dst->width, dst->height);
|
||||
(*gc->funcs->ChangeClip)(gc, CT_REGION, clip, 0);
|
||||
region = clip;
|
||||
pixman_region_init(&clip);
|
||||
pixman_region_intersect(&clip, &win->clipList, region);
|
||||
if (!pixman_region_not_empty(&clip)) {
|
||||
DBG(("%s: all clipped\n", __FUNCTION__));
|
||||
return;
|
||||
}
|
||||
region = &clip;
|
||||
}
|
||||
ValidateGC(dst, gc);
|
||||
|
||||
/* Invalidate src to reflect unknown modifications made by the client
|
||||
*
|
||||
* XXX But what about any conflicting shadow writes made by others
|
||||
* between the last flush and this request? Hopefully nobody will
|
||||
* hit that race window to find out...
|
||||
*/
|
||||
damage(src, region);
|
||||
|
||||
/* Wait for the scanline to be outside the region to be copied */
|
||||
if (sna->flags & SNA_SWAP_WAIT)
|
||||
flush = sna_wait_for_scanline(sna, get_drawable_pixmap(dst),
|
||||
NULL, region);
|
||||
assert(sna_pixmap(src)->cpu_damage == NULL);
|
||||
assert(sna_pixmap(dst)->cpu_damage == NULL);
|
||||
|
||||
/* It's important that this copy gets submitted before the
|
||||
* direct rendering client submits rendering for the next
|
||||
|
|
@ -419,11 +414,82 @@ sna_dri_copy_region(DrawablePtr drawable, RegionPtr region,
|
|||
* that will happen before the client tries to render
|
||||
* again.
|
||||
*/
|
||||
gc->ops->CopyArea(src, dst, gc,
|
||||
0, 0,
|
||||
drawable->width, drawable->height,
|
||||
0, 0);
|
||||
FreeScratchGC(gc);
|
||||
sna->render.copy_boxes(sna, GXcopy,
|
||||
src, src_priv->bo, draw->x, draw->y,
|
||||
dst, dst_priv->bo, draw->x, draw->y,
|
||||
REGION_RECTS(region),
|
||||
REGION_NUM_RECTS(region));
|
||||
|
||||
/* Invalidate src to reflect unknown modifications made by the client
|
||||
*
|
||||
* XXX But what about any conflicting shadow writes made by others
|
||||
* between the last flush and this request? Hopefully nobody will
|
||||
* hit that race window to find out...
|
||||
*/
|
||||
damage(draw, src, region);
|
||||
damage(draw, dst, region);
|
||||
if (region == &clip)
|
||||
pixman_region_fini(&clip);
|
||||
}
|
||||
|
||||
static void
|
||||
sna_dri_swap_blit(struct sna *sna, DrawablePtr draw, DRI2BufferPtr back)
|
||||
{
|
||||
struct sna_dri_private *src_priv = back->driverPrivate;
|
||||
PixmapPtr src = src_priv->pixmap;
|
||||
PixmapPtr dst = sna->front;
|
||||
bool flush = false;
|
||||
BoxRec box, *boxes;
|
||||
int n;
|
||||
|
||||
DBG(("%s: back -- attachment=%d, name=%d, handle=%d\n",
|
||||
__FUNCTION__,
|
||||
back->attachment,
|
||||
back->name,
|
||||
src_priv->bo->handle));
|
||||
|
||||
if (draw->type == DRAWABLE_PIXMAP) {
|
||||
box.x1 = box.y1 = 0;
|
||||
box.x2 = draw->width;
|
||||
box.y2 = draw->height;
|
||||
|
||||
boxes = &box;
|
||||
n = 1;
|
||||
} else {
|
||||
WindowPtr win = (WindowPtr)draw;
|
||||
|
||||
boxes = REGION_RECTS(&win->clipList);
|
||||
n = REGION_NUM_RECTS(&win->clipList);
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
flush = sna_wait_for_scanline(sna, sna->front,
|
||||
NULL, &win->clipList.extents);
|
||||
}
|
||||
|
||||
/* It's important that this copy gets submitted before the
|
||||
* direct rendering client submits rendering for the next
|
||||
* frame, but we don't actually need to submit right now. The
|
||||
* client will wait for the DRI2CopyRegion reply or the swap
|
||||
* buffer event before rendering, and we'll hit the flush
|
||||
* callback chain before those messages are sent. We submit
|
||||
* our batch buffers from the flush callback chain so we know
|
||||
* that will happen before the client tries to render
|
||||
* again.
|
||||
*/
|
||||
sna->render.copy_boxes(sna, GXcopy,
|
||||
src, src_priv->bo, draw->x, draw->y,
|
||||
dst, sna_pixmap_get_bo(dst), draw->x, draw->y,
|
||||
boxes, n);
|
||||
|
||||
/* Invalidate src to reflect unknown modifications made by the client
|
||||
*
|
||||
* XXX But what about any conflicting shadow writes made by others
|
||||
* between the last flush and this request? Hopefully nobody will
|
||||
* hit that race window to find out...
|
||||
*/
|
||||
damage(draw, src, NULL);
|
||||
damage(draw, dst, NULL);
|
||||
|
||||
DBG(("%s: flushing? %d\n", __FUNCTION__, flush));
|
||||
if (flush) /* STAT! */
|
||||
|
|
@ -432,12 +498,10 @@ sna_dri_copy_region(DrawablePtr drawable, RegionPtr region,
|
|||
|
||||
#if DRI2INFOREC_VERSION >= 4
|
||||
|
||||
|
||||
static int
|
||||
sna_dri_get_pipe(DrawablePtr pDraw)
|
||||
{
|
||||
ScreenPtr pScreen = pDraw->pScreen;
|
||||
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
|
||||
ScrnInfoPtr pScrn = xf86Screens[pDraw->pScreen->myNum];
|
||||
BoxRec box, crtcbox;
|
||||
xf86CrtcPtr crtc;
|
||||
int pipe;
|
||||
|
|
@ -533,7 +597,7 @@ sna_dri_add_frame_event(struct sna_dri_frame_event *frame_event)
|
|||
}
|
||||
|
||||
static void
|
||||
sna_dri_frame_event_info(struct sna_dri_frame_event *info)
|
||||
sna_dri_frame_event_info_free(struct sna_dri_frame_event *info)
|
||||
{
|
||||
if (info->client_id)
|
||||
FreeResourceByType(info->client_id,
|
||||
|
|
@ -559,7 +623,8 @@ sna_dri_exchange_buffers(DrawablePtr draw,
|
|||
{
|
||||
int tmp;
|
||||
|
||||
DBG(("%s()\n", __FUNCTION__));
|
||||
DBG(("%s(%d <--> %d)\n",
|
||||
__FUNCTION__, front->attachment, back->attachment));
|
||||
|
||||
assert(front->format == back->format);
|
||||
|
||||
|
|
@ -577,82 +642,20 @@ sna_dri_schedule_flip(struct sna *sna,
|
|||
DrawablePtr draw,
|
||||
struct sna_dri_frame_event *info)
|
||||
{
|
||||
struct sna_dri *dri = &sna->dri;
|
||||
struct sna_dri_private *back_priv;
|
||||
|
||||
/* Main crtc for this drawable shall finally deliver pageflip event. */
|
||||
int ref_crtc_hw_id = sna_dri_get_pipe(draw);
|
||||
|
||||
DBG(("%s()\n", __FUNCTION__));
|
||||
|
||||
dri->fe_frame = 0;
|
||||
dri->fe_tv_sec = 0;
|
||||
dri->fe_tv_usec = 0;
|
||||
|
||||
/* Page flip the full screen buffer */
|
||||
back_priv = info->back->driverPrivate;
|
||||
info->count = sna_do_pageflip(sna,
|
||||
back_priv->pixmap,
|
||||
info, ref_crtc_hw_id,
|
||||
info, info->pipe,
|
||||
&info->old_front,
|
||||
&info->old_fb);
|
||||
return info->count != 0;
|
||||
}
|
||||
|
||||
static Bool
|
||||
can_exchange(DRI2BufferPtr front,
|
||||
DRI2BufferPtr back)
|
||||
{
|
||||
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, *back_sna;
|
||||
|
||||
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 Bool
|
||||
can_flip(struct sna * sna,
|
||||
DrawablePtr draw,
|
||||
|
|
@ -773,78 +776,59 @@ static void sna_dri_vblank_handle(int fd,
|
|||
unsigned int tv_usec,
|
||||
void *data)
|
||||
{
|
||||
struct sna_dri_frame_event *swap_info = data;
|
||||
struct sna_dri_frame_event *info = data;
|
||||
DrawablePtr draw;
|
||||
ScreenPtr screen;
|
||||
ScrnInfoPtr scrn;
|
||||
struct sna *sna;
|
||||
int status;
|
||||
|
||||
DBG(("%s(id=%d, type=%d)\n", __FUNCTION__,
|
||||
(int)swap_info->drawable_id, swap_info->type));
|
||||
(int)info->drawable_id, info->type));
|
||||
|
||||
status = BadDrawable;
|
||||
if (swap_info->drawable_id)
|
||||
if (info->drawable_id)
|
||||
status = dixLookupDrawable(&draw,
|
||||
swap_info->drawable_id,
|
||||
info->drawable_id,
|
||||
serverClient,
|
||||
M_ANY, DixWriteAccess);
|
||||
if (status != Success)
|
||||
goto done;
|
||||
|
||||
screen = draw->pScreen;
|
||||
scrn = xf86Screens[screen->myNum];
|
||||
sna = to_sna(scrn);
|
||||
sna = to_sna_from_drawable(draw);
|
||||
|
||||
switch (swap_info->type) {
|
||||
switch (info->type) {
|
||||
case DRI2_FLIP:
|
||||
/* If we can still flip... */
|
||||
if (can_flip(sna, draw,
|
||||
swap_info->front, swap_info->back) &&
|
||||
sna_dri_schedule_flip(sna, draw, swap_info)) {
|
||||
sna_dri_exchange_buffers(draw,
|
||||
swap_info->front,
|
||||
swap_info->back);
|
||||
if (can_flip(sna, draw, info->front, info->back) &&
|
||||
sna_dri_schedule_flip(sna, draw, info)) {
|
||||
sna_dri_exchange_buffers(draw, info->front, info->back);
|
||||
return;
|
||||
}
|
||||
/* else fall through to exchange/blit */
|
||||
case DRI2_SWAP: {
|
||||
int swap_type;
|
||||
|
||||
if (DRI2CanExchange(draw) &&
|
||||
can_exchange(swap_info->front, swap_info->back)) {
|
||||
sna_dri_exchange_buffers(draw,
|
||||
swap_info->front,
|
||||
swap_info->back);
|
||||
swap_type = DRI2_EXCHANGE_COMPLETE;
|
||||
} else {
|
||||
sna_dri_copy_region(draw, NULL,
|
||||
swap_info->front,
|
||||
swap_info->back);
|
||||
swap_type = DRI2_BLIT_COMPLETE;
|
||||
}
|
||||
DRI2SwapComplete(swap_info->client,
|
||||
case DRI2_SWAP:
|
||||
sna_dri_swap_blit(sna, draw, info->back);
|
||||
case DRI2_SWAP_THROTTLE:
|
||||
DRI2SwapComplete(info->client,
|
||||
draw, frame,
|
||||
tv_sec, tv_usec,
|
||||
swap_type,
|
||||
swap_info->client ? swap_info->event_complete : NULL,
|
||||
swap_info->event_data);
|
||||
DRI2_BLIT_COMPLETE,
|
||||
info->client ? info->event_complete : NULL,
|
||||
info->event_data);
|
||||
break;
|
||||
}
|
||||
|
||||
case DRI2_WAITMSC:
|
||||
if (swap_info->client)
|
||||
DRI2WaitMSCComplete(swap_info->client, draw,
|
||||
if (info->client)
|
||||
DRI2WaitMSCComplete(info->client, draw,
|
||||
frame, tv_sec, tv_usec);
|
||||
break;
|
||||
default:
|
||||
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
|
||||
xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
|
||||
"%s: unknown vblank event received\n", __func__);
|
||||
/* Unknown type */
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
sna_dri_frame_event_info(swap_info);
|
||||
sna_dri_frame_event_info_free(info);
|
||||
}
|
||||
|
||||
static void sna_dri_flip_event(struct sna *sna,
|
||||
|
|
@ -855,9 +839,9 @@ static void sna_dri_flip_event(struct sna *sna,
|
|||
|
||||
DBG(("%s(frame=%d, tv=%d.%06d, type=%d)\n",
|
||||
__FUNCTION__,
|
||||
sna->dri.fe_frame,
|
||||
sna->dri.fe_tv_sec,
|
||||
sna->dri.fe_tv_usec,
|
||||
flip->fe_frame,
|
||||
flip->fe_tv_sec,
|
||||
flip->fe_tv_usec,
|
||||
flip->type));
|
||||
|
||||
if (!flip->drawable_id)
|
||||
|
|
@ -878,8 +862,8 @@ static void sna_dri_flip_event(struct sna *sna,
|
|||
* into account. This usually means some defective kms pageflip completion,
|
||||
* causing wrong (msc, ust) return values and possible visual corruption.
|
||||
*/
|
||||
if ((sna->dri.fe_frame < flip->frame) &&
|
||||
(flip->frame - sna->dri.fe_frame < 5)) {
|
||||
if ((flip->fe_frame < flip->frame) &&
|
||||
(flip->frame - flip->fe_frame < 5)) {
|
||||
static int limit = 5;
|
||||
|
||||
/* XXX we are currently hitting this path with older
|
||||
|
|
@ -888,25 +872,25 @@ static void sna_dri_flip_event(struct sna *sna,
|
|||
if (limit) {
|
||||
xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
|
||||
"%s: Pageflip completion has impossible msc %d < target_msc %d\n",
|
||||
__func__, sna->dri.fe_frame, flip->frame);
|
||||
__func__, flip->fe_frame, flip->frame);
|
||||
limit--;
|
||||
}
|
||||
|
||||
/* All-0 values signal timestamping failure. */
|
||||
sna->dri.fe_frame = sna->dri.fe_tv_sec = sna->dri.fe_tv_usec = 0;
|
||||
flip->fe_frame = flip->fe_tv_sec = flip->fe_tv_usec = 0;
|
||||
}
|
||||
|
||||
DBG(("%s: flip complete\n", __FUNCTION__));
|
||||
DRI2SwapComplete(flip->client, drawable,
|
||||
sna->dri.fe_frame,
|
||||
sna->dri.fe_tv_sec,
|
||||
sna->dri.fe_tv_usec,
|
||||
flip->fe_frame,
|
||||
flip->fe_tv_sec,
|
||||
flip->fe_tv_usec,
|
||||
DRI2_FLIP_COMPLETE,
|
||||
flip->client ? flip->event_complete : NULL,
|
||||
flip->event_data);
|
||||
break;
|
||||
|
||||
case DRI2_ASYNC_SWAP:
|
||||
case DRI2_ASYNC_FLIP:
|
||||
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]--;
|
||||
|
|
@ -925,16 +909,15 @@ 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;
|
||||
info->fe_frame = frame;
|
||||
info->fe_tv_sec = tv_sec;
|
||||
info->fe_tv_usec = tv_usec;
|
||||
}
|
||||
|
||||
if (--info->count)
|
||||
|
|
@ -943,7 +926,7 @@ sna_dri_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
|
|||
sna_dri_flip_event(info->sna, info);
|
||||
|
||||
sna_mode_delete_fb(info->sna, info->old_front, info->old_fb);
|
||||
sna_dri_frame_event_info(info);
|
||||
sna_dri_frame_event_info_free(info);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -976,16 +959,20 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
|
|||
struct sna *sna = to_sna(scrn);
|
||||
drmVBlank vbl;
|
||||
int pipe, flip;
|
||||
struct sna_dri_frame_event *info;
|
||||
enum DRI2FrameEventType swap_type = DRI2_SWAP;
|
||||
struct sna_dri_frame_event *info = NULL;
|
||||
enum frame_event_type swap_type = DRI2_SWAP;
|
||||
CARD64 current_msc;
|
||||
|
||||
DBG(("%s(target_msc=%llu)\n", __FUNCTION__, (long long)*target_msc));
|
||||
DBG(("%s(target_msc=%llu, divisor=%llu, remainder=%llu)\n",
|
||||
__FUNCTION__,
|
||||
(long long)*target_msc,
|
||||
(long long)divisor,
|
||||
(long long)remainder));
|
||||
|
||||
/* Drawable not displayed... just complete the swap */
|
||||
pipe = sna_dri_get_pipe(draw);
|
||||
if (pipe == -1)
|
||||
goto xchg_fallback;
|
||||
goto blit_fallback;
|
||||
|
||||
/* Truncate to match kernel interfaces; means occasional overflow
|
||||
* misses, but that's generally not a big deal */
|
||||
|
|
@ -995,7 +982,7 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
|
|||
|
||||
info = calloc(1, sizeof(struct sna_dri_frame_event));
|
||||
if (!info)
|
||||
goto xchg_fallback;
|
||||
goto blit_fallback;
|
||||
|
||||
info->sna = sna;
|
||||
info->drawable_id = draw->id;
|
||||
|
|
@ -1004,10 +991,12 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
|
|||
info->event_data = data;
|
||||
info->front = front;
|
||||
info->back = back;
|
||||
info->pipe = pipe;
|
||||
|
||||
if (!sna_dri_add_frame_event(info)) {
|
||||
free(info);
|
||||
goto xchg_fallback;
|
||||
info = NULL;
|
||||
goto blit_fallback;
|
||||
}
|
||||
|
||||
sna_dri_reference_buffer(front);
|
||||
|
|
@ -1064,8 +1053,23 @@ immediate:
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* Similarly, the CopyRegion blit is coupled to vsync. */
|
||||
goto blit_fallback;
|
||||
DBG(("%s: emitting immediate vsync'ed blit, throttling client\n"));
|
||||
|
||||
info->type = DRI2_SWAP_THROTTLE;
|
||||
|
||||
vbl.request.type =
|
||||
DRM_VBLANK_RELATIVE |
|
||||
DRM_VBLANK_EVENT |
|
||||
DRM_VBLANK_NEXTONMISS;
|
||||
if (pipe > 0)
|
||||
vbl.request.type |= DRM_VBLANK_SECONDARY;
|
||||
vbl.request.sequence = 0;
|
||||
vbl.request.signal = (unsigned long)info;
|
||||
if (drmWaitVBlank(sna->kgem.fd, &vbl))
|
||||
sna_dri_frame_event_info_free(info);
|
||||
|
||||
sna_dri_swap_blit(sna, draw, back);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Correct target_msc by 'flip' if swap_type == DRI2_FLIP.
|
||||
|
|
@ -1126,15 +1130,10 @@ immediate:
|
|||
|
||||
blit_fallback:
|
||||
DBG(("%s -- blit\n", __FUNCTION__));
|
||||
sna_dri_copy_region(draw, NULL, front, back);
|
||||
sna_dri_frame_event_info(info);
|
||||
swap_type = DRI2_BLIT_COMPLETE;
|
||||
goto fallback;
|
||||
xchg_fallback:
|
||||
swap_type = DRI2_EXCHANGE_COMPLETE;
|
||||
sna_dri_exchange_buffers(draw, front, back);
|
||||
fallback:
|
||||
DRI2SwapComplete(client, draw, 0, 0, 0, swap_type, func, data);
|
||||
sna_dri_swap_blit(sna, draw, back);
|
||||
if (info)
|
||||
sna_dri_frame_event_info_free(info);
|
||||
DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
|
||||
*target_msc = 0; /* offscreen, so zero out target vblank count */
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -1142,53 +1141,53 @@ fallback:
|
|||
#if DRI2INFOREC_VERSION >= 6
|
||||
static void
|
||||
sna_dri_async_swap(ClientPtr client, DrawablePtr draw,
|
||||
DRI2BufferPtr front, DRI2BufferPtr back,
|
||||
DRI2SwapEventPtr func, void *data)
|
||||
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_dri_get_pipe(draw);
|
||||
int type = DRI2_EXCHANGE_COMPLETE;
|
||||
struct sna_dri_private *back_priv = back->driverPrivate;
|
||||
struct sna_dri_private *front_priv = front->driverPrivate;
|
||||
PixmapPtr pixmap;
|
||||
int pipe;
|
||||
|
||||
DBG(("%s()\n", __FUNCTION__));
|
||||
|
||||
/* Drawable not displayed... just complete the swap */
|
||||
if (pipe == -1)
|
||||
goto exchange;
|
||||
|
||||
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;
|
||||
pipe = sna_dri_get_pipe(draw);
|
||||
if (pipe == -1 || !can_flip(sna, draw, front, back)) {
|
||||
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);
|
||||
DBG(("%s: fallback blit: %dx%d\n",
|
||||
__FUNCTION__, draw->width, draw->height));
|
||||
|
||||
if (n) {
|
||||
sna->render.copy_boxes(sna, GXcopy,
|
||||
back_priv->pixmap,
|
||||
back_priv->bo,
|
||||
0, 0,
|
||||
front_priv->pixmap,
|
||||
front_priv->bo,
|
||||
0, 0,
|
||||
boxes, n);
|
||||
}
|
||||
|
||||
DRI2SwapComplete(client, draw, 0, 0, 0,
|
||||
DRI2_BLIT_COMPLETE, func, data);
|
||||
|
|
@ -1197,72 +1196,60 @@ sna_dri_async_swap(ClientPtr client, DrawablePtr draw,
|
|||
|
||||
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;
|
||||
BoxRec box;
|
||||
DRI2BufferPtr t;
|
||||
|
||||
DBG(("%s: no pending flip on pipe %d, so updating scanout\n",
|
||||
__FUNCTION__, pipe));
|
||||
|
||||
copy = screen->CreatePixmap(screen,
|
||||
src->drawable.width,
|
||||
src->drawable.height,
|
||||
src->drawable.depth,
|
||||
SNA_CREATE_FB);
|
||||
if (copy == NullPixmap)
|
||||
goto exchange;
|
||||
|
||||
priv = sna_pixmap_force_to_gpu(copy);
|
||||
if (priv == NULL) {
|
||||
screen->DestroyPixmap(copy);
|
||||
goto exchange;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
sna_damage_all(&priv->gpu_damage,
|
||||
src->drawable.width, src->drawable.height);
|
||||
assert(priv->cpu_damage == NULL);
|
||||
|
||||
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->type = DRI2_ASYNC_FLIP;
|
||||
info->pipe = pipe;
|
||||
|
||||
if (!sna_dri_add_frame_event(info)) {
|
||||
free(info);
|
||||
screen->DestroyPixmap(copy);
|
||||
goto exchange;
|
||||
}
|
||||
|
||||
info->count = sna_do_pageflip(sna, copy, info, pipe,
|
||||
info->count = sna_do_pageflip(sna, back_priv->pixmap,
|
||||
info, pipe,
|
||||
&info->old_front, &info->old_fb);
|
||||
screen->DestroyPixmap(copy);
|
||||
|
||||
if (info->count == 0) {
|
||||
DBG(("%s: pageflip failed\n", __FUNCTION__));
|
||||
free(info);
|
||||
goto exchange;
|
||||
}
|
||||
|
||||
type = DRI2_FLIP_COMPLETE;
|
||||
sna->dri.flip_pending[pipe]++;
|
||||
|
||||
/* and flip the pointers */
|
||||
t = front;
|
||||
front = back;
|
||||
back = t;
|
||||
|
||||
front_priv = front->driverPrivate;
|
||||
back_priv = back->driverPrivate;
|
||||
}
|
||||
|
||||
if (front_priv->pixmap == sna->front &&
|
||||
(pixmap = screen->CreatePixmap(screen,
|
||||
draw->width,
|
||||
draw->height,
|
||||
draw->depth,
|
||||
SNA_CREATE_FB))) {
|
||||
screen->DestroyPixmap(front_priv->pixmap);
|
||||
front_priv->pixmap = pixmap;
|
||||
front_priv->bo = sna_pixmap_set_dri(sna, pixmap);
|
||||
front->name = kgem_bo_flink(&sna->kgem, front_priv->bo);
|
||||
front->pitch = front_priv->bo->pitch;
|
||||
}
|
||||
|
||||
exchange:
|
||||
|
|
@ -1278,11 +1265,9 @@ exchange:
|
|||
static int
|
||||
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);
|
||||
struct sna *sna = to_sna_from_drawable(draw);
|
||||
drmVBlank vbl;
|
||||
int ret, pipe = sna_dri_get_pipe(draw);
|
||||
int pipe = sna_dri_get_pipe(draw);
|
||||
|
||||
DBG(("%s()\n", __FUNCTION__));
|
||||
|
||||
|
|
@ -1298,22 +1283,21 @@ sna_dri_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
|
|||
vbl.request.type |= DRM_VBLANK_SECONDARY;
|
||||
vbl.request.sequence = 0;
|
||||
|
||||
ret = drmWaitVBlank(sna->kgem.fd, &vbl);
|
||||
if (ret) {
|
||||
if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
|
||||
static int limit = 5;
|
||||
if (limit) {
|
||||
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
|
||||
xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
|
||||
"%s:%d get vblank counter failed: %s\n",
|
||||
__FUNCTION__, __LINE__,
|
||||
strerror(errno));
|
||||
limit--;
|
||||
}
|
||||
DBG(("%s: failed on pipe %d\n", __FUNCTION__, pipe));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec;
|
||||
*msc = vbl.reply.sequence;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -1330,9 +1314,9 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
|
|||
ScreenPtr screen = draw->pScreen;
|
||||
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
|
||||
struct sna *sna = to_sna(scrn);
|
||||
struct sna_dri_frame_event *wait_info;
|
||||
struct sna_dri_frame_event *info;
|
||||
drmVBlank vbl;
|
||||
int ret, pipe = sna_dri_get_pipe(draw);
|
||||
int pipe = sna_dri_get_pipe(draw);
|
||||
CARD64 current_msc;
|
||||
|
||||
DBG(("%s(target_msc=%llu, divisor=%llu, rem=%llu)\n",
|
||||
|
|
@ -1351,22 +1335,21 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
|
|||
if (pipe == -1)
|
||||
goto out_complete;
|
||||
|
||||
wait_info = calloc(1, sizeof(struct sna_dri_frame_event));
|
||||
if (!wait_info)
|
||||
info = calloc(1, sizeof(struct sna_dri_frame_event));
|
||||
if (!info)
|
||||
goto out_complete;
|
||||
|
||||
wait_info->sna = sna;
|
||||
wait_info->drawable_id = draw->id;
|
||||
wait_info->client = client;
|
||||
wait_info->type = DRI2_WAITMSC;
|
||||
info->sna = sna;
|
||||
info->drawable_id = draw->id;
|
||||
info->client = client;
|
||||
info->type = DRI2_WAITMSC;
|
||||
|
||||
/* Get current count */
|
||||
vbl.request.type = DRM_VBLANK_RELATIVE;
|
||||
if (pipe > 0)
|
||||
vbl.request.type |= DRM_VBLANK_SECONDARY;
|
||||
vbl.request.sequence = 0;
|
||||
ret = drmWaitVBlank(sna->kgem.fd, &vbl);
|
||||
if (ret) {
|
||||
if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
|
||||
static int limit = 5;
|
||||
if (limit) {
|
||||
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
|
||||
|
|
@ -1398,9 +1381,8 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
|
|||
if (pipe > 0)
|
||||
vbl.request.type |= DRM_VBLANK_SECONDARY;
|
||||
vbl.request.sequence = target_msc;
|
||||
vbl.request.signal = (unsigned long)wait_info;
|
||||
ret = drmWaitVBlank(sna->kgem.fd, &vbl);
|
||||
if (ret) {
|
||||
vbl.request.signal = (unsigned long)info;
|
||||
if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
|
||||
static int limit = 5;
|
||||
if (limit) {
|
||||
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
|
||||
|
|
@ -1412,7 +1394,7 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
|
|||
goto out_complete;
|
||||
}
|
||||
|
||||
wait_info->frame = vbl.reply.sequence;
|
||||
info->frame = vbl.reply.sequence;
|
||||
DRI2BlockClient(client, draw);
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -1437,9 +1419,8 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
|
|||
if ((current_msc % divisor) >= remainder)
|
||||
vbl.request.sequence += divisor;
|
||||
|
||||
vbl.request.signal = (unsigned long)wait_info;
|
||||
ret = drmWaitVBlank(sna->kgem.fd, &vbl);
|
||||
if (ret) {
|
||||
vbl.request.signal = (unsigned long)info;
|
||||
if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
|
||||
static int limit = 5;
|
||||
if (limit) {
|
||||
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
|
||||
|
|
@ -1451,7 +1432,7 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
|
|||
goto out_complete;
|
||||
}
|
||||
|
||||
wait_info->frame = vbl.reply.sequence;
|
||||
info->frame = vbl.reply.sequence;
|
||||
DRI2BlockClient(client, draw);
|
||||
|
||||
return TRUE;
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ static OptionInfoRec sna_options[] = {
|
|||
{OPTION_PREFER_OVERLAY, "XvPreferOverlay", OPTV_BOOLEAN, {0}, FALSE},
|
||||
{OPTION_COLOR_KEY, "ColorKey", OPTV_INTEGER, {0}, FALSE},
|
||||
{OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE},
|
||||
{OPTION_SWAPBUFFERS_WAIT, "SwapbuffersWait", OPTV_BOOLEAN, {0}, TRUE},
|
||||
{OPTION_HOTPLUG, "HotPlug", OPTV_BOOLEAN, {0}, TRUE},
|
||||
{OPTION_THROTTLE, "Throttle", OPTV_BOOLEAN, {0}, TRUE},
|
||||
{OPTION_RELAXED_FENCING, "UseRelaxedFencing", OPTV_BOOLEAN, {0}, TRUE},
|
||||
|
|
@ -502,8 +501,6 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int flags)
|
|||
sna->flags = 0;
|
||||
if (!xf86ReturnOptValBool(sna->Options, OPTION_THROTTLE, TRUE))
|
||||
sna->flags |= SNA_NO_THROTTLE;
|
||||
if (xf86ReturnOptValBool(sna->Options, OPTION_SWAPBUFFERS_WAIT, TRUE))
|
||||
sna->flags |= SNA_SWAP_WAIT;
|
||||
|
||||
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Framebuffer %s\n",
|
||||
sna->tiling & SNA_TILING_FB ? "tiled" : "linear");
|
||||
|
|
@ -511,8 +508,6 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int flags)
|
|||
sna->tiling & SNA_TILING_2D ? "tiled" : "linear");
|
||||
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "3D buffers %s\n",
|
||||
sna->tiling & SNA_TILING_3D ? "tiled" : "linear");
|
||||
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "SwapBuffers wait %sabled\n",
|
||||
sna->flags & SNA_SWAP_WAIT ? "en" : "dis");
|
||||
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Throttling %sabled\n",
|
||||
sna->flags & SNA_NO_THROTTLE ? "dis" : "en");
|
||||
|
||||
|
|
@ -558,18 +553,11 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int flags)
|
|||
static void
|
||||
sna_block_handler(int i, pointer data, pointer timeout, pointer read_mask)
|
||||
{
|
||||
ScreenPtr screen = screenInfo.screens[i];
|
||||
ScrnInfoPtr scrn = xf86Screens[i];
|
||||
struct sna *sna = to_sna(scrn);
|
||||
struct sna *sna = data;
|
||||
|
||||
DBG(("%s\n", __FUNCTION__));
|
||||
|
||||
screen->BlockHandler = sna->BlockHandler;
|
||||
|
||||
(*screen->BlockHandler) (i, data, timeout, read_mask);
|
||||
|
||||
sna->BlockHandler = screen->BlockHandler;
|
||||
screen->BlockHandler = sna_block_handler;
|
||||
sna->BlockHandler(i, sna->BlockData, timeout, read_mask);
|
||||
|
||||
sna_accel_block_handler(sna);
|
||||
}
|
||||
|
|
@ -577,19 +565,10 @@ sna_block_handler(int i, pointer data, pointer timeout, pointer read_mask)
|
|||
static void
|
||||
sna_wakeup_handler(int i, pointer data, unsigned long result, pointer read_mask)
|
||||
{
|
||||
ScreenPtr screen = screenInfo.screens[i];
|
||||
ScrnInfoPtr scrn = xf86Screens[i];
|
||||
struct sna *sna = to_sna(scrn);
|
||||
struct sna *sna = data;
|
||||
|
||||
DBG(("%s\n", __FUNCTION__));
|
||||
|
||||
screen->WakeupHandler = sna->WakeupHandler;
|
||||
|
||||
(*screen->WakeupHandler) (i, data, result, 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;
|
||||
|
|
@ -597,6 +576,8 @@ sna_wakeup_handler(int i, pointer data, unsigned long result, pointer read_mask)
|
|||
if (FD_ISSET(sna->kgem.fd, (fd_set*)read_mask))
|
||||
sna_dri_wakeup(sna);
|
||||
|
||||
sna->WakeupHandler(i, sna->WakeupData, result, read_mask);
|
||||
|
||||
sna_accel_wakeup_handler(sna);
|
||||
}
|
||||
|
||||
|
|
@ -852,10 +833,14 @@ sna_screen_init(int scrnIndex, ScreenPtr screen, int argc, char **argv)
|
|||
scrn->vtSema = TRUE;
|
||||
|
||||
sna->BlockHandler = screen->BlockHandler;
|
||||
sna->BlockData = screen->blockData;
|
||||
screen->BlockHandler = sna_block_handler;
|
||||
screen->blockData = sna;
|
||||
|
||||
sna->WakeupHandler = screen->WakeupHandler;
|
||||
sna->WakeupData = screen->wakeupData;
|
||||
screen->WakeupHandler = sna_wakeup_handler;
|
||||
screen->wakeupData = sna;
|
||||
|
||||
screen->SaveScreen = xf86SaveScreen;
|
||||
sna->CloseScreen = screen->CloseScreen;
|
||||
|
|
|
|||
|
|
@ -238,6 +238,7 @@ sna_video_textured_put_image(ScrnInfoPtr scrn,
|
|||
BoxRec dstBox;
|
||||
xf86CrtcPtr crtc;
|
||||
int top, left, npixels, nlines;
|
||||
Bool flush = false;
|
||||
|
||||
if (!sna_video_clip_helper(scrn, video, &crtc, &dstBox,
|
||||
src_x, src_y, drw_x, drw_y,
|
||||
|
|
@ -267,7 +268,8 @@ sna_video_textured_put_image(ScrnInfoPtr scrn,
|
|||
}
|
||||
|
||||
if (crtc && video->SyncToVblank != 0)
|
||||
sna_wait_for_scanline(sna, pixmap, crtc, clip);
|
||||
flush = sna_wait_for_scanline(sna, pixmap, crtc,
|
||||
&clip->extents);
|
||||
|
||||
sna->render.video(sna, video, &frame, clip,
|
||||
src_w, src_h,
|
||||
|
|
@ -281,7 +283,8 @@ sna_video_textured_put_image(ScrnInfoPtr scrn,
|
|||
/* Push the frame to the GPU as soon as possible so
|
||||
* we can hit the next vsync.
|
||||
*/
|
||||
kgem_submit(&sna->kgem);
|
||||
if (flush)
|
||||
kgem_submit(&sna->kgem);
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue