i915tex: Schedule flips when possible.

Also move vsync related state from context to window, so it's possible to
schedule several flips ahead of time with triple buffering.
This commit is contained in:
Michel Dänzer
2007-02-22 17:24:09 +01:00
parent e33a9d6894
commit 641c966e3d
6 changed files with 228 additions and 179 deletions
+69 -126
View File
@@ -55,8 +55,6 @@ intelCopyBuffer(const __DRIdrawablePrivate * dPriv,
struct intel_context *intel;
const intelScreenPrivate *intelScreen;
GLboolean missed_target;
int64_t ust;
DBG("%s\n", __FUNCTION__);
@@ -68,41 +66,6 @@ intelCopyBuffer(const __DRIdrawablePrivate * dPriv,
intelScreen = intel->intelScreen;
if (!rect && !intel->swap_scheduled && intelScreen->drmMinor >= 6 &&
!(intel->vblank_flags & VBLANK_FLAG_NO_IRQ) &&
intelScreen->current_rotation == 0) {
unsigned int interval = driGetVBlankInterval(dPriv, intel->vblank_flags);
unsigned int target;
drm_i915_vblank_swap_t swap;
swap.drawable = dPriv->hHWDrawable;
swap.seqtype = DRM_VBLANK_ABSOLUTE;
target = swap.sequence = intel->vbl_seq + interval;
if (intel->vblank_flags & VBLANK_FLAG_SYNC) {
swap.seqtype |= DRM_VBLANK_NEXTONMISS;
} else if (interval == 0) {
goto noschedule;
}
if ( intel->vblank_flags & VBLANK_FLAG_SECONDARY ) {
swap.seqtype |= DRM_VBLANK_SECONDARY;
}
intel_batchbuffer_flush(intel->batch);
if (!drmCommandWriteRead(intel->driFd, DRM_I915_VBLANK_SWAP, &swap,
sizeof(swap))) {
intel->swap_scheduled = 1;
intel->vbl_seq = swap.sequence;
swap.sequence -= target;
missed_target = swap.sequence > 0 && swap.sequence <= (1 << 23);
}
} else {
intel->swap_scheduled = 0;
}
noschedule:
if (intel->last_swap_fence) {
driFenceFinish(intel->last_swap_fence, DRM_FENCE_TYPE_EXE, GL_TRUE);
driFenceUnReference(intel->last_swap_fence);
@@ -111,108 +74,88 @@ noschedule:
intel->last_swap_fence = intel->first_swap_fence;
intel->first_swap_fence = NULL;
if (!intel->swap_scheduled) {
if (!rect) {
driWaitForVBlank(dPriv, &intel->vbl_seq, intel->vblank_flags,
&missed_target);
/* The LOCK_HARDWARE is required for the cliprects. Buffer offsets
* should work regardless.
*/
LOCK_HARDWARE(intel);
if (dPriv && dPriv->numClipRects) {
struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
const struct intel_region *frontRegion
= intel_get_rb_region(&intel_fb->Base, BUFFER_FRONT_LEFT);
const struct intel_region *backRegion
= intel_get_rb_region(&intel_fb->Base, BUFFER_BACK_LEFT);
const int nbox = dPriv->numClipRects;
const drm_clip_rect_t *pbox = dPriv->pClipRects;
const int pitch = frontRegion->pitch;
const int cpp = frontRegion->cpp;
int BR13, CMD;
int i;
ASSERT(intel_fb);
ASSERT(intel_fb->Base.Name == 0); /* Not a user-created FBO */
ASSERT(frontRegion);
ASSERT(backRegion);
ASSERT(frontRegion->pitch == backRegion->pitch);
ASSERT(frontRegion->cpp == backRegion->cpp);
if (cpp == 2) {
BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24);
CMD = XY_SRC_COPY_BLT_CMD;
}
else {
BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24) | (1 << 25);
CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
XY_SRC_COPY_BLT_WRITE_RGB);
}
for (i = 0; i < nbox; i++, pbox++) {
drm_clip_rect_t box;
/* The LOCK_HARDWARE is required for the cliprects. Buffer offsets
* should work regardless.
*/
LOCK_HARDWARE(intel);
if (pbox->x1 > pbox->x2 ||
pbox->y1 > pbox->y2 ||
pbox->x2 > intelScreen->width || pbox->y2 > intelScreen->height)
continue;
if (dPriv && dPriv->numClipRects) {
const intelScreenPrivate *intelScreen = intel->intelScreen;
struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
const struct intel_region *frontRegion
= intel_get_rb_region(&intel_fb->Base, BUFFER_FRONT_LEFT);
const struct intel_region *backRegion
= intel_get_rb_region(&intel_fb->Base, BUFFER_BACK_LEFT);
const int nbox = dPriv->numClipRects;
const drm_clip_rect_t *pbox = dPriv->pClipRects;
const int pitch = frontRegion->pitch;
const int cpp = frontRegion->cpp;
int BR13, CMD;
int i;
box = *pbox;
ASSERT(intel_fb);
ASSERT(intel_fb->Base.Name == 0); /* Not a user-created FBO */
ASSERT(frontRegion);
ASSERT(backRegion);
ASSERT(frontRegion->pitch == backRegion->pitch);
ASSERT(frontRegion->cpp == backRegion->cpp);
if (rect) {
if (rect->x1 > box.x1)
box.x1 = rect->x1;
if (rect->y1 > box.y1)
box.y1 = rect->y1;
if (rect->x2 < box.x2)
box.x2 = rect->x2;
if (rect->y2 < box.y2)
box.y2 = rect->y2;
if (cpp == 2) {
BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24);
CMD = XY_SRC_COPY_BLT_CMD;
}
else {
BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24) | (1 << 25);
CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
XY_SRC_COPY_BLT_WRITE_RGB);
}
for (i = 0; i < nbox; i++, pbox++) {
drm_clip_rect_t box;
if (pbox->x1 > pbox->x2 ||
pbox->y1 > pbox->y2 ||
pbox->x2 > intelScreen->width || pbox->y2 > intelScreen->height)
if (box.x1 > box.x2 || box.y1 > box.y2)
continue;
box = *pbox;
if (rect) {
if (rect->x1 > box.x1)
box.x1 = rect->x1;
if (rect->y1 > box.y1)
box.y1 = rect->y1;
if (rect->x2 < box.x2)
box.x2 = rect->x2;
if (rect->y2 < box.y2)
box.y2 = rect->y2;
if (box.x1 > box.x2 || box.y1 > box.y2)
continue;
}
BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS);
OUT_BATCH(CMD);
OUT_BATCH(BR13);
OUT_BATCH((pbox->y1 << 16) | pbox->x1);
OUT_BATCH((pbox->y2 << 16) | pbox->x2);
OUT_RELOC(frontRegion->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, 0);
OUT_BATCH((pbox->y1 << 16) | pbox->x1);
OUT_BATCH(BR13 & 0xffff);
OUT_RELOC(backRegion->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, 0);
ADVANCE_BATCH();
}
if (intel->first_swap_fence)
driFenceUnReference(intel->first_swap_fence);
intel->first_swap_fence = intel_batchbuffer_flush(intel->batch);
driFenceReference(intel->first_swap_fence);
BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS);
OUT_BATCH(CMD);
OUT_BATCH(BR13);
OUT_BATCH((pbox->y1 << 16) | pbox->x1);
OUT_BATCH((pbox->y2 << 16) | pbox->x2);
OUT_RELOC(frontRegion->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, 0);
OUT_BATCH((pbox->y1 << 16) | pbox->x1);
OUT_BATCH(BR13 & 0xffff);
OUT_RELOC(backRegion->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, 0);
ADVANCE_BATCH();
}
UNLOCK_HARDWARE(intel);
if (intel->first_swap_fence)
driFenceUnReference(intel->first_swap_fence);
intel->first_swap_fence = intel_batchbuffer_flush(intel->batch);
driFenceReference(intel->first_swap_fence);
}
if (!rect) {
intel->swap_count++;
(*dri_interface->getUST) (&ust);
if (missed_target) {
intel->swap_missed_count++;
intel->swap_missed_ust = ust - intel->swap_ust;
}
intel->swap_ust = ust;
}
UNLOCK_HARDWARE(intel);
}
+112 -22
View File
@@ -226,7 +226,7 @@ intelWindowMoved(struct intel_context *intel)
.y2 = sarea->pipeB_y + sarea->pipeB_h };
GLint areaA = driIntersectArea( drw_rect, pipeA_rect );
GLint areaB = driIntersectArea( drw_rect, pipeB_rect );
GLuint flags = intel->vblank_flags;
GLuint flags = intel_fb->vblank_flags;
GLboolean pf_active;
GLint pf_pipes;
@@ -278,17 +278,17 @@ intelWindowMoved(struct intel_context *intel)
/* Update vblank info
*/
if (areaB > areaA || (areaA == areaB && areaB > 0)) {
flags = intel->vblank_flags | VBLANK_FLAG_SECONDARY;
flags = intel_fb->vblank_flags | VBLANK_FLAG_SECONDARY;
} else {
flags = intel->vblank_flags & ~VBLANK_FLAG_SECONDARY;
flags = intel_fb->vblank_flags & ~VBLANK_FLAG_SECONDARY;
}
if (flags != intel->vblank_flags) {
intel->vblank_flags = flags;
driGetCurrentVBlank(dPriv, intel->vblank_flags, &intel->vbl_seq);
if (flags != intel_fb->vblank_flags) {
intel_fb->vblank_flags = flags;
driGetCurrentVBlank(dPriv, intel_fb->vblank_flags, &intel_fb->vbl_seq);
}
} else {
intel->vblank_flags &= ~VBLANK_FLAG_SECONDARY;
intel_fb->vblank_flags &= ~VBLANK_FLAG_SECONDARY;
}
/* Update Mesa's notion of window size */
@@ -683,7 +683,6 @@ static GLboolean
intelPageFlip(const __DRIdrawablePrivate * dPriv)
{
struct intel_context *intel;
GLboolean missed_target;
int ret;
struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
@@ -701,13 +700,6 @@ intelPageFlip(const __DRIdrawablePrivate * dPriv)
intelFlush(&intel->ctx);
driWaitForVBlank(dPriv, &intel->vbl_seq, intel->vblank_flags, &missed_target);
if (missed_target) {
intel->swap_missed_count++;
(void)(*dri_interface->getUST) (&intel->swap_missed_ust);
}
ret = 0;
LOCK_HARDWARE(intel);
@@ -772,6 +764,83 @@ intelSwapBuffers(__DRIdrawablePrivate * dPriv)
#else
/* Trunk version:
*/
static GLboolean
intelScheduleSwap(const __DRIdrawablePrivate * dPriv, GLboolean *missed_target)
{
struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
unsigned int interval = driGetVBlankInterval(dPriv, intel_fb->vblank_flags);
struct intel_context *intel =
intelScreenContext(dPriv->driScreenPriv->private);
const intelScreenPrivate *intelScreen = intel->intelScreen;
unsigned int target;
drm_i915_vblank_swap_t swap;
GLboolean ret;
if ((intel_fb->vblank_flags & VBLANK_FLAG_NO_IRQ) ||
intelScreen->current_rotation != 0 ||
intelScreen->drmMinor < (intel_fb->pf_active ? 9 : 6))
return GL_FALSE;
swap.seqtype = DRM_VBLANK_ABSOLUTE;
if (intel_fb->vblank_flags & VBLANK_FLAG_SYNC) {
swap.seqtype |= DRM_VBLANK_NEXTONMISS;
} else if (interval == 0) {
return GL_FALSE;
}
swap.drawable = dPriv->hHWDrawable;
target = swap.sequence = intel_fb->vbl_seq + interval;
if ( intel_fb->vblank_flags & VBLANK_FLAG_SECONDARY ) {
swap.seqtype |= DRM_VBLANK_SECONDARY;
}
LOCK_HARDWARE(intel);
intel_batchbuffer_flush(intel->batch);
if ( intel_fb->pf_active ) {
swap.seqtype |= DRM_VBLANK_FLIP;
intel_fb->pf_current_page = (((intel->sarea->pf_current_page >>
(intel_fb->pf_pipes & 0x2)) & 0x3) + 1) %
intel_fb->pf_num_pages;
}
if (!drmCommandWriteRead(intel->driFd, DRM_I915_VBLANK_SWAP, &swap,
sizeof(swap))) {
intel_fb->vbl_seq = swap.sequence;
swap.sequence -= target;
*missed_target = swap.sequence > 0 && swap.sequence <= (1 << 23);
if (swap.seqtype & DRM_VBLANK_FLIP) {
intel_get_renderbuffer(&intel_fb->Base,
BUFFER_FRONT_LEFT)->vbl_pending =
intel_get_renderbuffer(&intel_fb->Base,
BUFFER_BACK_LEFT)->vbl_pending = intel_fb->vbl_seq;
intel_flip_renderbuffers(intel_fb);
intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
}
ret = GL_TRUE;
} else {
if (swap.seqtype & DRM_VBLANK_FLIP) {
intel_fb->pf_current_page = ((intel->sarea->pf_current_page >>
(intel_fb->pf_pipes & 0x2)) & 0x3) %
intel_fb->pf_num_pages;
}
ret = GL_FALSE;
}
UNLOCK_HARDWARE(intel);
return ret;
}
void
intelSwapBuffers(__DRIdrawablePrivate * dPriv)
{
@@ -786,13 +855,34 @@ intelSwapBuffers(__DRIdrawablePrivate * dPriv)
if (ctx->Visual.doubleBufferMode) {
intelScreenPrivate *screen = intel->intelScreen;
_mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */
if (screen->current_rotation != 0 || !intelPageFlip(dPriv)) {
intelCopyBuffer(dPriv, NULL);
}
if (screen->current_rotation != 0) {
intelRotateWindow(intel, dPriv, BUFFER_BIT_FRONT_LEFT);
}
GLboolean missed_target;
struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
int64_t ust;
_mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */
if (screen->current_rotation != 0 ||
!intelScheduleSwap(dPriv, &missed_target)) {
driWaitForVBlank(dPriv, &intel_fb->vbl_seq, intel_fb->vblank_flags,
&missed_target);
if (screen->current_rotation != 0 || !intelPageFlip(dPriv)) {
intelCopyBuffer(dPriv, NULL);
}
if (screen->current_rotation != 0) {
intelRotateWindow(intel, dPriv, BUFFER_BIT_FRONT_LEFT);
}
}
intel_fb->swap_count++;
(*dri_interface->getUST) (&ust);
if (missed_target) {
intel_fb->swap_missed_count++;
intel_fb->swap_missed_ust = ust - intel_fb->swap_ust;
}
intel_fb->swap_ust = ust;
}
}
else {
+26 -10
View File
@@ -443,10 +443,6 @@ intelInitContext(struct intel_context *intel,
intel->do_usleeps = (fthrottle_mode == DRI_CONF_FTHROTTLE_USLEEPS);
intel->vblank_flags = (intel->intelScreen->irq_active != 0)
? driGetDefaultVBlankFlags(&intel->optionCache) : VBLANK_FLAG_NO_IRQ;
(*dri_interface->getUST) (&intel->swap_ust);
_math_matrix_ctr(&intel->ViewportMatrix);
/* Disable imaging extension until convolution is working in
@@ -591,7 +587,12 @@ intelMakeCurrent(__DRIcontextPrivate * driContextPriv,
if (intel->ctx.DrawBuffer == &intel_fb->Base) {
if (intel->driDrawable != driDrawPriv) {
driDrawableInitVBlank(driDrawPriv, intel->vblank_flags, &intel->vbl_seq);
intel_fb->vblank_flags = (intel->intelScreen->irq_active != 0)
? driGetDefaultVBlankFlags(&intel->optionCache)
: VBLANK_FLAG_NO_IRQ;
(*dri_interface->getUST) (&intel_fb->swap_ust);
driDrawableInitVBlank(driDrawPriv, intel_fb->vblank_flags,
&intel_fb->vbl_seq);
intel->driDrawable = driDrawPriv;
intelWindowMoved(intel);
}
@@ -702,19 +703,34 @@ intelContendedLock(struct intel_context *intel, GLuint flags)
void LOCK_HARDWARE( struct intel_context *intel )
{
char __ret=0;
struct intel_framebuffer *intel_fb = NULL;
struct intel_renderbuffer *intel_rb = NULL;
_glthread_LOCK_MUTEX(lockMutex);
assert(!intel->locked);
if (intel->swap_scheduled) {
if (intel->driDrawable) {
intel_fb = intel->driDrawable->driverPrivate;
if (intel_fb)
intel_rb =
intel_get_renderbuffer(&intel_fb->Base,
intel_fb->Base._ColorDrawBufferMask[0] ==
BUFFER_BIT_FRONT_LEFT ? BUFFER_FRONT_LEFT :
BUFFER_BACK_LEFT);
}
if (intel_rb && (intel_fb->vbl_waited - intel_rb->vbl_pending) > (1<<23)) {
drmVBlank vbl;
vbl.request.type = DRM_VBLANK_ABSOLUTE;
if ( intel->vblank_flags & VBLANK_FLAG_SECONDARY ) {
if ( intel_fb->vblank_flags & VBLANK_FLAG_SECONDARY ) {
vbl.request.type |= DRM_VBLANK_SECONDARY;
}
vbl.request.sequence = intel->vbl_seq;
vbl.request.sequence = intel_rb->vbl_pending;
drmWaitVBlank(intel->driFd, &vbl);
intel->swap_scheduled = 0;
intel_fb->vbl_waited = intel_rb->vbl_pending;
}
DRM_CAS(intel->driHwLock, intel->hHWContext,
@@ -274,19 +274,6 @@ struct intel_context
*/
driOptionCache optionCache;
/* VBI
*/
GLuint vbl_seq;
GLuint vblank_flags;
int64_t swap_ust;
int64_t swap_missed_ust;
GLuint swap_count;
GLuint swap_missed_count;
GLuint swap_scheduled;
/* Rotation. Need to match that of the
* current screen.
*/
+14
View File
@@ -47,6 +47,18 @@ struct intel_framebuffer
GLint pf_pipes;
GLint pf_current_page;
GLint pf_num_pages;
/* VBI
*/
GLuint vbl_seq;
GLuint vblank_flags;
GLuint vbl_waited;
int64_t swap_ust;
int64_t swap_missed_ust;
GLuint swap_count;
GLuint swap_missed_count;
};
@@ -68,6 +80,8 @@ struct intel_renderbuffer
GLuint PairedStencil; /**< only used if this is a stencil renderbuffer */
GLuint pf_pending; /**< sequence number of pending flip */
GLuint vbl_pending; /**< vblank sequence number of pending flip */
};
+7 -8
View File
@@ -679,21 +679,20 @@ intelDestroyBuffer(__DRIdrawablePrivate * driDrawPriv)
static int
intelGetSwapInfo(__DRIdrawablePrivate * dPriv, __DRIswapInfo * sInfo)
{
struct intel_context *intel;
struct intel_framebuffer *intel_fb;
if ((dPriv == NULL) || (dPriv->driContextPriv == NULL)
|| (dPriv->driContextPriv->driverPrivate == NULL)
if ((dPriv == NULL) || (dPriv->driverPrivate == NULL)
|| (sInfo == NULL)) {
return -1;
}
intel = dPriv->driContextPriv->driverPrivate;
sInfo->swap_count = intel->swap_count;
sInfo->swap_ust = intel->swap_ust;
sInfo->swap_missed_count = intel->swap_missed_count;
intel_fb = dPriv->driverPrivate;
sInfo->swap_count = intel_fb->swap_count;
sInfo->swap_ust = intel_fb->swap_ust;
sInfo->swap_missed_count = intel_fb->swap_missed_count;
sInfo->swap_missed_usage = (sInfo->swap_missed_count != 0)
? driCalculateSwapUsage(dPriv, 0, intel->swap_missed_ust)
? driCalculateSwapUsage(dPriv, 0, intel_fb->swap_missed_ust)
: 0.0;
return 0;