summaryrefslogtreecommitdiff
path: root/src/drmmode_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/drmmode_display.c')
-rw-r--r--src/drmmode_display.c134
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