drm: pin new and unpin old buffer when setting a mode.
authorKristian Høgsberg <krh@redhat.com>
Thu, 18 Dec 2008 03:14:46 +0000 (22:14 -0500)
committerDave Airlie <airlied@linux.ie>
Mon, 29 Dec 2008 07:47:27 +0000 (17:47 +1000)
This removes the requirement for user space to pin a buffer before
setting a mode that is backed by the pixels from that buffer.

Signed-off-by: Kristian Høgsberg <krh@redhat.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@linux.ie>
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/i915/intel_display.c
include/drm/drm_crtc_helper.h

index 58e3359..d8a982b 100644 (file)
@@ -432,7 +432,8 @@ static void drm_setup_crtcs(struct drm_device *dev)
  */
 bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
                              struct drm_display_mode *mode,
-                             int x, int y)
+                             int x, int y,
+                             struct drm_framebuffer *old_fb)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_display_mode *adjusted_mode, saved_mode;
@@ -462,7 +463,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
 
        if (drm_mode_equal(&saved_mode, &crtc->mode)) {
                if (saved_x != crtc->x || saved_y != crtc->y) {
-                       crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y);
+                       crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y,
+                                                 old_fb);
                        goto done;
                }
        }
@@ -501,7 +503,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
        /* Set up the DPLL and any encoders state that needs to adjust or depend
         * on the DPLL.
         */
-       crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y);
+       crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
 
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
 
@@ -564,6 +566,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
        struct drm_device *dev;
        struct drm_crtc **save_crtcs, *new_crtc;
        struct drm_encoder **save_encoders, *new_encoder;
+       struct drm_framebuffer *old_fb;
        bool save_enabled;
        bool changed = false;
        bool flip_or_move = false;
@@ -684,13 +687,15 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                changed = true;
 
        if (changed) {
+               old_fb = set->crtc->fb;
                set->crtc->fb = set->fb;
                set->crtc->enabled = (set->mode != NULL);
                if (set->mode != NULL) {
                        DRM_DEBUG("attempting to set mode from userspace\n");
                        drm_mode_debug_printmodeline(set->mode);
                        if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
-                                                     set->x, set->y)) {
+                                                     set->x, set->y,
+                                                     old_fb)) {
                                ret = -EINVAL;
                                goto fail_set_mode;
                        }
@@ -701,9 +706,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                }
                drm_helper_disable_unused_functions(dev);
        } else if (flip_or_move) {
+               old_fb = set->crtc->fb;
                if (set->crtc->fb != set->fb)
                        set->crtc->fb = set->fb;
-               crtc_funcs->mode_set_base(set->crtc, set->x, set->y);
+               crtc_funcs->mode_set_base(set->crtc, set->x, set->y, old_fb);
        }
 
        kfree(save_encoders);
@@ -809,8 +815,8 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
                if (!crtc->enabled)
                        continue;
 
-               ret = drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
-                                              crtc->y);
+               ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
+                                              crtc->x, crtc->y, crtc->fb);
 
                if (ret == false)
                        DRM_ERROR("failed to set mode on crtc %p\n", crtc);
index 6e8b9ab..e5c1c80 100644 (file)
@@ -344,7 +344,8 @@ intel_wait_for_vblank(struct drm_device *dev)
 }
 
 static void
-intel_pipe_set_base(struct drm_crtc *crtc, int x, int y)
+intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
+                   struct drm_framebuffer *old_fb)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -359,7 +360,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y)
        int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF);
        int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
        int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
-       u32 dspcntr;
+       u32 dspcntr, alignment;
 
        /* no fb bound */
        if (!crtc->fb) {
@@ -368,10 +369,32 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y)
        }
 
        intel_fb = to_intel_framebuffer(crtc->fb);
-
        obj = intel_fb->obj;
        obj_priv = obj->driver_private;
 
+       switch (obj_priv->tiling_mode) {
+       case I915_TILING_NONE:
+               alignment = 64 * 1024;
+               break;
+       case I915_TILING_X:
+               if (IS_I9XX(dev))
+                       alignment = 1024 * 1024;
+               else
+                       alignment = 512 * 1024;
+               break;
+       case I915_TILING_Y:
+               /* FIXME: Is this true? */
+               DRM_ERROR("Y tiled not allowed for scan out buffers\n");
+               return;
+       default:
+               BUG();
+       }
+
+       if (i915_gem_object_pin(intel_fb->obj, alignment))
+               return;
+
+       i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1);
+
        Start = obj_priv->gtt_offset;
        Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8);
 
@@ -409,6 +432,12 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y)
                I915_READ(dspbase);
        }
 
+       intel_wait_for_vblank(dev);
+
+       if (old_fb) {
+               intel_fb = to_intel_framebuffer(old_fb);
+               i915_gem_object_unpin(intel_fb->obj);
+       }
 
        if (!dev->primary->master)
                return;
@@ -680,7 +709,8 @@ static int intel_panel_fitter_pipe (struct drm_device *dev)
 static void intel_crtc_mode_set(struct drm_crtc *crtc,
                                struct drm_display_mode *mode,
                                struct drm_display_mode *adjusted_mode,
-                               int x, int y)
+                               int x, int y,
+                               struct drm_framebuffer *old_fb)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -915,9 +945,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
        I915_WRITE(dspcntr_reg, dspcntr);
 
        /* Flush the plane changes */
-       intel_pipe_set_base(crtc, x, y);
-
-       intel_wait_for_vblank(dev);
+       intel_pipe_set_base(crtc, x, y, old_fb);
 
        drm_vblank_post_modeset(dev, pipe);
 }
@@ -1153,7 +1181,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output,
        if (!crtc->enabled) {
                if (!mode)
                        mode = &load_detect_mode;
-               drm_crtc_helper_set_mode(crtc, mode, 0, 0);
+               drm_crtc_helper_set_mode(crtc, mode, 0, 0, crtc->fb);
        } else {
                if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
                        crtc_funcs = crtc->helper_private;
index a341828..4bc04cf 100644 (file)
@@ -55,10 +55,12 @@ struct drm_crtc_helper_funcs {
                           struct drm_display_mode *adjusted_mode);
        /* Actually set the mode */
        void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
-                        struct drm_display_mode *adjusted_mode, int x, int y);
+                        struct drm_display_mode *adjusted_mode, int x, int y,
+                        struct drm_framebuffer *old_fb);
 
        /* Move the crtc on the current fb to the given position *optional* */
-       void (*mode_set_base)(struct drm_crtc *crtc, int x, int y);
+       void (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
+                             struct drm_framebuffer *old_fb);
 };
 
 struct drm_encoder_helper_funcs {
@@ -93,7 +95,8 @@ extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow);
 extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
 extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
                                     struct drm_display_mode *mode,
-                                    int x, int y);
+                                    int x, int y,
+                                    struct drm_framebuffer *old_fb);
 extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc);
 
 extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,