diff options
author | Ilija Hadzic <ihadzic@research.bell-labs.com> | 2012-12-19 10:35:43 -0500 |
---|---|---|
committer | Michel Dänzer <michel.daenzer@amd.com> | 2013-01-03 10:59:37 +0100 |
commit | 6981a5c087165b126c15ba0025cffdba218ab652 (patch) | |
tree | 09abdf221318025fdd9b93c0e04f2d1ec3a038c4 /src/radeon_dri2.c | |
parent | 3657672207322be651cdb94a811337b7c5668c84 (diff) |
DRI2: limit the swap rate when CRTC is in DPMS-off state
If drawable is displayed on a CRTC and relevant CRTC is in
DPMS off state, defer the swap by a fixed (hard-coded) time.
This patch fixes a bug that caused an application to render
at uncontrolled rate when CRTC goes into DPMS "off" state,
thus thrashing the GPU and CPU and likely offsetting the
power savings achieved by shutting off the display.
Signed-off-by: Ilija Hadzic <ihadzic@research.bell-labs.com>
Reviewed-by: Michel Dänzer <michel.daenzer@amd.com>
Diffstat (limited to 'src/radeon_dri2.c')
-rw-r--r-- | src/radeon_dri2.c | 42 |
1 files changed, 37 insertions, 5 deletions
diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c index 8ebc6871..27b04e3e 100644 --- a/src/radeon_dri2.c +++ b/src/radeon_dri2.c @@ -31,6 +31,7 @@ #include "radeon.h" #include "radeon_dri2.h" +#include "radeon_video.h" #ifdef DRI2 @@ -67,6 +68,8 @@ #define USE_DRI2_PRIME #endif +#define FALLBACK_SWAP_DELAY 16 + #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,0, 0) typedef DRI2BufferPtr BufferPtr; #else @@ -1263,6 +1266,14 @@ void radeon_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec, free(flip); } +static +CARD32 radeon_dri2_deferred_swap(OsTimerPtr timer, CARD32 now, pointer data) +{ + TimerFree(timer); + radeon_dri2_frame_event_handler(0, 0, 0, data); + return 0; +} + /* * ScheduleSwap is responsible for requesting a DRM vblank event for the * appropriate frame. @@ -1292,7 +1303,7 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, ScreenPtr screen = draw->pScreen; ScrnInfoPtr scrn = xf86ScreenToScrn(screen); RADEONInfoPtr info = RADEONPTR(scrn); - xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, FALSE); + xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); drmVBlank vbl; int ret, flip = 0; DRI2FrameEventPtr swap_info = NULL; @@ -1314,7 +1325,7 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, radeon_dri2_ref_buffer(front); radeon_dri2_ref_buffer(back); - /* Drawable not displayed... just complete the swap */ + /* either off-screen or CRTC not usable... just complete the swap */ if (crtc == NULL) goto blit_fallback; @@ -1337,6 +1348,18 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, goto blit_fallback; } + /* + * CRTC is in DPMS off state, fallback to blit, but pace the + * application at the rate that roughly approximates the + * nominal frame rate of the relevant CRTC + */ + if (!radeon_crtc_is_enabled(crtc)) { + TimerSet(NULL, 0, FALLBACK_SWAP_DELAY, radeon_dri2_deferred_swap, + swap_info); + *target_msc = 0; + return TRUE; + } + /* Get current count */ vbl.request.type = DRM_VBLANK_RELATIVE; vbl.request.type |= populate_vbl_request_type(info, crtc); @@ -1346,7 +1369,10 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, xf86DrvMsg(scrn->scrnIndex, X_WARNING, "first get vblank counter failed: %s\n", strerror(errno)); - goto blit_fallback; + TimerSet(NULL, 0, FALLBACK_SWAP_DELAY, radeon_dri2_deferred_swap, + swap_info); + *target_msc = 0; + return TRUE; } current_msc = vbl.reply.sequence; @@ -1395,7 +1421,10 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, xf86DrvMsg(scrn->scrnIndex, X_WARNING, "divisor 0 get vblank counter failed: %s\n", strerror(errno)); - goto blit_fallback; + TimerSet(NULL, 0, FALLBACK_SWAP_DELAY, radeon_dri2_deferred_swap, + swap_info); + *target_msc = 0; + return TRUE; } *target_msc = vbl.reply.sequence + flip; @@ -1440,7 +1469,10 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, xf86DrvMsg(scrn->scrnIndex, X_WARNING, "final get vblank counter failed: %s\n", strerror(errno)); - goto blit_fallback; + TimerSet(NULL, 0, FALLBACK_SWAP_DELAY, radeon_dri2_deferred_swap, + swap_info); + *target_msc = 0; + return TRUE; } /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ |