Skip to contentSkip to conversation

drm/tegra: dc: Implement legacy blending

PATCH In review Thierry Reding 2 participants 4 messages Dec 21, 2017 3 messages not in the archive

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 drm/tegra: dc: Implement legacy blending

From: Thierry Reding <[email protected]>

This implements alpha blending on legacy display controllers (Tegra20, Tegra30 and Tegra114). While it's theoretically possible to support the zpos property to enable userspace to specify the Z-order of each plane individually, this is not currently supported and the same fixed Z- order as previously defined is used.

Reverts commit 71835caa00e8 ("drm/tegra: fb: Force alpha formats") since the opaque formats are now supported.

Fixes 7772fdaef939 ("drm/tegra: Support ARGB and ABGR formats")

---
Changes in v2:
- properly implement blending if windows have different pixel formats

 drivers/gpu/drm/tegra/dc.c    |  81 +++++++++++++++++++++----
 drivers/gpu/drm/tegra/dc.h    |  12 ++++
 drivers/gpu/drm/tegra/fb.c    |  12 ----
 drivers/gpu/drm/tegra/plane.c | 138 ++++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/tegra/plane.h |   8 +++
 5 files changed, 226 insertions(+), 25 deletions(-)
drivers/gpu/drm/tegra/dc.c +68 -13
index 2a0c1e93f82e..4507063029e0 100644
@@ -154,30 +154,53 @@ static inline u32 compute_initial_dda(unsigned int in)
 
 static void tegra_plane_setup_blending_legacy(struct tegra_plane *plane)
 {
+	u32 background[3] = {
+		BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE,
+		BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE,
+		BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE,
+	};
+	u32 foreground = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255) |
+			 BLEND_COLOR_KEY_NONE;
+	u32 blendnokey = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255);
+	struct tegra_plane_state *state;
+	unsigned int i;
+
+	state = to_tegra_plane_state(plane->base.state);
+
+	/* alpha contribution is 1 minus sum of overlapping windows */
+	for (i = 0; i < 3; i++) {
+		if (state->dependent[i])
+			background[i] |= BLEND_CONTROL_DEPENDENT;
+	}
+
+	/* enable alpha blending if pixel format has an alpha component */
+	if (!state->opaque)
+		foreground |= BLEND_CONTROL_ALPHA;
+
 	/*
 	 * Disable blending and assume Window A is the bottom-most window,
 	 * Window C is the top-most window and Window B is in the middle.
 	 */
-	tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_NOKEY);
-	tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_1WIN);
+	tegra_plane_writel(plane, blendnokey, DC_WIN_BLEND_NOKEY);
+	tegra_plane_writel(plane, foreground, DC_WIN_BLEND_1WIN);
 
 	switch (plane->index) {
 	case 0:
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_X);
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_Y);
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_3WIN_XY);
+		tegra_plane_writel(plane, background[0], DC_WIN_BLEND_2WIN_X);
+		tegra_plane_writel(plane, background[1], DC_WIN_BLEND_2WIN_Y);
+		tegra_plane_writel(plane, background[2], DC_WIN_BLEND_3WIN_XY);
 		break;
 
 	case 1:
-		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_X);
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_Y);
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_3WIN_XY);
+		tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_X);
+		tegra_plane_writel(plane, background[1], DC_WIN_BLEND_2WIN_Y);
+		tegra_plane_writel(plane, background[2], DC_WIN_BLEND_3WIN_XY);
 		break;
 
 	case 2:
-		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_X);
-		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_Y);
-		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_3WIN_XY);
+		tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_X);
+		tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_Y);
+		tegra_plane_writel(plane, foreground, DC_WIN_BLEND_3WIN_XY);
 		break;
 	}
 }
@@ -353,6 +376,11 @@ static const u32 tegra20_primary_formats[] = {
 	DRM_FORMAT_RGBA5551,
 	DRM_FORMAT_ABGR8888,
 	DRM_FORMAT_ARGB8888,
+	/* non-native formats */
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_RGBX5551,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_XRGB8888,
 };
 
 static const u32 tegra114_primary_formats[] = {
@@ -409,18 +437,40 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
 	struct tegra_bo_tiling *tiling = &plane_state->tiling;
 	struct tegra_plane *tegra = to_tegra_plane(plane);
 	struct tegra_dc *dc = to_tegra_dc(state->crtc);
+	unsigned int format;
 	int err;
 
 	/* no need for further checks if the plane is being disabled */
 	if (!state->crtc)
 		return 0;
 
-	err = tegra_plane_format(state->fb->format->format,
-				 &plane_state->format,
+	err = tegra_plane_format(state->fb->format->format, &format,
 				 &plane_state->swap);
 	if (err < 0)
 		return err;
 
+	/*
+	 * Tegra20 and Tegra30 are special cases here because they support
+	 * only variants of specific formats with an alpha component, but not
+	 * the corresponding opaque formats. However, the opaque formats can
+	 * be emulated by disabling alpha blending for the plane.
+	 */
+	if (!dc->soc->supports_blending) {
+		if (!tegra_plane_format_has_alpha(format)) {
+			err = tegra_plane_format_get_alpha(format, &format);
+			if (err < 0)
+				return err;
+
+			plane_state->opaque = true;
+		} else {
+			plane_state->opaque = false;
+		}
+
+		tegra_plane_check_dependent(tegra, plane_state);
+	}
+
+	plane_state->format = format;
+
 	err = tegra_fb_get_tiling(state->fb, tiling);
 	if (err < 0)
 		return err;
@@ -737,6 +787,11 @@ static const u32 tegra20_overlay_formats[] = {
 	DRM_FORMAT_RGBA5551,
 	DRM_FORMAT_ABGR8888,
 	DRM_FORMAT_ARGB8888,
+	/* non-native formats */
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_RGBX5551,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_XRGB8888,
 	/* planar formats */
 	DRM_FORMAT_UYVY,
 	DRM_FORMAT_YUYV,
drivers/gpu/drm/tegra/dc.h +12 -0
index e2831e96ea96..096a81ad6d8d 100644
@@ -649,8 +649,20 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
 #define DC_WIN_DV_CONTROL			0x70e
 
 #define DC_WIN_BLEND_NOKEY			0x70f
+#define  BLEND_WEIGHT1(x) (((x) & 0xff) << 16)
+#define  BLEND_WEIGHT0(x) (((x) & 0xff) <<  8)
+
 #define DC_WIN_BLEND_1WIN			0x710
+#define  BLEND_CONTROL_FIX    (0 << 2)
+#define  BLEND_CONTROL_ALPHA  (1 << 2)
+#define  BLEND_COLOR_KEY_NONE (0 << 0)
+#define  BLEND_COLOR_KEY_0    (1 << 0)
+#define  BLEND_COLOR_KEY_1    (2 << 0)
+#define  BLEND_COLOR_KEY_BOTH (3 << 0)
+
 #define DC_WIN_BLEND_2WIN_X			0x711
+#define  BLEND_CONTROL_DEPENDENT (2 << 2)
+
 #define DC_WIN_BLEND_2WIN_Y			0x712
 #define DC_WIN_BLEND_3WIN_XY			0x713
 
drivers/gpu/drm/tegra/fb.c +0 -12
index 1af4ef9241f1..e05fde7172f8 100644
@@ -254,18 +254,6 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
 	cmd.pitches[0] = round_up(sizes->surface_width * bytes_per_pixel,
 				  tegra->pitch_align);
 
-	/*
-	 * Early generations of Tegra (Tegra20 and Tegra30) do not support any
-	 * of the X* or *X formats, only their A* or *A equivalents. Force the
-	 * legacy framebuffer format to include an alpha component so that the
-	 * framebuffer emulation can be supported on all generations.
-	 */
-	if (sizes->surface_bpp == 32 && sizes->surface_depth == 24)
-		sizes->surface_depth = 32;
-
-	if (sizes->surface_bpp == 16 && sizes->surface_depth == 15)
-		sizes->surface_depth = 16;
-
 	cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
 						     sizes->surface_depth);
 
drivers/gpu/drm/tegra/plane.c +138 -0

153 lines not on this page · raw message

drivers/gpu/drm/tegra/plane.h +8 -0
index dca66cb95d25..6938719e7e5d 100644
@@ -40,6 +40,10 @@ struct tegra_plane_state {
 	struct tegra_bo_tiling tiling;
 	u32 format;
 	u32 swap;
+
+	/* used for legacy blending support only */
+	bool opaque;
+	bool dependent[3];
 };
 
 static inline struct tegra_plane_state *
@@ -58,5 +62,9 @@ int tegra_plane_state_add(struct tegra_plane *plane,
 
 int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap);
 bool tegra_plane_format_is_yuv(unsigned int format, bool *planar);
+bool tegra_plane_format_has_alpha(unsigned int format);
+int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha);
+void tegra_plane_check_dependent(struct tegra_plane *tegra,
+				 struct tegra_plane_state *state);
 
 #endif /* TEGRA_PLANE_H */
Signature · 1 line
2.15.1

A message that is not in the archive (sent off-list or not yet received): 20171221140317.18447-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org

#2 lore raw
Quoted 234 lines · Thierry Reding

From: Thierry Reding <[email protected]>

This implements alpha blending on legacy display controllers (Tegra20, Tegra30 and Tegra114). While it's theoretically possible to support the zpos property to enable userspace to specify the Z-order of each plane individually, this is not currently supported and the same fixed Z- order as previously defined is used.

Reverts commit 71835caa00e8 ("drm/tegra: fb: Force alpha formats") since the opaque formats are now supported.

Fixes 7772fdaef939 ("drm/tegra: Support ARGB and ABGR formats")

---
Changes in v2:
- properly implement blending if windows have different pixel formats

 drivers/gpu/drm/tegra/dc.c    |  81 +++++++++++++++++++++----
 drivers/gpu/drm/tegra/dc.h    |  12 ++++
 drivers/gpu/drm/tegra/fb.c    |  12 ----
 drivers/gpu/drm/tegra/plane.c | 138 ++++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/tegra/plane.h |   8 +++
 5 files changed, 226 insertions(+), 25 deletions(-)
drivers/gpu/drm/tegra/dc.c +68 -13
index 2a0c1e93f82e..4507063029e0 100644
@@ -154,30 +154,53 @@ static inline u32 compute_initial_dda(unsigned int in)
 
 static void tegra_plane_setup_blending_legacy(struct tegra_plane *plane)
 {
+	u32 background[3] = {
+		BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE,
+		BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE,
+		BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE,
+	};
+	u32 foreground = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255) |
+			 BLEND_COLOR_KEY_NONE;
+	u32 blendnokey = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255);
+	struct tegra_plane_state *state;
+	unsigned int i;
+
+	state = to_tegra_plane_state(plane->base.state);
+
+	/* alpha contribution is 1 minus sum of overlapping windows */
+	for (i = 0; i < 3; i++) {
+		if (state->dependent[i])
+			background[i] |= BLEND_CONTROL_DEPENDENT;
+	}
+
+	/* enable alpha blending if pixel format has an alpha component */
+	if (!state->opaque)
+		foreground |= BLEND_CONTROL_ALPHA;
+
 	/*
 	 * Disable blending and assume Window A is the bottom-most window,
 	 * Window C is the top-most window and Window B is in the middle.
 	 */
-	tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_NOKEY);
-	tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_1WIN);
+	tegra_plane_writel(plane, blendnokey, DC_WIN_BLEND_NOKEY);
+	tegra_plane_writel(plane, foreground, DC_WIN_BLEND_1WIN);
 
 	switch (plane->index) {
 	case 0:
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_X);
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_Y);
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_3WIN_XY);
+		tegra_plane_writel(plane, background[0], DC_WIN_BLEND_2WIN_X);
+		tegra_plane_writel(plane, background[1], DC_WIN_BLEND_2WIN_Y);
+		tegra_plane_writel(plane, background[2], DC_WIN_BLEND_3WIN_XY);
 		break;
 
 	case 1:
-		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_X);
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_Y);
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_3WIN_XY);
+		tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_X);
+		tegra_plane_writel(plane, background[1], DC_WIN_BLEND_2WIN_Y);
+		tegra_plane_writel(plane, background[2], DC_WIN_BLEND_3WIN_XY);
 		break;
 
 	case 2:
-		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_X);
-		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_Y);
-		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_3WIN_XY);
+		tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_X);
+		tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_Y);
+		tegra_plane_writel(plane, foreground, DC_WIN_BLEND_3WIN_XY);
 		break;
 	}
 }
@@ -353,6 +376,11 @@ static const u32 tegra20_primary_formats[] = {
 	DRM_FORMAT_RGBA5551,
 	DRM_FORMAT_ABGR8888,
 	DRM_FORMAT_ARGB8888,
+	/* non-native formats */
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_RGBX5551,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_XRGB8888,
 };
 
 static const u32 tegra114_primary_formats[] = {
@@ -409,18 +437,40 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
 	struct tegra_bo_tiling *tiling = &plane_state->tiling;
 	struct tegra_plane *tegra = to_tegra_plane(plane);
 	struct tegra_dc *dc = to_tegra_dc(state->crtc);
+	unsigned int format;
 	int err;
 
 	/* no need for further checks if the plane is being disabled */
 	if (!state->crtc)
 		return 0;
 
-	err = tegra_plane_format(state->fb->format->format,
-				 &plane_state->format,
+	err = tegra_plane_format(state->fb->format->format, &format,
 				 &plane_state->swap);
 	if (err < 0)
 		return err;
 
+	/*
+	 * Tegra20 and Tegra30 are special cases here because they support
+	 * only variants of specific formats with an alpha component, but not
+	 * the corresponding opaque formats. However, the opaque formats can
+	 * be emulated by disabling alpha blending for the plane.
+	 */
+	if (!dc->soc->supports_blending) {
+		if (!tegra_plane_format_has_alpha(format)) {
+			err = tegra_plane_format_get_alpha(format, &format);
+			if (err < 0)
+				return err;
+
+			plane_state->opaque = true;
+		} else {
+			plane_state->opaque = false;
+		}
+
+		tegra_plane_check_dependent(tegra, plane_state);
+	}
+
+	plane_state->format = format;
+
 	err = tegra_fb_get_tiling(state->fb, tiling);
 	if (err < 0)
 		return err;
@@ -737,6 +787,11 @@ static const u32 tegra20_overlay_formats[] = {
 	DRM_FORMAT_RGBA5551,
 	DRM_FORMAT_ABGR8888,
 	DRM_FORMAT_ARGB8888,
+	/* non-native formats */
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_RGBX5551,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_XRGB8888,
 	/* planar formats */
 	DRM_FORMAT_UYVY,
 	DRM_FORMAT_YUYV,
drivers/gpu/drm/tegra/dc.h +12 -0
index e2831e96ea96..096a81ad6d8d 100644
@@ -649,8 +649,20 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
 #define DC_WIN_DV_CONTROL			0x70e
 
 #define DC_WIN_BLEND_NOKEY			0x70f
+#define  BLEND_WEIGHT1(x) (((x) & 0xff) << 16)
+#define  BLEND_WEIGHT0(x) (((x) & 0xff) <<  8)
+
 #define DC_WIN_BLEND_1WIN			0x710
+#define  BLEND_CONTROL_FIX    (0 << 2)
+#define  BLEND_CONTROL_ALPHA  (1 << 2)
+#define  BLEND_COLOR_KEY_NONE (0 << 0)
+#define  BLEND_COLOR_KEY_0    (1 << 0)
+#define  BLEND_COLOR_KEY_1    (2 << 0)
+#define  BLEND_COLOR_KEY_BOTH (3 << 0)
+
 #define DC_WIN_BLEND_2WIN_X			0x711
+#define  BLEND_CONTROL_DEPENDENT (2 << 2)
+
 #define DC_WIN_BLEND_2WIN_Y			0x712
 #define DC_WIN_BLEND_3WIN_XY			0x713
 
drivers/gpu/drm/tegra/fb.c +0 -12
index 1af4ef9241f1..e05fde7172f8 100644
@@ -254,18 +254,6 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
 	cmd.pitches[0] = round_up(sizes->surface_width * bytes_per_pixel,
 				  tegra->pitch_align);
 
-	/*
-	 * Early generations of Tegra (Tegra20 and Tegra30) do not support any
-	 * of the X* or *X formats, only their A* or *A equivalents. Force the
-	 * legacy framebuffer format to include an alpha component so that the
-	 * framebuffer emulation can be supported on all generations.
-	 */
-	if (sizes->surface_bpp == 32 && sizes->surface_depth == 24)
-		sizes->surface_depth = 32;
-
-	if (sizes->surface_bpp == 16 && sizes->surface_depth == 15)
-		sizes->surface_depth = 16;
-
 	cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
 						     sizes->surface_depth);
 
drivers/gpu/drm/tegra/plane.c +5 -0
index 9146aead973b..154b4d337d0a 100644
@@ -43,6 +43,7 @@ tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
 {
 	struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
 	struct tegra_plane_state *copy;
+	unsigned int i;
 
 	copy = kmalloc(sizeof(*copy), GFP_KERNEL);
 	if (!copy)
@@ -52,6 +53,10 @@ tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
 	copy->tiling = state->tiling;
 	copy->format = state->format;
 	copy->swap = state->swap;
+	copy->opaque = state->opaque;
+
+	for (i = 0; i < 3; i++)
+		copy->dependent[i] = state->dependent[i];
 
 	return &copy->base;
 }
@@ -238,3 +243,136 @@ bool tegra_plane_format_is_yuv(unsigned int format, bool *planar)
 

drivers/gpu/drm/tegra/plane.c bool tegra_plane_format_is_yuv(unsigned int format, bool *planar) · line 253

Quoted 10 lines
drivers/gpu/drm/tegra/plane.c +8 -0
 	return false;
 }
+
+static bool __drm_format_has_alpha(u32 format)
+{
+	switch (format) {
+	case DRM_FORMAT_ARGB1555:
+	case DRM_FORMAT_RGBA5551:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_ARGB8888:

DRM_FORMAT_ARGB4444 missing here?

Quoted 7 lines
drivers/gpu/drm/tegra/plane.c +7 -0
+		return true;
+	}
+
+	return false;
+}
+
+/*

drivers/gpu/drm/tegra/plane.c bool tegra_plane_format_is_yuv(unsigned int format, bool *planar) · line 270

Quoted 10 lines
drivers/gpu/drm/tegra/plane.c +10 -0
+ * This is applicable to Tegra20 and Tegra30 only where the opaque formats can
+ * be emulated using the alpha formats and alpha blending disabled.
+ */
+bool tegra_plane_format_has_alpha(unsigned int format)
+{
+	switch (format) {
+	case WIN_COLOR_DEPTH_B5G5R5A1:
+	case WIN_COLOR_DEPTH_A1B5G5R5:
+	case WIN_COLOR_DEPTH_R8G8B8A8:
+	case WIN_COLOR_DEPTH_B8G8R8A8:

WIN_COLOR_DEPTH_B4G4R4A4 missing here?

Quoted 54 lines
drivers/gpu/drm/tegra/plane.c +54 -0
+		return true;
+	}
+
+	return false;
+}
+
+int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha)
+{
+	switch (opaque) {
+	case WIN_COLOR_DEPTH_B5G5R5X1:
+		*alpha = WIN_COLOR_DEPTH_B5G5R5A1;
+		return 0;
+
+	case WIN_COLOR_DEPTH_X1B5G5R5:
+		*alpha = WIN_COLOR_DEPTH_A1B5G5R5;
+		return 0;
+
+	case WIN_COLOR_DEPTH_R8G8B8X8:
+		*alpha = WIN_COLOR_DEPTH_R8G8B8A8;
+		return 0;
+
+	case WIN_COLOR_DEPTH_B8G8R8X8:
+		*alpha = WIN_COLOR_DEPTH_B8G8R8A8;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane,
+					   struct tegra_plane *other)
+{
+	unsigned int index = 0, i;
+
+	WARN_ON(plane == other);
+
+	for (i = 0; i < 3; i++) {
+		if (i == plane->index)
+			continue;
+
+		if (i == other->index)
+			break;
+
+		index++;
+	}
+
+	return index;
+}
+
+void tegra_plane_check_dependent(struct tegra_plane *tegra,
+				 struct tegra_plane_state *state)
+{
+	struct drm_plane_state *old, *new;
+	struct drm_plane *plane;

drivers/gpu/drm/tegra/plane.c bool tegra_plane_format_is_yuv(unsigned int format, bool *planar) · line 334

Quoted 10 lines
drivers/gpu/drm/tegra/plane.c +10 -0
+	unsigned int zpos[2];
+	unsigned int i;
+
+	for (i = 0; i < 3; i++)
+		state->dependent[i] = false;
+
+	for (i = 0; i < 2; i++)
+		zpos[i] = 0;
+
+	for_each_oldnew_plane_in_state(state->base.state, plane, old, new, i) {

Somehow this works when 2 windows are blended (primary plane + cursor). But unfortunately this doesn't work at all in a case when 3 windows blended (primary
+ video overlay + cursor), for some reason there is only one plane in the state here, so blending dependency tracking doesn't work at all. I'll continue to look into it, but for now I don't know why it doesn't work as expected. If you have any idea, please tell.

Quoted 34 lines
drivers/gpu/drm/tegra/plane.c +34 -0
+		struct tegra_plane *p = to_tegra_plane(plane);
+		unsigned index;
+
+		/* skip this plane and planes on different CRTCs */
+		if (p == tegra || new->crtc != state->base.crtc)
+			continue;
+
+		index = tegra_plane_get_overlap_index(tegra, p);
+
+		/*
+		 * If any of the other planes is on top of this plane and uses
+		 * a format with an alpha component, mark this plane as being
+		 * dependent, meaning it's alpha value will be 1 minus the sum
+		 * of alpha components of the overlapping planes.
+		 */
+		if (p->index > tegra->index) {
+			if (__drm_format_has_alpha(new->fb->format->format))
+				state->dependent[index] = true;
+
+			/* keep track of the Z position */
+			zpos[index] = p->index;
+		}
+	}
+
+	/*
+	 * The region where three windows overlap is the intersection of the
+	 * two regions where two windows overlap. It contributes to the area
+	 * if any of the windows on top of it have an alpha component.
+	 */
+	for (i = 0; i < 2; i++)
+		state->dependent[2] = state->dependent[2] ||
+				      state->dependent[i];
+
+	/*

drivers/gpu/drm/tegra/plane.c bool tegra_plane_format_is_yuv(unsigned int format, bool *planar) · line 378

Quoted 10 lines
drivers/gpu/drm/tegra/plane.c +10 -0
+	 * However, if any of the windows on top of this window is opaque, it
+	 * will completely conceal this window within that area, so avoid the
+	 * window from contributing to the area.
+	 */
+	for (i = 0; i < 2; i++) {
+		if (zpos[i] > tegra->index)
+			state->dependent[2] = state->dependent[2] &&
+					      state->dependent[i];
+	}
+}

The above is a bit difficult to follow, could we do something like this?

-unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane,
- struct tegra_plane *other)
+static unsigned int tegra_plane_get_dependent_index(struct tegra_plane *plane,
+ struct tegra_plane *other)
{
- unsigned int index = 0, i;
-

        WARN_ON(plane == other);

- for (i = 0; i < 3; i++) {
- if (i == plane->index)
- continue;
+ switch (plane->index) {
+ case 0:
+ return other->index - 1;

- if (i == other->index)
- break;
+ case 1:
+ return other->index ? 1 : 0;

- index++;
+ case 2:

+               return other->index;
        }

- return index;
+ return 0;
}

void tegra_plane_check_dependent(struct tegra_plane *tegra,
@@ -322,14 +323,13 @@ void tegra_plane_check_dependent(struct tegra_plane *tegra,

 {
        struct drm_plane_state *old, *new;
        struct drm_plane *plane;
-       unsigned int zpos[2];
+       bool opaque[3];
        unsigned int i;

- for (i = 0; i < 3; i++)

+       for (i = 0; i < 3; i++) {
                state->dependent[i] = false;

-
- for (i = 0; i < 2; i++)
- zpos[i] = 0;
+ opaque[i] = false;
+ }

        for_each_oldnew_plane_in_state(state->base.state, plane, old, new, i) {
                struct tegra_plane *p = to_tegra_plane(plane);
@@ -339,7 +339,7 @@ void tegra_plane_check_dependent(struct tegra_plane *tegra,
                if (p == tegra || new->crtc != state->base.crtc)
                        continue;

- index = tegra_plane_get_overlap_index(tegra, p);
+ index = tegra_plane_get_dependent_index(tegra, p);

/*
* If any of the other planes is on top of this plane and uses
@@ -350,9 +350,8 @@ void tegra_plane_check_dependent(struct tegra_plane *tegra,

                if (p->index > tegra->index) {
                        if (__drm_format_has_alpha(new->fb->format->format))
                                state->dependent[index] = true;
-
-                       /* keep track of the Z position */
-                       zpos[index] = p->index;
+                       else
+                               opaque[index] = true;
                }
        }

@@ -361,18 +360,16 @@ void tegra_plane_check_dependent(struct tegra_plane *tegra,
* two regions where two windows overlap. It contributes to the area
* if any of the windows on top of it have an alpha component. */
- for (i = 0; i < 2; i++)
- state->dependent[2] = state->dependent[2] ||
- state->dependent[i];
+ state->dependent[2] = state->dependent[0] || state->dependent[1];

/*
* However, if any of the windows on top of this window is opaque, it
* will completely conceal this window within that area, so avoid the
* window from contributing to the area.
*/
- for (i = 0; i < 2; i++) {
- if (zpos[i] > tegra->index)
- state->dependent[2] = state->dependent[2] &&
- state->dependent[i];
- }
+ if (tegra->index == 0 && (opaque[0] || opaque[1]))
+ state->dependent[2] = false;
+
+ if (tegra->index == 1 && opaque[1])
+ state->dependent[2] = false;
}

[snip]

A message that is not in the archive (sent off-list or not yet received): 3ccf0299-95d9-0c46-dd86-de16434b6e42-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org

#4 lore raw
Quoted 16 lines · Dmitry Osipenko
Quoted 15 lines · Thierry Reding

From: Thierry Reding <[email protected]>

This implements alpha blending on legacy display controllers (Tegra20, Tegra30 and Tegra114). While it's theoretically possible to support the zpos property to enable userspace to specify the Z-order of each plane individually, this is not currently supported and the same fixed Z- order as previously defined is used.

Reverts commit 71835caa00e8 ("drm/tegra: fb: Force alpha formats") since the opaque formats are now supported.

Fixes 7772fdaef939 ("drm/tegra: Support ARGB and ABGR formats")

---

[snip]

Quoted 15 lines
Quoted 15 lines
drivers/gpu/drm/tegra/plane.c +15 -0
+
+void tegra_plane_check_dependent(struct tegra_plane *tegra,
+				 struct tegra_plane_state *state)
+{
+	struct drm_plane_state *old, *new;
+	struct drm_plane *plane;
+	unsigned int zpos[2];
+	unsigned int i;
+
+	for (i = 0; i < 3; i++)
+		state->dependent[i] = false;
+
+	for (i = 0; i < 2; i++)
+		zpos[i] = 0;
+
Quoted 8 lines

drivers/gpu/drm/tegra/plane.c bool tegra_plane_format_is_yuv(unsigned int format, bool *planar) · line 334

Quoted 1 line
drivers/gpu/drm/tegra/plane.c +1 -0
+	for_each_oldnew_plane_in_state(state->base.state, plane, old, new, i) {

Somehow this works when 2 windows are blended (primary plane + cursor). But unfortunately this doesn't work at all in a case when 3 windows blended (primary
+ video overlay + cursor), for some reason there is only one plane in the state here, so blending dependency tracking doesn't work at all. I'll continue to look into it, but for now I don't know why it doesn't work as expected. If you have any idea, please tell.

Actually, I think this code only works when all planes are updated in a single commit. We need to handle cases when only some of the active planes are adjusting the state.

[snip]

A message that is not in the archive (sent off-list or not yet received): cffaa2f8-42f4-557f-1824-a42fdca54aaa-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org

#6 lore raw
Quoted 44 lines · Dmitry Osipenko
Quoted 16 lines · Dmitry Osipenko
Quoted 15 lines · Thierry Reding

From: Thierry Reding <[email protected]>

This implements alpha blending on legacy display controllers (Tegra20, Tegra30 and Tegra114). While it's theoretically possible to support the zpos property to enable userspace to specify the Z-order of each plane individually, this is not currently supported and the same fixed Z- order as previously defined is used.

Reverts commit 71835caa00e8 ("drm/tegra: fb: Force alpha formats") since the opaque formats are now supported.

Fixes 7772fdaef939 ("drm/tegra: Support ARGB and ABGR formats")

---

[snip]

Quoted 15 lines
Quoted 15 lines
(quoted diff) +15 -0
+
+void tegra_plane_check_dependent(struct tegra_plane *tegra,
+				 struct tegra_plane_state *state)
+{
+	struct drm_plane_state *old, *new;
+	struct drm_plane *plane;
+	unsigned int zpos[2];
+	unsigned int i;
+
+	for (i = 0; i < 3; i++)
+		state->dependent[i] = false;
+
+	for (i = 0; i < 2; i++)
+		zpos[i] = 0;
+
Quoted 8 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+	for_each_oldnew_plane_in_state(state->base.state, plane, old, new, i) {

Somehow this works when 2 windows are blended (primary plane + cursor). But unfortunately this doesn't work at all in a case when 3 windows blended (primary
+ video overlay + cursor), for some reason there is only one plane in the state here, so blending dependency tracking doesn't work at all. I'll continue to look into it, but for now I don't know why it doesn't work as expected. If you have any idea, please tell.

Quoted 6 lines

Actually, I think this code only works when all planes are updated in a single commit. We need to handle cases when only some of the active planes are adjusting the state.

[snip]

I've moved blending state to CRTC and now seems it is really working correctly. I tried to run kms-planes-blend on my Intel desktop, but it crashes my machine and so can't compare the result of the test, it looks correct though. Video overlay + mouse cursor now working fine.

I've amended your patch, see it below.

---------------------------------------

Quoted 1 line

From e5264125fb81757999f6b11fec0e7cfffb2ca6d6 Mon Sep 17 00:00:00 2001

From: Thierry Reding <[email protected]>
Date: Wed, 20 Dec 2017 09:39:14 +0100
Subject: [PATCH] drm/tegra: dc: Implement legacy blending

This implements alpha blending on legacy display controllers (Tegra20, Tegra30 and Tegra114). While it's theoretically possible to support the zpos property to enable userspace to specify the Z-order of each plane individually, this is not currently supported and the same fixed Z- order as previously defined is used.

Reverts commit 71835caa00e8 ("drm/tegra: fb: Force alpha formats") since the opaque formats are now supported.

Fixes 7772fdaef939 ("drm/tegra: Support ARGB and ABGR formats")
---
 drivers/gpu/drm/tegra/dc.c    |  90 ++++++++++++++++++--------
 drivers/gpu/drm/tegra/dc.h    |  21 ++++++
 drivers/gpu/drm/tegra/fb.c    |  12 ----
 drivers/gpu/drm/tegra/plane.c | 145 ++++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/tegra/plane.h |   4 ++
 5 files changed, 233 insertions(+), 39 deletions(-)
drivers/gpu/drm/tegra/dc.c +63 -27
index 2a0c1e93f82e..fb7c0d211ac0 100644
@@ -154,32 +154,12 @@ static inline u32 compute_initial_dda(unsigned int in)
 
 static void tegra_plane_setup_blending_legacy(struct tegra_plane *plane)
 {
-	/*
-	 * Disable blending and assume Window A is the bottom-most window,
-	 * Window C is the top-most window and Window B is in the middle.
-	 */
-	tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_NOKEY);
-	tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_1WIN);
-
-	switch (plane->index) {
-	case 0:
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_X);
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_Y);
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_3WIN_XY);
-		break;
-
-	case 1:
-		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_X);
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_Y);
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_3WIN_XY);
-		break;
+	u32 foreground = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255) |
+			 BLEND_COLOR_KEY_NONE;
+	u32 blendnokey = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255);
 
-	case 2:
-		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_X);
-		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_Y);
-		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_3WIN_XY);
-		break;
-	}
+	tegra_plane_writel(plane, blendnokey, DC_WIN_BLEND_NOKEY);
+	tegra_plane_writel(plane, foreground, DC_WIN_BLEND_1WIN);
 }
 
 static void tegra_plane_setup_blending(struct tegra_plane *plane,
@@ -353,6 +333,11 @@ static const u32 tegra20_primary_formats[] = {
 	DRM_FORMAT_RGBA5551,
 	DRM_FORMAT_ABGR8888,
 	DRM_FORMAT_ARGB8888,
+	/* non-native formats */
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_RGBX5551,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_XRGB8888,
 };
 
 static const u32 tegra114_primary_formats[] = {
@@ -409,18 +394,38 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
 	struct tegra_bo_tiling *tiling = &plane_state->tiling;
 	struct tegra_plane *tegra = to_tegra_plane(plane);
 	struct tegra_dc *dc = to_tegra_dc(state->crtc);
+	unsigned int format;
 	int err;
 
 	/* no need for further checks if the plane is being disabled */
 	if (!state->crtc)
 		return 0;
 
-	err = tegra_plane_format(state->fb->format->format,
-				 &plane_state->format,
+	err = tegra_plane_format(state->fb->format->format, &format,
 				 &plane_state->swap);
 	if (err < 0)
 		return err;
 
+	/*
+	 * Tegra20 and Tegra30 are special cases here because they support
+	 * only variants of specific formats with an alpha component, but not
+	 * the corresponding opaque formats. However, the opaque formats can
+	 * be emulated by disabling alpha blending for the plane.
+	 */
+	if (!dc->soc->supports_blending) {
+		if (!tegra_plane_format_has_alpha(format)) {
+			err = tegra_plane_format_get_alpha(format, &format);
+			if (err < 0)
+				return err;
+		}
+
+		err = tegra_plane_update_blending_state(tegra, plane_state);
+		if (err < 0)
+			return err;
+	}
+
+	plane_state->format = format;
+
 	err = tegra_fb_get_tiling(state->fb, tiling);
 	if (err < 0)
 		return err;
@@ -737,6 +742,11 @@ static const u32 tegra20_overlay_formats[] = {
 	DRM_FORMAT_RGBA5551,
 	DRM_FORMAT_ABGR8888,
 	DRM_FORMAT_ARGB8888,
+	/* non-native formats */
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_RGBX5551,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_XRGB8888,
 	/* planar formats */
 	DRM_FORMAT_UYVY,
 	DRM_FORMAT_YUYV,
@@ -924,6 +934,7 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
 {
 	struct tegra_dc_state *state = to_dc_state(crtc->state);
 	struct tegra_dc_state *copy;
+	unsigned int i;
 
 	copy = kmalloc(sizeof(*copy), GFP_KERNEL);
 	if (!copy)
@@ -935,6 +946,9 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
 	copy->div = state->div;
 	copy->planes = state->planes;
 
+	for (i = 0; i < 3; i++)
+		copy->blend[i] = state->blend[i];
+
 	return &copy->base;
 }
 
@@ -1687,8 +1701,30 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc,
 {
 	struct tegra_dc_state *state = to_dc_state(crtc->state);
 	struct tegra_dc *dc = to_tegra_dc(crtc);
+	struct tegra_dc_blend_state *bs;
+	struct tegra_plane *plane;
+	struct drm_plane *p;
 	u32 value;
 
+	if (!dc->soc->supports_blending) {
+		drm_for_each_plane(p, crtc->dev) {
+			if (!(p->possible_crtcs & (1 << dc->pipe)))
+				continue;
+
+			plane = to_tegra_plane(p);
+			bs = &state->blend[plane->index];
+
+			tegra_plane_writel(plane, bs->to_win_x,
+					   DC_WIN_BLEND_2WIN_X);
+
+			tegra_plane_writel(plane,bs->to_win_y,
+					   DC_WIN_BLEND_2WIN_Y);
+
+			tegra_plane_writel(plane, bs->to_win_xy,
+					   DC_WIN_BLEND_3WIN_XY);
+		}
+	}
+
 	value = state->planes << 8 | GENERAL_UPDATE;
 	tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
 	value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
drivers/gpu/drm/tegra/dc.h +21 -0
index e2831e96ea96..2bfe4d46f007 100644
@@ -18,6 +18,13 @@
 
 struct tegra_output;
 
+struct tegra_dc_blend_state {
+	u32 to_win_x;
+	u32 to_win_y;
+	u32 to_win_xy;
+	bool opaque;
+};
+
 struct tegra_dc_state {
 	struct drm_crtc_state base;
 
@@ -26,6 +33,8 @@ struct tegra_dc_state {
 	unsigned int div;
 
 	u32 planes;
+
+	struct tegra_dc_blend_state blend[3];
 };
 
 static inline struct tegra_dc_state *to_dc_state(struct drm_crtc_state *state)
@@ -649,8 +658,20 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
 #define DC_WIN_DV_CONTROL			0x70e
 
 #define DC_WIN_BLEND_NOKEY			0x70f
+#define  BLEND_WEIGHT1(x) (((x) & 0xff) << 16)
+#define  BLEND_WEIGHT0(x) (((x) & 0xff) <<  8)
+
 #define DC_WIN_BLEND_1WIN			0x710
+#define  BLEND_CONTROL_FIX    (0 << 2)
+#define  BLEND_CONTROL_ALPHA  (1 << 2)
+#define  BLEND_COLOR_KEY_NONE (0 << 0)
+#define  BLEND_COLOR_KEY_0    (1 << 0)
+#define  BLEND_COLOR_KEY_1    (2 << 0)
+#define  BLEND_COLOR_KEY_BOTH (3 << 0)
+
 #define DC_WIN_BLEND_2WIN_X			0x711
+#define  BLEND_CONTROL_DEPENDENT (2 << 2)
+
 #define DC_WIN_BLEND_2WIN_Y			0x712
 #define DC_WIN_BLEND_3WIN_XY			0x713
 
drivers/gpu/drm/tegra/fb.c +0 -12
index 1af4ef9241f1..e05fde7172f8 100644
@@ -254,18 +254,6 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
 	cmd.pitches[0] = round_up(sizes->surface_width * bytes_per_pixel,
 				  tegra->pitch_align);
 
-	/*
-	 * Early generations of Tegra (Tegra20 and Tegra30) do not support any
-	 * of the X* or *X formats, only their A* or *A equivalents. Force the
-	 * legacy framebuffer format to include an alpha component so that the
-	 * framebuffer emulation can be supported on all generations.
-	 */
-	if (sizes->surface_bpp == 32 && sizes->surface_depth == 24)
-		sizes->surface_depth = 32;
-
-	if (sizes->surface_bpp == 16 && sizes->surface_depth == 15)
-		sizes->surface_depth = 16;
-
 	cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
 						     sizes->surface_depth);
 
drivers/gpu/drm/tegra/plane.c +0 -0
index 9146aead973b..6877fba46984 100644
@@ -238,3 +238,148 @@ bool tegra_plane_format_is_yuv(unsigned int format, bool

*planar)

return false;
}
+
+static bool __drm_format_has_alpha(u32 format)
+{
+ switch (format) {
+ case DRM_FORMAT_ARGB4444:
+ case DRM_FORMAT_ARGB1555:
+ case DRM_FORMAT_RGBA5551:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_ARGB8888:
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * This is applicable to Tegra20 and Tegra30 only where the opaque formats can
+ * be emulated using the alpha formats and alpha blending disabled.
+ */
+bool tegra_plane_format_has_alpha(unsigned int format)
+{
+ switch (format) {
+ case WIN_COLOR_DEPTH_B4G4R4A4:
+ case WIN_COLOR_DEPTH_A1B5G5R5:
+ case WIN_COLOR_DEPTH_B5G5R5A1:
+ case WIN_COLOR_DEPTH_R8G8B8A8:
+ case WIN_COLOR_DEPTH_B8G8R8A8:
+ return true;
+ }
+
+ return false;
+}
+
+int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha) +{
+ switch (opaque) {
+ case WIN_COLOR_DEPTH_B5G5R5X1:
+ *alpha = WIN_COLOR_DEPTH_B5G5R5A1;
+ return 0;
+
+ case WIN_COLOR_DEPTH_X1B5G5R5:
+ *alpha = WIN_COLOR_DEPTH_A1B5G5R5;
+ return 0;
+
+ case WIN_COLOR_DEPTH_R8G8B8X8:
+ *alpha = WIN_COLOR_DEPTH_R8G8B8A8;
+ return 0;
+
+ case WIN_COLOR_DEPTH_B8G8R8X8:
+ *alpha = WIN_COLOR_DEPTH_B8G8R8A8;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+int tegra_plane_update_blending_state(struct tegra_plane *tegra,
+ struct tegra_plane_state *state)
+{
+ u32 blend_transparent = BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0);
+ u32 blend_opaque = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255);
+ struct tegra_dc_blend_state *blend_state;
+ struct tegra_dc_blend_state *win_a_state;
+ struct tegra_dc_blend_state *win_b_state;
+ struct tegra_dc_blend_state *win_c_state;
+ struct tegra_dc_state *dc_state;
+ struct drm_crtc_state *crtc_state;
+
+ crtc_state = drm_atomic_get_crtc_state(state->base.state,
+ state->base.crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+
+ dc_state = to_dc_state(crtc_state);
+ blend_state = &dc_state->blend[tegra->index];
+ blend_state->opaque = !__drm_format_has_alpha(
+ state->base.fb->format->format);
+
+ win_a_state = &dc_state->blend[0];
+ win_b_state = &dc_state->blend[1];
+ win_c_state = &dc_state->blend[2];
+
+ /* setup blending state for window A */
+
+ if (win_b_state->opaque) {
+ win_a_state->to_win_x = blend_transparent;
+ } else {
+ if (win_a_state->opaque)
+ win_a_state->to_win_x = BLEND_CONTROL_DEPENDENT;
+ else
+ win_a_state->to_win_x = BLEND_CONTROL_ALPHA;
+ }
+
+ if (win_c_state->opaque) {
+ win_a_state->to_win_y = blend_transparent;
+ } else {
+ if (win_a_state->opaque)
+ win_a_state->to_win_y = BLEND_CONTROL_DEPENDENT;
+ else
+ win_a_state->to_win_y = BLEND_CONTROL_ALPHA;
+ }
+
+ if (win_b_state->opaque || win_c_state->opaque) {
+ win_a_state->to_win_xy = blend_transparent;
+ } else {
+ if (win_a_state->opaque)
+ win_a_state->to_win_xy = BLEND_CONTROL_DEPENDENT;
+ else
+ win_a_state->to_win_xy = BLEND_CONTROL_ALPHA;
+ }
+
+ /* setup blending state for window B */
+
+ if (win_b_state->opaque)
+ win_b_state->to_win_x = blend_opaque;
+ else
+ win_b_state->to_win_x = BLEND_CONTROL_ALPHA;
+
+ if (win_c_state->opaque) {
+ win_b_state->to_win_y = blend_transparent;
+ win_b_state->to_win_xy = blend_transparent;
+ } else {
+ if (win_b_state->opaque) {
+ win_b_state->to_win_y = BLEND_CONTROL_DEPENDENT;
+ win_b_state->to_win_xy = BLEND_CONTROL_DEPENDENT;
+ } else {
+ win_b_state->to_win_y = BLEND_CONTROL_ALPHA;
+ win_b_state->to_win_xy = BLEND_CONTROL_ALPHA;
+ }
+ }
+
+ /* setup blending state for window C */
+
+ if (win_c_state->opaque) {
+ win_c_state->to_win_x = blend_opaque;
+ win_c_state->to_win_y = blend_opaque;
+ win_c_state->to_win_xy = blend_opaque;
+ } else {
+ win_c_state->to_win_x = BLEND_CONTROL_ALPHA;
+ win_c_state->to_win_y = BLEND_CONTROL_ALPHA;
+ win_c_state->to_win_xy = BLEND_CONTROL_ALPHA;
+ }
+
+ return 0;
+}

drivers/gpu/drm/tegra/plane.h +4 -0
index dca66cb95d25..13d410099772 100644
@@ -58,5 +58,9 @@ int tegra_plane_state_add(struct tegra_plane *plane,
 
 int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap);
 bool tegra_plane_format_is_yuv(unsigned int format, bool *planar);
+bool tegra_plane_format_has_alpha(unsigned int format);
+int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha);
+int tegra_plane_update_blending_state(struct tegra_plane *tegra,
+				      struct tegra_plane_state *state);
 
 #endif /* TEGRA_PLANE_H */
Signature · 1 line
2.15.1