[PATCH 29/51] drm/i915: Split clipping and checking from update_plane hook

2012-10-25 Thread ville.syrj...@linux.intel.com
From: Ville Syrj?l? 

Split the update_plane() codepath into two separate steps. The first
step checkis and clips the plane, and the second step actually commits
the changes to the hardware. This allows the atomic modesetting code
to perform all checks before clobering hardware state.

The update_plane() hook is reduced to a thin wrapper calling both check
and commit functions.

Buffer (un)pinning is still being performed in the commit step. This
needs to be changed as well, so that the atomic modesetting code can
try to pin all new buffers before touching the hardware.

Signed-off-by: Ville Syrj?l? 
---
 drivers/gpu/drm/i915/intel_drv.h|   15 +-
 drivers/gpu/drm/i915/intel_sprite.c |  367 ++
 2 files changed, 247 insertions(+), 135 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 64d87c2..0660d38 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -214,6 +214,15 @@ struct intel_crtc {
struct intel_pch_pll *pch_pll;
 };

+struct intel_plane_coords {
+   /* disabled or fully clipped? */
+   bool visible;
+   /* coordinates clipped against pipe dimensions */
+   int32_t crtc_x, crtc_y;
+   uint32_t crtc_w, crtc_h;
+   uint32_t src_x, src_y, src_w, src_h;
+};
+
 struct intel_plane {
struct drm_plane base;
enum pipe pipe;
@@ -222,11 +231,7 @@ struct intel_plane {
u32 lut_r[1024], lut_g[1024], lut_b[1024];
void (*update_plane)(struct drm_plane *plane,
 struct drm_framebuffer *fb,
-struct drm_i915_gem_object *obj,
-int crtc_x, int crtc_y,
-unsigned int crtc_w, unsigned int crtc_h,
-uint32_t x, uint32_t y,
-uint32_t src_w, uint32_t src_h);
+const struct intel_plane_coords *clip);
void (*disable_plane)(struct drm_plane *plane);
int (*update_colorkey)(struct drm_plane *plane,
   struct drm_intel_sprite_colorkey *key);
diff --git a/drivers/gpu/drm/i915/intel_sprite.c 
b/drivers/gpu/drm/i915/intel_sprite.c
index cd6777f..fee6f17 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -36,16 +36,173 @@
 #include 
 #include "i915_drv.h"

+static bool
+format_is_yuv(uint32_t format)
+{
+   switch (format) {
+   case DRM_FORMAT_YUYV:
+   case DRM_FORMAT_UYVY:
+   case DRM_FORMAT_VYUY:
+   case DRM_FORMAT_YVYU:
+   return true;
+   default:
+   return false;
+   }
+}
+
+static void intel_clip_plane(const struct drm_plane *plane,
+const struct drm_crtc *crtc,
+const struct drm_framebuffer *fb,
+struct intel_plane_coords *coords)
+{
+   const struct intel_plane *intel_plane = to_intel_plane(plane);
+   const struct drm_display_mode *mode = &crtc->mode;
+   int hscale, vscale;
+   struct drm_region src = {
+   .x1 = coords->src_x,
+   .x2 = coords->src_x + coords->src_w,
+   .y1 = coords->src_y,
+   .y2 = coords->src_y + coords->src_h,
+   };
+   struct drm_region dst = {
+   .x1 = coords->crtc_x,
+   .x2 = coords->crtc_x + coords->crtc_w,
+   .y1 = coords->crtc_y,
+   .y2 = coords->crtc_y + coords->crtc_h,
+   };
+   const struct drm_region clip = {
+   .x2 = mode->hdisplay,
+   .y2 = mode->vdisplay,
+   };
+
+   hscale = drm_calc_hscale(&src, &dst, 1, intel_plane->max_downscale << 
16);
+   vscale = drm_calc_vscale(&src, &dst, 1, intel_plane->max_downscale << 
16);
+
+   coords->visible = drm_region_clip_scaled(&src, &dst, &clip, hscale, 
vscale);
+
+   coords->crtc_x = dst.x1;
+   coords->crtc_y = dst.y1;
+   coords->crtc_w = drm_region_width(&dst);
+   coords->crtc_h = drm_region_height(&dst);
+
+   /* HW doesn't seem to like smaller sprite, even when scaling */
+   /* FIXME return an error instead? */
+   if (coords->crtc_w < 3 || coords->crtc_h < 3)
+   coords->visible = false;
+
+   /*
+* Hardware doesn't handle subpixel coordinates.
+* Round to nearest (macro)pixel boundary.
+*/
+   if (format_is_yuv(fb->pixel_format)) {
+   coords->src_x = ((src.x1 + 0x1) >> 17) << 1;
+   coords->src_w = (((src.x2 + 0x1) >> 17) << 1) - 
coords->src_x;
+   } else {
+   coords->src_x = (src.x1 + 0x8000) >> 16;
+   coords->src_w = ((src.x2 + 0x8000) >> 16) - coords->src_x;
+   }
+   coords->src_y = (src.y1 + 0x8000) >> 16;
+   coords->src_h = ((src.y2 + 0x8000) >> 16) - coords->src_y;
+
+   /* Account for minimum source size when scali

[PATCH 29/51] drm/i915: Split clipping and checking from update_plane hook

2012-10-25 Thread ville . syrjala
From: Ville Syrjälä 

Split the update_plane() codepath into two separate steps. The first
step checkis and clips the plane, and the second step actually commits
the changes to the hardware. This allows the atomic modesetting code
to perform all checks before clobering hardware state.

The update_plane() hook is reduced to a thin wrapper calling both check
and commit functions.

Buffer (un)pinning is still being performed in the commit step. This
needs to be changed as well, so that the atomic modesetting code can
try to pin all new buffers before touching the hardware.

Signed-off-by: Ville Syrjälä 
---
 drivers/gpu/drm/i915/intel_drv.h|   15 +-
 drivers/gpu/drm/i915/intel_sprite.c |  367 ++
 2 files changed, 247 insertions(+), 135 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 64d87c2..0660d38 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -214,6 +214,15 @@ struct intel_crtc {
struct intel_pch_pll *pch_pll;
 };
 
+struct intel_plane_coords {
+   /* disabled or fully clipped? */
+   bool visible;
+   /* coordinates clipped against pipe dimensions */
+   int32_t crtc_x, crtc_y;
+   uint32_t crtc_w, crtc_h;
+   uint32_t src_x, src_y, src_w, src_h;
+};
+
 struct intel_plane {
struct drm_plane base;
enum pipe pipe;
@@ -222,11 +231,7 @@ struct intel_plane {
u32 lut_r[1024], lut_g[1024], lut_b[1024];
void (*update_plane)(struct drm_plane *plane,
 struct drm_framebuffer *fb,
-struct drm_i915_gem_object *obj,
-int crtc_x, int crtc_y,
-unsigned int crtc_w, unsigned int crtc_h,
-uint32_t x, uint32_t y,
-uint32_t src_w, uint32_t src_h);
+const struct intel_plane_coords *clip);
void (*disable_plane)(struct drm_plane *plane);
int (*update_colorkey)(struct drm_plane *plane,
   struct drm_intel_sprite_colorkey *key);
diff --git a/drivers/gpu/drm/i915/intel_sprite.c 
b/drivers/gpu/drm/i915/intel_sprite.c
index cd6777f..fee6f17 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -36,16 +36,173 @@
 #include 
 #include "i915_drv.h"
 
+static bool
+format_is_yuv(uint32_t format)
+{
+   switch (format) {
+   case DRM_FORMAT_YUYV:
+   case DRM_FORMAT_UYVY:
+   case DRM_FORMAT_VYUY:
+   case DRM_FORMAT_YVYU:
+   return true;
+   default:
+   return false;
+   }
+}
+
+static void intel_clip_plane(const struct drm_plane *plane,
+const struct drm_crtc *crtc,
+const struct drm_framebuffer *fb,
+struct intel_plane_coords *coords)
+{
+   const struct intel_plane *intel_plane = to_intel_plane(plane);
+   const struct drm_display_mode *mode = &crtc->mode;
+   int hscale, vscale;
+   struct drm_region src = {
+   .x1 = coords->src_x,
+   .x2 = coords->src_x + coords->src_w,
+   .y1 = coords->src_y,
+   .y2 = coords->src_y + coords->src_h,
+   };
+   struct drm_region dst = {
+   .x1 = coords->crtc_x,
+   .x2 = coords->crtc_x + coords->crtc_w,
+   .y1 = coords->crtc_y,
+   .y2 = coords->crtc_y + coords->crtc_h,
+   };
+   const struct drm_region clip = {
+   .x2 = mode->hdisplay,
+   .y2 = mode->vdisplay,
+   };
+
+   hscale = drm_calc_hscale(&src, &dst, 1, intel_plane->max_downscale << 
16);
+   vscale = drm_calc_vscale(&src, &dst, 1, intel_plane->max_downscale << 
16);
+
+   coords->visible = drm_region_clip_scaled(&src, &dst, &clip, hscale, 
vscale);
+
+   coords->crtc_x = dst.x1;
+   coords->crtc_y = dst.y1;
+   coords->crtc_w = drm_region_width(&dst);
+   coords->crtc_h = drm_region_height(&dst);
+
+   /* HW doesn't seem to like smaller sprite, even when scaling */
+   /* FIXME return an error instead? */
+   if (coords->crtc_w < 3 || coords->crtc_h < 3)
+   coords->visible = false;
+
+   /*
+* Hardware doesn't handle subpixel coordinates.
+* Round to nearest (macro)pixel boundary.
+*/
+   if (format_is_yuv(fb->pixel_format)) {
+   coords->src_x = ((src.x1 + 0x1) >> 17) << 1;
+   coords->src_w = (((src.x2 + 0x1) >> 17) << 1) - 
coords->src_x;
+   } else {
+   coords->src_x = (src.x1 + 0x8000) >> 16;
+   coords->src_w = ((src.x2 + 0x8000) >> 16) - coords->src_x;
+   }
+   coords->src_y = (src.y1 + 0x8000) >> 16;
+   coords->src_h = ((src.y2 + 0x8000) >> 16) - coords->src_y;
+
+   /* Account for minimum source size when sca