Commit b2081525 authored by Maarten Lankhorst's avatar Maarten Lankhorst

drm/i915: Add plane alpha blending support, v2.

Add plane alpha blending support with the different blend modes.
This has been tested on a icl to show the correct results,
on earlier platforms small rounding errors cause issues. But this
already happens case with fully transparant or fully opaque RGB8888
fb's.

The recommended HW workaround is to disable alpha blending when the
plane alpha is 0 (transparant, hide plane) or 0xff (opaque, disable blending).
This is easy to implement on any platform, so just do that.

The tests for userspace are also available, and pass on gen11.

Changes since v1:
- Change mistaken < 0xff0 to 0xff00.
- Only set PLANE_KEYMSK_ALPHA_ENABLE when plane alpha < 0xff00, ignore blend mode.
- Rework disabling FBC when per pixel alpha is used.
Signed-off-by: default avatarMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
[mlankhorst: Change MISSING_CASE default to explicit alpha disable (mattrope)]
Link: https://patchwork.freedesktop.org/patch/msgid/20180815103405.22679-1-maarten.lankhorst@linux.intel.comReviewed-by: default avatarMatt Roper <matthew.d.roper@intel.com>
parent 7569bf95
...@@ -548,6 +548,8 @@ struct intel_fbc { ...@@ -548,6 +548,8 @@ struct intel_fbc {
int adjusted_y; int adjusted_y;
int y; int y;
uint16_t pixel_blend_mode;
} plane; } plane;
struct { struct {
......
...@@ -6554,8 +6554,10 @@ enum { ...@@ -6554,8 +6554,10 @@ enum {
#define _PLANE_KEYVAL_2_A 0x70294 #define _PLANE_KEYVAL_2_A 0x70294
#define _PLANE_KEYMSK_1_A 0x70198 #define _PLANE_KEYMSK_1_A 0x70198
#define _PLANE_KEYMSK_2_A 0x70298 #define _PLANE_KEYMSK_2_A 0x70298
#define PLANE_KEYMSK_ALPHA_ENABLE (1 << 31)
#define _PLANE_KEYMAX_1_A 0x701a0 #define _PLANE_KEYMAX_1_A 0x701a0
#define _PLANE_KEYMAX_2_A 0x702a0 #define _PLANE_KEYMAX_2_A 0x702a0
#define PLANE_KEYMAX_ALPHA_SHIFT 24
#define _PLANE_AUX_DIST_1_A 0x701c0 #define _PLANE_AUX_DIST_1_A 0x701c0
#define _PLANE_AUX_DIST_2_A 0x702c0 #define _PLANE_AUX_DIST_2_A 0x702c0
#define _PLANE_AUX_OFFSET_1_A 0x701c4 #define _PLANE_AUX_OFFSET_1_A 0x701c4
......
...@@ -3155,6 +3155,10 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state) ...@@ -3155,6 +3155,10 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
if (ret) if (ret)
return ret; return ret;
/* HW only has 8 bits pixel precision, disable plane if invisible */
if (!(plane_state->base.alpha >> 8))
plane_state->base.visible = false;
if (!plane_state->base.visible) if (!plane_state->base.visible)
return 0; return 0;
...@@ -3568,29 +3572,38 @@ static u32 skl_plane_ctl_format(uint32_t pixel_format) ...@@ -3568,29 +3572,38 @@ static u32 skl_plane_ctl_format(uint32_t pixel_format)
return 0; return 0;
} }
/* static u32 skl_plane_ctl_alpha(const struct intel_plane_state *plane_state)
* XXX: For ARBG/ABGR formats we default to expecting scanout buffers
* to be already pre-multiplied. We need to add a knob (or a different
* DRM_FORMAT) for user-space to configure that.
*/
static u32 skl_plane_ctl_alpha(uint32_t pixel_format)
{ {
switch (pixel_format) { if (!plane_state->base.fb->format->has_alpha)
case DRM_FORMAT_ABGR8888: return PLANE_CTL_ALPHA_DISABLE;
case DRM_FORMAT_ARGB8888:
switch (plane_state->base.pixel_blend_mode) {
case DRM_MODE_BLEND_PIXEL_NONE:
return PLANE_CTL_ALPHA_DISABLE;
case DRM_MODE_BLEND_PREMULTI:
return PLANE_CTL_ALPHA_SW_PREMULTIPLY; return PLANE_CTL_ALPHA_SW_PREMULTIPLY;
case DRM_MODE_BLEND_COVERAGE:
return PLANE_CTL_ALPHA_HW_PREMULTIPLY;
default: default:
MISSING_CASE(plane_state->base.pixel_blend_mode);
return PLANE_CTL_ALPHA_DISABLE; return PLANE_CTL_ALPHA_DISABLE;
} }
} }
static u32 glk_plane_color_ctl_alpha(uint32_t pixel_format) static u32 glk_plane_color_ctl_alpha(const struct intel_plane_state *plane_state)
{ {
switch (pixel_format) { if (!plane_state->base.fb->format->has_alpha)
case DRM_FORMAT_ABGR8888: return PLANE_COLOR_ALPHA_DISABLE;
case DRM_FORMAT_ARGB8888:
switch (plane_state->base.pixel_blend_mode) {
case DRM_MODE_BLEND_PIXEL_NONE:
return PLANE_COLOR_ALPHA_DISABLE;
case DRM_MODE_BLEND_PREMULTI:
return PLANE_COLOR_ALPHA_SW_PREMULTIPLY; return PLANE_COLOR_ALPHA_SW_PREMULTIPLY;
case DRM_MODE_BLEND_COVERAGE:
return PLANE_COLOR_ALPHA_HW_PREMULTIPLY;
default: default:
MISSING_CASE(plane_state->base.pixel_blend_mode);
return PLANE_COLOR_ALPHA_DISABLE; return PLANE_COLOR_ALPHA_DISABLE;
} }
} }
...@@ -3667,7 +3680,7 @@ u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state, ...@@ -3667,7 +3680,7 @@ u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
plane_ctl = PLANE_CTL_ENABLE; plane_ctl = PLANE_CTL_ENABLE;
if (INTEL_GEN(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv)) { if (INTEL_GEN(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv)) {
plane_ctl |= skl_plane_ctl_alpha(fb->format->format); plane_ctl |= skl_plane_ctl_alpha(plane_state);
plane_ctl |= plane_ctl |=
PLANE_CTL_PIPE_GAMMA_ENABLE | PLANE_CTL_PIPE_GAMMA_ENABLE |
PLANE_CTL_PIPE_CSC_ENABLE | PLANE_CTL_PIPE_CSC_ENABLE |
...@@ -3709,7 +3722,7 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, ...@@ -3709,7 +3722,7 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
plane_color_ctl |= PLANE_COLOR_PIPE_CSC_ENABLE; plane_color_ctl |= PLANE_COLOR_PIPE_CSC_ENABLE;
} }
plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE; plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE;
plane_color_ctl |= glk_plane_color_ctl_alpha(fb->format->format); plane_color_ctl |= glk_plane_color_ctl_alpha(plane_state);
if (fb->format->is_yuv) { if (fb->format->is_yuv) {
if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709)
...@@ -13863,7 +13876,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) ...@@ -13863,7 +13876,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
DRM_MODE_ROTATE_0, DRM_MODE_ROTATE_0,
supported_rotations); supported_rotations);
if (INTEL_GEN(dev_priv) >= 9) if (INTEL_GEN(dev_priv) >= 9) {
drm_plane_create_color_properties(&primary->base, drm_plane_create_color_properties(&primary->base,
BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT601) |
BIT(DRM_COLOR_YCBCR_BT709), BIT(DRM_COLOR_YCBCR_BT709),
...@@ -13872,6 +13885,13 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) ...@@ -13872,6 +13885,13 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_BT709,
DRM_COLOR_YCBCR_LIMITED_RANGE); DRM_COLOR_YCBCR_LIMITED_RANGE);
drm_plane_create_alpha_property(&primary->base);
drm_plane_create_blend_mode_property(&primary->base,
BIT(DRM_MODE_BLEND_PIXEL_NONE) |
BIT(DRM_MODE_BLEND_PREMULTI) |
BIT(DRM_MODE_BLEND_COVERAGE));
}
drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs); drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs);
return primary; return primary;
......
...@@ -674,6 +674,8 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc, ...@@ -674,6 +674,8 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc,
cache->plane.adjusted_y = plane_state->color_plane[0].y; cache->plane.adjusted_y = plane_state->color_plane[0].y;
cache->plane.y = plane_state->base.src.y1 >> 16; cache->plane.y = plane_state->base.src.y1 >> 16;
cache->plane.pixel_blend_mode = plane_state->base.pixel_blend_mode;
if (!cache->plane.visible) if (!cache->plane.visible)
return; return;
...@@ -748,6 +750,12 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc) ...@@ -748,6 +750,12 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
return false; return false;
} }
if (cache->plane.pixel_blend_mode != DRM_MODE_BLEND_PIXEL_NONE &&
cache->fb.format->has_alpha) {
fbc->no_fbc_reason = "per-pixel alpha blending is incompatible with FBC";
return false;
}
/* WaFbcExceedCdClockThreshold:hsw,bdw */ /* WaFbcExceedCdClockThreshold:hsw,bdw */
if ((IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) && if ((IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) &&
cache->crtc.hsw_bdw_pixel_rate >= dev_priv->cdclk.hw.cdclk * 95 / 100) { cache->crtc.hsw_bdw_pixel_rate >= dev_priv->cdclk.hw.cdclk * 95 / 100) {
......
...@@ -380,6 +380,7 @@ skl_update_plane(struct intel_plane *plane, ...@@ -380,6 +380,7 @@ skl_update_plane(struct intel_plane *plane,
uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16; uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16; uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
unsigned long irqflags; unsigned long irqflags;
u32 keymsk = 0, keymax = 0;
/* Sizes are 0 based */ /* Sizes are 0 based */
src_w--; src_w--;
...@@ -393,10 +394,19 @@ skl_update_plane(struct intel_plane *plane, ...@@ -393,10 +394,19 @@ skl_update_plane(struct intel_plane *plane,
if (key->flags) { if (key->flags) {
I915_WRITE_FW(PLANE_KEYVAL(pipe, plane_id), key->min_value); I915_WRITE_FW(PLANE_KEYVAL(pipe, plane_id), key->min_value);
I915_WRITE_FW(PLANE_KEYMAX(pipe, plane_id), key->max_value);
I915_WRITE_FW(PLANE_KEYMSK(pipe, plane_id), key->channel_mask); keymax |= key->max_value & 0xffffff;
keymsk |= key->channel_mask & 0x3ffffff;
} }
keymax |= (plane_state->base.alpha >> 8) << PLANE_KEYMAX_ALPHA_SHIFT;
if (plane_state->base.alpha < 0xff00)
keymsk |= PLANE_KEYMSK_ALPHA_ENABLE;
I915_WRITE_FW(PLANE_KEYMAX(pipe, plane_id), keymax);
I915_WRITE_FW(PLANE_KEYMSK(pipe, plane_id), keymsk);
I915_WRITE_FW(PLANE_OFFSET(pipe, plane_id), (y << 16) | x); I915_WRITE_FW(PLANE_OFFSET(pipe, plane_id), (y << 16) | x);
I915_WRITE_FW(PLANE_STRIDE(pipe, plane_id), stride); I915_WRITE_FW(PLANE_STRIDE(pipe, plane_id), stride);
I915_WRITE_FW(PLANE_SIZE(pipe, plane_id), (src_h << 16) | src_w); I915_WRITE_FW(PLANE_SIZE(pipe, plane_id), (src_h << 16) | src_w);
...@@ -1916,6 +1926,15 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, ...@@ -1916,6 +1926,15 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_BT709,
DRM_COLOR_YCBCR_LIMITED_RANGE); DRM_COLOR_YCBCR_LIMITED_RANGE);
if (INTEL_GEN(dev_priv) >= 9) {
drm_plane_create_alpha_property(&intel_plane->base);
drm_plane_create_blend_mode_property(&intel_plane->base,
BIT(DRM_MODE_BLEND_PIXEL_NONE) |
BIT(DRM_MODE_BLEND_PREMULTI) |
BIT(DRM_MODE_BLEND_COVERAGE));
}
drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs); drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs);
return intel_plane; return intel_plane;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment