diff options
Diffstat (limited to 'src/drmmode_display.c')
-rw-r--r-- | src/drmmode_display.c | 134 |
1 files changed, 129 insertions, 5 deletions
diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 0a6e338e..9248cb0e 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -29,6 +29,7 @@ #include "config.h" #endif +#include <errno.h> #ifdef XF86DRM_MODE #include <sys/ioctl.h> #include "micmap.h" @@ -266,9 +267,10 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, uint32_t tiling_flags = 0; int height; - /* no tiled scanout on r6xx+ yet */ if (info->allowColorTiling) { - if (info->ChipFamily < CHIP_FAMILY_R600) + if (info->ChipFamily >= CHIP_FAMILY_R600) + tiling_flags |= RADEON_TILING_MICRO; + else tiling_flags |= RADEON_TILING_MACRO; } @@ -1167,9 +1169,10 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) if (front_bo) radeon_bo_wait(front_bo); - /* no tiled scanout on r6xx+ yet */ if (info->allowColorTiling) { - if (info->ChipFamily < CHIP_FAMILY_R600) + if (info->ChipFamily >= CHIP_FAMILY_R600) + tiling_flags |= RADEON_TILING_MICRO; + else tiling_flags |= RADEON_TILING_MACRO; } @@ -1278,6 +1281,39 @@ drmmode_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec, } static void +drmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, + unsigned int tv_usec, void *event_data) +{ + drmmode_flipevtcarrier_ptr flipcarrier = event_data; + drmmode_ptr drmmode = flipcarrier->drmmode; + + /* Is this the event whose info shall be delivered to higher level? */ + if (flipcarrier->dispatch_me) { + /* Yes: Cache msc, ust for later delivery. */ + drmmode->fe_frame = frame; + drmmode->fe_tv_sec = tv_sec; + drmmode->fe_tv_usec = tv_usec; + } + free(flipcarrier); + + /* Last crtc completed flip? */ + drmmode->flip_count--; + if (drmmode->flip_count > 0) + return; + + /* Release framebuffer */ + drmModeRmFB(drmmode->fd, drmmode->old_fb_id); + + if (drmmode->event_data == NULL) + return; + + /* Deliver cached msc, ust from reference crtc to flip event handler */ + radeon_dri2_flip_event_handler(drmmode->fe_frame, drmmode->fe_tv_sec, + drmmode->fe_tv_usec, drmmode->event_data); +} + + +static void drm_wakeup_handler(pointer data, int err, pointer p) { drmmode_ptr drmmode = data; @@ -1320,8 +1356,9 @@ Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) drmmode->flip_count = 0; drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION; drmmode->event_context.vblank_handler = drmmode_vblank_handler; - drmmode->event_context.page_flip_handler = NULL; + drmmode->event_context.page_flip_handler = drmmode_flip_handler; if (!pRADEONEnt->fd_wakeup_registered && info->dri->pKernelDRMVersion->version_minor >= 4) { + drmmode->flip_count = 0; AddGeneralSocket(drmmode->fd); RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, drm_wakeup_handler, drmmode); @@ -1561,4 +1598,91 @@ void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) #endif } +Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data, int ref_crtc_hw_id) +{ + RADEONInfoPtr info = RADEONPTR(scrn); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + unsigned int pitch = scrn->displayWidth * info->CurrentLayout.pixel_bytes; + int i, old_fb_id; + uint32_t tiling_flags = 0; + int height; + drmmode_flipevtcarrier_ptr flipcarrier; + + if (info->allowColorTiling) { + if (info->ChipFamily >= CHIP_FAMILY_R600) + tiling_flags |= RADEON_TILING_MICRO; + else + tiling_flags |= RADEON_TILING_MACRO; + } + + pitch = RADEON_ALIGN(pitch, drmmode_get_pitch_align(scrn, info->CurrentLayout.pixel_bytes, tiling_flags)); + height = RADEON_ALIGN(scrn->virtualY, drmmode_get_height_align(scrn, tiling_flags)); + + /* + * Create a new handle for the back buffer + */ + old_fb_id = drmmode->fb_id; + if (drmModeAddFB(drmmode->fd, scrn->virtualX, height, + scrn->depth, scrn->bitsPerPixel, pitch, + new_front->handle, &drmmode->fb_id)) + goto error_out; + + /* + * Queue flips on all enabled CRTCs + * Note that if/when we get per-CRTC buffers, we'll have to update this. + * Right now it assumes a single shared fb across all CRTCs, with the + * kernel fixing up the offset of each CRTC as necessary. + * + * Also, flips queued on disabled or incorrectly configured displays + * may never complete; this is a configuration error. + */ + drmmode->fe_frame = 0; + drmmode->fe_tv_sec = 0; + drmmode->fe_tv_usec = 0; + + for (i = 0; i < config->num_crtc; i++) { + if (!config->crtc[i]->enabled) + continue; + + drmmode->event_data = data; + drmmode->flip_count++; + drmmode_crtc = config->crtc[i]->driver_private; + + flipcarrier = calloc(1, sizeof(drmmode_flipevtcarrier_rec)); + if (!flipcarrier) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "flip queue: carrier alloc failed.\n"); + goto error_undo; + } + + /* Only the reference crtc will finally deliver its page flip + * completion event. All other crtc's events will be discarded. + */ + flipcarrier->dispatch_me = (drmmode_crtc->hw_id == ref_crtc_hw_id); + flipcarrier->drmmode = drmmode; + + if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, flipcarrier)) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "flip queue failed: %s\n", strerror(errno)); + free(flipcarrier); + goto error_undo; + } + } + + drmmode->old_fb_id = old_fb_id; + return TRUE; + +error_undo: + drmModeRmFB(drmmode->fd, drmmode->fb_id); + drmmode->fb_id = old_fb_id; + +error_out: + xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", + strerror(errno)); + return FALSE; +} + #endif |