From: Damien Lespiau <damien.lesp...@intel.com>

This patch adds the blend functions, and as per the
blend function, updates the plane control register values

V2: Add blend support for all RGB8888 formats
Fix the reg writes on plane_ctl_alpha bits.

V3: Add support support for primary and cursor planes.
fix an issue where the previous value was not
retained, change the logic to do so.

Signed-off-by: Damien Lespiau <damien.lespiau at intel.com>
Signed-off-by: vandita kulkarni <vandita.kulkarni at intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 121 +++++++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/intel_drv.h     |  14 +++-
 drivers/gpu/drm/i915/intel_sprite.c  |   6 +-
 3 files changed, 133 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index c5b9687..037407f 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2921,8 +2921,29 @@ static void skl_detach_scalers(struct intel_crtc 
*intel_crtc)
        }
 }

-u32 skl_plane_ctl_format(uint32_t pixel_format)
+u32 skl_plane_ctl_format(uint32_t pixel_format,
+                       enum per_pixel_alpha_state alpha)
 {
+       u32 plane_ctl_alpha = 0;
+
+       if (pixel_format == DRM_FORMAT_ABGR8888 ||
+               pixel_format == DRM_FORMAT_ARGB8888) {
+
+               switch (alpha) {
+               case DROP_ALPHA:
+                       plane_ctl_alpha = PLANE_CTL_ALPHA_DISABLE;
+                       break;
+               case PRE_MULTIPLIED_ALPHA:
+                       plane_ctl_alpha = PLANE_CTL_ALPHA_SW_PREMULTIPLY;
+                       break;
+               case NON_PRE_MULTIPLIED_ALPHA:
+                       plane_ctl_alpha = PLANE_CTL_ALPHA_HW_PREMULTIPLY;
+                       break;
+               default:
+                       MISSING_CASE(alpha);
+               }
+       }
+
        switch (pixel_format) {
        case DRM_FORMAT_C8:
                return PLANE_CTL_FORMAT_INDEXED;
@@ -2938,11 +2959,11 @@ u32 skl_plane_ctl_format(uint32_t pixel_format)
         * DRM_FORMAT) for user-space to configure that.
         */
        case DRM_FORMAT_ABGR8888:
-               return PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX |
-                       PLANE_CTL_ALPHA_SW_PREMULTIPLY;
+               return ((PLANE_CTL_FORMAT_XRGB_8888 | (PLANE_CTL_ORDER_RGBX
+                               & (~PLANE_CTL_ALPHA_MASK))) | plane_ctl_alpha);
        case DRM_FORMAT_ARGB8888:
-               return PLANE_CTL_FORMAT_XRGB_8888 |
-                       PLANE_CTL_ALPHA_SW_PREMULTIPLY;
+               return ((PLANE_CTL_FORMAT_XRGB_8888 & ~PLANE_CTL_ALPHA_MASK)
+                                               | plane_ctl_alpha);
        case DRM_FORMAT_XRGB2101010:
                return PLANE_CTL_FORMAT_XRGB_2101010;
        case DRM_FORMAT_XBGR2101010:
@@ -3031,7 +3052,8 @@ static void skylake_update_primary_plane(struct drm_plane 
*plane,
                    PLANE_CTL_PIPE_GAMMA_ENABLE |
                    PLANE_CTL_PIPE_CSC_ENABLE;

-       plane_ctl |= skl_plane_ctl_format(fb->pixel_format);
+       plane_ctl |= skl_plane_ctl_format(fb->pixel_format,
+                                       plane_state->per_pixel_alpha);
        plane_ctl |= skl_plane_ctl_tiling(fb->modifier[0]);
        plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE;
        plane_ctl |= skl_plane_ctl_rotation(rotation);
@@ -3087,6 +3109,69 @@ static void skylake_update_primary_plane(struct 
drm_plane *plane,
        POSTING_READ(PLANE_SURF(pipe, 0));
 }

+static int intel_plane_state_check_blend(struct drm_plane_state *plane_state)
+{
+       struct drm_device *dev = plane_state->state->dev;
+       struct intel_plane_state *state = to_intel_plane_state(plane_state);
+       const struct drm_framebuffer *fb = plane_state->fb;
+       const struct drm_blend_mode *mode = &state->base.blend_mode;
+       bool has_per_pixel_blending;
+
+       /*
+        * We don't install the properties pre-SKL, so this is SKL+ specific
+        * code for now.
+        */
+       if (INTEL_INFO(dev)->gen < 9)
+               return 0;
+
+       if (!fb)
+               return 0;
+
+       has_per_pixel_blending = fb->pixel_format == DRM_FORMAT_ABGR8888 ||
+                               fb->pixel_format == DRM_FORMAT_RGBA8888 ||
+                               fb->pixel_format == DRM_FORMAT_ARGB8888 ||
+                               fb->pixel_format == DRM_FORMAT_BGRA8888;
+
+       /* drop alpha for all fbs without an alpha channel */
+       if (!has_per_pixel_blending)
+               state->per_pixel_alpha = DROP_ALPHA;
+
+       switch (mode->func) {
+       /*
+        * The 'AUTO' behaviour is the default and keeps compatibility with
+        * kernels before the introduction of the blend_func property:
+        *   - pre-multiplied alpha if the fb has an alpha channel
+        *   - usual DRM_BLEND_FUNC(ONE, ZERO) otherwise
+        */
+       case DRM_BLEND_FUNC(AUTO, AUTO):
+               if (has_per_pixel_blending)
+                       state->per_pixel_alpha = PRE_MULTIPLIED_ALPHA;
+               break;
+       /* fbs without an alpha channel, or dropping the alpha channel */
+       case DRM_BLEND_FUNC(ONE, ZERO):
+               if (has_per_pixel_blending)
+                       state->per_pixel_alpha = DROP_ALPHA;
+               break;
+       /* pre-multiplied alpha */
+       case DRM_BLEND_FUNC(ONE, ONE_MINUS_SRC_ALPHA):
+               if (!has_per_pixel_blending)
+                       state->per_pixel_alpha = DROP_ALPHA;
+               else
+                       state->per_pixel_alpha = PRE_MULTIPLIED_ALPHA;
+               break;
+       /* non pre-multiplied alpha */
+       case DRM_BLEND_FUNC(SRC_ALPHA, ONE_MINUS_SRC_ALPHA):
+               if (!has_per_pixel_blending)
+                       state->per_pixel_alpha = DROP_ALPHA;
+               else
+                       state->per_pixel_alpha = NON_PRE_MULTIPLIED_ALPHA;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
 static void skylake_disable_primary_plane(struct drm_plane *primary,
                                          struct drm_crtc *crtc)
 {
@@ -11892,6 +11977,10 @@ int intel_plane_atomic_calc_changes(struct 
drm_crtc_state *crtc_state,
            !needs_scaling(old_plane_state))
                pipe_config->disable_lp_wm = true;

+       ret = intel_plane_state_check_blend(plane_state);
+       if (ret)
+               return ret;
+
        return 0;
 }

@@ -14095,6 +14184,9 @@ static struct drm_plane 
*intel_primary_plane_create(struct drm_device *dev,
        if (INTEL_INFO(dev)->gen >= 4)
                intel_create_rotation_property(dev, primary);

+       if (INTEL_INFO(dev)->gen == 9)
+               intel_plane_add_blend_properties(primary);
+
        drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs);

        return &primary->base;
@@ -14124,6 +14216,20 @@ void intel_create_rotation_property(struct drm_device 
*dev, struct intel_plane *
                                plane->base.state->rotation);
 }

+void intel_plane_add_blend_properties(struct intel_plane *plane)
+{
+       struct drm_device *dev = plane->base.dev;
+       struct drm_property *prop;
+
+       if (INTEL_INFO(dev)->gen < 9)
+               return;
+
+       prop = dev->mode_config.prop_blend_func;
+       if (prop)
+               drm_object_attach_property(&plane->base.base, prop,
+                                          DRM_BLEND_FUNC(AUTO, AUTO));
+}
+
 static int
 intel_check_cursor_plane(struct drm_plane *plane,
                         struct intel_crtc_state *crtc_state,
@@ -14166,6 +14272,9 @@ intel_check_cursor_plane(struct drm_plane *plane,
                return -EINVAL;
        }

+       if (INTEL_INFO(plane->dev)->gen == 9)
+               intel_plane_add_blend_properties(to_intel_plane(plane));
+
        /*
         * There's something wrong with the cursor on CHV pipe C.
         * If it straddles the left edge of the screen then
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index e13ce22..1939440 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -303,6 +303,12 @@ struct intel_atomic_state {
        bool skip_intermediate_wm;
 };

+enum per_pixel_alpha_state {
+       DROP_ALPHA = 0,
+       PRE_MULTIPLIED_ALPHA,
+       NON_PRE_MULTIPLIED_ALPHA,
+};
+
 struct intel_plane_state {
        struct drm_plane_state base;
        struct drm_rect src;
@@ -332,6 +338,9 @@ struct intel_plane_state {

        struct drm_intel_sprite_colorkey ckey;

+       /* per pixel alpha channel state */
+       enum per_pixel_alpha_state per_pixel_alpha;
+
        /* async flip related structures */
        struct drm_i915_gem_request *wait_req;
 };
@@ -1195,6 +1204,7 @@ intel_rotation_90_or_270(unsigned int rotation)

 void intel_create_rotation_property(struct drm_device *dev,
                                        struct intel_plane *plane);
+void intel_plane_add_blend_properties(struct intel_plane *plane);

 void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
                                    enum pipe pipe);
@@ -1267,7 +1277,9 @@ u32 intel_plane_obj_offset(struct intel_plane 
*intel_plane,
                           struct drm_i915_gem_object *obj,
                           unsigned int plane);

-u32 skl_plane_ctl_format(uint32_t pixel_format);
+u32 skl_plane_ctl_format(uint32_t pixel_format,
+                               enum per_pixel_alpha_state alpha);
+
 u32 skl_plane_ctl_tiling(uint64_t fb_modifier);
 u32 skl_plane_ctl_rotation(unsigned int rotation);

diff --git a/drivers/gpu/drm/i915/intel_sprite.c 
b/drivers/gpu/drm/i915/intel_sprite.c
index 0f3e230..9474b76 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -210,7 +210,9 @@ skl_update_plane(struct drm_plane *drm_plane,
                PLANE_CTL_PIPE_GAMMA_ENABLE |
                PLANE_CTL_PIPE_CSC_ENABLE;

-       plane_ctl |= skl_plane_ctl_format(fb->pixel_format);
+       plane_ctl |= skl_plane_ctl_format(fb->pixel_format,
+                                       plane_state->per_pixel_alpha);
+
        plane_ctl |= skl_plane_ctl_tiling(fb->modifier[0]);

        plane_ctl |= skl_plane_ctl_rotation(rotation);
@@ -1120,6 +1122,8 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, 
int plane)

        intel_create_rotation_property(dev, intel_plane);

+       intel_plane_add_blend_properties(intel_plane);
+
        drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs);

        return 0;
-- 
1.9.1

Reply via email to