drm/vkms: add XRGB planes composition
Add support for composing XRGB888 planes in addition to the ARGB8888 format. In the case of an XRGB plane at the top, the composition consists of copying the RGB values of a pixel from src to dst and clearing alpha channel, without the need for alpha blending operations for each pixel. Blend equations assume a completely opaque background, i.e., primary plane is not cleared before pixel blending but alpha channel is explicitly opaque (a = 0xff). Also, there is room for performance evaluation in switching pixel blend operation according to the plane format. v4: - clear alpha channel (0xff) after blend color values by pixel - improve comments on blend ops to reflect the current state - describe in the commit message future improvements for plane composition Signed-off-by: Melissa Wen <melissa.srw@gmail.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/07bcf4643d11da9480599fe1b165e478bff58b25.1619250933.git.melissa.srw@gmail.com
This commit is contained in:
parent
cac80e71cf
commit
32a1648aca
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <drm/drm_atomic.h>
|
#include <drm/drm_atomic.h>
|
||||||
#include <drm/drm_atomic_helper.h>
|
#include <drm/drm_atomic_helper.h>
|
||||||
|
#include <drm/drm_fourcc.h>
|
||||||
#include <drm/drm_gem_framebuffer_helper.h>
|
#include <drm/drm_gem_framebuffer_helper.h>
|
||||||
#include <drm/drm_gem_shmem_helper.h>
|
#include <drm/drm_gem_shmem_helper.h>
|
||||||
#include <drm/drm_vblank.h>
|
#include <drm/drm_vblank.h>
|
||||||
|
@ -64,7 +65,17 @@ static u8 blend_channel(u8 src, u8 dst, u8 alpha)
|
||||||
return new_color;
|
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;
|
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[0] = blend_channel(argb_src[0], argb_dst[0], alpha);
|
||||||
argb_dst[1] = blend_channel(argb_src[1], argb_dst[1], 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);
|
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
|
* @vaddr_src: source address
|
||||||
* @dst_composer: destination framebuffer's metadata
|
* @dst_composer: destination framebuffer's metadata
|
||||||
* @src_composer: source 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
|
* Blend the vaddr_src value with the vaddr_dst value using a pixel blend
|
||||||
* alpha blending equation, since DRM currently assumes that the pixel color
|
* equation according to the supported plane formats DRM_FORMAT_(A/XRGB8888)
|
||||||
* values have already been pre-multiplied with the alpha channel values. See
|
* and clearing alpha channel to an completely opaque background. This function
|
||||||
* more drm_plane_create_blend_mode_property(). This function uses buffer's
|
* uses buffer's metadata to locate the new composite values at vaddr_dst.
|
||||||
* 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,
|
static void blend(void *vaddr_dst, void *vaddr_src,
|
||||||
struct vkms_composer *dst_composer,
|
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 i, j, j_dst, i_dst;
|
||||||
int offset_src, offset_dst;
|
int offset_src, offset_dst;
|
||||||
|
@ -119,7 +142,9 @@ static void blend(void *vaddr_dst, void *vaddr_src,
|
||||||
|
|
||||||
pixel_src = (u8 *)(vaddr_src + offset_src);
|
pixel_src = (u8 *)(vaddr_src + offset_src);
|
||||||
pixel_dst = (u8 *)(vaddr_dst + offset_dst);
|
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++;
|
i_dst++;
|
||||||
}
|
}
|
||||||
|
@ -131,6 +156,8 @@ static void compose_plane(struct vkms_composer *primary_composer,
|
||||||
{
|
{
|
||||||
struct drm_gem_object *plane_obj;
|
struct drm_gem_object *plane_obj;
|
||||||
struct drm_gem_shmem_object *plane_shmem_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);
|
||||||
|
|
||||||
plane_obj = drm_gem_fb_get_obj(&plane_composer->fb, 0);
|
plane_obj = drm_gem_fb_get_obj(&plane_composer->fb, 0);
|
||||||
plane_shmem_obj = to_drm_gem_shmem_obj(plane_obj);
|
plane_shmem_obj = to_drm_gem_shmem_obj(plane_obj);
|
||||||
|
@ -138,8 +165,13 @@ static void compose_plane(struct vkms_composer *primary_composer,
|
||||||
if (WARN_ON(!plane_shmem_obj->vaddr))
|
if (WARN_ON(!plane_shmem_obj->vaddr))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
blend(vaddr_out, plane_shmem_obj->vaddr,
|
if (fb->format->format == DRM_FORMAT_ARGB8888)
|
||||||
primary_composer, plane_composer);
|
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_active_planes(void **vaddr_out,
|
static int compose_active_planes(void **vaddr_out,
|
||||||
|
|
|
@ -16,8 +16,9 @@ static const u32 vkms_formats[] = {
|
||||||
DRM_FORMAT_XRGB8888,
|
DRM_FORMAT_XRGB8888,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const u32 vkms_cursor_formats[] = {
|
static const u32 vkms_plane_formats[] = {
|
||||||
DRM_FORMAT_ARGB8888,
|
DRM_FORMAT_ARGB8888,
|
||||||
|
DRM_FORMAT_XRGB8888
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct drm_plane_state *
|
static struct drm_plane_state *
|
||||||
|
@ -200,8 +201,8 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
|
||||||
int nformats;
|
int nformats;
|
||||||
|
|
||||||
if (type == DRM_PLANE_TYPE_CURSOR) {
|
if (type == DRM_PLANE_TYPE_CURSOR) {
|
||||||
formats = vkms_cursor_formats;
|
formats = vkms_plane_formats;
|
||||||
nformats = ARRAY_SIZE(vkms_cursor_formats);
|
nformats = ARRAY_SIZE(vkms_plane_formats);
|
||||||
funcs = &vkms_primary_helper_funcs;
|
funcs = &vkms_primary_helper_funcs;
|
||||||
} else {
|
} else {
|
||||||
formats = vkms_formats;
|
formats = vkms_formats;
|
||||||
|
|
Loading…
Reference in New Issue