summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/vkms/vkms_composer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/vkms/vkms_composer.c')
-rw-r--r--drivers/gpu/drm/vkms/vkms_composer.c104
1 files changed, 72 insertions, 32 deletions
diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c
index 66c6842d70db..e49523866e1d 100644
--- a/drivers/gpu/drm/vkms/vkms_composer.c
+++ b/drivers/gpu/drm/vkms/vkms_composer.c
@@ -4,6 +4,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fourcc.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_vblank.h>
@@ -64,7 +65,17 @@ static u8 blend_channel(u8 src, u8 dst, u8 alpha)
return new_color;
}
-static void alpha_blending(const u8 *argb_src, u8 *argb_dst)
+/**
+ * alpha_blend - alpha blending equation
+ * @argb_src: src pixel on premultiplied alpha mode
+ * @argb_dst: dst pixel completely opaque
+ *
+ * blend pixels using premultiplied blend formula. The current DRM assumption
+ * is that pixel color values have been already pre-multiplied with the alpha
+ * channel values. See more drm_plane_create_blend_mode_property(). Also, this
+ * formula assumes a completely opaque background.
+ */
+static void alpha_blend(const u8 *argb_src, u8 *argb_dst)
{
u8 alpha;
@@ -72,8 +83,16 @@ static void alpha_blending(const u8 *argb_src, u8 *argb_dst)
argb_dst[0] = blend_channel(argb_src[0], argb_dst[0], alpha);
argb_dst[1] = blend_channel(argb_src[1], argb_dst[1], alpha);
argb_dst[2] = blend_channel(argb_src[2], argb_dst[2], alpha);
- /* Opaque primary */
- argb_dst[3] = 0xFF;
+}
+
+/**
+ * x_blend - blending equation that ignores the pixel alpha
+ *
+ * overwrites RGB color value from src pixel to dst pixel.
+ */
+static void x_blend(const u8 *xrgb_src, u8 *xrgb_dst)
+{
+ memcpy(xrgb_dst, xrgb_src, sizeof(u8) * 3);
}
/**
@@ -82,16 +101,20 @@ static void alpha_blending(const u8 *argb_src, u8 *argb_dst)
* @vaddr_src: source address
* @dst_composer: destination framebuffer's metadata
* @src_composer: source framebuffer's metadata
+ * @pixel_blend: blending equation based on plane format
*
- * Blend the vaddr_src value with the vaddr_dst value using the pre-multiplied
- * alpha blending equation, since DRM currently assumes that the pixel color
- * values have already been pre-multiplied with the alpha channel values. See
- * more drm_plane_create_blend_mode_property(). This function uses buffer's
- * metadata to locate the new composite values at vaddr_dst.
+ * Blend the vaddr_src value with the vaddr_dst value using a pixel blend
+ * equation according to the supported plane formats DRM_FORMAT_(A/XRGB8888)
+ * and clearing alpha channel to an completely opaque background. This function
+ * uses buffer's metadata to locate the new composite values at vaddr_dst.
+ *
+ * TODO: completely clear the primary plane (a = 0xff) before starting to blend
+ * pixel color values
*/
static void blend(void *vaddr_dst, void *vaddr_src,
struct vkms_composer *dst_composer,
- struct vkms_composer *src_composer)
+ struct vkms_composer *src_composer,
+ void (*pixel_blend)(const u8 *, u8 *))
{
int i, j, j_dst, i_dst;
int offset_src, offset_dst;
@@ -119,36 +142,46 @@ static void blend(void *vaddr_dst, void *vaddr_src,
pixel_src = (u8 *)(vaddr_src + offset_src);
pixel_dst = (u8 *)(vaddr_dst + offset_dst);
- alpha_blending(pixel_src, pixel_dst);
+ pixel_blend(pixel_src, pixel_dst);
+ /* clearing alpha channel (0xff)*/
+ pixel_dst[3] = 0xff;
}
i_dst++;
}
}
-static void compose_cursor(struct vkms_composer *cursor_composer,
- struct vkms_composer *primary_composer,
- void *vaddr_out)
+static void compose_plane(struct vkms_composer *primary_composer,
+ struct vkms_composer *plane_composer,
+ void *vaddr_out)
{
- struct drm_gem_object *cursor_obj;
- struct drm_gem_shmem_object *cursor_shmem_obj;
+ struct drm_gem_object *plane_obj;
+ struct drm_gem_shmem_object *plane_shmem_obj;
+ struct drm_framebuffer *fb = &plane_composer->fb;
+ void (*pixel_blend)(const u8 *p_src, u8 *p_dst);
- cursor_obj = drm_gem_fb_get_obj(&cursor_composer->fb, 0);
- cursor_shmem_obj = to_drm_gem_shmem_obj(cursor_obj);
+ plane_obj = drm_gem_fb_get_obj(&plane_composer->fb, 0);
+ plane_shmem_obj = to_drm_gem_shmem_obj(plane_obj);
- if (WARN_ON(!cursor_shmem_obj->vaddr))
+ if (WARN_ON(!plane_shmem_obj->vaddr))
return;
- blend(vaddr_out, cursor_shmem_obj->vaddr,
- primary_composer, cursor_composer);
+ if (fb->format->format == DRM_FORMAT_ARGB8888)
+ pixel_blend = &alpha_blend;
+ else
+ pixel_blend = &x_blend;
+
+ blend(vaddr_out, plane_shmem_obj->vaddr, primary_composer,
+ plane_composer, pixel_blend);
}
-static int compose_planes(void **vaddr_out,
- struct vkms_composer *primary_composer,
- struct vkms_composer *cursor_composer)
+static int compose_active_planes(void **vaddr_out,
+ struct vkms_composer *primary_composer,
+ struct vkms_crtc_state *crtc_state)
{
struct drm_framebuffer *fb = &primary_composer->fb;
struct drm_gem_object *gem_obj = drm_gem_fb_get_obj(fb, 0);
struct drm_gem_shmem_object *shmem_obj = to_drm_gem_shmem_obj(gem_obj);
+ int i;
if (!*vaddr_out) {
*vaddr_out = kzalloc(shmem_obj->base.size, GFP_KERNEL);
@@ -163,8 +196,14 @@ static int compose_planes(void **vaddr_out,
memcpy(*vaddr_out, shmem_obj->vaddr, shmem_obj->base.size);
- if (cursor_composer)
- compose_cursor(cursor_composer, primary_composer, *vaddr_out);
+ /* If there are other planes besides primary, we consider the active
+ * planes should be in z-order and compose them associatively:
+ * ((primary <- overlay) <- cursor)
+ */
+ for (i = 1; i < crtc_state->num_active_planes; i++)
+ compose_plane(primary_composer,
+ crtc_state->active_planes[i]->composer,
+ *vaddr_out);
return 0;
}
@@ -186,7 +225,7 @@ void vkms_composer_worker(struct work_struct *work)
struct drm_crtc *crtc = crtc_state->base.crtc;
struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
struct vkms_composer *primary_composer = NULL;
- struct vkms_composer *cursor_composer = NULL;
+ struct vkms_plane_state *act_plane = NULL;
bool crc_pending, wb_pending;
void *vaddr_out = NULL;
u32 crc32 = 0;
@@ -210,11 +249,11 @@ void vkms_composer_worker(struct work_struct *work)
if (!crc_pending)
return;
- if (crtc_state->num_active_planes >= 1)
- primary_composer = crtc_state->active_planes[0]->composer;
-
- if (crtc_state->num_active_planes == 2)
- cursor_composer = crtc_state->active_planes[1]->composer;
+ if (crtc_state->num_active_planes >= 1) {
+ act_plane = crtc_state->active_planes[0];
+ if (act_plane->base.plane->type == DRM_PLANE_TYPE_PRIMARY)
+ primary_composer = act_plane->composer;
+ }
if (!primary_composer)
return;
@@ -222,7 +261,8 @@ void vkms_composer_worker(struct work_struct *work)
if (wb_pending)
vaddr_out = crtc_state->active_writeback;
- ret = compose_planes(&vaddr_out, primary_composer, cursor_composer);
+ ret = compose_active_planes(&vaddr_out, primary_composer,
+ crtc_state);
if (ret) {
if (ret == -EINVAL && !wb_pending)
kfree(vaddr_out);